SPI TX Fifo Issues

Tip / Sign in to post questions, reply, level up, and achieve exciting badges. Know more

cross mob
JoWi_4630346
Level 1
Level 1
First like given

Hi !

I'm working on interfacing the CY8CPROTO-061-04343W Wifi-BT prototyping kit to a network interface controller through SPI and I'm running into several problems.

For one the Rx buffer of the SPI fifo only ever returns 0xFF.

Secondly, the Tx buffer of the SPI fifo never seems to get populated with the value I am sending. I have tried sending dummy values and those are never properly read on the MOSI line. Any suggestions are greatly appreciated.

The relevant code is below :

main.c

int main(void){

for(;;)

        {

        cmd_send = !cmd_send;

        cyhal_gpio_write((cyhal_gpio_t)CYBSP_USER_LED, cmd_send);

        spi_nic_send( &mSPI, (uint8_t) 0x11, (uint16_t) 0x11, (uint8_t) 0x11) ;

}

spi_wrapper.c - The wrapper function I wrote over the cyhal spi functions to conform ot the message structure expected by the NIC

cy_rslt_t spi_nic_send(cyhal_spi_t *obj, uint8_t controlReg , uint16_t NICaddr, uint8_t NICdata)

{

      cy_rslt_t result = CY_RSLT_SUCCESS;

      uint32_t maskdata = 0xFF;

      uint32_t clientmsg; // message is 32bits for a standard full message length ( controlReg + address offset + data)

  /* compose message so first 8 bits are write/read command,

   * followed 16 address followed by the data */

  clientmsg = (uint32_t) (controlReg << 24) | ((uint32_t) NICaddr  << 😎  ;

  clientmsg = clientmsg | ( NICdata ) ;

  result = cyhal_spi_send(obj,clientmsg); //double check me

      return result;

}

Avenues I have tried:

I read in other threads that the fifo's (rx/tx) don't clear completely and need extra time so introducing a delay between reads and transmits helps. I added this delay in the cyhal_spi_send function and that did not help.

I have also tried switching completely to the lower level handlers specifically those defined in cy_scb_spi.c and that was not successful as well.

Below is a snippet of what the MOSI , MISO, nCS and SCLK lines are reading. Thank youSPI_issues.PNG

0 Likes
1 Solution
BragadeeshV
Moderator
Moderator
Moderator
First question asked 1000 replies posted 750 replies posted

Hi jowi_4630346​,

1. cyhal_spi_send() can only send the number of bits as defined in the cyhal_spi_init() function. Parameter bits in cyhal_spi_init() function can either be 8 or 16 bits. The following image shows 16 bit transfer.

Snippet:

cyhal_spi_init(&mSPI, mSPI_MOSI, mSPI_MISO, mSPI_SCLK, mSPI_SS, NULL, 16, CYHAL_SPI_MODE_00_MSB, false);

cyhal_spi_send(&mSPI, 0x1234);

pastedImage_3.png

You can configure to send the MSB or LSB first using cyhal_spi_mode_t of cyhal_spi_init() function.

Snippet:

cyhal_spi_init(&mSPI, mSPI_MOSI, mSPI_MISO, mSPI_SCLK, mSPI_SS, NULL, 16, CYHAL_SPI_MODE_00_LSB, false);

cyhal_spi_send(&mSPI, 0x1234);

I've shown it in binary to show that LSB is sent first (0x1234 - 0b0001 0010 0011 0100)

pastedImage_7.png

Note: cyhal_spi_send() will discard the received byte. Therefore do not use this API when you want to send and receive at the same time.

2. cyhal_spi_recv() can be used to receive one byte (or two bytes as defined in init function). It receives a byte by sending a dummy byte.

3. In case you need to send and receive at the same time, we recommend you to use either cyhal_spi_transfer() or cyhal_spi_transfer_async().

cyhal_spi_transfer() - It is a blocking function. The function doesn't return until the specified number of bytes is transferred.

cyhal_spi_transfer_async() - It is a non - blocking function. This function initiates a transfer. cyhal_spi_register_callback() can be used to check whether the transaction is complete or not (recommended method since it is non blocking).

Both of the above APIs uses internal interrupt function to carry out transaction.

4. If you need to send 32 bits in a single transaction, cyhal_spi_send() and cyhal_spi_recv()  should not be used. Please use cyhal_spi_transfer_async() or cyhal_spi_transfer(). Split the 32 bit integer into four 8 bits values and perform the transaction.

Example using cyhal_spi_transfer():

cyhal_spi_t mSPI; // Declare as global variable

int main()

{

//BSP is initialized before this

    cy_rslt_t result;

    uint32_t cmd_send = 0x12345678;

    uint8_t txbuffer[4]  = {0,0,0,0};

    txbuffer[3] = (uint8_t)(0xFF & cmd_send);//LSB

    txbuffer[2] = (uint8_t)((0xFF00 & cmd_send) >> 8 );

    txbuffer[1] = (uint8_t)((0xFF0000 & cmd_send) >> 16 );

    txbuffer[0] = (uint8_t)(cmd_send >> 24u);//MSB

    uint8_t rxbuffer[4];

__enable_irq();

   result = cyhal_spi_init(&mSPI, mSPI_MOSI, mSPI_MISO, mSPI_SCLK, mSPI_SS, NULL, 8, CYHAL_SPI_MODE_00_MSB, false);

    if(result != CY_SCB_SPI_SUCCESS)

    {

    handle_error();

    }

cyhal_spi_transfer(&mSPI,txbuffer,4,rxbuffer,4,0xff);

for(;;);

}

Note: For proper functioning of cyhal_spi_transfer() please declare SPI object as a global variable for now. This will be fixed in future releases of hal.

pastedImage_18.png

Example using cyhal_spi_transfer_async and callbacks :

    uint32_t cmd_send = 0x12345678;

    uint8_t txbuffer[4]  = {0,0,0,0};

    txbuffer[3] = (uint8_t)(0xFF & cmd_send);//LSB

    txbuffer[2] = (uint8_t)((0xFF00 & cmd_send) >> 8 );

    txbuffer[1] = (uint8_t)((0xFF0000 & cmd_send) >> 16 );

    txbuffer[0] = (uint8_t)(cmd_send >> 24u);//MSB

    uint8_t rxbuffer[4];

__enable_irq();

/*Configuring the  SPI interface:  Specify the SPI interface pins, frame size, SPI Motorola mode and master/slave mode*/

rslt = cyhal_spi_init(&mSPI, P10_0, P10_1, P10_2, P10_3, NULL, 8,CYHAL_SPI_MODE_00_MSB, false);

/*Set the data rate to 1 Mbps*/

rslt = cyhal_spi_set_frequency(&mSPI, spi_frequency);

/*Register a callback function to be called when the interrupt fires*/

cyhal_spi_register_callback(&mSPI,

(cyhal_spi_event_callback_t) spi_interrupt_callback, NULL);

/*Enable the events that will trigger the call back function*/

cyhal_spi_enable_event(&mSPI, CYHAL_SPI_IRQ_DONE, 3, true);

/*Master: Initiates a data transfer. Slave: Prepares the slave for data transfer. It is a non-blocking function */

if (CY_RSLT_SUCCESS ==  cyhal_spi_transfer_async(&mSPI, txbuffer, 4,rxbuffer, 4)) {

/*SPI Master: Transfer started. SPI Slave: Prepares for data transfer*/

}

//Callback for ISR

void spi_interrupt_callback(void *arg, cyhal_gpio_irq_event_t event) {

(void *) arg;

if ((event & CYHAL_SPI_IRQ_DONE) != 0u) {

/*Transmission is complete. Handle Event*/

}

}

Hope this helps!

Regards,

Bragadeesh

Regards,
Bragadeesh

View solution in original post

1 Reply
BragadeeshV
Moderator
Moderator
Moderator
First question asked 1000 replies posted 750 replies posted

Hi jowi_4630346​,

1. cyhal_spi_send() can only send the number of bits as defined in the cyhal_spi_init() function. Parameter bits in cyhal_spi_init() function can either be 8 or 16 bits. The following image shows 16 bit transfer.

Snippet:

cyhal_spi_init(&mSPI, mSPI_MOSI, mSPI_MISO, mSPI_SCLK, mSPI_SS, NULL, 16, CYHAL_SPI_MODE_00_MSB, false);

cyhal_spi_send(&mSPI, 0x1234);

pastedImage_3.png

You can configure to send the MSB or LSB first using cyhal_spi_mode_t of cyhal_spi_init() function.

Snippet:

cyhal_spi_init(&mSPI, mSPI_MOSI, mSPI_MISO, mSPI_SCLK, mSPI_SS, NULL, 16, CYHAL_SPI_MODE_00_LSB, false);

cyhal_spi_send(&mSPI, 0x1234);

I've shown it in binary to show that LSB is sent first (0x1234 - 0b0001 0010 0011 0100)

pastedImage_7.png

Note: cyhal_spi_send() will discard the received byte. Therefore do not use this API when you want to send and receive at the same time.

2. cyhal_spi_recv() can be used to receive one byte (or two bytes as defined in init function). It receives a byte by sending a dummy byte.

3. In case you need to send and receive at the same time, we recommend you to use either cyhal_spi_transfer() or cyhal_spi_transfer_async().

cyhal_spi_transfer() - It is a blocking function. The function doesn't return until the specified number of bytes is transferred.

cyhal_spi_transfer_async() - It is a non - blocking function. This function initiates a transfer. cyhal_spi_register_callback() can be used to check whether the transaction is complete or not (recommended method since it is non blocking).

Both of the above APIs uses internal interrupt function to carry out transaction.

4. If you need to send 32 bits in a single transaction, cyhal_spi_send() and cyhal_spi_recv()  should not be used. Please use cyhal_spi_transfer_async() or cyhal_spi_transfer(). Split the 32 bit integer into four 8 bits values and perform the transaction.

Example using cyhal_spi_transfer():

cyhal_spi_t mSPI; // Declare as global variable

int main()

{

//BSP is initialized before this

    cy_rslt_t result;

    uint32_t cmd_send = 0x12345678;

    uint8_t txbuffer[4]  = {0,0,0,0};

    txbuffer[3] = (uint8_t)(0xFF & cmd_send);//LSB

    txbuffer[2] = (uint8_t)((0xFF00 & cmd_send) >> 8 );

    txbuffer[1] = (uint8_t)((0xFF0000 & cmd_send) >> 16 );

    txbuffer[0] = (uint8_t)(cmd_send >> 24u);//MSB

    uint8_t rxbuffer[4];

__enable_irq();

   result = cyhal_spi_init(&mSPI, mSPI_MOSI, mSPI_MISO, mSPI_SCLK, mSPI_SS, NULL, 8, CYHAL_SPI_MODE_00_MSB, false);

    if(result != CY_SCB_SPI_SUCCESS)

    {

    handle_error();

    }

cyhal_spi_transfer(&mSPI,txbuffer,4,rxbuffer,4,0xff);

for(;;);

}

Note: For proper functioning of cyhal_spi_transfer() please declare SPI object as a global variable for now. This will be fixed in future releases of hal.

pastedImage_18.png

Example using cyhal_spi_transfer_async and callbacks :

    uint32_t cmd_send = 0x12345678;

    uint8_t txbuffer[4]  = {0,0,0,0};

    txbuffer[3] = (uint8_t)(0xFF & cmd_send);//LSB

    txbuffer[2] = (uint8_t)((0xFF00 & cmd_send) >> 8 );

    txbuffer[1] = (uint8_t)((0xFF0000 & cmd_send) >> 16 );

    txbuffer[0] = (uint8_t)(cmd_send >> 24u);//MSB

    uint8_t rxbuffer[4];

__enable_irq();

/*Configuring the  SPI interface:  Specify the SPI interface pins, frame size, SPI Motorola mode and master/slave mode*/

rslt = cyhal_spi_init(&mSPI, P10_0, P10_1, P10_2, P10_3, NULL, 8,CYHAL_SPI_MODE_00_MSB, false);

/*Set the data rate to 1 Mbps*/

rslt = cyhal_spi_set_frequency(&mSPI, spi_frequency);

/*Register a callback function to be called when the interrupt fires*/

cyhal_spi_register_callback(&mSPI,

(cyhal_spi_event_callback_t) spi_interrupt_callback, NULL);

/*Enable the events that will trigger the call back function*/

cyhal_spi_enable_event(&mSPI, CYHAL_SPI_IRQ_DONE, 3, true);

/*Master: Initiates a data transfer. Slave: Prepares the slave for data transfer. It is a non-blocking function */

if (CY_RSLT_SUCCESS ==  cyhal_spi_transfer_async(&mSPI, txbuffer, 4,rxbuffer, 4)) {

/*SPI Master: Transfer started. SPI Slave: Prepares for data transfer*/

}

//Callback for ISR

void spi_interrupt_callback(void *arg, cyhal_gpio_irq_event_t event) {

(void *) arg;

if ((event & CYHAL_SPI_IRQ_DONE) != 0u) {

/*Transmission is complete. Handle Event*/

}

}

Hope this helps!

Regards,

Bragadeesh

Regards,
Bragadeesh