Hello folks, I am having some problems at setting up SPI Interrupt communication in the S32K144 board. The project aims to communicate with a PC33771B device, but for now is in a kind of loopback provided by the 33664EVB.
For the most part it seems to work, but how the data is actually stored inside my buffer is funky. I have a 5 bytes message, and in general it obeys this order:
B5 0 0 0 B1 B2 B3 B4
which I assume should be correct given that the LPSPI works in words. But that is not the order all the times for some reason. When starting the board, sometimes the order is:
B1 B2 B3 B4 B5 0 0 0
And sometimes its just:
B1 B2 B3 B4 0 0 0 0
Losing the fifth byte completely.
I made a small testing code to be able to debug it using CAN. I send the message i want from it into SPI_1, and receive back the message that ends in the buffer on SPI_0. I also am using the logic analyzer to see whats happening:
First message:
First of all, the spi messages are following the S32K144 convention, so the fifth byte would be the CRC. It is also stepping into the fourth byte with the cmd, I just conviniently put it to four. It yields zero always even if I wait the SPI_0 to be ready again. This only happens on the first.
Second message:
Last byte doesn t show at all. Maybe it was lost somehow, but even then the other four bytes shouldn t be in the first word if it is ordered by MSB.
Third message:
This seems to work as intended, getting all the data and what I guess its the expected order. I say I guess it is the expected order as its what i consistently get in all messages after it settles.
The problem with this is that its not always the third message the one is good, sometimes its the fifth or the sixth, sometimes the fifth byte doesn t appear at all, and other times it appears on the second word. Once it starts doing it correctly, it works consistently. Any ideas of what may cause this issue? Below the code and configuration:
void response420(zc_can_packet* packet){
zc_spi_transfer(&spi_rx, &spi_to_can_packet);
transfer_E2E_spi_packet(&E2E_spi, &can_to_spi_packet, &packet->temp_data[0]);
memcpy(&can_response.temp_data, spi_to_can_packet.rx_buffer, 8);
zc_can_send(&can, &can_response, MAILBOX_0);
}
void zc_spi_transfer(zc_spi_hw* hw_config,zc_spi_packet* packet){
hw_config->transfered_packet = packet;
if(hw_config->hw_mode == MASTER){
SPI_MasterTransfer(hw_config->inst,packet->tx_buffer,packet->rx_buffer,(packet->message_bytes_length*NUMBER_OF_BITS_IN_BYTE)/hw_config->master_config->frameSize);
}else{
SPI_SlaveTransfer(hw_config->inst,packet->tx_buffer,packet->rx_buffer,(packet->message_bytes_length*NUMBER_OF_BITS_IN_BYTE)/hw_config->slave_config->frameSize);
}
}
void transfer_E2E_spi_packet(E2E_spi_handler* E2E_spi, E2E_spi_packet* packet, uint8_t* data){
E2E_spi->protector_handler->protect_package(E2E_spi->protector_handler, data, packet->packet_data.data_length_bytes,
&(packet->raw_spi_packet.tx_buffer[0]), packet->packet_data.E2E_packet_id, packet->packet_data.counter);
zc_spi_transfer(E2E_spi->spi_handler, &(packet->raw_spi_packet));
packet->packet_data.counter++; //This one is not actually used in this CRC format, but this function works with multiple CRC formats
if(packet->packet_data.counter > E2E_spi->protector_handler->counter_overflow_number){packet->packet_data.counter = 0;}
}
The response420 function is the "callback" of receiving the CAN packet, which is called inside the main when a flag is risen by the CAN callback itself. The CAN part isn t really important, as this bug happens without CAN, I tried CAN after this bug showed in the debugger to be able to test more inputs.
In general, I am using PAL, as it can be seen in the functions SPI_SlaveTransfer and SPI_Master transfer. This is the PAL configuration:
SPI_1 config:
{
.baudRate = 2000000U,
.frameSize = 40U,
.bitOrder = SPI_TRANSFER_MSB_FIRST,
.clockPolarity = SPI_ACTIVE_HIGH,
.ssPolarity = SPI_ACTIVE_LOW,
.clockPhase = READ_ON_EVEN_EDGE,
.ssPin = 0,
.transferType = SPI_USING_INTERRUPTS,
.rxDMAChannel = 0U,
.txDMAChannel = 0U,
.callback = NULL,
.callbackParam = NULL,
.extension = NULL
}
SPI_0 config:
{
.frameSize = 40U,
.bitOrder = SPI_TRANSFER_MSB_FIRST,
.clockPolarity = SPI_ACTIVE_HIGH,
.ssPolarity = SPI_ACTIVE_LOW,
.clockPhase = READ_ON_EVEN_EDGE,
.transferType = SPI_USING_INTERRUPTS,
.rxDMAChannel = 0U,
.txDMAChannel = 0U,
.callback = NULL,
.callbackParam = NULL,
.extension = NULL
}
Anyone found a similar problem?
Okay, great to know. Thanks a lot @danielmartynek!
Great, it seems to be working as expected now.
The HW support byte swapping, but the SDK drivers don't.
Okay, i simplified the code to the maximum:
uint8_t data_to_send[8] = {0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8};
uint8_t data_received[8];
lpspi_state_t lpspiState;
int main(){
zc_clock_init();
zc_start_scheduler();
const clock_names_t clocknames[LPSPI_INSTANCE_COUNT] = FEATURE_LPSPI_CLOCKS_NAMES;
clock_names_t clockname = clocknames[1];
lpspi_master_config_t spiConfig = {
.bitcount = 8U,
.bitsPerSec = 20000000,
.callback = NULL,
.callbackParam = NULL,
.clkPhase = 1,
.clkPolarity = 0,
.isPcsContinuous = true,
.lpspiSrcClk = clockname,
.lsbFirst = false,
.pcsPolarity = 0,
.rxDMAChannel = 0,
.transferType = LPSPI_USING_INTERRUPTS,
.txDMAChannel = 0,
.whichPcs = 0,
};
LPSPI_DRV_MasterInit(1, &lpspiState, &spiConfig);
config_spi_pinout(spi_pinoutconfigs[1].pinout);
while(1){
LPSPI_DRV_MasterTransfer(1, &data_to_send[0], &data_received[0], 8);
zc_delay_milliseconds(1000);
}
return 0;
}
If i do this and put the bitcount on 8 this is the result:
The spacings are the problem here, but at least it works more or less as expected
The same with bitcount 32:
The bytes get reversed inside each word...
And at last, same with bitcount 64 to check what would happen:
Same thing.
And what happens if i put it in a word array instead of an uint8_t array?
uint32_t data_to_send[2] = {0x01020304, 0x05060708};
uint8_t data_received[8];
lpspi_state_t lpspiState;
int main(){
zc_clock_init();
zc_start_scheduler();
const clock_names_t clocknames[LPSPI_INSTANCE_COUNT] = FEATURE_LPSPI_CLOCKS_NAMES;
clock_names_t clockname = clocknames[1];
lpspi_master_config_t spiConfig = {
.bitcount = 64U,
.bitsPerSec = 20000000,
.callback = NULL,
.callbackParam = NULL,
.clkPhase = 1,
.clkPolarity = 0,
.isPcsContinuous = true,
.lpspiSrcClk = clockname,
.lsbFirst = false,
.pcsPolarity = 0,
.rxDMAChannel = 0,
.transferType = LPSPI_USING_INTERRUPTS,
.txDMAChannel = 0,
.whichPcs = 0,
};
LPSPI_DRV_MasterInit(1, &lpspiState, &spiConfig);
config_spi_pinout(spi_pinoutconfigs[1].pinout);
while(1){
LPSPI_DRV_MasterTransfer(1, (uint8_t*) &data_to_send[0], &data_received[0], 8);
zc_delay_milliseconds(1000);
}
return 0;
}
It actually works...
So it seems that if you are not working with frame size 8, it sends it by words, which are on Little endian. Is there a way to change the endianess?
Hello @danielmartynek
I already use a uint8_t array
Hi @rchust,
How do you define the tx_buffer?
The driver expects an 8bit pointer to an 8bit array (in LPSPI_DRV_MasterTransfer()).
So, can you use uint8_t[5] tx_buffer instead of passing words there?
Thank you
Hello @danielmartynek ,
I tested with 8 bit frames and it works properly, sending the bytes in order. There are two problems though.
The first is that with 8 bit frames the hardware splits the data by byte, which it should as that is the definition of the frames, but that may give me problems in the future, I have yet to test if the PC33771 accepts messages with those spacings. It should, but its not exactly what it expects.
The second one (and the reason i haven t tested with PC33771 yet) is that pal library doesn t let me set Continuous mode in true, the method Master_init in the pal library just hard sets it to false before passing it to the LPSPI_DRV_MasterInit:
status_t SPI_MasterInit(const spi_instance_t * const instance, const spi_master_t *config)
{
status_t status = STATUS_ERROR;
uint8_t index = 0;
/* Define SPI PAL over LPSPI */
#if (defined (SPI_OVER_LPSPI))
/*! @brief Clock names for LPSPI */
const clock_names_t g_lpspiClock[LPSPI_INSTANCE_COUNT] = FEATURE_LPSPI_CLOCKS_NAMES
if (instance->instType == SPI_INST_TYPE_LPSPI)
{
lpspi_master_config_t lpspiConfig;
lpspiConfig.bitsPerSec = config->baudRate;
lpspiConfig.whichPcs = (lpspi_which_pcs_t)config->ssPin;
lpspiConfig.pcsPolarity = (lpspi_signal_polarity_t)(!(bool)(config->ssPolarity));
lpspiConfig.bitcount = config->frameSize;
(void)CLOCK_SYS_GetFreq(g_lpspiClock[(uint32_t)instance->instIdx] ,&lpspiConfig.lpspiSrcClk);
lpspiConfig.clkPhase = (lpspi_clock_phase_t)config->clockPhase;
lpspiConfig.clkPolarity = (lpspi_sck_polarity_t)config->clockPolarity;
lpspiConfig.lsbFirst = config->bitOrder;
lpspiConfig.transferType = (lpspi_transfer_type)config->transferType;
lpspiConfig.rxDMAChannel = config->rxDMAChannel;
lpspiConfig.txDMAChannel = config->txDMAChannel;
lpspiConfig.callback = config->callback;
lpspiConfig.callbackParam = config->callbackParam;
lpspiConfig.isPcsContinuous = false;
/* Allocate one of the LPSPI state structure for this instance */
index = SpiAllocateState(LpspiStateIsAllocated, LpspiStateInstanceMapping, instance->instIdx, NO_OF_LPSPI_INSTS_FOR_SPI);
status = LPSPI_DRV_MasterInit(instance->instIdx, (lpspi_state_t*)(&LpspiState[index]), &lpspiConfig);
}
else
#endif
I will need to change all the library to stop using pal and start using the DRV methods before i can test it in continuous mode. I will do so and update with the results, but it seems that it does send it in the correct order at 8 bit frames. Its still frustrating that it does not at 40 bit frames though.
Hi @rchust,
Thank you for the update.
Can you use an 8bit array for the tx_buffer?
Okay, after some testing i could find the root of the problem.
It seems that even when i wasn t using the CAN i was configuring its pins, and one pin did collide with the CS of the master. I am not sure how come one thing ends in the other, but after removing the CAN configuration most of the problems dissapeared, but one.
For some reason when i send data in higher than 8 bit frames the bytes inside each word swap. If i put a 64 bit frame with the data 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 -> 0x04 0x03 0x02 0x01 0x8 0x07 0x06 0x05. It seems to be because the spi works internally with words and i am putting the data byte by byte. That or it may be the pal library.
Hello @danielmartynek ,
First you are right, i said my IDE version, SDK is 4.0.2; sorry about that.
The code I am showing is a CAN callback, and i copy the CAN data into the SPI buffer. The code is like that because we are trying to embed it into a custom library, but in reality it just sends what it reads from CAN into SPI (SPI1), and then what the slave (SPI0) reads into CAN.
CAN sends 4 bytes, then protect adds the last byte which is the CRC so SPI sends 5, then it reads 5, and then CAN just sends whatever it is inside the first 8 bytes of the buffer. The buffer itself is actually bigger, but the SPI_MasterTransfer is sending just the first 5 bytes of it.
I checked in debug mode and the SPI while sending always has the bytes in the expected order without gaps when inside SPI_MasterTransfer. It always seems to send it properly (or at least with consistency), so it seems that the problem is the reception of the slave.
With master blocking it seems that the same problem arises. I cannot check with slave blocking because then i block the master from sending. I also found that setting both master and slave to clock polarity low makes it miss a lot of high bits, but lets tackle the reception of first messages not working first.
Hi @rchust,
It seems you specified the IDE (3.6.2) not the SDK/RTD.
If I have the number of the release I can check for reported bugs.
I see you use the non-blocking method, can you test it with the blocking transfer function?
The code is not very readable.
What values do you place as arguments in the transfer function?
How do you fill the buffer?
The observed gap in SPI communication is caused by driver overhead - the driver is unable to populate the transmit FIFO quickly enough. In 8-bit mode, the driver writes data to the FIFO one byte at a time, which introduces latency between successive writes. This delay becomes more noticeable at higher SPI clock speeds. To mitigate this issue, using DMA is recommended.
Regards,
Daniel
Hello daniel,
My SDK is 3.6.2, I am using SPI through the 33664EVB board and its TPL, I am not using chip select, and the channels are SPI1_clock, SPI1_tx, TPL1_data and TPL1_clock respectively. I will name them in future images to avoid confusion. I will point it out that i tested putting the latter two directly into the SPI0_rx and SPI0_clock and same results show.
I tested it in 8 bit mode and these are the results:
First message:
Fourth message:
First noticeable thing, the enormous gap between first word and second. I also tested with bigger messages and the gap arises between each word when using 8 bit. If I try lower frequency, the gap lowers, until around 500kHz, in which it dissapears. Still, the 33664EVB and 3771 application notes recommends using 2MHz, and generally having less speed is not desirable.
Then the problem is still similar, although not exactly the same. At first the last byte doesn t appear at all, then it appears first, followed by the other bytes in correct order. It is also worth pointing out that with 8 bit the data is sent in the order I put it, while with 40 bit mode it swaps the data in the signal, then it is swapped again by the slave.
If it wasn t for the huge gap between words 8 bit would be more desirable, but the problem still arises. With 8 bit 500kHz:
First message:
Second message:
Third message and so on:
This shows two problems, first the one of inconsistencies on the data read by the slave that i am talking about, and then seeing the clock of the TPL we can see a second problem; TPL keeps the pulses width as if it was 2MHz. Thats one of the reasons why I need that speed.
Hi @rchust,
Can you specify the version of the drivers?
What protocol are you using? Do you use the chip select signal?
Can you label the channels in the logic analyzer capture?
The LPSPI hardware supports sending 8-bit frames continuously, and our software drivers are compatible with that.
You can transmit 40-bit frames in continuous mode by placing 8-bit data into the FIFO.
Also, please try testing the SPI communication at lower baud rates to eliminate any potential issues related to timing or signal integrity.
Regards,
Daniel