2023-04-15 08:56 AM - edited 2023-11-20 08:03 AM
Dear all,
A newbie here. Any help is much appreciated.
I appreciate this is an STM forum and while I am using ESP-IDF to interface with STM's lsm303, I believe the problem is caused by my incorrect configuration of the STM lsm303 sensor. Hence any guidance is much appreciated.
I am using an LSM303 sensor, connected via I2C to an ESP32 and programmed via ESP-IDF to retrieve the magnetometer and accelerometer data. I was previously using an Ardunio and the the Pololu LSM303 library and everything worked with the same wiring.
However, when using bare i2c in ESP-IDF, it seems like I have messed something up as the magnetometer data freezes unless I power cycle the LSM303 (rebooting the ESP32 doesn't seem to change the readings, while unplugging the VCC of the lsm303 and plugging it back in again results in new readings).
Here is the code, which reads the data at 50 Hz via I2C. I have checked various sources including the stack exchange electrical engineering forum and others but I am worried I missed something that may actually be quite obvious.
I have followed someone's advice to set "ODR[0:3]" to 220hz, which I believe I did as confirmed by a i2cdump (I assume it is chip 0x1E register 0x00) has hex 0x70, which is equivalent to 0b01110000.
Here is the i2c dump for reference:
Just for reference, here is the Code related to the i2c implementation, using ESP-IDF
#include "lsm303v2_clement.h"
#include "driver/i2c.h"
#include "esp_log.h"
#include "freertos/FreeRTOS.h"
#define LSM303_ADDR_ACCEL 0x19 // Accelerometer I2C address //0x19 seems to work
#define LSM303_ADDR_MAG 0x1E // Magnetometer I2C address
// Register addresses
#define LSM303_CTRL_REG1_A 0x20
#define LSM303_CTRL_REG4_A 0x23
#define LSM303_OUT_X_L_A 0x28
#define LSM303_CTRL_REG1_M 0x20
#define LSM303_CTRL_REG2_M 0x21
#define LSM303_CTRL_REG3_M 0x22
#define LSM303_CTRL_REG4_M 0x23
#define LSM303_OUT_X_H_M 0x03
//self added test
#define LSM303_OUT_X_L_M 0x04
//self added for setting to cont mode
#define LSM303_SR_REG_M 0x09
#define LSM303_MR_REG_M 0x02
// Circular buffer settings
#define BUFFER_SIZE 100 // 50 Hz * 2 seconds = 100 samples
#define BUFFER_MASK (BUFFER_SIZE - 1)
static lsm303_data_t buffer[BUFFER_SIZE];
static volatile uint32_t buffer_head = 0;
//static esp_err_t i2c_init(void);
//static esp_err_t lsm303_read_bytes(uint8_t addr, uint8_t reg, uint8_t *data, uint8_t len);
//new code
static esp_err_t i2c_init(void)
{
i2c_config_t conf = {
.mode = I2C_MODE_MASTER,
.sda_io_num = GPIO_NUM_21,
.sda_pullup_en = GPIO_PULLUP_ENABLE,
.scl_io_num = GPIO_NUM_22,
.scl_pullup_en = GPIO_PULLUP_ENABLE,
.master.clk_speed = 400000
};
i2c_param_config(I2C_NUM_0, &conf);
return i2c_driver_install(I2C_NUM_0, conf.mode, 0, 0, 0);
}
static esp_err_t lsm303_read_bytes(uint8_t addr, uint8_t reg, uint8_t *data, uint8_t len)
{
if (len == 0) {
return ESP_OK;
}
i2c_cmd_handle_t cmd = i2c_cmd_link_create();
i2c_master_start(cmd);
i2c_master_write_byte(cmd, (addr << 1) | I2C_MASTER_WRITE, true);
i2c_master_write_byte(cmd, reg, true);
i2c_master_start(cmd);
i2c_master_write_byte(cmd, (addr << 1) | I2C_MASTER_READ, true);
if (len > 1) {
i2c_master_read(cmd, data, len - 1, I2C_MASTER_ACK);
}
i2c_master_read_byte(cmd, data + len - 1, I2C_MASTER_NACK);
i2c_master_stop(cmd);
esp_err_t ret = i2c_master_cmd_begin(I2C_NUM_0, cmd, pdMS_TO_TICKS(10)); //was 1000ms
i2c_cmd_link_delete(cmd);
return ret;
}
static esp_err_t lsm303_write_bytes(uint8_t addr, const uint8_t *data, uint8_t len)
{
if (len == 0) {
return ESP_OK;
}
i2c_cmd_handle_t cmd = i2c_cmd_link_create();
i2c_master_start(cmd);
i2c_master_write_byte(cmd, (addr << 1) | I2C_MASTER_WRITE, true);
i2c_master_write(cmd, data, len, true);
i2c_master_stop(cmd);
esp_err_t ret = i2c_master_cmd_begin(I2C_NUM_0, cmd, pdMS_TO_TICKS(10));
i2c_cmd_link_delete(cmd);
return ret;
}
//end of new code
void lsm303_init()
{
i2c_init();
// Set up the accelerometer
uint8_t accel_config[2] = {LSM303_CTRL_REG1_A, 0x47}; // 50 Hz, normal mode, all axes enabled
lsm303_write_bytes(LSM303_ADDR_ACCEL, accel_config, 2);
vTaskDelay(pdMS_TO_TICKS(100)); //self added for debugging
// Set up the magnetometer
//uint8_t mag_config[5] = {LSM303_CTRL_REG1_M, 0x14, 0x00, 0x00, 0x00}; // 50 Hz, low power mode, continuous conversion
uint8_t mag_config[5] = {LSM303_CTRL_REG1_M, 0x1C, 0x00, 0x00, 0x00}; // 50 Hz, high power mode, continuous conversion
lsm303_write_bytes(LSM303_ADDR_MAG, mag_config, 5);
//doesn't seem to fix the problem either
//lsm303_write_bytes(LSM303_ADDR_MAG, LSM303_MR_REG_M, 0x00);
uint8_t data[2] = {LSM303_MR_REG_M, 0x00};
esp_err_t retfix2 = lsm303_write_bytes(LSM303_ADDR_MAG, data , 1);
if (retfix2 != ESP_OK) {
// Handle error
ESP_LOGE("lsm303_init - fix2", "Fix2 failed, error: %d", retfix2);
} else {
ESP_LOGI("lsm303_init - fix2", "Fix2 Success");
}
//lets try the ODR[0:3] to magnetometer 220hz fix suggested by the stack forum
//uint8_t ODRdata = 0x06; // Set ODR to 220Hz
uint8_t dataODR[2] = {0x00, 0x70}; //data was 0x06, now changed to 0x70
esp_err_t retODR = lsm303_write_bytes(LSM303_ADDR_MAG, dataODR, 2);
if (retODR != ESP_OK) {
// Handle error
ESP_LOGE("lsm303_init - ODR", "Set ODR to 220hz failed, error: %d", retODR);
} else {
ESP_LOGI("lsm303_init - ODR", "Success");
}
/*uint8_t data = 0x94; // bits 7-6 set to 10
esp_err_t ret = i2c_master_write_byte_data(I2C_MASTER_NUM, LSM303_MAG_ADDR, LSM303_MAG_CTRL_REG5, data);
if (ret != ESP_OK) {
printf("Failed to set LSM303 magnetometer data rate: %d\n", ret);
}*/
}
void sensor_read_task(void *arg)
{
TickType_t xLastWakeTime = xTaskGetTickCount();
while (1)
{
lsm303_data_t data;
// Read magnetometer data //note: originally it was accel data first but I decided to swap it around to see if it fixes the problem
uint8_t mag_data[6];
lsm303_read_bytes(LSM303_ADDR_MAG, LSM303_OUT_X_H_M, mag_data, 6); //was X_H_M
data.mx = (int16_t)(mag_data[0] << 8 | mag_data[1]);
data.my = (int16_t)(mag_data[2] << 8 | mag_data[3]);
data.mz = (int16_t)(mag_data[4] << 8 | mag_data[5]);
/*lsm303_read_bytes(LSM303_ADDR_MAG, LSM303_OUT_X_L_M, mag_data, 6); //was X_H_M
data.mx = (int16_t)(mag_data[1] << 8 | mag_data[0]);
data.my = (int16_t)(mag_data[3] << 8 | mag_data[2]);
data.mz = (int16_t)(mag_data[5] << 8 | mag_data[4]);*/
vTaskDelay(pdMS_TO_TICKS(10));
// Read accelerometer data
uint8_t accel_data[6];
lsm303_read_bytes(LSM303_ADDR_ACCEL, LSM303_OUT_X_L_A | 0x80, accel_data, 6);
data.ax = (int16_t)(accel_data[1] << 8 | accel_data[0]);
data.ay = (int16_t)(accel_data[3] << 8 | accel_data[2]);
data.az = (int16_t)(accel_data[5] << 8 | accel_data[4]);
// Save the data to the circular buffer
buffer[buffer_head & BUFFER_MASK] = data;
buffer_head++;
ESP_LOGI("lsm303v2 - sensor_read_task", "accel data %s mag data %s", accel_data, mag_data);
ESP_LOGI("lsm303v2 - sensor_read_task", "Accel Data %hd, %hd, %hd Mag data %hd, %hd, %hd", data.ax, data.ay, data.az, data.mx, data.my, data.mz);
// Sleep for 20 ms (50 Hz)
vTaskDelayUntil(&xLastWakeTime, pdMS_TO_TICKS(20));
//for testing purposes, reducing to 7Hz
//vTaskDelayUntil(&xLastWakeTime, pdMS_TO_TICKS(143));
}
}
Solved! Go to Solution.
2023-04-15 10:21 PM
Solved:
Needed to change: Chip: 0x1E Address: 0x02 Data: 0x0
I ended up going through the data sheet and checking the i2c dump 1 by 1 and found out!
The reason for this is in P.38 of the data sheet: https://www.st.com/resource/en/datasheet/lsm303dlhc.pdf
MR_REG_M(02h) needs to be set to 0,0 to be in continuous conversion mode (the i2cdump revealed it was 0x03, which is 0b11.... in binary, representing sleep mode), but we want 0b00.
Thanks for all the help.
2023-04-15 10:21 PM
Solved:
Needed to change: Chip: 0x1E Address: 0x02 Data: 0x0
I ended up going through the data sheet and checking the i2c dump 1 by 1 and found out!
The reason for this is in P.38 of the data sheet: https://www.st.com/resource/en/datasheet/lsm303dlhc.pdf
MR_REG_M(02h) needs to be set to 0,0 to be in continuous conversion mode (the i2cdump revealed it was 0x03, which is 0b11.... in binary, representing sleep mode), but we want 0b00.
Thanks for all the help.
2024-09-30 03:17 PM
Hi there,
I am having the same issues with an ESP32-S3 and the LSM303 device. Would you mind posting your full code resolution please?
Thanks in advance.