[solved] how to bme280 spi read?

steeveone
Posts: 10
Joined: Fri Jan 10, 2020 10:17 pm

[solved] how to bme280 spi read?

Postby steeveone » Tue Jan 03, 2023 1:17 am

Hello,
i am trying to use the bosh bme280 driver to interface the sensor trought spi.
this is how i init the spi line:

Code: Select all

#define CLK_PIN     GPIO_NUM_18
#define MISO_PIN    GPIO_NUM_19
#define MOSI_PIN    GPIO_NUM_23
#define CS_PIN      GPIO_NUM_5

spi_device_handle_t spi2;
void spi_master_init()
{
    esp_err_t ret;
    spi_bus_config_t buscfg={
        .miso_io_num = MISO_PIN,
        .mosi_io_num = MOSI_PIN,
        .sclk_io_num = CLK_PIN,
        .quadwp_io_num = -1,
        .quadhd_io_num = -1,
        .max_transfer_sz = 32,
    };
    ret = spi_bus_initialize(VSPI_HOST, &buscfg, SPI_DMA_CH_AUTO);
    ESP_ERROR_CHECK(ret);
    spi_device_interface_config_t devcfg={
        .clock_speed_hz = 1000000,  // 1 MHz
        .mode = 0,                  //SPI mode 0
        .spics_io_num = CS_PIN,
        .queue_size = 1,
        .pre_cb = NULL,
        .post_cb = NULL
    };
    ESP_ERROR_CHECK(spi_bus_add_device(VSPI_HOST, &devcfg, &spi2));
}

and this is the function required from driver to read from spi

Code: Select all

int8_t user_spi_read(uint8_t reg_addr, uint8_t *reg_data, uint32_t len, void *intf_ptr)
{
    int8_t rslt = 0; /* Return 0 for Success, non-zero for failure */

    /*
     * The parameter intf_ptr can be used as a variable to select which Chip Select pin has
     * to be set low to activate the relevant device on the SPI bus
     */

    /*
     * Data on the bus should be like
     * |----------------+---------------------+-------------|
     * | MOSI           | MISO                | Chip Select |
     * |----------------+---------------------|-------------|
     * | (don't care)   | (don't care)        | HIGH        |
     * | (reg_addr)     | (don't care)        | LOW         |
     * | (don't care)   | (reg_data[0])       | LOW         |
     * | (....)         | (....)              | LOW         |
     * | (don't care)   | (reg_data[len - 1]) | LOW         |
     * | (don't care)   | (don't care)        | HIGH        |
     * |----------------+---------------------|-------------|
     */
    spi_transaction_t t;
    memset(&t, 0, sizeof(t));       //Zero out the transaction
    t.length = 8;
    t.rxlength = 8*len;
    t.tx_buffer = NULL;
    t.rx_buffer = reg_data;
    t.addr = reg_addr;

    rslt = spi_device_polling_transmit(spi2, &t);
    ESP_LOGI(TAG, "spi read rslt %s addr is %i data is %s len is %lu", esp_err_to_name(rslt), reg_addr,reg_data, len);

    if (rslt ==  ESP_OK)
        return 0;
    return rslt;
}

there is for sure a problem in how i do the transaction, because this is what i read:

Code: Select all

I (1829) example: spi read rslt ESP_OK addr is 208 data is � len is 1
I (2829) example: spi read rslt ESP_OK addr is 208 data is � len is 1
I (3829) example: spi read rslt ESP_OK addr is 208 data is � len is 1
i don't know how to proceed, i don't understand spi transaction well, any help is appirciated!
Last edited by steeveone on Thu Jan 05, 2023 10:50 am, edited 1 time in total.

ESP_michael
Posts: 37
Joined: Mon Aug 28, 2017 10:25 am

Re: how to bme280 spi read?

Postby ESP_michael » Tue Jan 03, 2023 2:53 am

When using full duplex mode, the rxlength should also include the length of MOSI.

Now the first byte received is supposed to be the MISO while you are sending reg_addr.

Please try increase the len and receive buffer size and see if the hardware starts receiving data from 2nd byte.

steeveone
Posts: 10
Joined: Fri Jan 10, 2020 10:17 pm

Re: how to bme280 spi read?

Postby steeveone » Tue Jan 03, 2023 2:24 pm

hello,

if i put rxlength to 8+(8*len) i get

Code: Select all

E (828) spi_master: check_trans_valid(694): rx length > tx length in full duplex mode
I (828) example: spi read rslt ERROR addr is 208 data is  len is 1
if i increase t.lenght to 8+(8*len) i get 1 byte of junk.
If i increase both t.lenght and t.rxlenght to 8+(8*len) i read 2 bytes of junk.

any other suggestion?
thanks

steeveone
Posts: 10
Joined: Fri Jan 10, 2020 10:17 pm

Re: how to bme280 spi read?

Postby steeveone » Tue Jan 03, 2023 6:14 pm

i have a 2 probe scope, triggered by !CS in attach what i see with the following transaction:

Code: Select all

    spi_transaction_t t;
    memset(&t, 0, sizeof(t));       //Zero out the transaction
    t.length = 8+8*len;
    t.rxlength = 8*len;
    t.tx_buffer = NULL;
    t.rx_buffer = reg_data;
    t.addr = reg_addr;
Clk line, i see 16 clock pulses and seems right
20230103_181158.jpg
20230103_181158.jpg (12.36 MiB) Viewed 4131 times
Miso line, after 8 click cycles it goes to 0, i suppose this is why i read 0xFF from it
20230103_180515.jpg
20230103_180515.jpg (8.09 MiB) Viewed 4131 times
Mosi line, it transmit for all 16 clock cycles and seems incorrect to me
20230103_180412.jpg
20230103_180412.jpg (10.24 MiB) Viewed 4131 times
--- edit ---
with following transaction

Code: Select all

spi_transaction_t t;
    memset(&t, 0, sizeof(t));       //Zero out the transaction
    t.length = 8+8*len;
    t.rxlength = 8*len;
    t.tx_buffer = &reg_addr;
    t.rx_buffer = reg_data;
i get some data in mosi/miso lines but in reg_data i still read 255... any ideas?

steeveone
Posts: 10
Joined: Fri Jan 10, 2020 10:17 pm

Re: how to bme280 spi read?

Postby steeveone » Thu Jan 05, 2023 10:39 am

solved. i attach code for future reference

Code: Select all

int8_t user_spi_read(uint8_t reg_addr, uint8_t *reg_data, uint32_t len, void *intf_ptr)
{
    int8_t rslt = 0; /* Return 0 for Success, non-zero for failure */

    spi_transaction_t t;
    memset(&t, 0, sizeof(t));       //Zero out the transaction
    t.length = 8+8*len;
    t.rxlength = 8*len;
    t.tx_buffer = &reg_addr;

    char * buf = malloc(len+1);
    memset(buf, 0, len+1);
    t.rx_buffer = buf;

    rslt = spi_device_polling_transmit(spi2, &t);
   
    memmove(reg_data, &buf[1], len);
    free(buf);
    
    if (rslt ==  ESP_OK)
        return 0;
    return rslt;
}

int8_t user_spi_write(uint8_t reg_addr, const uint8_t *reg_data, uint32_t len, void *intf_ptr)
{
    int8_t rslt = 0; /* Return 0 for Success, non-zero for failure */

    spi_transaction_t t;
    memset(&t, 0, sizeof(t));       //Zero out the transaction
    t.length = 8*len+8;

    char * buf = malloc(len+1);
    buf[0] = reg_addr;
    memcpy(&buf[1], reg_data, len);
    t.tx_buffer = buf;
    rslt = spi_device_polling_transmit(spi2, &t);
    free(buf);   
    //had to add this delay, without it the bme280_init(&dev) return -6 BME280_E_NVM_COPY_FAILED
    //you can set  uint8_t try_run = 50; into bme280_soft_reset function in bme280.c and remove this delay
    vTaskDelay(pdMS_TO_TICKS(10)); 
    
    if (rslt ==  ESP_OK)
        return 0;
    return rslt;
}

Who is online

Users browsing this forum: Gaston1980, Google [Bot], Majestic-12 [Bot] and 257 guests