LPSPI and EDMA RT1050 Too Slow

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

LPSPI and EDMA RT1050 Too Slow

1,948 Views
kamal1
Contributor III

 

Hello,

 

I am working on a custom board based off the MIMXRT1050-EVK demo board using Keilv5 Pro edition. I am currently testing the LPSPI with EDMA and am following the example projects.

 

My issue is that the LPSPI EDMA is too slow for my project to function correctly. I need to transfer 1280 bits of data using the EDMA to LPSPI transmit buffer at 13Mhz in under 100us. Right now, it is taking about 124us according to my read out.

 

I set a probe on the LPSPI clock and I notice there is a 300ns delay between every 32 bits sent, shown in the picture below. Why is there a delay every 32 bits? Is there any way I can remove the delay or speed up the EDMA or LPSPI without changing the LPSPI clock frequency?

 

The function I am using to make the EDMA transfer to LPSPI is LPSPI_MasterTransferEDMA(). In this function is a bunch of LPSPI API calls and configuration. I am currently testing adjusting this function to increase the speed of the transfer or remove the delay between the 32 bits. 

 

I also have another issue where the LPSPI_MasterTransferEDMA() function does not start sending data right way. I am calling this function within an interrupt, it then takes 18us to begin transferring data while still in that same interrupt. I need it to begin immediately. Is there a flag or something that needs to be set to start the EDMA transfer? 

 

My questions:

  1. Why is there a delay after every 32 bits sent through the LPSPI? Can that be removed?
  2. Why is the EDMA LPSPI transfer not beginning right away? 

 

nxp.PNG

0 Kudos
9 Replies

1,937 Views
jeremyzhou
NXP Employee
NXP Employee

Hi,
Thank you for your interest in NXP Semiconductor products and for the opportunity to serve you.
1) Why is there a delay after every 32 bits sent through the LPSPI? Can that be removed?
-- Whether you mean that there's a stalled period during transmitting the whole 64 bytes, maybe you can try to increase the txWatermark since transfers will stall when transmit FIFO is empty or receive FIFO is full.
2) Why is the EDMA LPSPI transfer not beginning right away?
-- It needs the developer to optimize and simplify the code by himself.
Have a great day,
TIC

-------------------------------------------------------------------------------
Note:
- If this post answers your question, please click the "Mark Correct" button. Thank you!

 

- We are following threads for 7 weeks after the last post, later replies are ignored
Please open a new thread and refer to the closed one, if you have a related question at a later point in time.
-------------------------------------------------------------------------------

0 Kudos

1,929 Views
kamal1
Contributor III

Also can you confirm if this LPSPI on the Cortex M7 can only send 32 bits at a time? Can this be adjusted to send 16 bits? 

I read in the manual that we can only send data 32 bits at a time, so if I send 16 bit it will fill the other 16 bits with zeros. It would be better for me if I could send 16 bits, a short, instead of 32 bits, a word.

0 Kudos

1,896 Views
jeremyzhou
NXP Employee
NXP Employee

Hi,
1) Also can you confirm if this LPSPI on the Cortex M7 can only send 32 bits at a time? Can this be adjusted to send 16 bits?
-- Yes, it will transfer 16-bits in the unit after setting bitsPerFrame is 16, just as the following figure shows.

jeremyzhou_0-1620724876483.png

 


Have a great day,
TIC

-------------------------------------------------------------------------------
Note:
- If this post answers your question, please click the "Mark Correct" button. Thank you!

 

- We are following threads for 7 weeks after the last post, later replies are ignored
Please open a new thread and refer to the closed one, if you have a related question at a later point in time.
-------------------------------------------------------------------------------

0 Kudos

1,886 Views
kamal1
Contributor III

@jeremyzhou 

I have that working now the issue I am having is that if I send in write data too fast I dont see the correct data on the output SPI device. If I include a delay of 3 microseconds after each write or wait for the tx fifo to empty, I do get the correct data. My application does not have enough time to include these delays, how can I avoid them?

I think this delay is needed to account for the stall when the tx fifo gets full. The LPSPI_CFGR1_NOSTALL_MASK is cleared which means Transfers will stall when the transmit FIFO is empty or the receive FIFO is full. Whye is the TX fifo ever getting full? Even after setting the tx watermark to 0, I still have the same issue.

How can I get the LPSPI to transmit data immediately without needing a delay? 

 

Below is my LPSPI configuration code and example for loop for sending data based of the LPSPI example projects. I have set the RXMSK flasg to ignore the RX fifo. My only goal is to send data to the transmit fifo of the LPSPI quickly.

 

 

CLOCK_SetMux(kCLOCK_LpspiMux, LPSPI_CLOCK_SOURCE_SELECT);

CLOCK_SetDiv(kCLOCK_LpspiDiv, LPSPI_CLOCK_SOURCE_DIVIDER);

 

lpspi_master_config_t masterConfig;

 

/*Master config*/

masterConfig.baudRate = 13000000;

masterConfig.bitsPerFrame = 16; //same issue using 32 bitsPerFrame

masterConfig.cpol = kLPSPI_ClockPolarityActiveHigh;

masterConfig.cpha = kLPSPI_ClockPhaseFirstEdge;

masterConfig.direction = kLPSPI_MsbFirst;

 

masterConfig.pcsToSckDelayInNanoSec = 1000000000 / masterConfig.baudRate;

masterConfig.lastSckToPcsDelayInNanoSec = 1000000000 / masterConfig.baudRate;

masterConfig.betweenTransferDelayInNanoSec = 1000000000 / masterConfig.baudRate;

 

masterConfig.whichPcs = kLPSPI_Pcs0;

masterConfig.pcsActiveHighOrLow = kLPSPI_PcsActiveLow;

 

masterConfig.pinCfg = kLPSPI_SdiInSdoOut;

masterConfig.dataOutConfig = kLpspiDataOutRetained;

 

LPSPI_MasterInit(LPSPI1, &masterConfig, LPSPI_CLOCK_FREQ);

 

LPSPI_Enable(LPSPI1, false);

LPSPI1->CFGR1 &= (~LPSPI_CFGR1_NOSTALL_MASK);

LPSPI_Enable(LPSPI1, true);

 

LPSPI_FlushFifo(LPSPI1, true, true);

 

LPSPI1->TCR =

(LPSPI1->TCR &

~(LPSPI_TCR_CONT_MASK | LPSPI_TCR_CONTC_MASK | LPSPI_TCR_RXMSK_MASK | LPSPI_TCR_PCS_MASK)) |

LPSPI_TCR_CONT(1) | LPSPI_TCR_CONTC(0) | LPSPI_TCR_RXMSK(1) | LPSPI_TCR_TXMSK(0) | LPSPI_TCR_PCS(EXAMPLE_LPSPI_MASTER_PCS_FOR_INIT);

 

LPSPI_EnableInterrupts(EXAMPLE_LPSPI_MASTER_BASEADDR, kLPSPI_RxInterruptEnable);

/*TCR is also shared the FIFO , so wait for TCR written.*/

while (LPSPI_GetTxFifoCount(EXAMPLE_LPSPI_MASTER_BASEADDR) != 0) { }

 

for(int a=0; a<80; a++) // this function only works correctly if I include the 3 microsecond delay or wait loop

{

LPSPI_WriteData(LPSPI1, data1);

//mirocsecDelay(3);

//while (LPSPI_GetTxFifoCount(LPSPI1) == 16) { }

}

 

 

 

void LPSPI1_IRQHandler(void)

{

if (masterRxCount < TRANSFER_SIZE)

{

/* First, disable the interrupts to avoid potentially triggering another interrupt

* while reading out the RX FIFO as more data may be coming into the RX FIFO. We'll

* re-enable the interrupts EXAMPLE_LPSPI_MASTER_BASEADDRd on the LPSPI state after reading out the FIFO.

*/

LPSPI_DisableInterrupts(LPSPI1, kLPSPI_RxInterruptEnable);

 

while (LPSPI_GetRxFifoCount(LPSPI1))

{

/*Read out the data*/

masterRxData[masterRxCount] = LPSPI_ReadData(LPSPI1);

 

masterRxCount++;

 

if (masterRxCount == TRANSFER_SIZE)

{

break;

}

}

 

/* Re-enable the interrupts only if rxCount indicates there is more data to receive,

* else we may get a spurious interrupt.

* */

if (masterRxCount < TRANSFER_SIZE)

{

/* Set the TDF and RDF interrupt enables simultaneously to avoid race conditions */

LPSPI_EnableInterrupts(LPSPI1, kLPSPI_RxInterruptEnable);

}

}

 

/*Update rxWatermark. There isn't RX interrupt for the last datas if the RX count is not greater than rxWatermark.*/

if ((TRANSFER_SIZE - masterRxCount) <= g_masterRxWatermark)

{

LPSPI1->FCR =

(LPSPI1->FCR & (~LPSPI_FCR_RXWATER_MASK)) |

LPSPI_FCR_RXWATER(((TRANSFER_SIZE - masterRxCount) > 1) ? ((TRANSFER_SIZE - masterRxCount) - 1U) : (0U));

}

 

if (masterTxCount < TRANSFER_SIZE)

{

while ((LPSPI_GetTxFifoCount(LPSPI1) < g_masterFifoSize) &&

(masterTxCount - masterRxCount < g_masterFifoSize))

{

/*Write the word to TX register*/

LPSPI_WriteData(LPSPI1, masterTxData[masterTxCount]);

++masterTxCount;

 

if (masterTxCount == TRANSFER_SIZE)

{

break;

}

}

}

 

/* Check if we're done with this transfer.*/

if ((masterTxCount == TRANSFER_SIZE) && (masterRxCount == TRANSFER_SIZE))

{

isMasterTransferCompleted = true;

/* Complete the transfer and disable the interrupts */

LPSPI_DisableInterrupts(LPSPI1, kLPSPI_AllInterruptEnable);

}

/* Add for ARM errata 838869, affects Cortex-M4, Cortex-M4F Store immediate overlapping

exception return operation might vector to incorrect interrupt */

#if defined __CORTEX_M && (__CORTEX_M == 4U)

__DSB();

#endif

}

0 Kudos

1,876 Views
jeremyzhou
NXP Employee
NXP Employee

Hi,

Thanks for your reply.
1) How can I get the LPSPI to transmit data immediately without needing a delay?
-- 1) The steps of modifying the lpspi_edma_b2b_transfer_master demo (SDK library version is 2.8.5)
a) in lpspi_edma_b2b_transfer_master.c, increae the number of tranmit data and transfer baudrate.
#define TRANSFER_SIZE 160U //64U /* Transfer dataSize */
#define TRANSFER_BAUDRATE 15000000U /* Transfer baudrate - 15M */
b) in the LPSPI_MasterGetDefaultConfig() function in the fsl_lpspi.c,
increase the baudRate and bits of per frame, meanwhile, decrease the delay value, below illustrates the modified LPSPI_MasterGetDefaultConfig() function.

void LPSPI_MasterGetDefaultConfig(lpspi_master_config_t *masterConfig)
{
    assert(masterConfig != NULL);

    /* Initializes the configure structure to zero. */
    (void)memset(masterConfig, 0, sizeof(*masterConfig));

    masterConfig->baudRate     = 15000000;
    masterConfig->bitsPerFrame = 32; //8;
    masterConfig->cpol         = kLPSPI_ClockPolarityActiveHigh;
    masterConfig->cpha         = kLPSPI_ClockPhaseFirstEdge;
    masterConfig->direction    = kLPSPI_MsbFirst;

    masterConfig->pcsToSckDelayInNanoSec        = 1000000000U / masterConfig->baudRate;//masterConfig->baudRate * 2U;
    masterConfig->lastSckToPcsDelayInNanoSec    = 1000000000U / masterConfig->baudRate;//masterConfig->baudRate * 2U;
    masterConfig->betweenTransferDelayInNanoSec = 1000000000U / masterConfig->baudRate;//masterConfig->baudRate * 2U;

    masterConfig->whichPcs           = kLPSPI_Pcs0;
    masterConfig->pcsActiveHighOrLow = kLPSPI_PcsActiveLow;

    masterConfig->pinCfg        = kLPSPI_SdiInSdoOut;
    masterConfig->dataOutConfig = kLpspiDataOutRetained;
}


2) Testing result
After the above modification, the SPI can transfer 160 bytes in 86.3 us which only takes about 1 us longer than the none-delay condition (as Fig 1 shows). And the interval time between per frame is 56 ns (as Fig 2 shows).

In a word, the transmit speed is enough fast for your requirement.

Note: The testing platform is MIMXRT1050.

jeremyzhou_0-1620804211269.png

Fig 1

jeremyzhou_1-1620804253605.png

Fig 2

Have a great day,
TIC

-------------------------------------------------------------------------------
Note:
- If this post answers your question, please click the "Mark Correct" button. Thank you!

 

- We are following threads for 7 weeks after the last post, later replies are ignored
Please open a new thread and refer to the closed one, if you have a related question at a later point in time.
-------------------------------------------------------------------------------

 

 

 

 

0 Kudos

1,146 Views
KaveriA
Contributor I

Hi @jeremyzhou 

 

Can you tell me how to check the master clock on the board ? 

I am using the MIMXRT1050 eval board. Example code is LPSPI edma b2b code.

 

Thanks 

Kaveri A

0 Kudos

1,920 Views
jeremyzhou
NXP Employee
NXP Employee

Hi,

Thanks for your reply.
I'm a bit confused with your question, so I'd like to suggest if you can provide more information, for instance: use the logic analyzer to capture the SPI transmit since it's easy to analyze, introduce the testing steps in brief.
Looking forward to your reply.
Have a great day,
TIC

-------------------------------------------------------------------------------
Note:
- If this post answers your question, please click the "Mark Correct" button. Thank you!

 

- We are following threads for 7 weeks after the last post, later replies are ignored
Please open a new thread and refer to the closed one, if you have a related question at a later point in time.
-------------------------------------------------------------------------------

 

0 Kudos

1,941 Views
kamal1
Contributor III

Here is my code for the configuration of the LPSPI:

/*Set clock source for LPSPI*/
CLOCK_SetMux(kCLOCK_LpspiMux, LPSPI_CLOCK_SOURCE_SELECT);
CLOCK_SetDiv(kCLOCK_LpspiDiv, LPSPI_CLOCK_SOURCE_DIVIDER);

uint32_t errorCount;
uint32_t i;
lpspi_master_config_t masterConfig;
lpspi_slave_config_t slaveConfig;

uint8_t txWatermark;

/*Set up the transfer data*/
for (i = 0; i < TRANSFER_SIZE; i++)
{
masterTxData[i] = i % 256;
masterRxData[i] = 0;
}

/*Master config*/
masterConfig.baudRate = 13000000;
masterConfig.bitsPerFrame = 32;
masterConfig.cpol = kLPSPI_ClockPolarityActiveHigh;
masterConfig.cpha = kLPSPI_ClockPhaseFirstEdge;
masterConfig.direction = kLPSPI_MsbFirst;

masterConfig.pcsToSckDelayInNanoSec = 1000000000 / masterConfig.baudRate;
masterConfig.lastSckToPcsDelayInNanoSec = 1000000000 / masterConfig.baudRate;
masterConfig.betweenTransferDelayInNanoSec = 1000000000 / masterConfig.baudRate;

masterConfig.whichPcs = kLPSPI_Pcs0;
masterConfig.pcsActiveHighOrLow = kLPSPI_PcsActiveLow;

masterConfig.pinCfg = kLPSPI_SdiInSdoOut;
masterConfig.dataOutConfig = kLpspiDataOutRetained;

LPSPI_MasterInit(LPSPI1, &masterConfig, LPSPI_CLOCK_FREQ);

/////////////////////////////////////////// DMA STUFF ////////////////////////////////////////////
//LPSPI EDMA MASTER TESTING
edma_config_t config;

/*Init DMA for example.*/
DMAMUX_Init(EXAMPLE_LPSPI_MASTER_DMAMUX_BASEADDR);
EDMA_GetDefaultConfig(&config);
EDMA_Init(EXAMPLE_LPSPI_MASTER_DMA_LPSPI_BASEADDR, &config);

/* Request DMA channels for TX & RX. */
DMAMUX_SetSource(EXAMPLE_LPSPI_MASTER_DMAMUX_BASEADDR, EXAMPLE_LPSPI_MASTER_TX_DMA_LPSPI_CHANNEL, EXAMPLE_LPSPI_MASTER_TX_DMA_SOURCE);
DMAMUX_SetSource(EXAMPLE_LPSPI_MASTER_DMAMUX_BASEADDR, EXAMPLE_LPSPI_MASTER_RX_DMA_LPSPI_CHANNEL, EXAMPLE_LPSPI_MASTER_RX_DMA_SOURCE);
DMAMUX_EnableChannel(EXAMPLE_LPSPI_MASTER_DMAMUX_BASEADDR, EXAMPLE_LPSPI_MASTER_TX_DMA_LPSPI_CHANNEL);
DMAMUX_EnableChannel(EXAMPLE_LPSPI_MASTER_DMAMUX_BASEADDR, EXAMPLE_LPSPI_MASTER_RX_DMA_LPSPI_CHANNEL);
EDMA_CreateHandle(&txHandle, EXAMPLE_LPSPI_MASTER_DMA_LPSPI_BASEADDR, EXAMPLE_LPSPI_MASTER_TX_DMA_LPSPI_CHANNEL);
EDMA_CreateHandle(&rxHandle, EXAMPLE_LPSPI_MASTER_DMA_LPSPI_BASEADDR, EXAMPLE_LPSPI_MASTER_RX_DMA_LPSPI_CHANNEL);

/* Set up master transfer */
LPSPI_MasterTransferCreateHandleEDMA(EXAMPLE_LPSPI_MASTER_BASEADDR, &g_m_handle, LPSPI_MasterUserCallbackEDMA, NULL, &rxHandle,
&txHandle);
/////////////////////////////////////////// DMA STUFF ////////////////////////////////////////////

0 Kudos

1,150 Views
KaveriA
Contributor I

Hi, 

 

Can you tell me how to check the master clock on the board ? 

I am using the MIMXRT1050 eval board. Example code is LPSPI edma b2b code.

 

Thanks 

KAveri A

0 Kudos