SPI write and read Multiple bytes.

Hi All,

         I am using nrf52840 in my project and working on sdk 17.0.2. I have an SPI based IC MAX3421E connected to my device. I am able to read and write single bytes through SPI code. But I am having issues with reading and writing multiple bytes. I am not getting proper response when I try to read or write multiple bytes. The sample code from the library and the converted ones are attached below:-

Sample code from MAX3421 library:-

//SAMPLE CODE FROM MAX3421 LIBRARY


BYTE SPI_wr( BYTE data )
{
    SSPBUF = data;              // write byte to SSP2BUF register
    while( !SSPSTATbits.BF );   // wait until bus cycle completes
    return ( SSPBUF );          //
}

/* Single host register write   */
void MAXreg_wr(BYTE reg, BYTE val)
{
    Select_MAX3421E;
    SPI_wr ( reg + 2 ); //set WR bit and send register number
    SPI_wr ( val );
    Deselect_MAX3421E;
}


/* multiple-byte write */
/* returns a pointer to a memory position after last written */
char* MAXbytes_wr( BYTE reg, BYTE nbytes, char* data )
{
    Select_MAX3421E;    //assert SS
    SPI_wr ( reg + 2 ); //set W/R bit and select register   
    while( nbytes ) {                
        SPI_wr( *data );    // send the next data byte
        data++;             // advance the pointer
        nbytes--;
    }
    Deselect_MAX3421E;  //deassert SS
    return( data );
}



/* Single host register read        */
BYTE MAXreg_rd( BYTE reg )    
{
 BYTE tmp;
    Select_MAX3421E;
    SPI_wr ( reg );         //send register number
    tmp = SPI_wr ( 0x00 );  //send empty byte, read register contents
    Deselect_MAX3421E; 
    return (tmp);
}



/* multiple-bytes register read                             */
/* returns a pointer to a memory position after last read   */
char* MAXbytes_rd ( BYTE reg, BYTE nbytes, char* data )
{
    Select_MAX3421E;    //assert SS
    SPI_wr ( reg );     //send register number
    while( nbytes ) {
        *data = SPI_wr ( 0x00 );    //send empty byte, read register contents
        data++;
        nbytes--;
    }
    Deselect_MAX3421E;  //deassert SS
    return( data );   
}

The above code has been converted to NRF library format.

void max3421eRegWr(uint8_t reg, uint8_t data)
{
    SPIWriteLength = 2; 
    SPIReadLength = 0; 
    
    spi_tx_buf[0] = reg + 0x02 ; 
    spi_tx_buf[1] = data; 
	
    spi_xfer_done = false;
    nrf_gpio_pin_clear(SPI_SS_PIN);
	
    nrf_drv_spi_transfer(&m_spi, spi_tx_buf, SPIWriteLength, spi_rx_buf, SPIReadLength);
    while(spi_xfer_done == false){}; // this flag will be set to true in the spi interrupt handler function
	
    nrf_gpio_pin_set(SPI_SS_PIN);
    vTaskDelay(1000);
}			 


uint8_t max3421eRegRd(uint8_t reg)
{
    spi_tx_buf[0] = reg;
    spi_tx_buf[1] = 0x00;
        
    spi_xfer_done = false;

    nrf_gpio_pin_clear(SPI_SS_PIN);

    nrf_drv_spi_transfer(&m_spi, spi_tx_buf, 2, spi_rx_buf, 2);
    while(spi_xfer_done == false){};

    nrf_gpio_pin_set(SPI_SS_PIN);

    return spi_rx_buf[1];
}

char* MAXbytes_rd ( uint8_t reg, uint8_t nbytes, char* data )
{
    spi_tx_buf[0] = reg;

    nrf_gpio_pin_clear(SPI_SS_PIN);

    nrf_drv_spi_transfer(&m_spi, spi_tx_buf, 1, spi_rx_buf, 0);

    spi_tx_buf[0] = 0x00;

    while( nbytes ) {
    *data = nrf_drv_spi_transfer(&m_spi, spi_tx_buf, 1, spi_rx_buf, 0);
        data++;
        nbytes--;
    }
        nrf_gpio_pin_set(SPI_SS_PIN);
    return( data );   
}

uint8_t dataOut[80];

void  max3421e_writebytes(uint8_t reg, uint8_t nbytes, char* data)
{
      nrf_gpio_pin_clear(SPI_SS_PIN);

      dataOut[0] = reg+0x02;			
      nrf_drv_spi_transfer(&m_spi, dataOut, SPIWriteLength+1, spi_rx_buf, SPIReadLength);

    while( nbytes ) {                
        //SPI_wr( *data );    // send the next data byte
        nrf_drv_spi_transfer(&m_spi, data, 1, spi_rx_buf, 0);
        data++;             // advance the pointer
        nbytes--;
    }

    nrf_gpio_pin_set(SPI_SS_PIN);

}

I feel something is wrong with my "max3421e_writebytes" and "MAXbytes_rd" function. Need some help on this.

Thanks & Regards,

Snehal

Parents
  • Hi,

    You should make sure to check the error codes returned from functions like nrf_drv_spi_transfer(), in your functions you do not do this. It also looks like you have misunderstood the return value from this function in MAXbytes_rd(), it only returns an error code, not the data received by the SPI. Normally, the SPI driver is non-blocking, which means that you have to wait for a transfer to complete before starting a new one, for instance by waiting for the spi_xfer_done flag like you have in one of the functions. 

    It should be sufficient to call nrf_drv_spi_transfer() once with the requested number of TX and RX bytes. Note that RX and TX buffer will be filled at the same time, meaning that if you want to receive a number of bytes after all data in the TX buffer have been clocked out, you need to set the RX length to TX length + number of expected RX bytes, the bytes clocked into the RX buffer while clocking out TX buffer can be ignored.

    Best regards,
    Jørgen

  • Hi,

    The warning is likely because you are passing the reference to 'data' to nrf_drv_spi_transfer(), while data is already a pointer in the input to the function.

    I think your approach of translating each line of the original function to a similar line in nRF code is not optimal, you should rather understand how the SPI driver works and rewrite the entire function to give the same functionality.

    I would do something like this:

    char* MAXbytes_rd ( uint8_t reg, uint8_t nbytes, char* data )
    {
    
    spi_tx_buf[0] = reg;    //Only need to send the actual register address, the driver will automatically clock out OCR byte to clock in data in RX buffer
    
    nrf_gpio_pin_clear(SPI_SS_PIN);
    
    nrf_drv_spi_transfer(&m_spi, spi_tx_buf, 1, data, nbytes);  // No need for a while loop handling each byte separately. SPI driver will fill buffer with requested number of bytes (nbytes)
    
    while(!spi_xfer_done)   // Wait for transfer to complete
    spi_xfer_done = false;
    
    nrf_gpio_pin_set(SPI_SS_PIN);
    
    
    return( data );
    
    }

    Best regards,
    Jørgen

  • Hi Jorgen, can you help me with converting this function??

    I did conversion like mentioned above but its not working. Please help.

    char* MAXbytes_wr( BYTE reg, BYTE nbytes, char* data )
    {
    Select_MAX3421E; //assert SS
    SPI_wr ( reg + 2 ); //set W/R bit and select register
    while( nbytes ) {
    SPI_wr( *data ); // send the next data byte
    data++; // advance the pointer
    nbytes--;
    }
    Deselect_MAX3421E; //deassert SS
    return( data );
    }

    Regards,
    Snehal

  • Something like this would be equivalent for Nordic TWI driver API:

    char* MAXbytes_wr( uint8_t reg, uint8_t nbytes, char* data )
    {
    	static uint8_t spi_tx_buf[nbytes + 1];	// Declare buffer that can hold reg address + data
    	spi_tx_buf[0] = reg;					// Set first byte of TX buffer to register address
    	memcpy(&spi_tx_buf[1], data, nbytes);	// Copy data to TX buffer
    	
    	nrf_gpio_pin_clear(SPI_SS_PIN);			// assert SS
    
    	nrf_drv_spi_transfer(&m_spi, spi_tx_buf, nbytes+1 , NULL, 0);  // No need for a while loop handling each byte separately. SPI driver will transfer all bytes in one go.
    
    	while(!spi_xfer_done)					// Wait for transfer to complete
    	{
    		spi_xfer_done = false;
    	}
    
    	nrf_gpio_pin_set(SPI_SS_PIN);			// deassert SS
    	return( data );
    }

Reply
  • Something like this would be equivalent for Nordic TWI driver API:

    char* MAXbytes_wr( uint8_t reg, uint8_t nbytes, char* data )
    {
    	static uint8_t spi_tx_buf[nbytes + 1];	// Declare buffer that can hold reg address + data
    	spi_tx_buf[0] = reg;					// Set first byte of TX buffer to register address
    	memcpy(&spi_tx_buf[1], data, nbytes);	// Copy data to TX buffer
    	
    	nrf_gpio_pin_clear(SPI_SS_PIN);			// assert SS
    
    	nrf_drv_spi_transfer(&m_spi, spi_tx_buf, nbytes+1 , NULL, 0);  // No need for a while loop handling each byte separately. SPI driver will transfer all bytes in one go.
    
    	while(!spi_xfer_done)					// Wait for transfer to complete
    	{
    		spi_xfer_done = false;
    	}
    
    	nrf_gpio_pin_set(SPI_SS_PIN);			// deassert SS
    	return( data );
    }

Children
Related