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

How to use EasyDMA as an event for PPI?

I combined the BLE UART and SPIS Peripheral example of SDK V17.0.2 to receive data from a microcontroller using SPIS protocol in every 32 milliseconds and send it over through BLE at 128 milliseconds intervals. However, the EasyDMA is turned on all the time (see the main loop in the attached code) and thus the nRF52832 is consuming around 2mA current all the time.

So, to reduce current consumption, I want to enable EasyDMA only when the SPIS transfer is occurring i.e., 32 milliseconds. Thus, I am planning to use PPI and GPIOTE to sense chip select (CS) pin and use it as an Event and enable EasyDMA as the Task. 

However, as I went through the documentation, I could not find any reference on how to get the task endpoint address for EasyDMA. I need that address to configure the PPI.

Please let me know how can I get the EasyDMA task endpoint address or any other way to enable EasyDMA only for 32 milliseconds

int main(void)
{
    bool erase_bonds;
    
    // Initialize.
    log_init();
    timers_init();
    power_management_init();
    ble_stack_init();
    gap_params_init();
    gatt_init();
    services_init();
    advertising_init();
    conn_params_init();

    // Start execution.
    NRF_LOG_INFO("Debug logging for UART over RTT started.");
    advertising_start();
    
    conn_evt_len_ext_set(true);

    uint32_t       err_code;
    //SPI Initialization
    NRF_LOG_INFO("SPIS example");
    nrf_drv_spis_config_t spis_config = NRF_DRV_SPIS_DEFAULT_CONFIG;
    spis_config.csn_pin               = APP_SPIS_CS_PIN;
    spis_config.miso_pin              = APP_SPIS_MISO_PIN;
    spis_config.mosi_pin              = APP_SPIS_MOSI_PIN;
    spis_config.sck_pin               = APP_SPIS_SCK_PIN;

    APP_ERROR_CHECK(nrf_drv_spis_init(&spis, &spis_config, spis_event_handler));

    // Enter main loop.
    for (;;)
    {
      // Reset rx buffer and transfer done flag
        if (master_connected == true) //Start SPIS receive only when master is connected
        {
            memset(m_rx_buf, 0, m_length);
            spis_xfer_done = false;

            APP_ERROR_CHECK(nrf_drv_spis_buffers_set(&spis, connected_buf, m_length_connected, m_rx_buf, m_length));
     
            connected_buf[m_length] = 1; //connected_buf is used to send data to the SPI master
            while (!spis_xfer_done)
            {
                __WFE();
            }
            //__NOP();
        }
        else
        {
            connected_buf[m_length] = 0; //connected_buf is used to send data to the SPI master
        }
        //NRF_LOG_INFO("idle state started.");
        idle_state_handle();
    }
}

  • Hello ,

    Thank you for your reply. You were right. After removing the “NRF_POWER->TASKS_CONSTLAT = 1;” the current consumption was ~40uA, which is close to our calculation.

    However, in my BLE+SPIS code, I did not use “NRF_POWER->TASKS_CONSTLAT = 1;”

    I will refer to my code for details.

    When I disabled the constant latency in the BLE+SPI code with this command, NRF_POWER->TASKS_CONSTLAT = 0; in line 24 below, the BLE stopped advertising.

    int main(void)
    {
        bool erase_bonds;
        // Initialize.
        log_init();
        timers_init();
        power_management_init();
        ble_stack_init();
        gap_params_init();
        gatt_init();
        services_init();
        advertising_init();
        conn_params_init();
        advertising_start();
        conn_evt_len_ext_set(true);
        
        //SPI Initialization
        nrf_drv_spis_config_t spis_config = NRF_DRV_SPIS_DEFAULT_CONFIG;
        spis_config.csn_pin               = APP_SPIS_CS_PIN;
        spis_config.miso_pin              = APP_SPIS_MISO_PIN;
        spis_config.mosi_pin              = APP_SPIS_MOSI_PIN;
        spis_config.sck_pin               = APP_SPIS_SCK_PIN;
    
        NRF_POWER->TASKS_CONSTLAT = 0;
    
        nrf_drv_spis_init(&spis, &spis_config, spis_event_handler);
        // Enter main loop.
        for (;;)
        {
            memset(m_rx_buf, 0, m_length);
            spis_xfer_done = false;
            APP_ERROR_CHECK(nrf_drv_spis_buffers_set(&spis, connected_buf, m_length_connected, m_rx_buf, m_length));
            connected_buf[m_length] = 1;
            while (!spis_xfer_done)
            {
                __WFE();
            }
            idle_state_handle();
        }
    }

    Only after commenting out that previous command, on line 24, the BLE start to advertise.

    As I understand, this means the softdevice needs constant latency to operate properly and it enables it whenever necessary. Thus, when constant latency is enabled, the SPIS also starts using HFCLK. I checked the clock register values and found that HFCLK is indeed active all the time (attached screenshot)

    Thus, my queries are,

    1. While keeping TASKS_CONSTLAT = 0, is there any other option that I can enable for the advertising to work?
    2. How can I use HFCLK only for softdevice and keep LFCLK active during the SPIS event?

    A brief overview of my observations before I added the TASKS_CONSTLAT part of the code on line 24 above:

    1. If I remove the SPIS part from the code and keep the BLE part active (code below), the current consumption is ~16uA. BLE part active means that the device is only advertising and the advertising interval is 1.5s.

    int main(void)
    {
        bool erase_bonds;
        // Initialize.
        log_init();
        timers_init();
        power_management_init();
        ble_stack_init();
        gap_params_init();
        gatt_init();
        services_init();
        advertising_init();
        conn_params_init();
        advertising_start();
        conn_evt_len_ext_set(true);
        
        // Enter main loop.
        for (;;)
        {
            idle_state_handle();
        }
    }

    1. On the other hand, if I remove the BLE part from the code and keep the SPIS part active, the current consumption is ~40uA (code below). SPIS part active means that I am receiving 244 bytes of data from the microcontroller every 32ms.

    int main(void)
    {
        bool erase_bonds;
        // Initialize.
        log_init();
        timers_init();
        power_management_init();
        
        //SPI Initialization
        nrf_drv_spis_config_t spis_config = NRF_DRV_SPIS_DEFAULT_CONFIG;
        spis_config.csn_pin               = APP_SPIS_CS_PIN;
        spis_config.miso_pin              = APP_SPIS_MISO_PIN;
        spis_config.mosi_pin              = APP_SPIS_MOSI_PIN;
        spis_config.sck_pin               = APP_SPIS_SCK_PIN;
    
        nrf_drv_spis_init(&spis, &spis_config, spis_event_handler);
        // Enter main loop.
        for (;;)
        {
            memset(m_rx_buf, 0, m_length);
            spis_xfer_done = false;
            APP_ERROR_CHECK(nrf_drv_spis_buffers_set(&spis, connected_buf, m_length_connected, m_rx_buf, m_length));
            connected_buf[m_length] = 1;
            while (!spis_xfer_done)
            {
                __WFE();
            }
            idle_state_handle();
        }
    }

    1. However, if I keep both SPIS and BLE active, the current consumption is ~890uA (code below).

    int main(void)
    {
        bool erase_bonds;
        // Initialize.
        log_init();
        timers_init();
        power_management_init();
        ble_stack_init();
        gap_params_init();
        gatt_init();
        services_init();
        advertising_init();
        conn_params_init();
        advertising_start();
        conn_evt_len_ext_set(true);
        
        //SPI Initialization
        nrf_drv_spis_config_t spis_config = NRF_DRV_SPIS_DEFAULT_CONFIG;
        spis_config.csn_pin               = APP_SPIS_CS_PIN;
        spis_config.miso_pin              = APP_SPIS_MISO_PIN;
        spis_config.mosi_pin              = APP_SPIS_MOSI_PIN;
        spis_config.sck_pin               = APP_SPIS_SCK_PIN;
    
        nrf_drv_spis_init(&spis, &spis_config, spis_event_handler);
        // Enter main loop.
        for (;;)
        {
            memset(m_rx_buf, 0, m_length);
            spis_xfer_done = false;
            APP_ERROR_CHECK(nrf_drv_spis_buffers_set(&spis, connected_buf, m_length_connected, m_rx_buf, m_length));
            connected_buf[m_length] = 1;
            while (!spis_xfer_done)
            {
                __WFE();
            }
            idle_state_handle();
        }
    }

    PS.: I DO NOT send any data over BLE in any of these configurations. Only, the advertisement part of the BLE code remains active. My application requires sending data in a 127ms connection interval. As I am receiving 244 bytes of data in every 32ms over SPI communication, I have to send (127/32) ~4 packets in each connection interval. In my application, if I send (244*4) or 976 bytes in 127ms connection interval, the current consumption jumps to 1.2mA.

  • Hi,

     

    Rafi said:
    Only after commenting out that previous command, on line 24, the BLE start to advertise

    You should not write '0' to a task. Only '1' is valid for all TASKS_* prefixed registers.

    Rafi said:
    On the other hand, if I remove the BLE part from the code and keep the SPIS part active, the current consumption is ~40uA (code below). SPIS part active means that I am receiving 244 bytes of data from the microcontroller every 32ms.

    This is expected if the SPIS is active in such a interval, as it will draw added current when the CSN pin is asserted and at the end, the cpu will be awoken to handle the event itself.

     

    Kind regards,

    Håkon

Related