Pause and resume PPI

I am controlling the SPI via PPI at regular time intervals and it is working as expected.

However, I want the SPI to operate manually at any given time under certain conditions, and then when those conditions are lifted, I want to control the SPI again via the SPI.

To do this, it would seem that I would need to disable PPI once before I allow SPI to operate manually, and then re-enable PPI when the condition is lifted.
However, I do not know what steps or functions to use to disable PPI once and what steps or functions to use to restart PPI.
Could you please tell me?

Parents
  • Hello,

    I don't know what API you are currently using to set up the PPI. I guess you are either writing to some bare metal registers manually, or you are using some PPI API. 

    If you are using the registers directly, then you are probably enabling the PPI using the CHENSET register to enable the PPI channel. Then you can use the CHENCLR register to disable that same channel(s).

    If you are using some API, then you are probably using something like: nrf_drv_ppi_channel_enable() (or an equivalent using the softdevice API). In that case, look for a function called nrf_drv_ppi_channel_disable() (or the equivalent softdevice API version). 

    Then, when you are done with the custom SPI operations, you can enable the PPI channel like you did when you first set it up. The configuration will probably still be the same, so you just need to enable the channel(s).

    Best regards,

    Edvin

  • Thanks for the reply.

    I am using the API to set up the PPI. A part of the programme is shown below.

    // ----------------------------------------
    //  PWM_PPI_INIT (only use RX)
    // ----------------------------------------
    void pwm_ppi_init( void )
    {
        uint32_t rfrx_evt_addr;
        uint32_t pwm_task_addr;
        nrf_ppi_channel_t pwm_ppi_channel0;
    
    //  PPI
        nrf_drv_ppi_init();
    
        rfrx_evt_addr = nrf_radio_event_address_get(NRF_RADIO_EVENT_PAYLOAD);
        pwm_task_addr = nrfx_pwm_task_address_get(&PWM_0,NRF_PWM_TASK_SEQSTART1);
    
        nrf_drv_ppi_channel_alloc(&pwm_ppi_channel0);
        nrf_drv_ppi_channel_assign(pwm_ppi_channel0, rfrx_evt_addr, pwm_task_addr);
        nrf_drv_ppi_channel_enable(pwm_ppi_channel0);
    
        return;
    }
    
    
    
    
    // ----------------------------------------
    //  GPIOE_PIN become to make SPI (only use RX)
    // ----------------------------------------
    void ppi_init(void)
    {
        uint32_t gpio_evt1_addr, gpio_evt2_addr, spi_evt_addr;
        uint32_t spi_task_addr, spiss_task_addr1, spiss_task_addr2;
        
        uint32_t rfrx_evt_addr, gpio_evt_addr, timer_evt_addr;
        uint32_t gpioh_task_addr, gpiol_task_addr;
    
        nrf_drv_gpiote_init();
        nrf_drv_ppi_init();
    
        nrf_gpio_cfg_output(SPI_CONV);
        nrf_gpio_pin_set(SPI_CONV);
        nrf_drv_gpiote_out_config_t spiss_gpiote_config = GPIOTE_CONFIG_OUT_TASK_LOW;
        nrf_drv_gpiote_out_init(SPI_CONV, &spiss_gpiote_config); 
    
    
    //  ----------- Initialize of GPIO's output & input -----------
    //  The timing of GPIOE's output.
    //  GPIOE_POUT is first timing. Other timing is by PWM(9 pulses).
    //  ------------------------------------------------------------
        nrf_drv_gpiote_out_config_t gpiote_config = NRFX_GPIOTE_CONFIG_OUT_TASK_TOGGLE(false);
        nrf_drv_gpiote_out_init(GPIOE_POUT, &gpiote_config);
    
    
    //  ------------------------------------------------------------
    //  Initialize of GOIO's input
    //  GPIO_PIN11 & GPIO_PIN12 are the timing of spi's action.
    //  Config of INPUT GPIO_PIN11 & GPIO_PIN12
    //  ------------------------------------------------------------
        nrf_drv_gpiote_in_config_t gpiote_spi_config1 = GPIOTE_CONFIG_IN_SENSE_LOTOHI(true);    //CAUTION!! false
        nrf_drv_gpiote_in_init(GPIO_PIN11,&gpiote_spi_config1,gpioe_event_handler1);
        nrf_drv_gpiote_in_init(GPIO_PIN12,&gpiote_spi_config1,gpioe_event_handler2);
    
    
    //  ----------- Configuration of PPI ----------
    //  PPI for GPIOE_POUT (The first timing)
    
    //  GPIOE_POUT (L to H)
        rfrx_evt_addr = nrf_radio_event_address_get(NRF_RADIO_EVENT_PAYLOAD);                   //triger by RX
        gpioh_task_addr=nrf_drv_gpiote_out_task_addr_get(GPIOE_POUT);
    
        nrf_drv_ppi_channel_alloc(&gpio_ppi_channel0);
        nrf_drv_ppi_channel_assign(gpio_ppi_channel0, rfrx_evt_addr, gpioh_task_addr);
        nrf_drv_ppi_channel_enable(gpio_ppi_channel0);
    
    
    //  PPI for SPI
        gpio_evt1_addr = nrf_drv_gpiote_in_event_addr_get (GPIO_PIN11);
        gpio_evt2_addr = nrf_drv_gpiote_in_event_addr_get (GPIO_PIN12);
        spi_task_addr=nrf_drv_spi_start_task_get(&SPI_0);
    
        nrf_drv_ppi_channel_alloc(&spi_ppi_channel1);
        nrf_drv_ppi_channel_assign(spi_ppi_channel1, gpio_evt1_addr, spi_task_addr);
        nrf_drv_ppi_channel_alloc(&spi_ppi_channel2);
        nrf_drv_ppi_channel_assign(spi_ppi_channel2, gpio_evt2_addr, spi_task_addr);
    
        nrf_drv_ppi_channel_enable(spi_ppi_channel1);
        nrf_drv_ppi_channel_enable(spi_ppi_channel2);
    
    
    //  GPIOE_POUT (H to L)
        gpiol_task_addr = nrf_drv_gpiote_clr_task_addr_get(GPIOE_POUT);
    
        nrf_drv_ppi_channel_alloc(&gpio_ppi_channel1);
        nrf_drv_ppi_channel_assign(gpio_ppi_channel1, gpio_evt2_addr, gpiol_task_addr);
        nrf_drv_ppi_channel_enable(gpio_ppi_channel1);
    
        nrf_drv_gpiote_out_task_enable(GPIOE_POUT);
    
    //    nrfx_gpiote_in_event_enable(GPIO_PIN11,false);    2022/05/26
    //    nrfx_gpiote_in_event_enable(GPIO_PIN12,false);
        nrfx_gpiote_in_event_enable(GPIO_PIN11,true);
        nrfx_gpiote_in_event_enable(GPIO_PIN12,true);
    
    
    //  PPI for SPI_CONV 
    //  (H to L)
        spiss_task_addr1=nrf_drv_gpiote_clr_task_addr_get(SPI_CONV);
        nrf_drv_ppi_channel_alloc(&spiss_channl1);
        nrf_drv_ppi_channel_assign(spiss_channl1, gpio_evt1_addr, spiss_task_addr1);
        nrf_drv_ppi_channel_enable(spiss_channl1);
    
        nrf_drv_ppi_channel_alloc(&spiss_channl2);
        nrf_drv_ppi_channel_assign(spiss_channl2, gpio_evt2_addr, spiss_task_addr1);
        nrf_drv_ppi_channel_enable(spiss_channl2);
    
    //  (L to H)
        spiss_task_addr2=nrf_drv_gpiote_set_task_addr_get(SPI_CONV);
        spi_evt_addr=nrf_drv_spi_end_event_get(&SPI_0);
        nrf_drv_ppi_channel_alloc(&spiss_channl3);
        nrf_drv_ppi_channel_assign(spiss_channl3, spi_evt_addr, spiss_task_addr2);
        nrf_drv_ppi_channel_enable(spiss_channl3);
    
        nrf_drv_gpiote_out_task_enable(SPI_CONV);
    
        return;
    }
    
    

    (Program overview)

    Triggered by the reception of an ESB, the GPI outputs a total of 10 pulses, 9 PWM and 1 'GPIOE' via the PPI.
    I input those 10 pulses to another GPIO port and trigger that GPIOE input to run the SPI via PPI.

    What I want to do is to stop the sequence of these pulses when a certain condition is met, and run the SPI at an arbitrary timing, and when that condition is lifted, restart the above sequence again.
    When the condition is lifted, the above sequence is restarted again.

    (Pause)
    Question (1).
    I am aware that the API includes xxx_event_enable, xxx_task_enable, xxx_channel_enable, etc.
    To stop the system at once, do I need to disable all events, tasks and channels using the API?

    Question (2).
    Are there any other APIs to be executed other than disable?


    (Resume)
    Question (3).
    To restart PPI, is it sufficient to enable event, task and channel using the API?
    If so, should the order in which they are enabled be as in the above programe?

  • Hi
    By executing 'nrf_drv_ppi_channel_disable()' for each configured PPI channel, PPI could be stopped and SPI could be controlled at any time PPI

    PPI operation could also be restarted by reconfiguring PPI with the above programme.

    Thank you very much for your advice.

Reply Children
No Data
Related