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

Proper technique for triggering PWM and BLE Advertising from a button press interrupt?

I am currently tasked with programming the NRF52810 to boot up upon a button press and then sit and wait for further button presses to trigger various functionality including sending out a few second PWM pulse and beginning to stream BLE advertisements. 

As a very novice with firmware development, my boss informed me that triggering larger blocks of code during an interrupt (i.e the button press if I understand the button event handler correctly) can be a bad idea as it might cause a hang up in the system by blocking the execution of essential code.  He instead suggested using simple flags that are set during the button presses that then tell a loop in main() to execute that same code instead. 

My questions, and issues, are:

1) Is this technique of setting flags and leaving the execution to a loop in main() advised for performing the type of tasks I've mentioned such as BLE advertising and PWM?

2) If so, how would that be done?  The example project I'm using is ble_peripheral/ble_app_blinky/pca10040/s132/ses and is where I've tried doing things with this technique.  I've added the following after the idle_state_handle() call but from my debugging I'm not seeing the loop actually loop, I think I'm misunderstanding something:

  // Enter main loop.
    for (;;)
    {
        idle_state_handle();

        if (begin_advertising)
        {
          advertising_start();
        }

        if (activate_motor)
        {
          pwm_motor_start();
        }
    }

Thank you and I'll try to be prompt to answer any comments!

Parents
  • Hi

    1) Yes, using flags like you describe is a very common way to avoid running large blocks of code in an interrupt context, but I wouldn't really count tasks like starting advertising or setting the PWM frequency as large blocks of code. These operations should run in a couple of microseconds, which you can safely do in an interrupt. 

    The critical aspect is that when accessing the SoftDevice (Bluetooth stack) from an interrupt you need to be running at interrupt priority 6 or 7. Any higher than that (lower number) and the SoftDevice API will not work properly. 

    All the standard interrupts, such as the button handler and Bluetooth event handler, will be running in one of these priorities. 

    2) How is the begin_advertising and activate_motor flags set?

    The idle_state_handle() function should exit as soon as any application interrupt occurs, such as the press of a button or the expiration of a timer. 

    Also, you normally need to clear the flags after you act upon them, otherwise you risk running the same block of code over and over again:

    if(flag)
    {
      flag = false;
      
      // Run code
    }

    Best regards
    Torbjørn

Reply
  • Hi

    1) Yes, using flags like you describe is a very common way to avoid running large blocks of code in an interrupt context, but I wouldn't really count tasks like starting advertising or setting the PWM frequency as large blocks of code. These operations should run in a couple of microseconds, which you can safely do in an interrupt. 

    The critical aspect is that when accessing the SoftDevice (Bluetooth stack) from an interrupt you need to be running at interrupt priority 6 or 7. Any higher than that (lower number) and the SoftDevice API will not work properly. 

    All the standard interrupts, such as the button handler and Bluetooth event handler, will be running in one of these priorities. 

    2) How is the begin_advertising and activate_motor flags set?

    The idle_state_handle() function should exit as soon as any application interrupt occurs, such as the press of a button or the expiration of a timer. 

    Also, you normally need to clear the flags after you act upon them, otherwise you risk running the same block of code over and over again:

    if(flag)
    {
      flag = false;
      
      // Run code
    }

    Best regards
    Torbjørn

Children
  • Hello,

    Thank you for your response, this is really helpful info to clarify things.

    In our case, the PWM was slightly more complex than just setting the frequency since we were doing a loop to perform a timed pulse before exiting the loop and deactivating PWM.  Not sure if that makes a difference, but I was seeing an issue where if the PWM was triggered in main it would work fine but if called during a button press interrupt it would hang eternally on the   " while (!ready_flag); "  check.  I chalked it up to being an interrupt issue but am really not sure.


    Ultimately though, we were able to use the flag method and everything works perfectly now.  Thank you again for your assistance, I really appreciate it.

    -Nick

  • Hi Nick

    That makes sense. Running long code sequences like that is definitely better done from main. 

    Good to hear you got it working Slight smile

    BR
    Torbjørn

Related