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.

  • @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);
    }
    
  • @Henry: Could you double check ? It worked fine in my test. I attached the code here, SDK v7.2 S110 v7.1.

    experimental_ble_app_uart - Copy.zip

  • Thanks for the example code Hung. Yes, that is essentially what I am doing. It's strange because calling sd_app_evt_wait() for the SPI0 is working fine--and it was working fine even BEFORE I put in the SCB_SCR_SEVONPEND_Msk or NVIC_ClearPendingIRQ(SPI0_TWI0_IRQn). So WFE() returned for SPI0 when it shouldn't have, and now UART0 WFE is NOT returning when it should?!

    The production code is quite a bit more complex, so I really can't isolate it effectively--nor do I have the time to undo all the debugging setup. This is not the 1st time where I had this kind of predicament --unable to run small isolation code due to the complexity of the full setup. I should just buy another nRF51 DK board and set it up as an isolation bed.

    I need to solve a more pressing problem, so I'll come back to this later (perhaps when I get another nRF51 DK). Thanks Hung.

Related