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

Any relation between SPIM, PPI, TIMER and DFU bootloader?

Hi All,

Another question for those out there much smarter than myself...

We're developing an application using nrf52, sdk11 and softdevice s132 2.0.0 and have been using DFU single bank to successfully update the application OTA.

Recently, we've made some changes to enable the use of easyDMA with the SPI master, which broke the previously working OTA updates.

At a high level, we're using NRF_DRV_TIMER_INSTANCE(1) task to toggle an external CS pin and trigger a SPI transaction event every 1ms, to draw a line to a display without any mcu involvement.

All of this works fine and well, but when this application is loaded to the nrf52, and I try to OTA update another application, I get stuck in what seems to be an app_error_check() or hard fault inside of the bootloader unless I disable the ppi channel connecting the timer event with the SPIM task in bootloader_util.c

The single bank bootloader used is essentially the dual bank bootloader from the sdk examples, with the dual_bank_bootloader.c swapped with single_bank.c with two additions to main to toggle GPIO 0.15 HIGH and 0.26 LOW

I didn't find any possible explanations in the softdevice specification, which places a restriction on the upper 3 PPI channels but nothing related to SPIM I could see. Has anybody seen anything like this before, or can think of any possible explanations as to why this could be the case? Is this possibly a bug/PAN?

nrf_ppi_channel_t       m_ppi_channel;           // Used for the SPI transfer (originally the SAADC)

void dma_events_init(void){
        uint32_t ticks = nrf_drv_timer_ms_to_ticks(&m_timer, 1);
        
        nrf_drv_timer_extended_compare(&m_timer, NRF_TIMER_CC_CHANNEL0, ticks, NRF_TIMER_SHORT_COMPARE0_CLEAR_MASK, false);
    nrf_drv_timer_enable(&m_timer);

    uint32_t timer_compare_event_addr = nrf_drv_timer_compare_event_address_get(&m_timer, NRF_TIMER_CC_CHANNEL0);
    
    // GPIOTE Stuff
    nrf_drv_gpiote_out_config_t cs_config = GPIOTE_CONFIG_OUT_TASK_HIGH;
    err_code = nrf_drv_gpiote_out_init(GPIO_DISP_CS0, &cs_config);    
    
    uint32_t gpiote_toggle_event_addr = nrf_drv_gpiote_out_task_addr_get(15);
    
    // SPI Stuff
    uint32_t spi_transfer_event_addr = nrf_drv_spi_start_task_get(&spi);
    
    // Setup next transfer sequence
    nrf_drv_spi_xfer_desc_t xfer = NRF_DRV_SPI_XFER_TX(dma_sharp_mlcd_display_buffer_line, 52);
    
    // Set flags for next transfer sequence
    uint32_t flags = NRF_DRV_SPI_FLAG_HOLD_XFER;
    
    err_code = nrf_drv_spi_xfer(&spi, &xfer, flags);
 
    /* setup ppi channel so that timer compare event is triggering SPI transfer */
    err_code = nrf_drv_ppi_channel_alloc(&m_ppi_channel);
   APP_ERROR_CHECK(err_code);

   err_code = nrf_drv_ppi_channel_assign(m_ppi_channel, timer_compare_event_addr, spi_transfer_event_addr);
   APP_ERROR_CHECK(err_code);

   err_code = nrf_drv_ppi_channel_enable(m_ppi_channel);
   APP_ERROR_CHECK(err_code);
}

changes to bootloader_util.c:

#include "nrf_drv_ppi.h"

void bootloader_util_app_start(uint32_t start_addr)
{
    nrf_drv_ppi_channel_free(m_ppi_channel);  // m_ppi_channel is the "short" between timer event and SPIM task
    bootloader_util_reset(start_addr);
}
Parents
  • @bvuong87: please correct me if I'm wrong. You want to continue doing the SPI task when you are in bootloader mode by using PPI and let the timer and SPI running without CPU involvement ? But you have hardfault/assert when you enter bootloader ?

    If you call nrf_drv_ppi_channel_free() you don't have any issue continue with the bootloader ?

    You would need to make sure all the interrupt handler is implemented or you disable the interrupt flag the peripherals you use but don't handle them in the bootloader code.

    The nrf_driver actually enable interrupt flag for the timer and the SPI. I would suggest to use the TIMER and SPI directly so you know for sure what you enable.

Reply
  • @bvuong87: please correct me if I'm wrong. You want to continue doing the SPI task when you are in bootloader mode by using PPI and let the timer and SPI running without CPU involvement ? But you have hardfault/assert when you enter bootloader ?

    If you call nrf_drv_ppi_channel_free() you don't have any issue continue with the bootloader ?

    You would need to make sure all the interrupt handler is implemented or you disable the interrupt flag the peripherals you use but don't handle them in the bootloader code.

    The nrf_driver actually enable interrupt flag for the timer and the SPI. I would suggest to use the TIMER and SPI directly so you know for sure what you enable.

Children
No Data
Related