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

SPI inter-byte duration

Hello, I've been working on porting a bit-banged control of a peripheral to use nRF51 SPI--which is just SPI rather than SPIM (therefore no DMA). Observe the SPICLK waveform when I choose 4 MHz: image description

The byte itself is emitted at 4 MHz. But the huge inter-byte distance remains constant down to about 1 MHz CLK speed. I guess that's just how it is with SPI (not SPIM). In the waveform above, one can see that the maximum effective SPI speed is roughly 14 us / 1 B => 570 KHz, which is only slightly faster than the maximum effective SPI speed when I bit-bang using GPIO on an STM32L1 (Cortex M3) ~ 400 KHz. It nearly negates the arguments for using the SPI peripheral over bit-bang (except for some battery savings by using WFE).

I doubt there is anything I can do to improve the situation, but thought I'd check with experts just in case. Thanks for reading.

Parents
  • Thank you for the reply Wojtek and Hung, you were right: I was taking much too long in my checking for the nrf_spi_event_check(p_spi, NRF_SPI_EVENT_READY). There is still some ~4 us until I see the EVENT_READY flag in the register, but the effective BW is now up to 1.23 MHz (when using the 4 MHz SPI speed). BTW, why can't I call sd_app_evt_wait() (which just calls WFE) while waiting for NRF_SPI_EVENT_READY? I find this to be true even while waiting for NRF_UART0->EVENTS_TXDRDY (in another context) as well. Shouldn't these events wake up the nRF that is sleeping on WFE?

Reply
  • Thank you for the reply Wojtek and Hung, you were right: I was taking much too long in my checking for the nrf_spi_event_check(p_spi, NRF_SPI_EVENT_READY). There is still some ~4 us until I see the EVENT_READY flag in the register, but the effective BW is now up to 1.23 MHz (when using the 4 MHz SPI speed). BTW, why can't I call sd_app_evt_wait() (which just calls WFE) while waiting for NRF_SPI_EVENT_READY? I find this to be true even while waiting for NRF_UART0->EVENTS_TXDRDY (in another context) as well. Shouldn't these events wake up the nRF that is sleeping on WFE?

Children
  • @Henry: You should call sd_app_evt_wait() only if the softdevice is enabled. Otherwise you should call __WFE() instead. Have you made sure you enable interrupt for those event (NVIC_EnableIRQ) ?

  • I am indeed using the SD. Just to be clear Hung, we are talking about WFE rather than WFI. From ARM infocenter doc, WFE should return when an "event signaled by a peripheral ..." occurs. Don't you think the nRF peripheral EVENTS_XXXX all should lead to WFE() returning?

  • @Henry Choi: I see, but from my understanding you should still enable the interrupt on READY event (with INTENSET register), if you want to wake CPU up when in WFE.

    Still from my understanding, what ARM described as "events from peripheral" actually are the events that are enabled as interrupts from the peripheral. Without enabling interrupt, the peripheral has no way to tell the CPU about its events.

    Also you need to enable SEVONPEND with SCB->SCR |= SCB_SCR_SEVONPEND_Msk; to wake the chip up from pended event.

    So, NVIC_EnableIRQ() is not needed if you don't want to handle the interrupt, but INTENSET should be set, and also you should clear the interrupt pending flag NVIC_ClearPendingIRQ(XXX_IRQn); after it wake the chip up.

  • Thank you Hung, I found other information from this forum yesterday, but did not think about NVIC_ClearPending(). I found the interrupt number for SPI1 and UART0, but what is the corresponding NVIC number for NRF_CLOCK->EVENTS_HFCLKSTARTED on nRF51822? I don't see it in the IRQn_Type enum...

  • I think POWER_CLOCK_IRQn is the IRQ I was looking for. Anyway, I can't seem to get the nRF to return from sd_app_evt_wait() using the technique you describe. Can you please point out anything obviously wrong I am doing below:

    In init():

        NRF_UART0->ENABLE          = UART_ENABLE_ENABLE_Enabled;
        NRF_UART0->INTENSET = UART_INTENSET_TXDRDY_Msk;//required to wake up from WFE
        NRF_UART0->TASKS_STARTTX   = 1;
        NRF_UART0->TASKS_STARTRX   = 1;
        SCB->SCR |= SCB_SCR_SEVONPEND_Msk;
    
    void put_byte(uint8_t b) {
        NRF_UART0->TXD = b;
        while (!NRF_UART0->EVENTS_TXDRDY) {
            sd_app_evt_wait();
        }
        NRF_UART0->EVENTS_TXDRDY = 0;
        NVIC_ClearPendingIRQ(UART0_IRQn);
    }
    
Related