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

NRF52 interrupt logic level event handler

Hello,

I am doing a project on a NRF52DK, using SDK15 and SES.

I have been trying to implement a basic feature, which will be a part of a bigger system:

  • Detect interrupt from sensor (HIGH or LOW)
  • When HIGH:
    • //do something
  • When LOW
    • //do something else

How should I do it? I have been looking into examples such as pin_change_int, gpiote, simple_timer and bsp but have not gotten them to work on both states, only on state change, using the bsp_init() or GPIOE.

I think that the function I should be looking into is "bsp_event_to_button_action_assign()" from "bsp.c" but due to my inexperience, I have not figured out how.

I could compile:

err_code = bsp_event_to_button_action_assign(2, BSP_BUTTON_ACTION_LONG_PUSH, BSP_EVENT_KEY_2_ACTIVE);
APP_ERROR_CHECK(err_code);

... where 2 is just the GPIO pin where the interrupt would happen, long push would be the action and BSP_EVENT_KEY_2_ACTIVE is my added special event at bsp_event_t type definition but I have not figured out how to make a function like that in my main.c.

Ideally I would like to have a function, which uses a switch statement on events (yes, just like bsp_event_handler) but according to my own rules, without modifying the libraries - instead of using them.

I have found a lot of useful links but basically all of them are for SDK11, which is very frustrating as version 15 is pretty different and I would like to make this project on the latest version.

I apologize for the confusion. I have just started with nRF development and I am coming from Arduino platform. If you have any suggestions or would like more information, then let me know and I can try them out and post the output. If I am on the wrong track or you have any useful links for SDK 15, then let me know.

Parents
  • Hello,

    If I understand you correctly, you want an interrupt whenever a pin changes state, and you want to do an action depending on what state the pin is in.

    so something like:

    pin_interrupt_callback()
    {
        if (pin_is_pressed)
        {
            //do something
        }
        else if(pin_is_not_pressed)
        {
            //do something else
        }
    }

    Is that correct?

     

    A very simple approach is using the pin_int_change example, and adding something in the handler to read the state of the pin. You can e.g. use nrf_gpio_pin_read(uint32_t pin_number);

     

    If you take the SDK15\examples\peripheral\pin_int_change, and replace the main file with the attached main file, it should toggle one of the LEDs when you push the button down, and another when you release it.

    /**
     * Copyright (c) 2014 - 2018, Nordic Semiconductor ASA
     * 
     * All rights reserved.
     * 
     * Redistribution and use in source and binary forms, with or without modification,
     * are permitted provided that the following conditions are met:
     * 
     * 1. Redistributions of source code must retain the above copyright notice, this
     *    list of conditions and the following disclaimer.
     * 
     * 2. Redistributions in binary form, except as embedded into a Nordic
     *    Semiconductor ASA integrated circuit in a product or a software update for
     *    such product, must reproduce the above copyright notice, this list of
     *    conditions and the following disclaimer in the documentation and/or other
     *    materials provided with the distribution.
     * 
     * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
     *    contributors may be used to endorse or promote products derived from this
     *    software without specific prior written permission.
     * 
     * 4. This software, with or without modification, must only be used with a
     *    Nordic Semiconductor ASA integrated circuit.
     * 
     * 5. Any software provided in binary form under this license must not be reverse
     *    engineered, decompiled, modified and/or disassembled.
     * 
     * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
     * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
     * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
     * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
     * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
     * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
     * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     * 
     */
    /** @file
     * @defgroup pin_change_int_example_main main.c
     * @{
     * @ingroup pin_change_int_example
     * @brief Pin Change Interrupt Example Application main file.
     *
     * This file contains the source code for a sample application using interrupts triggered by GPIO pins.
     *
     */
    
    #include <stdbool.h>
    #include "nrf.h"
    #include "nrf_drv_gpiote.h"
    #include "app_error.h"
    #include "boards.h"
    
    #ifdef BSP_BUTTON_0
        #define PIN_IN BSP_BUTTON_0
    #endif
    #ifndef PIN_IN
        #error "Please indicate input pin"
    #endif
    
    #ifdef BSP_LED_0
        #define PIN_OUT_1 BSP_LED_0
    #endif
    #ifdef BSP_LED_1
        #define PIN_OUT_2 BSP_LED_1
    #endif
    #ifndef PIN_OUT_1
        #error "Please indicate output pin 1"
    #endif
    #ifndef PIN_OUT_2
        #error "Please indicate output pin 2"
    #endif
    
    
    void in_pin_handler(nrf_drv_gpiote_pin_t pin, nrf_gpiote_polarity_t action)
    {
        if(nrf_gpio_pin_read(pin))
        {
            nrf_drv_gpiote_out_toggle(PIN_OUT_1);
        }
        else
        {
            nrf_drv_gpiote_out_toggle(PIN_OUT_2);
        }
    }
    /**
     * @brief Function for configuring: PIN_IN pin for input, PIN_OUT pin for output,
     * and configures GPIOTE to give an interrupt on pin change.
     */
    static void gpio_init(void)
    {
        ret_code_t err_code;
    
        err_code = nrf_drv_gpiote_init();
        APP_ERROR_CHECK(err_code);
    
        nrf_drv_gpiote_out_config_t out_config = GPIOTE_CONFIG_OUT_SIMPLE(false);
    
        err_code = nrf_drv_gpiote_out_init(PIN_OUT_1, &out_config);
        APP_ERROR_CHECK(err_code);
        err_code = nrf_drv_gpiote_out_init(PIN_OUT_2, &out_config);
        APP_ERROR_CHECK(err_code);
    
        nrf_drv_gpiote_in_config_t in_config = GPIOTE_CONFIG_IN_SENSE_TOGGLE(true);
        in_config.pull = NRF_GPIO_PIN_PULLUP;
    
        err_code = nrf_drv_gpiote_in_init(PIN_IN, &in_config, in_pin_handler);
        APP_ERROR_CHECK(err_code);
    
        nrf_drv_gpiote_in_event_enable(PIN_IN, true);
    }
    
    /**
     * @brief Function for application main entry.
     */
    int main(void)
    {
        gpio_init();
    
        while (true)
        {
            // Do nothing.
        }
    }
    
    
    /** @} */
    

     

    Best regards,

    Edvinn

     

  • Good morning. Thank you for your answer. Something like that is the easiest approach indeed and I had an example working like that.

    What I would like is:

    void event handler(event){
    
        switch(event){
        
            case interrupt_high: //**// break;
            
            case interrupt_low: //**// break;
            
            case reset_button_toggle: //**// break;
            
            case another_button_long_press: //**// break;
            
            default: break;
    
    }}

    I think that this would be a better approach for multiple events that may happen further along as the system evolves and new peripherals are added and the clear example is bsp_event_handler(bsp_event_t event). I will start experimenting again and appreciate any instructions.

    EDIT: Have not got anything to work... I tried to make a event handler again but without luck. Now I tried again with the simpler example and having problems as well. When I log the text to console, while having NRF_LOG_FLUSH in the while loop in main, then it works. If I flush logs inside the handler, then the handler ceases to work (doesnt detect pin changes anymore). If I want to get the temperature from SPI and print it inside the handler, it does not print anything and ceases to function.

    This seems really complicated to implement... does anybody have some good suggestions?

    I would like to:

    • Detect interrupts from sensor (active/inactive)
    • Then based on that, set the state of the machine (machine is working, not working etc.)
    • If the machine would be working, then get data from sensor with SPI and update advertising package with the data

    I have a separate file where the SPI connection works and in another file where I can send test BLE data in manufacturer data. I want to have a low-power communication where I just send sensor data through BLE to phone when machine is working and I am trying to implement features step by step - in the hopes of combining smaller functions in the end.

    void in_pin_handler(nrf_drv_gpiote_pin_t pin, nrf_gpiote_polarity_t action)
    {
        if(nrf_gpio_pin_read(INT_2) == 0){
            NRF_LOG_INFO("Machine active");
            //float temperature = read_temperature();
            //NRF_LOG_INFO("Temperature is: " NRF_LOG_FLOAT_MARKER "\r\n", NRF_LOG_FLOAT(temperature));
            //NRF_LOG_FLUSH();
        }
        else if(nrf_gpio_pin_read(INT_2) == 1){
            NRF_LOG_INFO("Machine inactive");
            //NRF_LOG_FLUSH();
        }
    }

  • Hello,

    I suspect that you have some IRQ priority issues, when you move the flush function to your event handler. It is trying to run the event handler, but is not allowed, since the event has a higher priority, so you are stuck in a deadlock. You can try to lower your interrupt priority, but is there a reason for why you need to move the flushing to the event handler? You can still call NRF_LOG_INFO(); from your events.

     

    Best regards,

    Edvin

  • Thank you for replying. I do not want to have the flush in the handler. This was just for testing and due to my lack of knowledge I tried out many things which were not working. I wanted to add the logging feature to the application in Segger Studio but did not get it to work even though I added the header files in main.c and CMSIS had the necessary defines enabled.

    Right now I have moved a bit on from the initial problem as I was not able to do my function how I want, which is an event handler in bsp_event_handler and where I could sense if the pin has went from high to low or vice versa. I am using right now the pin_int_change which obviously works but my goal is to get the same function to work in bsp. I feel that I need to learn a bit more pointers, callbacks and events - I was trying to trace down how the bsp_event_handler gets called and how to assign events to custom pins on the board but got confused in the process... If you have any thoughts, feel free to share them and I will try them out.

Reply
  • Thank you for replying. I do not want to have the flush in the handler. This was just for testing and due to my lack of knowledge I tried out many things which were not working. I wanted to add the logging feature to the application in Segger Studio but did not get it to work even though I added the header files in main.c and CMSIS had the necessary defines enabled.

    Right now I have moved a bit on from the initial problem as I was not able to do my function how I want, which is an event handler in bsp_event_handler and where I could sense if the pin has went from high to low or vice versa. I am using right now the pin_int_change which obviously works but my goal is to get the same function to work in bsp. I feel that I need to learn a bit more pointers, callbacks and events - I was trying to trace down how the bsp_event_handler gets called and how to assign events to custom pins on the board but got confused in the process... If you have any thoughts, feel free to share them and I will try them out.

Children
  • Hello,

    The BSP library (without modifications) looks like it is only meant for simple button handling. To be honest, it is a bit confusing, and difficult to understand how it works.

     

    If you want to use a button library, I suggest that you use the app_button.c/h directly library instead. This is also used by the bsp library, but the bsp library strips away an awful lot in the actual event. You will only get the button number in the bsp event, and you can't trigger the event on both push and pull.

     

    Look into the app_button instead.

     

    The app_button library is good if you intend to use it for physical buttons, because it has a debounce filter functionality. If you intend to control the GPIOs by wires (and don't need debounce), I don't see a reason why not to use the pin_int_change implementation.

     

     

    Best regards,

    Edvin

  • Thank you for such a constructive and towards solution leading reply. I will follow your instructions!

Related