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

GPIOTE can toggle led but cannot set boolean

board: nRF52 DK

[update - fixed this - see #2]

When I use the following (shortened) code, the LED blinks when I press button 2 but I see no logs. NRF_LOG_INFO() is working in other areas of the code.

#define BMA_TAP_INTERRUPT_PIN BUTTON_2
bool foo = false;

void bma_tap_interrupt_handler(nrf_drv_gpiote_pin_t pin, nrf_gpiote_polarity_t action)
{
    nrf_drv_gpiote_out_toggle(LED1);
    foo = true;
}

void bma_enable_tap_interrupt(uint32_t pin, nrf_drv_gpiote_evt_handler_t evt_handler)
{
    ret_code_t ret_code;

    if (!nrf_drv_gpiote_is_init())
    {
        ret_code = nrf_drv_gpiote_init();
        APP_ERROR_CHECK(ret_code);
    }

    nrf_drv_gpiote_in_config_t gpiote_config = GPIOTE_CONFIG_IN_SENSE_TOGGLE(true);
    gpiote_config.pull = NRF_GPIO_PIN_PULLUP;

    ret_code = nrf_drv_gpiote_in_init(pin, &gpiote_config, evt_handler);
    APP_ERROR_CHECK(ret_code);

    nrf_drv_gpiote_in_event_enable(pin, true);

    NRF_LOG_INFO("initialised pin %d for tap intr", pin);

    /** for debug **/
    nrf_drv_gpiote_out_config_t out_config = GPIOTE_CONFIG_OUT_SIMPLE(false);

    ret_code = nrf_drv_gpiote_out_init(LED1, &out_config);
    APP_ERROR_CHECK(ret_code);
    /** for debug **/
}

int main(void)
{
    bma_enable_tap_interrupt(BMA_TAP_INTERRUPT_PIN, bma_tap_interrupt_handler);

    for (;;)
    {
        if (foo)
        {
            NRF_LOG_INFO("bar");
            foo = false;
        }
        idle_state_handle();
    }
}

It doesn't make sense to me that nrf_drv_gpiote_out_toggle(LED1) gets called but foo does not get set to true.

[#2]

For an extra challenge, when I add the following function call to main (setup pins: sck=2, dout=26), LED1 turns on but pressing button 2 does not actuate the led anymore.

void hx711_init(enum hx711_mode mode, struct hx711_setup *setup, hx711_evt_handler_t callback)
{
    ret_code_t ret_code;
    hx711_callback = callback;
    m_setup = setup;
    m_mode = mode;

    if (m_setup != NULL)
    {
        nrf_gpio_cfg_output(m_setup->pd_sck);
        nrf_gpio_pin_set(m_setup->pd_sck);

        if (!nrf_drv_gpiote_is_init())
        {
            ret_code = nrf_drv_gpiote_init();
            APP_ERROR_CHECK(ret_code);
        }

        nrf_drv_gpiote_in_config_t gpiote_config = GPIOTE_CONFIG_IN_SENSE_HITOLO(true);
        nrf_gpio_cfg_input(m_setup->dout, NRF_GPIO_PIN_NOPULL);
        ret_code = nrf_drv_gpiote_in_init(m_setup->dout, &gpiote_config, gpiote_evt_handler);
        APP_ERROR_CHECK(ret_code);


        /* Set up timers, gpiote, and ppi for clock signal generation*/
        NRF_TIMER1->CC[0]     = 1;
        NRF_TIMER1->CC[1]     = HX711_DEFAULT_TIMER_COMPARE;
        NRF_TIMER1->CC[2]     = HX711_DEFAULT_TIMER_COUNTERTOP;
        NRF_TIMER1->SHORTS    = (uint32_t) (1 << 2);    //COMPARE2_CLEAR
        NRF_TIMER1->PRESCALER = 0;

        NRF_TIMER2->CC[0]     = m_mode;
        NRF_TIMER2->MODE      = 2;

        NRF_GPIOTE->CONFIG[1] = (uint32_t) (3 | (m_setup->pd_sck << 8) | (1 << 16) | (1 << 20));

        NRF_PPI->CH[0].EEP   = (uint32_t) &NRF_TIMER1->EVENTS_COMPARE[0];
        NRF_PPI->CH[0].TEP   = (uint32_t) &NRF_GPIOTE->TASKS_SET[1];
        NRF_PPI->CH[1].EEP   = (uint32_t) &NRF_TIMER1->EVENTS_COMPARE[1];
        NRF_PPI->CH[1].TEP   = (uint32_t) &NRF_GPIOTE->TASKS_CLR[1];
        NRF_PPI->FORK[1].TEP = (uint32_t) &NRF_TIMER2->TASKS_COUNT; // Increment on falling edge
        NRF_PPI->CH[2].EEP   = (uint32_t) &NRF_TIMER2->EVENTS_COMPARE[0];
        NRF_PPI->CH[2].TEP   = (uint32_t) &NRF_TIMER1->TASKS_SHUTDOWN;
        NRF_PPI->CHEN = NRF_PPI->CHEN | 7;
    }
    else
    {
        NRF_LOG_WARNING("hx711 setup has not been assigned yet");
    }
}

For this problem, I suspect it has something to do with GPIOTE channels, but I can't watch the registers because my vscode cortex debugger is not working right now. I'm not overlapping  any pins I believe.

Parents Reply Children
  •  The channel is setup as a toggle, meaning that you get the handler called when it goes active and inactive, is that the intended behavior?

    Just for debug. I will change it to LOTOHI/HITOLO when I've fixed the bug below.

    You are clearing and shutting down the timer when CC[2] hits. Do you start the timer again manually?

    Yes I start the timer again in hx711_sample() using NRF_TIMER1->TASKS_START = 1. To give you a sense of the code flow, I have an APP_TIMER setup to call hx711_start() every 2s. Then when dout goes low, gpiote clocks out the adc value using the sck pin

    void hx711_start()
    {
        NRF_LOG_DEBUG("start sampling");
        
        NRF_GPIOTE->TASKS_CLR[1] = 1;
        // Generates interrupt when new sampling is available. 
        nrf_drv_gpiote_in_event_enable(m_setup->dout, true);
    }
    
    void hx711_stop()
    {
        NRF_LOG_DEBUG("stop sampling");
        nrf_drv_gpiote_in_event_disable(m_setup->dout);
    }
    
    /* Clocks out HX711 result - if readout fails consistently, try to increase the clock period and/or enable compiler optimization */
    void hx711_sample()
    {
        NRF_TIMER2->TASKS_CLEAR = 1;
        m_sample.count = 0;
        m_sample.value = 0;
        m_sample.status = Busy;
        NRF_TIMER1->TASKS_START = 1; // Starts clock signal on PD_SCK
        NRF_LOG_INFO("sampling hx711");
    
        for (uint32_t i=0; i < HX711_DEFAULT_ADC_RES; i++)
        {
            do
            {
                /* NRF_TIMER->CC[1] contains number of clock cycles.*/
                NRF_TIMER2->TASKS_CAPTURE[1] = 1;
                if (NRF_TIMER2->CC[1] >= HX711_DEFAULT_ADC_RES)
                {
                    NRF_LOG_WARNING("readout not in sync");
                    goto EXIT; // Readout not in sync with PD_CLK. Abort and notify error.
                }
            }
            while(NRF_TIMER1->EVENTS_COMPARE[0] == 0);
            NRF_TIMER1->EVENTS_COMPARE[0] = 0;
            m_sample.value |= (nrf_gpio_pin_read(m_setup->dout) << (23 - i));
            m_sample.count++;
            m_sample.status = Unread;
        }
        EXIT:
    
        m_sample.value = hx711_convert(m_sample.value);
        
        if (m_sample.value > 0x7FFFFF)
        {
            NRF_LOG_WARNING("sample returned a negative value. Check connections");
            return;
        }
        NRF_LOG_DEBUG("number of bits: %d. ADC val: 0x%x or 0d%d", 
        m_sample.count,
        m_sample.value,
        m_sample.value);
    
        if (hx711_callback != NULL)
        {
            hx711_callback(&m_sample.value);
        }
    }

    Is the input signal in the MHz range? If so, you should look at implementing the workaround for this errata

    My TIMER1 prescaler is set to 0, so my timer is running in the MHz. The input signal from the hx711 to the dout pin is at most 80 Hz.

    I checked to see which pins each GPIOTE was assigned to. GPIOTE[0] is pin 26 (dout) and GPIOTE[1] is pin 14 (button 2 in pca10040.h). So the channels appear to be separated. Still not sure what the source of my problem is.

  • Hi,

     

    Is the issue that you read out incorrectly using this function, or is the initial issue with button 2 (GPIO P0.14) still present? 

    Did you try to implement the errata workaround? If you are sampling several channels asynchronously, you can still get into this scenario, even if the sampled signals are of lower frequency, as they can overlap with a very low time difference.

     

    Kind regards,

    Håkon

  • I added the fix to main after initialising both gpiote channels (using hx711_init and bma_enable_tap_interrupt)

    #define BMA_TAP_INTERRUPT_PIN BUTTON_2
    bool foo = false;
    
    void bma_tap_interrupt_handler(nrf_drv_gpiote_pin_t pin, nrf_gpiote_polarity_t action)
    {
        nrf_drv_gpiote_out_toggle(LED1);
        foo = true;
    }
    
    void bma_enable_tap_interrupt(uint32_t pin, nrf_drv_gpiote_evt_handler_t evt_handler)
    {
        ret_code_t ret_code;
    
        if (!nrf_drv_gpiote_is_init())
        {
            ret_code = nrf_drv_gpiote_init();
            APP_ERROR_CHECK(ret_code);
        }
    
        nrf_drv_gpiote_in_config_t gpiote_config = GPIOTE_CONFIG_IN_SENSE_TOGGLE(true);
        gpiote_config.pull = NRF_GPIO_PIN_PULLUP;
    
        ret_code = nrf_drv_gpiote_in_init(pin, &gpiote_config, evt_handler);
        APP_ERROR_CHECK(ret_code);
    
        nrf_drv_gpiote_in_event_enable(pin, true);
    
        NRF_LOG_INFO("initialised pin %d for tap intr", pin);
    
        /** for debug **/
        nrf_drv_gpiote_out_config_t out_config = GPIOTE_CONFIG_OUT_SIMPLE(false);
    
        ret_code = nrf_drv_gpiote_out_init(LED1, &out_config);
        APP_ERROR_CHECK(ret_code);
        /** for debug **/
    }
    
    int main(void)
    {
        hx711_init() // when this is commented out, the bma tap interrupt works
        bma_enable_tap_interrupt(BMA_TAP_INTERRUPT_PIN, bma_tap_interrupt_handler);
        
        /* Add fix for errata 155 */
        uint32_t GPIOTE_CH_USED = 0;
        uint32_t GPIOTE_CH_USED_1 = 1;
        *(volatile uint32_t *)(NRF_GPIOTE_BASE + 0x600 + (4 * GPIOTE_CH_USED)) = 1;
        *(volatile uint32_t *)(NRF_GPIOTE_BASE + 0x600 + (4 * (GPIOTE_CH_USED_1))) = 1;
    
        for (;;)
        {
            if (foo)
            {
                NRF_LOG_INFO("bar");
                foo = false;
            }
            idle_state_handle();
        }
    }

    Still having the issue where when hx711_init() is called, pressing button 2 no longer triggers bma_tap_interrupt_handler(). When hx711_init() is commented out everything works fine

  • Hi,

    mbards said:
    Still having the issue where when hx711_init() is called, pressing button 2 no longer triggers bma_tap_interrupt_handler(). When hx711_init() is commented out everything works fine

    Could that be related to the NRF_GPIOTE->CONFIG[1] call inside that function? That seems to overwrite your "LED1" configuration? You should check the pin and action, as mentioned earlier; if the pin pulse is very short, the handler will be called twice in a short time frame, and its likely that your program will not work as intended.

     

    Kind regards,

    Håkon

Related