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

Parents
  • Hi Jared,

    SPI just transfers data, and if you are writing to a specific register on the slave device it just still just data seen from the nRF. From what I can see from the BMA400 datasheet under "SPI Interface and protocol", the address should just be the first byte when you write (then you can add another register and data byte if you like, and so on).

    Einar

  • Hello Einar,

    Thank you for the quick response! 

    I was hoping you could take a look at SPI code in the post and give me some pointers on best practices of how to make sure my data is in the proper format and length. When I create the buffer, it seems to cut off the rest of the data and only shows eight bits.

    Best regards,

    Jared

  • 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;

  • Hi,

    Yes, this is more or less what I was thinking. With one important exception that your declare a buffer of variable length, and it is also on the stack. So the first line here should probably be something like this instead:

    static uint8_t buffer[BMA4_MAX_LEN]; // BMA4_MAX_LEN should have a value that is larger than you will ever need

    Does this not work? If not, why? How does the Tx (MOSI) signal look and how is it compared to what you would expect?

  • Hello,

    This was very helpful! I have been trying to wrap my head around buffers and you have help me understand them better! The SPI MOSI on this custom board is impossible to access as there were no connections made to access the pins (sorry, I know you asked about it twice and I forgot to mention it). 

    Here is the updated code:

    static uint8_t buffer[5025]; //declared globaly
    
    BMA4_INTF_RET_TYPE bma4_spi_write(uint8_t reg_addr, const uint8_t *reg_data, uint32_t len, void *intf_ptr)
    {    
        
        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        
        };
    
        const struct spi_buf_set tx_bufs = {
        .buffers = &tx,.count = 1
        };
    
        rslt= spi_write_dt(&dev_spi, &tx_bufs);          
        return rslt;
    }

    On a side note, I was hoping to review a custom board design with Nordic. We are using the NPM1100 and the nRF52832-CIAA. Do I just ask about it on a private chat over the DevZone?

Reply
  • Hello,

    This was very helpful! I have been trying to wrap my head around buffers and you have help me understand them better! The SPI MOSI on this custom board is impossible to access as there were no connections made to access the pins (sorry, I know you asked about it twice and I forgot to mention it). 

    Here is the updated code:

    static uint8_t buffer[5025]; //declared globaly
    
    BMA4_INTF_RET_TYPE bma4_spi_write(uint8_t reg_addr, const uint8_t *reg_data, uint32_t len, void *intf_ptr)
    {    
        
        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        
        };
    
        const struct spi_buf_set tx_bufs = {
        .buffers = &tx,.count = 1
        };
    
        rslt= spi_write_dt(&dev_spi, &tx_bufs);          
        return rslt;
    }

    On a side note, I was hoping to review a custom board design with Nordic. We are using the NPM1100 and the nRF52832-CIAA. Do I just ask about it on a private chat over the DevZone?

Children
Related