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
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
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:
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:
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.