ESP32 + Max30102 sensor.

b00nba
Posts: 2
Joined: Sat Aug 31, 2024 12:18 pm

ESP32 + Max30102 sensor.

Postby b00nba » Sat Aug 31, 2024 12:26 pm

I am currently working on the implementation of SVM in an embedded system (ESP32) as a stress prediction tool. Since I have failed to get FIFO memory reading to work properly, it seems I am stuck at the very beginning of my project.

I am using an ESP32 with a Max30102 sensor to get HR readings. I also use ESP-IDF and the <driver/i2c.h> library to access the needed memory registers.

From my understanding of the Max30102 sensor documentation, I have two registers, FIFO_RD_PTR and FIFO_DATA, that give me access to memory. However, accessing only FIFO_RD_PTR increments the reading pointer, so it points to the next byte I can read. I am really confused by my output.

First libraries used:

#include "driver/gpio.h"
#include "driver/i2c.h"
#include "esp_err.h"
#include "esp_log.h"
#include "esp_system.h"
MAX30102 Configuration:

MAXwrite_to_register(Mode_Configuration, 0x02); // 0x02 HR Mode, 0x03 SpO2 Mode, 0x07 Multi-LED.

// LED Power config
MAXwrite_to_register(LED_Pulse_Amplitude_RED, 0xFF);
MAXwrite_to_register(LED_Pulse_Amplitude_IR, 0xFF); // 0x24

// FIFO config
MAXwrite_to_register(FIFO_Configuration, 0x10); // Enable FIFO_ROLLOVER
// MAXwrite_to_register(FIFO_Configuration, 0x80); // Setting sampling size. Commented on purpose to disable it

// Setting Pointers and Counter to 0.
MAXwrite_to_register(FIFO_Read_Pointer, 0x00);
MAXwrite_to_register(FIFO_Write_Pointer, 0x00);
MAXwrite_to_register(Overflow_Counter, 0x00);
Memory accessing code:

uint8_t WritePointer; // Write pointer Get.
i2c_cmd_handle_t cmd = i2c_cmd_link_create();
i2c_master_start(cmd);
i2c_master_write_byte(cmd, (MAX30102_ADDRESS << 1) | I2C_MASTER_WRITE, true);
i2c_master_write_byte(cmd, FIFO_Write_Pointer, true);
i2c_master_stop(cmd);
i2c_master_cmd_begin(I2C_NUM_0, cmd, 1000 / portTICK_PERIOD_MS);
i2c_cmd_link_delete(cmd);

cmd = i2c_cmd_link_create();
i2c_master_start(cmd);
i2c_master_write_byte(cmd, (MAX30102_ADDRESS << 1) | I2C_MASTER_READ, true);
i2c_master_read_byte(cmd, &WritePointer, I2C_MASTER_NACK);
i2c_master_stop(cmd);
i2c_master_cmd_begin(I2C_NUM_0, cmd, 1000 / portTICK_PERIOD_MS);
i2c_cmd_link_delete(cmd);

// Read Pointer Get
uint8_t ReadPointer;
cmd = i2c_cmd_link_create();

i2c_master_start(cmd);
i2c_master_write_byte(cmd, (MAX30102_ADDRESS << 1) | I2C_MASTER_WRITE, true);
i2c_master_write_byte(cmd, FIFO_Read_Pointer, true);
i2c_master_stop(cmd);
i2c_master_cmd_begin(I2C_NUM_0, cmd, 1000 / portTICK_PERIOD_MS);
i2c_cmd_link_delete(cmd);

cmd = i2c_cmd_link_create();
i2c_master_start(cmd);
i2c_master_write_byte(cmd, (MAX30102_ADDRESS << 1) | I2C_MASTER_READ, true);
i2c_master_read_byte(cmd, &ReadPointer, I2C_MASTER_NACK);
i2c_master_stop(cmd);
i2c_master_cmd_begin(I2C_NUM_0, cmd, 1000 / portTICK_PERIOD_MS);
i2c_cmd_link_delete(cmd);

ESP_LOGI(SIGNAL, "Write: %i", WritePointer);
ESP_LOGI(SIGNAL, "Read: %i", ReadPointer);

// Calculate DataAmount
uint8_t DataAmount;
if (WritePointer >= ReadPointer)
{
DataAmount = (WritePointer - ReadPointer) % 32;
}
else
{
DataAmount = (32 + WritePointer - ReadPointer) % 32;
}

ESP_LOGI(SIGNAL, "Amount: %i", DataAmount);
uint8_t LED1[3];

cmd = i2c_cmd_link_create;
cmd = i2c_cmd_link_create();
i2c_master_start(cmd);
i2c_master_write_byte(cmd, (MAX30102_ADDRESS << 1) | I2C_MASTER_WRITE, true);
i2c_master_write_byte(cmd, FIFO_Data_Register, true);
i2c_master_stop(cmd);
i2c_master_cmd_begin(I2C_NUM_0, cmd, 1000 / portTICK_PERIOD_MS);
i2c_cmd_link_delete(cmd);

cmd = i2c_cmd_link_create();
i2c_master_start(cmd);
i2c_master_write_byte(cmd, (MAX30102_ADDRESS << 1) | I2C_MASTER_READ, true);

for (int i = 0; i < 3; i++)
{
i2c_master_read_byte(cmd, &LED1, i < (DataAmount - 1) ? I2C_MASTER_ACK : I2C_MASTER_NACK);
ESP_LOGI(SIGNAL, "Byte[%i]: %i", i, LED1);
}

i2c_master_stop(cmd);
i2c_master_cmd_begin(I2C_NUM_0, cmd, 1000 / portTICK_PERIOD_MS);
i2c_cmd_link_delete(cmd);

/*
cmd = i2c_cmd_link_create();
i2c_master_start(cmd);
i2c_master_write_byte(cmd, (MAX30102_ADDRESS << 1) | I2C_MASTER_WRITE, true);
i2c_master_write_byte(cmd, FIFO_Read_Pointer, true);
i2c_master_stop(cmd);
i2c_master_cmd_begin(I2C_NUM_0, cmd, 1000 / portTICK_PERIOD_MS);
i2c_cmd_link_delete(cmd);

cmd = i2c_cmd_link_create();
i2c_master_start(cmd);
i2c_master_write_byte(cmd, (MAX30102_ADDRESS << 1) | I2C_MASTER_READ, true);
i2c_master_read_byte(cmd, &ReadPointer, I2C_MASTER_NACK);
i2c_master_stop(cmd);
i2c_master_cmd_begin(I2C_NUM_0, cmd, 1000 / portTICK_PERIOD_MS);
i2c_cmd_link_delete(cmd);

ESP_LOGI(SIGNAL, "Read2: %i", ReadPointer);
*/

uint32_t HR = ((uint32_t)LED1[0] << 10) | ((uint32_t)LED1[1] << 2) | (LED1[2] >> 6);
return HR;
I understand that I can obtain one sample by "merging" 3 bytes of data into one sample since one sample from Max30102 consists of 3 bytes.

From the following function I get following example output:

I (24676) SIGNAL: Write: 5

I (24686) SIGNAL: Read: 27

I (24686) SIGNAL: Amount: 10

I (24686) SIGNAL: Byte[0]: 64

I (24696) SIGNAL: Byte[1]: 63

I (24696) SIGNAL: Byte[2]: 95

I (24696) SIGNAL: Data is: 95

I (24706) SIGNAL: Write: 6

I (24706) SIGNAL: Read: 28

I (24706) SIGNAL: Amount: 10

I (24716) SIGNAL: Byte[0]: 64

I (24716) SIGNAL: Byte[1]: 63

I (24726) SIGNAL: Byte[2]: 95

I (24726) SIGNAL: Data is: 97

I (24726) SIGNAL: Write: 7

I (24736) SIGNAL: Read: 29

I (24736) SIGNAL: Amount: 10

I (24736) SIGNAL: Byte[0]: 64

I (24746) SIGNAL: Byte[1]: 63

I (24746) SIGNAL: Byte[2]: 97

I (24746) SIGNAL: Data is: 96
No matter what I do, it seems that neither of these registers actually increments because the data in the first two bytes stays constant.

When I put my finger on the sensor, the data increases to:

I (22686) SIGNAL: Data is: 65535.
This result also does not seem correct because it remains constant. In other projects, I have seen that the sample is a 6-digit number, not a 5-digit one.

I am really confused. What am I missing here? I would greatly appreciate any advice or critique regarding my understanding of my code.

Thank you!

MicroController
Posts: 1724
Joined: Mon Oct 17, 2022 7:38 pm
Location: Europe, Germany

Re: ESP32 + Max30102 sensor.

Postby MicroController » Mon Sep 02, 2024 8:38 am

Code: Select all

for (int i = 0; i < 3; i++)
{
  i2c_master_read_byte(cmd, &LED1, i < (DataAmount - 1) ? I2C_MASTER_ACK : I2C_MASTER_NACK);
  ESP_LOGI(SIGNAL, "Byte[%i]: %i", i, LED1);
}
This successively reads 3 bytes, but stores each byte at LED1[0]; after that, LED1[0] contains the last byte read, LED1[1] and LED1[2] stay uninitialized.

Try using i2c_master_read() to read DataAmount*3 (or 6) bytes in one go into a buffer of (at least) DataAmount*3 (or 6) (<=192) bytes.

b00nba
Posts: 2
Joined: Sat Aug 31, 2024 12:18 pm

Re: ESP32 + Max30102 sensor.

Postby b00nba » Sat Sep 07, 2024 10:43 am

I have tried to do as you said, unfortunately with no effect:

Code: Select all

uint8_t LED1[DataAmount * 3];

i2c_master_read(cmd, &LED1, DataAmount * 3, false);     // I have set it to HR mode so its 3 bytes per sample.
and the output i get after placing a finger:

Code: Select all

I (89766) SIGNAL: LED1[0]: 63
I (89766) SIGNAL: LED1[1]: 255
I (89766) SIGNAL: LED1[2]: 255
I (89776) SIGNAL: LED1[3]: 63
I (89776) SIGNAL: LED1[4]: 255
I (89786) SIGNAL: LED1[5]: 255
I (89786) SIGNAL: LED1[6]: 63
I am not sure if my implementation of your idea is right though.

Who is online

Users browsing this forum: pmi2410 and 120 guests