SPI slave with variable message length

cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

SPI slave with variable message length

Jump to solution
4,124 Views
antoine_monmarc
Contributor V

Hello,

I'm using S32K148EVB board.
The SW uses:
- FreeRTOS
- SPI slave (spi_pal with lpspi0 using DMA)
- additional Output pin PTA30 for Spi Slave to request the master to start SPI communication
- additional Input pin PTA6 for Spi Slave, connected to SPI CS pin and configure as interrupt

Sending data from Slave to Master works fine.
Detecting CS pin change with PTA6 Interrupt works fine.

Our application protocol starts with 1 byte with value 0x55 and as variable length (with lenght indicated in the payload).

For reception I'm calling API SPI_SlaveTransfer(SPI_INSTANCE, slave_send, slave_receive, BUFFER_SIZE) and wait for the master to poll the SPI.


The issue is that we don't know in advance the size of the packet that the master will send.
So the spi callback will not be triggered unless all the bytes are received.

What would be the best solution for our case (being able to receive any length, any time)? Should we wait for CS to be disabled before reading the DMA rx buffer?

I would like to avoid modifying as much as possible the spi_pal and lpspi drivers provided in the SDK.


There seems to be no clear answer from all the NXP Community thread I read:

my first thread: https://community.nxp.com/message/1160105

https://community.nxp.com/message/1123908
https://community.nxp.com/message/1068750

0 Kudos
1 Solution
3,445 Views
razva_tilimpea
NXP Employee
NXP Employee

Hi,

So when pin interrupt occurs you can't get all frames?

I suppose the root cause is the interrupt priorities. Pins interrupt priority is higher than lpspi interrupt. In this case when you get the rising edge on PCS some SPI frames are still in the hardware fifo.

Can you try to use interrupt manager API to change the interrupts priorities for LPSPI and pins?

Best regards,

Razvan

View solution in original post

0 Kudos
7 Replies
1,508 Views
mdecandia
Contributor III

Hi all,

is this true also for dspi on MK6x kinetis microcontrollers with or without DMA enabled? To enable variable message len on dspi slave we need to use an external GPIO to signal received message has been totally sent?

Thank you,

Michele

 

 

0 Kudos
3,445 Views
antoine_monmarc
Contributor V

We are using the following configuration for interrupt

  • LPSPI_DRV_SlaveInit => INT_SYS_SetPriority(g_lpspiIrqId[instance], 2);
  • EDMA_DRV_Init => INT_SYS_SetPriority(irqNumber, 3);
  • GPIO Interrupt => INT_SYS_SetPriority(SPI_CS_PORT_IRQn, 1);

Any combinaison will give the same result.

FreeRTOSConfig.h:

#define configLIBRARY_LOWEST_INTERRUPT_PRIORITY  0x0F

#define configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY 0x01

0 Kudos
3,445 Views
antoine_monmarc
Contributor V

Changing Interrupt priority like this will do the job:

  • LPSPI_DRV_SlaveInit => INT_SYS_SetPriority(g_lpspiIrqId[instance], 2);
  • EDMA_DRV_Init => INT_SYS_SetPriority(irqNumber, 1);
  • GPIO Interrupt => INT_SYS_SetPriority(SPI_CS_PORT_IRQn, 3);

Calling the LPSPI_DRV_SlaveTransfer function direclty in the IRQ handler will lost the first received byte. To avoid this, we call the LPSPI_DRV_SlaveTransfer right after the transmission is complete (CS pin disabled) so it is ready for next time.

0 Kudos
3,445 Views
razva_tilimpea
NXP Employee
NXP Employee

Hi,

Ok I didn't know this that you are using the DMA mode, but the point is to abort the transfer only when you are sure that you have processed all frames.

Sorry for this workaround, but from hardware perspective is hard to know when to finish the transfer.

Best regards,

Razvan

0 Kudos
3,445 Views
antoine_monmarc
Contributor V

Hello,

We have implemented the CS pin detection IRQ. The CS pin state change works fine.

In the IRQ handler we are doing the following:

static void spi_cs_detection(void)
{
if(bIsSpiCsPinActive()==true)
{
LPSPI_DRV_SlaveAbortTransfer(SPI_OVER_LPSPI00_INSTANCE);
memset(slave_receive, 0xFF, BUFFER_SIZE);
memset(slave_send, 0xFF, BUFFER_SIZE);
LPSPI_DRV_SlaveTransfer(SPI_OVER_LPSPI00_INSTANCE, slave_send, slave_receive, BUFFER_SIZE);
}
else
{
LPSPI_DRV_SlaveAbortTransfer(SPI_OVER_LPSPI00_INSTANCE);
LPSPI_DRV_ReadRXBuffer(SPI_OVER_LPSPI00_INSTANCE);
}

PINS_DRV_ClearPinIntFlagCmd(SPI_CS_PORT, SPI_CS_PIN);
}

Problem is, the rxBuff is always truncated:

pastedImage_5.png

Also, we always get a LPSPI_TRANSMIT_ERROR in the LPSPI_DRV_SlaveIRQHandler:

pastedImage_6.png

0 Kudos
3,446 Views
razva_tilimpea
NXP Employee
NXP Employee

Hi,

So when pin interrupt occurs you can't get all frames?

I suppose the root cause is the interrupt priorities. Pins interrupt priority is higher than lpspi interrupt. In this case when you get the rising edge on PCS some SPI frames are still in the hardware fifo.

Can you try to use interrupt manager API to change the interrupts priorities for LPSPI and pins?

Best regards,

Razvan

0 Kudos
3,445 Views
razva_tilimpea
NXP Employee
NXP Employee

Hi,

The solution for your problem is on second post.

Because the LPSPI hardware doesn't have any method to detect when CS is negated you must use another GPIO pin to monitor CS pin and when the transfer is done (CS switch from low to high) you can call transfer abort function. 

Best regards,

Razvan

0 Kudos