0

Although Punchthrough no longer supports the Bean and Bean+ they still maintain the online compiler and reference materials: Bean Github Bean reference

One of the external libraries they've included in the cloud compiler is FreeRTOS, linked libs Arduino FreeRTOS port, and the cloud compiler/BeanLoader seems to properly link to the lib and download my compiled app to the bean:

// minimal test for freeRTOS

// works on UNO, fails on Bean

#include <Arduino_FreeRTOS.h>

// Logging hackery
// 0 disables, 1 enables
// #define LogConstantly 0
#define LogConstantly 1

#if(LogConstantly)
  #define Dump(x) Serial.print(x)
  #define Dumpln(x) Serial.println(x)
  #define DumpS Serial
#else // ! LogConstantly
  #define Dump(x)
  #define Dumpln(x)
  #define DumpS
#endif // LogConstantly

// LED handling 
// Find the Bean files in [apps]Bean\ Loader[vers?].app/Contents/Resources/Arduino/hardware/bean/avr/cores/bean/
// Defined in bean.h:  BEAN_BEAN_BEAN_H
#ifdef BEAN_BEAN_BEAN_H  
  #define LED_ON  Bean.setLed(0,0,127)  // light the blue segment at 50%
  #define LED_OFF Bean.setLed(0,0,0)
#else
  #define LED_ON  digitalWrite(LED_BUILTIN, HIGH);
  #define LED_OFF digitalWrite(LED_BUILTIN, LOW);
#endif // BEAN_BEAN_BEAN_H

#define RELAYOUTPUT 2 // pin for relay control.

// tasks for RTOS scheduling

void TaskBlink(void *pvParameters)  // This is a task.
{
  (void) pvParameters; 
  while(true) { // A Task never exits.
    LED_ON;
    Dumpln("BlinkenLit");
    vTaskDelay( 1000 / portTICK_PERIOD_MS ); // wait for one second
    LED_OFF;   
    Dumpln("BlinkenDark");
    vTaskDelay( 1000 / portTICK_PERIOD_MS ); // wait for one second
  }
}

void TaskRelay(void *pvParameters) 
{
  (void) pvParameters;
  while(true) { // A Task never exits.
    digitalWrite(RELAYOUTPUT, HIGH);   // engage the relay
    Dumpln("relay enabled");
    vTaskDelay( 2500 / portTICK_PERIOD_MS ); // wait for 2.5 seconds
    digitalWrite(RELAYOUTPUT, LOW);    // disengage the relay
    Dumpln("relay disabled");
    vTaskDelay( 900 / portTICK_PERIOD_MS ); // wait for .9 second
  }
}


// setup runs once on reset/power
void setup() {

  Serial.begin(115200);
  while (!Serial) { ; } // wait for USB serial port on 32u4 boards.

  pinMode(RELAYOUTPUT, OUTPUT);
#ifndef BEAN_BEAN_BEAN_H        // Bean's tricolor LED is already initialized.
  pinMode(LED_BUILTIN, OUTPUT); // just in case UNO LED line uninitialized.
#endif 

  // test and display hardware connections
  LED_ON;
  digitalWrite(RELAYOUTPUT, HIGH);
  Dumpln("everybody lit?");
  delay(2000); // 2 second nap
  LED_OFF;
  digitalWrite(RELAYOUTPUT, LOW);
  Dumpln("everybody should be unlit, RTOS schedule starts in 5 seconds...");
  delay(5000);

  // set up tasks to run independently.
  xTaskCreate(
    TaskBlink
    ,  (const portCHAR *)"Blink"   // A name just for humans
    ,  128  // This stack size can be checked & adjusted by reading the Stack Highwater
    ,  NULL
    ,  1  // Priority, with 3 (configMAX_PRIORITIES - 1) being the highest, and 0 being the lowest.
    ,  NULL );

  xTaskCreate(
    TaskRelay
    ,  (const portCHAR *) "Relay"
    ,  128  // Stack size
    ,  NULL
    ,  1  // Priority
    ,  NULL );

  // Now the task scheduler, which takes over control of scheduling individual tasks, is automatically started.
}

void loop()
{
  // Empty. Things are done in Tasks.
}

This code works as expected on an UNO, but never seems to execute its tasks on a Bean+. The Bean clearly passes through the setup function, triggering both LED and relay for 2 seconds as expected, but then it never manages to execute a task.

FreeRTOS uses the AVR's Watchdog timer for scheduling. My suspicion is that the Bean may use the AVR's watchdog timer for Bean.sleep() and there's a conflict there. But their docs imply that the Bluetooth chip manages AVR sleep. From Power Management::

What wakes up Bean? What actually happens in Bean sleep is that the ATmega (the microcontroller running your Arduino sketch) goes fully to sleep. Meanwhile, the Bluetooth chip sleeps in between small periods of Bluetooth stack activity. This means the Bluetooth chip can wake up the ATmega for a variety of events:

A client connecting to Bean can wake the ATmega if Bean is configured for wake-on-connect A received serial message will wake the ATmega Any type of interrupt will wake the ATmega A common practice is to have Bean sleep for as long as possible using Bean.sleep(0xFFFFFFFF). This way, Bean will stay asleep indefinitely, and you can wake up Bean with a serial message or interrupt.

OTOH, this subsequent line in the Bean Docs is very suspicious, because FreeRTOS docs note that the AVR watchdog timer's granularity is 15 ms. That's an odd coincidence, I'd expect the BLE chip to have finer grained timers available, and I seem to recall the AVR chips need about 7 ms to wake from deep sleep.

Minimum Sleep Time It’s important to keep in mind that Bean.sleep() has a minimum sleep time of 15 ms. If you need delays under 15 ms, you will have to use delay or delayMicroseconds instead.

So, finally the questions: Does the Bean sleep implementation depend upon the watchdog timer? If so, can FreeRTOS and/or the Bean be persuaded to play nice? If not, what might be breaking FreeRTOS in the Bean?

(And yes, I know the Beans, unsupported and (slightly) obsolete are now a poor choice for a real-time control task. But I like the Bean and Bean+, still have a few in my parts bin, and have a task that's a perfect match for the Bean. I don't blame Punchthrough for abandoning the Bean, though I do wish they'd left up, or at least archived, the user forum.)

  • A minor rant: I know the arduino is intended as an inexpensive gentle entry to low-power, connected computing, but it's a crime that the environment provides so little support or guidance for its natural uses: sensing, machine control, environmental reporting, etc. No builtin example I've seen shows proper interrupt management. All the timing examples use power hogging, cycle wasting, busy-wait delays. Where's the scheduler? Maybe a task queue? Libdispatch lite, anyone? I guess the moral is: if I want it, why aren't I contributing? :( Insert usual lame excuses ): – Taryn Jun 6 at 17:07
  • to your comment: it wouldn't be Arduino then. you can do it all without Arduino or mixed with Arduino – Juraj Jun 6 at 17:41
  • @Juraj Yeah, true ... but the Arduino environment is sooo convenient :) I've done a lot of bare-metal real-time, but the setup time for new hardware, and the often-crummy dev tools, makes it tedious for hobby hackery. I'm planning to explore this as an alternative: platformio.org/platformio-ide – Taryn Jun 6 at 19:08
  • I use Eclipse plugin Sloeber. With it I can very fast solve questions like yours by 'drilling' down into source code of the core and libraries. It is like x-ray vision compared to Arduino IDE. But first I would need to install the 'bean' core. – Juraj Jun 6 at 19:54

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.