Page 1 of 1

[solved] how to bme280 spi read?

Posted: Tue Jan 03, 2023 1:17 am
by steeveone
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!

Re: how to bme280 spi read?

Posted: Tue Jan 03, 2023 2:53 am
by ESP_michael
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.

Re: how to bme280 spi read?

Posted: Tue Jan 03, 2023 2:24 pm
by steeveone
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

Re: how to bme280 spi read?

Posted: Tue Jan 03, 2023 6:14 pm
by steeveone
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 3846 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 3846 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 3846 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?

Re: how to bme280 spi read?

Posted: Thu Jan 05, 2023 10:39 am
by steeveone
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;
}