SPI with Registers: Shifting Issues in Data transferring

60 Views Asked by At

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);
}
0

There are 0 best solutions below