How to use spi_write_dt

Hello,

I am attempting to use the function spi_write_dt to write data (configuration files and lots of data) to a specific register. is there a better function for SPI that would do what I need it to?

This is my read function and I think it is working...

BMA4_INTF_RET_TYPE bma4_spi_read(uint8_t reg_addr, uint8_t *reg_data, uint32_t len, void *intf_ptr)
{
    tx.buf = &reg_addr;    
    tx.len = sizeof(reg_addr);
    printf("tx.buf read = %x\n", tx.buf);
    rx.buf = (uint8_t *)reg_data;
    rx.len = len;
    rslt= spi_transceive_dt(&dev_spi, &tx_bufs, &rx_bufs);
    reg_data = rx.buf; //<-Does this do what I think?   
    return rslt;
}

I want the read to something similar to the I2C. the reg_data needs to hold the read info from the register for the program to work properly.

BMA4_INTF_RET_TYPE bma4_i2c_read(uint8_t reg_addr, uint8_t *reg_data, uint32_t len, void *intf_ptr)
{   
    uint8_t buffer[] = {reg_addr, *reg_data};         
    rslt = i2c_write_read_dt(&dev_i2c, &buffer[0], 1, reg_data, len);
    return rslt;   
}

Here is my attempted write function but I am stuck on how to put the register address in front of the data being sent.

The device tree:

&spi1 {
    // compatible = "nordic,nrf-spim";
	status = "okay";
	pinctrl-0 = <&spi1_default>;
	pinctrl-1 = <&spi1_sleep>;
	// pinctrl-names = "default", "sleep";  
    cs-gpios = <&gpio0 28 GPIO_ACTIVE_LOW>; 
    a: bma456-a@0 {        
        compatible = "revel,spi-device";
        status = "okay";       
        reg = <0>;  
        spi-max-frequency = <7000000>;
        //spi-max-frequency = <900000>;                   
    };
};

Here are some of the definitions:

#define SPI1_NODE DT_NODELABEL(a)
#define SPI_OP  SPI_OP_MODE_MASTER | SPI_WORD_SET(8) | SPI_TRANSFER_MSB
static const struct spi_dt_spec dev_spi = SPI_DT_SPEC_GET(SPI1_NODE, SPI_OP, 0);

static struct spi_buf rx;
const static struct spi_buf_set rx_bufs = {
	.buffers = &rx,
	.count = 1,
};

static struct spi_buf tx;
const static struct spi_buf_set tx_bufs = {
	.buffers = &tx,
	.count = 1,
}; 

BMA4_INTF_RET_TYPE bma4_spi_write(uint8_t reg_addr, const uint8_t *reg_data, uint32_t len, void *intf_ptr)
{    
    tx.buf = &reg_addr;    
    printf("tx.buf = %x\n", tx.buf);
    tx.len = sizeof(reg_addr);
    rslt= spi_write_dt(&dev_spi, &tx_bufs); 
    tx.buf = (uint8_t *)reg_data;
    printf("tx.buf 2= %x\n", tx.buf);
    tx.len = len;
    rslt= spi_write_dt(&dev_spi, &tx_bufs);    
    return rslt;
}

The biggest problem is trying to figure out how to write data to a specific register address. I want it to do what the I2c version does.

BMA4_INTF_RET_TYPE bma4_i2c_write(uint8_t reg_addr, const uint8_t *reg_data, uint32_t len, void *intf_ptr)
{   
    uint8_t buffer[] = {reg_addr, *reg_data};
    rslt= i2c_burst_write_dt(&dev_i2c, buffer[0], (uint8_t *)reg_data, len);
    return rslt;
}
and another write version...
BMA4_INTF_RET_TYPE bma4_spi_write(uint8_t reg_addr, const uint8_t *reg_data, uint32_t len, void *intf_ptr)
{    
    uint8_t txbuffer[2] = {reg_addr, *reg_data};
    struct spi_buf tx = {
        .buf = txbuffer,  .len = sizeof(txbuffer),};
    struct spi_buf_set tx_bufs = {
        .buffers = &tx, .count = 1,};
    rslt= spi_write_dt(&dev_spi, &tx_bufs);       
    return rslt;
}

Any help would be much appreciated!!

Best regards,

Jared

  • Hello Einar,

    Thank you for the update. I look forward to hearing back from you after the holidays.

    Here is some additional info for the time being.

    I need the SPI function to write a configuration file approximately 5016 bytes which can be broken up into smaller pieces. This is passed to the write function as a pointer to the file.I can't wrap my head around how to do that with the spi_buf and spi_buf_set structs.

    I am having trouble understanding the zephyr version spi_write_dt and having changeable sizes of transactions they seem to want the same size buffers for every SPI transaction.

    I have tried to get a different version of SPI to work using the spim examples in the ncs folder, but it ultimately wouldn't initialize the SPI and seemed like it needed a ton of different files (header and .c) to get working.

    Thanks again,

    Jared

  • Hello,

    We are severely understaffed this week because of the Christmas holidays, and Einar will have to get back to you on this next week. Sorry for the inconvenience.

    Kind regards,
    Øyvind

  • BMA4_INTF_RET_TYPE bma4_spi_write(uint8_t reg_addr, const uint8_t *reg_data, uint32_t len, void *intf_ptr)
    {    
        struct spi_buf tx[2];
        tx[0].buf = &reg_addr;
        tx[0].len = 1;  
        tx[1].buf = (uint8_t *)reg_data;
        tx[1].len = len;        
       
        const struct spi_buf_set tx_bufs = {
            .buffers = tx,
            .count = ARRAY_SIZE(tx)
        };     
        rslt= spi_write_dt(&dev_spi, &tx_bufs);       
        return rslt;
    }
    This seems to almost do what I want it to. I think I may not be addressing the write properly. I would love to just have register address in front of the data buffer, but I can't seem to wrap my head around the steps to do that.

  • Hi,

    I see burst write is supported by the BMA456 for the initialization data, then you write the 1 byte address and the multi byte data. I am not sure why yo split this up in two Tx buffers, though. This is one transaction, so I would make a single buffer and copy the data in to the first possition (index 0), and the data to the next position (index 1 and so on in case you have more data for a burst write). Other than that I don't see any problems.

    In what way does it not work? If you look at the data on the SPI line with a logic analyzer, how does it differ from what you would have expected?

  • Hello,

    Thank you for getting back to me. Your insight and help is much appreciated. My biggest issue is trying to understand how to use the buffers in the way you described. Here is another attempt and any help would be very appreciated!

      uint8_t buffer[len +1];
        buffer[0] = reg_addr;
        memcpy(&buffer[1], &reg_data, len);    
       
        /*This SPI attempts to put the register address in front of the data buffer */
        struct spi_buf tx[] = {
            {.buf = buffer,.len = len+1}, 
            //{.buf = (uint8_t *)reg_data,.len = len}, 
        };
    
        const struct spi_buf_set tx_bufs = {
        .buffers = tx,.count = 1
        };
    
        rslt= spi_write_dt(&dev_spi, &tx_bufs);          
        return rslt;

Related