Calling SPI_MasterTransferNonBlocking(): FIFOINTENSET slow?

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

Calling SPI_MasterTransferNonBlocking(): FIFOINTENSET slow?

345 Views
danielholala
Senior Contributor II

Hello,

I'm using a LPC5536 which I connected to an external part via SPI.

The SPI clock is 5 MHz and on the scope I can see that an SPI transfer of 16 bit takes less than 4 microseconds with this clock (i.e., scope is on chip select signal). However, doing consecutive SPI transfers, I see on the scope that they are at least 50 microseconds apart. I wondered where that latency comes from and therefore profiled the SDK driver code.

To initiate the transfer, at some point the code calls  SPI_MasterTransferNonBlocking() in drivers/fsl_spi.c, see

 https://github.com/nxp-mcuxpresso/mcux-sdk/blob/main/drivers/flexcomm/spi/fsl_spi.c#L699 

The last statement in this function is

    base->FIFOINTENSET |= SPI_FIFOINTENSET_TXLVL_MASK | SPI_FIFOINTENSET_RXLVL_MASK;

 

Using DWT->CYCCNT cycle counter, I measured that this statement takes 35 microseconds for execution.

Why is this?

The driver sets and resets the FIFO interrupt flags before and after every SPI transfer. This delay adds up causing a substantial latency.

Further, can I replace the |= operator with just = as follows?

    base->FIFOINTENSET = SPI_FIFOINTENSET_TXLVL_MASK | SPI_FIFOINTENSET_RXLVL_MASK;

That would save a couple of microseconds. It is my understanding that the  "SET" registers are special registers where every "1" bit written to the  "SET" register will be set in the underlying register. Writing a "0" bit will not change or clear the bit in the underlying register. So to set a certain bit a simple assignment is sufficient and a read is not required.

So why does the driver use "|=" with these special registers?

Thanks.
Dan

 

 

0 Kudos
2 Replies

313 Views
xiangjun_rong
NXP TechSupport
NXP TechSupport

Hi,

Regarding the SPI FIFO interrupt enable register

base->FIFOINTENSET

I suppose that the register is FIFO Interrupt Enable Register instead of FIFO Interrupt Enable Register set register, because the setting the FIFOINTENCLR reg can clear the corresponding bit in FIFOINTENSET reg.

So the driver code is correct, you have to use |= operator.

Hope it can help you

BR

XiangJun Rong

 

xiangjun_rong_0-1701052914299.png

 

0 Kudos

307 Views
danielholala
Senior Contributor II

Dear @xiangjun_rong ,

Thank you for your response.

Regarding the disputed use of the '|=' operator, I understand that you claim that the

 

base->FIFOINTENSET

 

register also allows to clear bits and thus disable interrupt sources. 

The reference manual's description of FIFOINTENSET reads:

danielholala_0-1701073427868.png

It does not explicitly state how the CPU handles writing '0' bits to FIFOINTENSET. It does insinuate that to clear bits the user should use FIFOINTENCLR, though.

Then there's the explanation of each bit in the register, e.g., RXLVL and TXLVL:

danielholala_1-1701074138570.png

The reference manual does not distinguish between reading and writing to this register. The explanation for a "0" bit could apply to reading from the register, only. This is ambiguous.

Thus I tried it by example: I set some bits and then cleared all bits with setting FIFOINTENSET to 0 as follows

 

    base->FIFOINTENSET |= SPI_FIFOINTENSET_TXLVL_MASK | SPI_FIFOINTENSET_RXLVL_MASK;
    base->FIFOINTENSET = 0;
    RTT_WriteStringf("03 clear %08x\n", base->FIFOINTENSET );

 

The output is "03 clear 0000000c". Also "peripherals+" view in MCUXpresso IDE shows the  value  0x0000000c (when stepping through these instructions using the debugger).

From this observation I conclude that writing 0 bits to FIFOINTENSET does NOT clear bits.

Please comment.


Thanks
Daniel

PS: Regarding "FIFOINTENSET slow?", I now know why writing to FIFOINTENSET is supposedly slow. The transfer is started by the empty TXFIFO interrupt and this interrupt is fired as soon as the FIFOINTENSET is written to.

 

 

0 Kudos