This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts

Strange behaviour SPI_MASTER peripheral

Dear Nordic developers,

SPI_MASTER peripheral behaves in a way, that I cannot understand from manual is it normal or no.

I have implemented something similar to loopback example. After initialization I'm writing first byte to the TXD register and immediately after the first one second byte. (as it has double buffer). As I expect, I'm getting two READY events. In a first READY event I'm reading RXD register two times and I get expected two values already in a first READY event.

I was thinking that I should get first byte in a first READY event and the second byte in a second READY event. My simplified code is bellow.

void SPI0_TWI0_IRQHandler(void)
{
    if ((NRF_SPI0->EVENTS_READY == 1) && (NRF_SPI0->INTENSET & SPI_INTENSET_READY_Msk))
    {
        NRF_SPI0->EVENTS_READY = 0;
        if (first_ready_event)
        {
           rx_data[0] = (uint8_t)spi_base->RXD;
           rx_data[1] = (uint8_t)spi_base->RXD;
        }
     if (second_ready_event)
     // do nothing
    }
}


 int main()
 {
    while(true)
    {
       master_spi->TXD =cnt;
       master_spi->TXD =cnt + 1;
       nrf_delay_us(100);
    }
  }

I'd really appreciate if someone could help me and clarify all this.

Thanks and regards, Harut

Parents
  • Hi harutakop,

    Sorry for the late reply.

    The behaviour you see is normal because you are pushing two bytes into TX buffer so fast. So when the first byte is received after transmitting master_spi->TXD =cnt; the ISR starts executing and before you start reading the RXD buffer, the second byte is also transmitted master_spi->TXD =cnt + 1; and equivalent byte received. If you change you code little you will be able to see two READY events

    void SPI0_TWI0_IRQHandler(void)
    {
        if ((NRF_SPI0->EVENTS_READY == 1) && (NRF_SPI0->INTENSET & SPI_INTENSET_READY_Msk))
        {
            NRF_SPI0->EVENTS_READY = 0;
            if (first_ready_event)
            {
               rx_data[0] = (uint8_t)spi_base->RXD; // as soon as you do this RXD-1 value is pushed into RXD and this will cause the READY event again
            }
         if (second_ready_event)
         {
               rx_data[1] = (uint8_t)spi_base->RXD;
         }
        }
    }
    
    
     int main()
     {
        while(true)
        {
           master_spi->TXD =cnt;
           master_spi->TXD =cnt + 1;
           nrf_delay_us(100);
        }
      }
    

    To summarize, what you are seeing is normal because you are pushing two bytes so fast in double buffered SPITX that it is able to serialize them. It might actually JUST finished transmitted the second byte before you read the first byte in ISR. This will not work if you do this

     int main()
     {
        while(true)
        {
           master_spi->TXD =cnt;
           master_spi->TXD =cnt + 1;
           master_spi->TXD =cnt + 2;
           nrf_delay_us(100);
        }
      }
    
  • The second READY event will be generated exactly after you read the first byte, that will make RXD-1 byte to move in RXD and will generate second READY event.

    You can do it the other way around, execute your ISR every first READY event and ignore the second Ready event. You cannot ignore the first because if you do not read RXD in first ready event then you wont get second ready event. This is because ready event is generated when the byte moves from RXD-1 to RXD internal buffer.

    You solution will work for reading two bytes in first event and ignoring the second with a minor twist. Look at the code below.

    void SPI0_TWI0_IRQHandler(void)
    {
        if ((NRF_SPI0->EVENTS_READY == 1) && (NRF_SPI0->INTENSET & SPI_INTENSET_READY_Msk))
        {
            NRF_SPI0->EVENTS_READY = 0;
            if (first_ready_event)
            {
               rx_data[0] = (uint8_t)spi_base->RXD;
               while(NRF_SPI0->EVENTS_READY != 1);   // clear the second event here
               NRF_SPI0->EVENTS_READY = 0;
               rx_data[1] = (uint8_t)spi_base->RXD;
            }
         if (second_ready_event)
         // do nothing
        }
    }
    
    
     int main()
     {
        while(true)
        {
           master_spi->TXD =cnt;
           master_spi->TXD =cnt + 1;
           nrf_delay_us(100);
        }
      }
    
Reply
  • The second READY event will be generated exactly after you read the first byte, that will make RXD-1 byte to move in RXD and will generate second READY event.

    You can do it the other way around, execute your ISR every first READY event and ignore the second Ready event. You cannot ignore the first because if you do not read RXD in first ready event then you wont get second ready event. This is because ready event is generated when the byte moves from RXD-1 to RXD internal buffer.

    You solution will work for reading two bytes in first event and ignoring the second with a minor twist. Look at the code below.

    void SPI0_TWI0_IRQHandler(void)
    {
        if ((NRF_SPI0->EVENTS_READY == 1) && (NRF_SPI0->INTENSET & SPI_INTENSET_READY_Msk))
        {
            NRF_SPI0->EVENTS_READY = 0;
            if (first_ready_event)
            {
               rx_data[0] = (uint8_t)spi_base->RXD;
               while(NRF_SPI0->EVENTS_READY != 1);   // clear the second event here
               NRF_SPI0->EVENTS_READY = 0;
               rx_data[1] = (uint8_t)spi_base->RXD;
            }
         if (second_ready_event)
         // do nothing
        }
    }
    
    
     int main()
     {
        while(true)
        {
           master_spi->TXD =cnt;
           master_spi->TXD =cnt + 1;
           nrf_delay_us(100);
        }
      }
    
Children
No Data
Related