RAK WisBlock – Timer Events

In this post I’ll reexamine my last example, updating the code to use a non-blocking approach like EventTimer rather than the blocking delay() function.

Link to previous example for easy reference: RAK WisBlock – Getting started using LEDs

If you’re already an experience Arduino developer then this may be a quick review, for those who are new to these systems it will teach you the basics of using Arduino event timers.

Prerequisites:

When coding low power devices it is important to save cycles where you can and in this example limit the time the LEDs are lit in a non-blocking approach. Key here being to use TimerEvent_t structure. It took a bit of research to find all the structures and include files to determine exactly how the system should work so I’ve includes some references below in the event you want to dig a little deeper into the system:

  • timer.h – \Arduino\libraries\SX126x-Arduino\src\boards\mcu
  • timer.cpp – \Arduino\libraries\SX126x-Arduino\src\boards\ mcu\nrf52832
  • ticker.h and ticker.cpp – \AppData\Local\Arduino15\packages\ rakwireless\hardware\esp32\1.0.4\libraries\Ticker\src
  • SoftwareTimer.h and SoftwareTimer.cpp – \AppData\Local\ Arduino15\packages\rakwireless\hardware\nrf52\ 0.21.20\cores\nRF5\utility

NOTE: The above file structure may differ depending on your OS and system configuration. This is shown from a Windows 10 OS.

Important lesson

When writing code using interrupt timers (IRQ) do not put Serial.println statements in the routine called by the interrupt. In this case setOnLED() and setOffLED(). Keep these routines as short as possible by setting a flag such as eventTriggered and handle the event in the main loop. Using the Serial output is much to slow compared to IRQs and you may find that your code doesn’t complete before the next interrupt fires and begins the same routine again. I fell victim to this pitfall while trying to debug this routine and it took me much too long to figure out what the root cause.

The code

The code below will alternate blinking the green and blue LEDs. You can control the frequency and duration of the blinks using the timerBlinkInterval and timerBlinkDelay variables respectively.

// Copyright Coinpie.Academy (c) 2021 except as cited
// RAK4630 supply two LED
// This version of CoinPie-Blink implements the TimerEvent

#include <Arduino.h>
#include <LoRaWan-RAK4630.h> //http://librarymanager/All#SX126x

// Green LED 
#define MY_LED_GREEN 35
bool greenOn = true;
// Blue LED
#define MY_LED_BLUE 36
bool blueOn = false;

// whichLED, true = green, false = blue
bool whichLED = true;

// setup constants to control the timer
const int timerBlinkInterval = 500;  // How much time should pass before the next blink
const int timerBlinkDelay = 125;     // How long should each blink (period LED is on) last
bool eventTriggered = false;

// Instanciate the event timers
TimerEvent_t timerBlinkSpeed;
TimerEvent_t timer100Milli;

void setup() {
  // set LEDs to output mode
  pinMode(MY_LED_GREEN, OUTPUT);
  pinMode(MY_LED_BLUE, OUTPUT);

  // turn off both LEDs
  digitalWrite(MY_LED_GREEN, LOW);
  digitalWrite(MY_LED_BLUE, LOW);

  time_t timeout = millis();
  Serial.begin(115200);
  while (!Serial)
  {
    if ((millis() - timeout) < 5000)
    {
      delay(100);
    }
    else
    {
      break;
    }
  }

  // initalize the timers
  TimerInit(&timerBlinkSpeed, setOnLED);
  TimerSetValue(&timerBlinkSpeed, timerBlinkInterval);
  
  TimerInit(&timer100Milli, setOffLED);
  TimerSetValue(&timer100Milli, timerBlinkDelay);

  TimerStart(&timerBlinkSpeed);
  TimerStart(&timer100Milli);

  Serial.println("|======================================|");
  Serial.println("|     Welcome to CoinPie Academy!!!    |");
  Serial.println("|RAK4630 LoRaWan Setup Routine Complete|");
}

void setOffLED() {
  eventTriggered = true;
  if(whichLED) {
    greenOn = false;
  } else
  {
    blueOn = false;
  }
  // Swap which LED will turn on next
  whichLED = !whichLED;

}

void setOnLED() {
  if(whichLED) {
     greenOn = true;
  } else
  {
     blueOn = true;
  }
  eventTriggered = true;
  // reset the timers
  TimerSetValue(&timerBlinkSpeed, timerBlinkInterval);
  TimerSetValue(&timer100Milli, timerBlinkDelay);
  
  TimerStart(&timerBlinkSpeed);
  TimerStart(&timer100Milli);
}

void loop() {
  // each loop, check if an event was triggered, if so update the status of the LEDs:
    if(eventTriggered) {
      eventTriggered = false;
      if(blueOn) {
        digitalWrite(MY_LED_BLUE, HIGH);
      } else {
        digitalWrite(MY_LED_BLUE, LOW);
      }
      if(greenOn) {
        digitalWrite(MY_LED_GREEN, HIGH);
      } else {
        digitalWrite(MY_LED_GREEN, LOW);
      }
      Serial.printf("Blue = %d, Green = %d\n", blueOn, greenOn);
   }
}

Summary

Using non-blocking code is important to keep your WisBlock code running smoothly. As noted there are some pitfalls to avoid but if properly programmed you’ll find that your sketch will perform like a champ!

Leave a comment

Your email address will not be published. Required fields are marked *

ninety four − eighty eight =