Basic read LSM6D33 accelerometer via SPI using ESP32-C3 luatos

Gusti_made
Posts: 2
Joined: Thu Dec 14, 2023 9:26 am

Basic read LSM6D33 accelerometer via SPI using ESP32-C3 luatos

Postby Gusti_made » Thu Dec 14, 2023 9:54 am

Hello, I'm a beginner at SPI protocol, I want to read LSM6D33 accelerometer data, and start reading WHO_AM_I register, here is the datasheet
https://www.mouser.com/datasheet/2/389/ ... 849769.pdf , and here is datasheet of ESP32-C3 luatos esp32C3-CORE https://wiki.luatos.org/chips/esp32c3/board.html
I have written the code, but the output is not expected (0xFF) I think based on datasheet the output must 0x69 , here is my code

Code: Select all

#include <string.h>
#include <stdio.h>
#include <freertos/FreeRTOS.h>
#include <freertos/task.h>
#include <driver/spi_master.h>
#include <driver/gpio.h>

#define SPI_BUS SPI2_HOST
#define DMA_CHAN 1
#define PIN_NUM_MISO 10
#define PIN_NUM_MOSI 3
#define PIN_NUM_CLK  2
#define PIN_NUM_CS   7

#define LSM6DS33_WHO_AM_I_REG 0x0F
#define LSM6DS33_READ_CMD 0x80   //0b100000

spi_device_handle_t lsm6ds33_spi;


void lsm6s3dtr_spi_init() {
    esp_err_t ret;
    spi_bus_config_t bus_config = {
        .miso_io_num = PIN_NUM_MISO,
        .mosi_io_num = PIN_NUM_MOSI,
        .sclk_io_num = PIN_NUM_CLK,
        .quadwp_io_num = -1,
        .quadhd_io_num = -1
    };

    ret = spi_bus_initialize(SPI_BUS, &bus_config, SPI_DMA_CH_AUTO);
    ESP_ERROR_CHECK(ret);

    spi_device_interface_config_t dev_config = {
        .command_bits=0,
        .address_bits=0,
        .dummy_bits=0,
        .clock_speed_hz = 1000000,           // SPI clock frequency
        .mode = 0,                           // SPI mode 0
        .spics_io_num = PIN_NUM_CS,
        .queue_size = 1,
    };

    spi_bus_add_device(SPI_BUS, &dev_config, &lsm6ds33_spi);

    vTaskDelay(100 / portTICK_PERIOD_MS);
}

uint8_t lsm6ds3tr_read_register(uint8_t reg) {
    spi_transaction_t t;
    memset(&t, 0, sizeof(t));
    t.flags = SPI_TRANS_USE_TXDATA | SPI_TRANS_USE_RXDATA;
    t.length = 8;
    t.tx_data[0] = LSM6DS33_READ_CMD | reg;

    esp_err_t ret = spi_device_polling_transmit(lsm6ds33_spi, &t);
    if (ret != ESP_OK) {
        printf("SPI transmit error: %s\n", esp_err_to_name(ret));
        return 0;
    }
    return t.rx_data[0];
}

void lsm6s3dtr_task(void *pvParameter) {
    while (1) 
    {

        uint8_t who_am_i = lsm6ds3tr_read_register(0x0F); // WHO_AM_I register
        printf("LSM6DS3TR WHO_AM_I adalah: 0x%02X\n", who_am_i);

        // Add your LSM6DS33 read and processing code here

        vTaskDelay(1000 / portTICK_PERIOD_MS);
    }
}

void app_main() 
{
    lsm6s3dtr_spi_init();

    xTaskCreate(lsm6s3dtr_task, "LSM6DS3TR_task", 2048, NULL, 10, NULL);
}
I have checked the accelerometer can work well using arduino code, so the sensor guaranteed to work well.

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

Re: Basic read LSM6D33 accelerometer via SPI using ESP32-C3 luatos

Postby MicroController » Thu Dec 14, 2023 2:35 pm

Code: Select all

    spi_transaction_t t;
    memset(&t, 0, sizeof(t));
    t.flags = SPI_TRANS_USE_TXDATA | SPI_TRANS_USE_RXDATA;
    t.length = 8;
    t.tx_data[0] = LSM6DS33_READ_CMD | reg;
This implicitly performs an 8-bit 'full-duplex' transaction, i.e. 8 bits are sent and at the same time 8 bits are received, which then is the data you find in rx_data. What you want is actually to first write 8 bits and then transfer (read) 8 more bits which contain the result of the read.
You have a at least two options to get the desired result (see also https://docs.espressif.com/projects/esp ... ansactions):
a) make use of 'command phase' (8 bits) + 'read phase' (8 bits) to first send a 'command' and only then read the following data,
b) manually craft a 16-bit write (0xff00 + (LSM6DS33_READ_CMD | reg)), then do a 16-bit transaction thereby receiving 16-bit read data, of which you simply discard the first byte.

Gusti_made
Posts: 2
Joined: Thu Dec 14, 2023 9:26 am

Re: Basic read LSM6D33 accelerometer via SPI using ESP32-C3 luatos

Postby Gusti_made » Fri Dec 15, 2023 9:37 am

MicroController wrote:
Thu Dec 14, 2023 2:35 pm

Code: Select all

    spi_transaction_t t;
    memset(&t, 0, sizeof(t));
    t.flags = SPI_TRANS_USE_TXDATA | SPI_TRANS_USE_RXDATA;
    t.length = 8;
    t.tx_data[0] = LSM6DS33_READ_CMD | reg;
This implicitly performs an 8-bit 'full-duplex' transaction, i.e. 8 bits are sent and at the same time 8 bits are received, which then is the data you find in rx_data. What you want is actually to first write 8 bits and then transfer (read) 8 more bits which contain the result of the read.
You have a at least two options to get the desired result (see also https://docs.espressif.com/projects/esp ... ansactions):
a) make use of 'command phase' (8 bits) + 'read phase' (8 bits) to first send a 'command' and only then read the following data,
b) manually craft a 16-bit write (0xff00 + (LSM6DS33_READ_CMD | reg)), then do a 16-bit transaction thereby receiving 16-bit read data, of which you simply discard the first byte.
Hi,
thanks for replying, honestly I'm beginner on this so I use chatGPT to assist me,

for option a) I write the code like this

Code: Select all

uint8_t lsm6ds33_read_register(uint8_t reg_addr) {
    esp_err_t ret;
    spi_transaction_t t;
    memset(&t, 0, sizeof(t));

    // Command phase: Send the register address to read
    uint8_t cmd_data = LSM6DS33_READ_CMD | reg_addr;
    t.length = 8;
    t.tx_buffer = &cmd_data;
    t.user = (void *)0;
    ret = spi_device_polling_transmit(spi, &t);
    assert(ret == ESP_OK);

    // Read phase: Receive the data
    uint8_t rx_data;
    t.length = 8;
    t.rx_buffer = &rx_data;
    ret = spi_device_polling_transmit(spi, &t);
    assert(ret == ESP_OK);

    // Extract the received data
    return rx_data;
}
but the output is still same 0xFF

I also try option b) and here is my code

Code: Select all

uint8_t lsm6ds33_read_register(uint8_t reg_addr) {
    esp_err_t ret;
    spi_transaction_t t;
    memset(&t, 0, sizeof(t));

    // Manually craft a 16-bit write command
    uint16_t cmd_data = 0xFF00 | (LSM6DS33_READ_CMD | reg_addr);
    t.length = 16;
    t.tx_data[0] = (cmd_data >> 8) & 0xFF;
    t.tx_data[1] = cmd_data & 0xFF;
    t.user = (void *)0;
    ret = spi_device_polling_transmit(spi, &t);
    assert(ret == ESP_OK);

    // Extract the received data (discard the first byte)
    uint8_t rx_data = t.rx_data[1];

    return rx_data;
}
and I get Guru Meditation Error: Core 0 panic'ed (Load access fault). Exception was unhandled

Who is online

Users browsing this forum: Baidu [Spider] and 99 guests