Reputation: 153
I am trying to receive multiple bytes over SPI. The aim is when the master starts the SPI transfer, slave MCU is interrupted, and it should read the data via SPI and store it in an array, which will be then used by my application for other operations such as determining the device ID and the contents of the packet.
void interrupt __high_priority my_isr_high(void) {
if (PIR1bits.SSP1IF) { // Interrupt from SPI?
rx[buffer_pointer] = SSP1BUF; // Get data from MSSP and store in RX buffer
buffer_pointer++; // Next data
if (buffer_pointer < FRAME_SIZE) // Ended?
SSP1BUF = tx[buffer_pointer]; // Send next byte to SPI
else
buffer_pointer = FRAME_SIZE;
PIR1bits.SSP1IF = 0; // Clear interrupt flag
}
}
However, I am not receiving the 3 bytes correctly. I am sending the following from the master:
dataPacket[0] = 0x43; // Decimal 67
dataPacket[1] = 0x42; //66
dataPacket[2] = 0x41; //65
While I am receiving as follows from the ISR():
rx[0]: 67
rx[1]: 65
rx[2]: 67
Am I missing something or handling the SPI incorrectly?
This will really solve the issue that I am stuck with and maybe will also help others who what to rx multiple bytes.
I am sharing my codes here so that it helps to find the solution quickly. Also included is a .zip file for compiling. Check the Codes here
So far the above code did not work for me properly. Therefore, after a little bit of digging online and other forums I found the following way to read multiple bytes:
uint8_t SPI_ExchangeHandler(uint8_t byte){
static uint8_t i = 0;
for(i=0; i<3; i++){
SSP1BUF =0x00;
while(!SSP1STATbits.BF);
rx_buff[i]=SSP1BUF;
}
State = SEND;
return byte;
}
Although the above codes give me what expected (i.e, correct data packets in the ordered manner), however, it misses two SPI interrupts every time and then displays/captures the correct data. Hence, two sets of data are always lost and then the third one is received correctly. Is something wrongly configured or missing?
Upvotes: 2
Views: 998
Reputation: 153
Finally, I managed to receive all the 3 bytes correctly. Sharing the codes below: My interrupt service routine that triggers the MCU when master SPI has data to send.
void interrupt INTERRUPT_InterruptManager (void){
if(PIE1bits.SSP1IE == 1 && PIR1bits.SSP1IF == 1)
{
SPI_ISR();
}
}
The SPI_ISR code was autogenerated by the MCC GUI.
void SPI_ISR(void)
{
SSP1BUF = SPI_xchgHandler(SSP1BUF);
}
void SPI_setExchangeHandler(uint8_t (* InterruptHandler)(uint8_t))
{
SPI_xchgHandler = InterruptHandler;
}
Then I handle the SPI via a custom function using SPI_setExchangeHandler() as follows:
#define FRAME_SIZE 10 // Frame fixed size
volatile static uint8_t rx_buff[FRAME_SIZE]; //RX buffer
uint8_t SPI_ExchangeHandler(uint8_t byte)
{
static uint8_t i = 0;
rx_buff[i]=SSP1BUF;
i++;
if(i <= 2){
rx_buff[i]=SSP1BUF;
SSP1BUF = 0x00;
while(!SSP1STATbits.BF){};
i++;
}
else{
i = 2;
}
PIR1bits.SSP1IF = 0; // Clear the SPI interrupt flag
State = SEND;
return byte;
}
And I print out the values as follows for debugging:
printf("CMD:%d \n", rx_buff[0]);
printf("BUF1: %d \n", rx_buff[1]);
printf("BUF2: %d \n\n", rx_buff[2]);
However, I am pretty sure this is not the best/optimized way to handle multiple bytes from SPI, therefore, if there is an alternative, share...
Upvotes: 0