I want to transfer data between NVIDIA Jetson Nano (Master) and STM32F756ZG (Slave) using SPI. On the master side, I am using spidev python library. On the slave side, I am coding using registers (without using HAL).
I want to send and receive data continuously between the two systems. When I run the codes, the data are correct for the first few cycles. However, after some cycles, the data are right-shifted by one bit. It happens randomly after some cycles in a circular mode (after some shifting, the data will be correct for some cycles and then the shifting continue again and so on). What could be the issue that is causing this shifting? I want to make sure SPI is always transferring correct data continuously. Is it possible that there are some buffers that need to be cleared after each cycle?
I am using SPI with interrupts. Here is my SPI configuration (spi_enable and disable just change the SPE bit):
void spi_config()
{
// 1. Enable SPI clock
RCC->APB2ENR &= ~(0b1 << 13);
RCC->APB2ENR |= (0b1 << 13); // Enable SPI4 clock
// 2. Configure the control register 1
spi_disable();
SPI4->CR1 &= ~(0b111 << 0);
SPI4->CR1 |= (0b0 << 0); // CPHA to 0: leading edge
SPI4->CR1 |= (0b0 << 1); // CPOL to 0: CLK is 0 when idle
SPI4->CR1 |= (0b0 << 2); // SPI as slave
SPI4->CR1 &= ~(0b1 << 7);
SPI4->CR1 |= (0b0 << 7); // MSB first
SPI4->CR1 &= ~(0b111 << 8);
SPI4->CR1 |= (0b01 << 8); // NSS stuff (SSM and SSI)
SPI4->CR1 |= (0b0 << 10); // Full-duplex (transmit and receive)
// 3. Configure the control register 2
SPI4->CR2 &= ~(0b1 << 2); // NSS stuff
SPI4->CR2 |= (0b0 << 2);
SPI4->CR2 &= ~(0b111 << 3);
SPI4->CR2 |= (0b101 << 3); // baud rate division by 64
SPI4->CR2 &= ~(0b1111 << 8);
SPI4->CR2 |= (0b0111 << 8); // data size is 8 bits
SPI4->CR2 &= ~(0b1 << 6);
SPI4->CR2 |= (0b1 << 6); // Enable RXNEIE
SPI4->CR2 &= ~(0b1 << 12);
SPI4->CR2 |= (0b1 << 12); // Set FRXTH to 8 bits
NVIC_SetPriority(SPI4_IRQn, 0);
NVIC_EnableIRQ(SPI4_IRQn); // enable SPI4 interrupt in NVIC
spi_enable();
}
My interrupt callback function is as follows:
void SPI4_IRQHandler()
{
if (SPI4->SR & (0b1 << 0)) { // if Rx is not empty
SPI4->DR = 0;
data_rx[rx_buffer_head] = SPI4->DR;
data[rx_buffer_head] = data_rx[rx_buffer_head];
data_rx[rx_buffer_head] = 0;
if(rx_buffer_head == (BUFFER_SIZE - 1)) {
counter++;
}
rx_buffer_head = (rx_buffer_head + 1) % BUFFER_SIZE;
SPI4->SR &= ~(0b1 << 0);
}
// Check for errors
if (SPI4->SR & (SPI_SR_OVR | SPI_SR_MODF | SPI_SR_CRCERR)) {
// Handle errors
SPI4->SR &= ~(SPI_SR_OVR | SPI_SR_MODF | SPI_SR_CRCERR); // Clear error flags
}
}
Note that for testing purposes, I am sending 4 bytes at a time from Jetson Nano.
Also, I monitored the 4 lines of SPI using an oscilloscope. Data are correct, so I am assuming the problem is not on the master side.
If needed, here is my GPIO configuration:
void gpio_init()
{
// Enable the GPIO clock
RCC->AHB1ENR &= ~(0b1 << 4);
RCC->AHB1ENR |= (0b1 << 4); // GPIOE
// Pins Mode
GPIOE->MODER &= ~(0b11 << 4); // Reset the SPI4 SCK pin
GPIOE->MODER |= (0b10 << 4); // SPI4 SCK Alternate function mode
GPIOE->MODER &= ~(0b11 << 10); // Reset the SPI4 MISO pin
GPIOE->MODER |= (0b10 << 10); // SPI4 MISO Alternate function mode
GPIOE->MODER &= ~(0b11 << 12); // Reset the SPI4 MOSI pin
GPIOE->MODER |= (0b10 << 12); // SPI4 MOSI Alternate function mode
GPIOE->MODER &= ~(0b11 << 8); // Reset the SPI4 CS pin
GPIOE->MODER |= (0b00 << 8); // SPI4 CS input mode
// Set the Pins Speed to very high speed
GPIOE->OSPEEDR &= ~(0b11 << 4);
GPIOE->OSPEEDR |= (0b11 << 4);
GPIOE->OSPEEDR &= ~(0b11 << 10);
GPIOE->OSPEEDR |= (0b11 << 10);
GPIOE->OSPEEDR &= ~(0b11 << 12);
GPIOE->OSPEEDR |= (0b11 << 12);
GPIOE->OSPEEDR &= ~(0b11 << 8);
GPIOE->OSPEEDR |= (0b11 << 8);
// Set the alternate functions of the pins to SPI
GPIOE->AFR[0] &= ~(0b0101 << 8);
GPIOE->AFR[0] |= (0b0101 << 8);
GPIOE->AFR[0] &= ~(0b0101 << 20);
GPIOE->AFR[0] |= (0b0101 << 20);
GPIOE->AFR[0] &= ~(0b0101 << 24);
GPIOE->AFR[0] |= (0b0101 << 24);
}