B4R Tutorial Timers, Loopers and CallSubPlus

Discussion in 'B4R Tutorials' started by Erel, Apr 19, 2016.

  1. Erel

    Erel Administrator Staff Member Licensed User

    Arduino C example #1:
    Code:
    void setup() {
      pinMode(
    13, OUTPUT);
    }

    // the loop function runs over and over again forever
    void loop() {
      digitalWrite(13, HIGH);   // turn the LED on (HIGH is the voltage level)
      delay(1000);              // wait for a second
      digitalWrite(13, LOW);    // turn the LED off by making the voltage LOW
      delay(1000);              // wait for a second
    }
    While the above design is simple and works properly for very small examples, it doesn't work with larger programs as the single thread cannot do anything else while it sleeps.

    The B4R solution is to use a Timer instead. There could be many timers running and they will all work without interfering each other.

    Blink program with a timer:
    Code:
    Sub Process_Globals
       
    Public Serial1 As Serial
       
    Private Timer1 As Timer
       
    Private pin13 As Pin
    End Sub

    Private Sub AppStart
       Serial1.Initialize(
    115200)
       
    Log("AppStart")
       pin13.Initialize(
    13, pin13.MODE_OUTPUT)
       Timer1.Initialize(
    "Timer1_Tick"1000)
       Timer1.Enabled = 
    True 'don't forget to enable it
    End Sub

    Private Sub Timer1_Tick
       pin13.DigitalWrite(
    Not(pin13.DigitalRead))
    End Sub
    CallSubPlus is similar to a timer that fires once. CallSubPlus allows you to run a sub after a specified duration. Like a timer it doesn't block the thread.

    Blink example based on CallSubPlus:

    Code:
    Sub Process_Globals
      
    Public Serial1 As Serial
      
    Private pin13 As Pin
    End Sub

    Private Sub AppStart
      Serial1.Initialize(
    115200)
      
    Log("AppStart")
      pin13.Initialize(
    13, pin13.MODE_OUTPUT)
      LedOn(
    0)
    End Sub

    Private Sub LedOn (tag As Byte)
      pin13.DigitalWrite(
    True)
      CallSubPlus(
    "LedOff"10000)
    End Sub

    Private Sub LedOff(tag As Byte)
      pin13.DigitalWrite(
    False)
      CallSubPlus(
    "LedOn"10000)
    End Sub
    The sub signature must be the same as the subs above.

    Note that CallSubPlus was recently added to other B4X tools with CallSubUtils class: https://www.b4x.com/android/forum/threads/60877/#content

    Internally the single thread runs in a loop and manages a messages queue.
    You can use AddLooper keyword to set a sub that will be called on each internal loop. This is similar to a timer that runs as fast as possible.
    Note that you can call this method multiple times to add multiple subs that will run each loop.

    If you find yourself calling AddLooper and then calling Delay in the "looper" sub then you should replace it with a timer.

    AddLooper example:
    Code:
    Sub Process_Globals
      
    Public Serial1 As Serial
      
    Private counter As ULong
    End Sub

    Private Sub AppStart
      Serial1.Initialize(
    115200)
      
    Log("AppStart")
      AddLooper(
    "Looper1")
    End Sub

    Sub Looper1
       counter = counter + 
    1
       
    If counter mod 100000 = 0 Then
         
    Log("Took me ", Millis, " milliseconds to count to ", counter)
         
    Log(counter / Millis, " loops per milliseconds")
       
    End If
    End Sub
    Arduino Uno: 19.6 loops per millisecond
    Arduino MKR1000: 150 loops per millisecond
    Arduino 101: 150 loops per millisecond
    Arduino Due: 415 loops per millisecond.
    ESP8266: 500 loops per milliseconds.
    ESP32: 1750 loops per millisecond
     
    Last edited: Jan 8, 2017
  2. swissmade

    swissmade Active Member Licensed User

    Very nice Erel
     
  3. Kevin Golding

    Kevin Golding Member Licensed User

    B4R rocks. Well done Erel!
     
  4. max123

    max123 Member Licensed User

    Hi Erel, I've tried your example to test addLooper keyword on my ESP8266 (NodeMCU 1.0 board).

    If I use this setting as Board Type (NodeMCU 1.0 (ESP-12E Module) (UploadSpeed = 921600)) I get about 300 cycles loops every millisecond, I think that by default the CPU is at 80MHz, but if I put this setting ((1.0 NodeMCU (ESP-12E Module) (CPUfrequency = 160)), the serial write speed remains at 921600 but the CPU runs at 160MHz and actually get a doubling of speed coming around 550-600 loop cycles per millisecond.

    All this I had already tried long time ago with Arduino IDE and doing various tests I saw that the doubling of frequency is effective and you will get twice the performance, this seems to be the same for all ESP8266 boards, I have an ESP-01 and works even with that.

    Many thanks for this fantastic Tool (B4R simply the Best) ;)

    Screen Shot 06-23-16 at 10.59 AM.PNG
     
    Johan Hormaza and Erel like this.
  5. Erel

    Erel Administrator Staff Member Licensed User

    I get similar results. v1.20 BETA #2 allows you to set all parameters:

    [​IMG]
     
    max123 likes this.
  6. miker2069

    miker2069 Active Member Licensed User

    For what it's worth I ran the looper timing test on a Arduino Nano (16 Mhz) and average about 18 loops / ms :)
     
  7. Erel

    Erel Administrator Staff Member Licensed User

    ESP32 added to the list. Very fast...
     
  8. positrom2

    positrom2 Active Member Licensed User

    Which list? :)
    Will it be supported by B4R in the "near" future?
    Apparently, the ESP32 Arduino core is now supporting a Webserver but there is no example yet included.
     
  9. Erel

    Erel Administrator Staff Member Licensed User

    The performance list in the first post. B4R v1.80 beta #2 will add (initial) support for ESP32.
     
    positrom2 likes this.
Loading...