Working on a SAMD Arduino, I found myself in need for multiple alarms, triggering events at interrupt time.
Most people suggest TimeAlarm.h, which is a library to schedule timers and alarms with the Time.h library. Unfortunately the alarms don't run on interrupt time.
Instead of adding Time and TimeAlarms libraries I came up with "daisychaining" RTC alarms. I am wondering if this is good or bad practice. Could such a thing bite back?
A snapshot of the code:
void main() {
...
//set alarm at 16:0:0 and trigger Event_1 at interrupt time
rtc.enableAlarm(16,0,0);
rtc.attachInterrupt(Event_1_isr);
...
}
void Event_1_isr() {
...some code...
//Set next alarm and interrupt Event_2
rtc.setAlarmTime(16, 0, 15);
rtc.enableAlarm(rtc.MATCH_HHMMSS);
rtc.detachInterrupt();
rtc.attachInterrupt(Event_2_isr);
}
void Event_2_isr() {
...some code...
//I guess you get the point
rtc.setAlarmTime(16, 0, 30);
rtc.enableAlarm(rtc.MATCH_HHMMSS);
rtc.detachInterrupt();
rtc.attachInterrupt(Event_3_isr);
}
I would try to get in and out of the interrupts as fast as possible. I think that's nearly always good advice.
You ask "could such a think bite back" - yes, in maintenance headaches. Your logic and settings are scattered throughout the code.
I would consider turning it around: make one or two routines responsible for setting up and handling the RTC interrupts. Let it use a table of times and routines to set the correct delay and dispatch the appropriate action. Then you don't need the overhead of attach/detach-interrupts, all the relevant code is in one place, and your data tells you what to do.
Related
I'm trying to build an NES emulator using winit, which entails building a game loop which should run exactly 60 times per second.
At first, I used std::thread to create a separate thread where the game loop would run and wait 16 milliseconds before running again. This worked quite well, until I tried to compile the program again targeting WebAssembly. I then found out that both winit::window::Window and winit::event_loop::EventLoopProxy are not Send when targeting Wasm, and that std::thread::spawn panics in Wasm.
After some struggle, I decided to try to do the same thing using task::spawn_local from one of the main asynchronous runtimes. Ultimately, I went with async_std.
I'm not used to asynchronous programming, so I'm not even sure if what I'm trying to do could work.
My idea is to do something like this:
use winit::{window::WindowBuilder, event_loop::EventLoop};
use std::time::Duration;
fn main() {
let event_loop = EventLoop::new();
let _window = WindowBuilder::new()
.build(&event_loop);
async_std::task::spawn_local(async {
// game loop goes here
loop {
// [update game state]
// [update frame buffer]
// [send render event with EventLoopProxy]
async_std::task::sleep(Duration::from_millis(16)).await;
// ^ note: I'll be using a different sleep function with Wasm
}
});
event_loop.run(move |event, _, control_flow| {
control_flow.set_wait();
match event {
// ...
_ => ()
}
});
}
The problem with this approach is that the game loop will never run. If I'm not mistaken, some asynchronous code in the main thread would need to be blocked (by calling .await) for the runtime to poll other Futures, such as the one spawned by the spawn_local function. I can't do this easily, since event_loop.run is not asynchronous.
Having time to await other events shouldn't be a problem, since the control flow is set to wait.
Testing this on native code, nothing inside the game loop ever runs. Testing this on Wasm code (with wasm_timer::Delay as the sleep function), the game loop does run, but at a very low framerate and with long intervals of halting.
Having explained my situation, I would like to ask: is it possible to do what I'm trying to do, and if it is, how would I approach it? I will also accept answers telling me how I could try to do this differently, such as by using web workers.
Thanks in advance!
I'm making an LED control program (using FastLED, of course) and using Serial (with the Serial monitor) to control it. I just connected it via USB and for the most part it works just fine. However, I noticed with the long, flashing routines that I couldn't stop them and make the LEDs do something else. The flash routine in my code is very simple:
void flash(CRGB color, int count, int del){
for(int i = 0; i < count; i++){
if(pause){
break;
}
fillLeds(color.r, color.g, color.b);
milliDelay(del);
fillLeds(0,0,0);
milliDelay(del);
}
}
With fillLeds(r,g,b) being a for loop, looping through and setting all LEDs to a certain color, and milliDelay is just delay() using millis and not the delay() function.
I need to be able to pause not just this, but other functions as well (probably using break;) and then execute other code. It seems easy, right? Well, I've noticed that when I send a byte over Serial, it goes into this "queue," if you will, and then is sequentially read.
I can’t have this happen. I need the next byte entering Serial to activate some kind of event that pauses the other flash() function running, and then be used. I have implemented this like:
void loop()
{
if (Serial.available() > 0)
{
int x = Serial.read();
Serial.print(x);
handleRequest(x);
}
FastLED.show();
FastLED.delay(1000 / UPDATES_PER_SECOND);
}
Where handleRequest(x); is just a long switch statement with calls to the flash method, with different colors being used, etc.
How can I make the Arduino pause other loops whenever a new byte is received, instead of adding it to this "queue" to be acted upon later? If this is not possible thanks for reading anyway. I've tried using serialEvent() which doesn't appear to work.
I think you need two loops. You have one, which is your main loop, and you can add another (like a multi threading) with the TimerOne library. Like this:
Timer1.initialize(your desired delay in this loop);
Timer1.attachInterrupt(your desired function in this loop);
So maybe you can add an if statement with a variable in your second loop to prevent some function and update the variable in your first loop or something like that.
Presuming you want interrupt-like functionality when a new byte arrives:
Unfortunately, serialEvent() is not a true interrupt. It only runs at the end of loop(), if there is serial data available.
However, serialEvent() is just a function, and there isn't any reason why you can't call it in your code as often as you like. This is effectively polling for new serial data as often as possible. So, while your loops are running, call serialEvent() during your delays and handle the serial data there.
You may need to restructure your code to avoid recursion though. If flash calls serialEvent(), which calls flash, which calls serialEvent, etc... then you may end up overflowing the stack.
using QtCreator to make a loftier interface to a sofware.
There is basically a set of buttons to tune and inputs, a start and stop job
buttons, my problem comes from an infinite loop that freezes the display so I came up with using fork() so that the loop have to compete with the main program instead of eating up the whole resources (no multithreading), but the program crashes spiting:
[xcb] Unknown sequence number while processing queue
[xcb] Most likely this is a multi-threaded client and XInitThreads has not
been called
[xcb] Aborting, sorry about that.
a.out: ../../src/xcb_io.c:274: poll_for_event: Assertion
`!xcb_xlib_threads_sequence_lost' failed.
the fonction calling the loop is called 'ON', 'OFF' is supposed to exit the forked process.
//in button 'ON' func
ps = fork();
if(getpid() == ps)
{
while(1)
{
strcpy(word, charset(minlength, maxlength, N));
ui->pass->setText(word);//operation on the display
....SNIP
}
}
//In button 'OFF' func
if(getpid() == ps)
exit(0);
I'm really asking what is the correct way of starting a while(1) and be able to break, exit, or return from it while not freezing the window using QT, thanks.
You crash probably here:
ui->pass->setText(word);//operation on the display
as in Qt, you can not change UI from non UI threads directly. Only from signals and slots mechanism.
The proper way to not freeze UI is obviously to compute lengthy operations in another thread.
You can achieve this in several ways:
One is by sub-classing QObject class to create 'worker object' which would perform all heavy operations. You create new QThread object that should live as long as you need your object. And use QObject::moveToThread method to move created object to new thread. To control your worker object you should send signals from object and call it's slots also via signal-slot mechanism. If you call them directly - they will be executed in caller thread (so do not perform stuff like worker->startHeavyJob(); in UI thread). Instead emit signal in UI (emit sigStartHeavyStuff();) and connect it to slot of your worker object (slotDoHeavyStuff();)
if you do not want to bother with this (if operation is pretty small)
- you can use QApplication::processEvents() to process events in UI event loop while going in your infinite while loop.
Another way is to use QtConcurrentRun framework to run function in separate thread which manages itself. Threads are taken from thread pool and are managed by Qt. This approach looks like something you want to do. Though you still will be able to access UI objects only through signals and slots.
I see one big issue in the presented code that is causing your freeze: You never let Qt process anything while you are in the loop. You need to allow Qt to run it's event loop. The easiest way is to use QApplication::processEvents() inside the loop.
I'm also not a fan of a while(1) loop for a couple of reasons. The first of which is that it can eat machine cycles waiting for things to happen. I doubt you really need to run the code as fast as possible, you could probably get away with some sleeping in your loop.
The other issue is that it is hard to break out. A cleaner approach would be something like this
void MyClass::on_pushButton_ON_clicked()
{
MyClass::done = false; // this is a class attribute
while (!MyClass::done) {
QApplication::processEvents();
//...
}
}
void MyClass::on_pushButton_OFF_clicked()
{
MyClass::done = true;
}
#include <Arduino.h>
#include "include/MainComponent.h"
/*
Turns on an LED on for one second, then off for one second, repeatedly.
*/
MainComponent* mainComponent;
void setup()
{
mainComponent = new MainComponent();
mainComponent->beginComponent();
}
void loop()
{
mainComponent->runComponent();
}
is there any callback to release memory in Arduino ?(e.g to call delete mainComponent)
or this will happen automatically as the loop ends?
what is the strategy to ensure freeing the memory allocated in that code snippet?
SCENARIO :"I wanted to access the object in both methods , so the object is declared in the global scope then instantiated at setup."
What happen when loop() terminated ? will mainComponent still remain in the memory?
If it was in OS NO , process will terminated then resources will be deallocated.
So in Arduino how can I achieve above SCENARIO , by ensuring memory will be deallocated when the controller is switched off ?
What is confusing you is that the main() function is hidden by the basic Arduino IDE. Your programs have a main() function just like on any other platform, and have a lifecycle same as when run on a computer with OS. If you look under arduino___\hardware\cores\aduino, you will find a file main.cpp, which is included into your binaries:
int main(void)
{
init();
//...
setup();
for (;;) {
loop();
if (serialEventRun) serialEventRun();
}
return 0;
}
Considering this file you will now see, that while you exit the loop(), it is continuously called. Your program never exits. In general, your best pattern is to new objects once and never delete, like you have done here. If you are new'ing and delete'ing objects repeatedly on a microcontroller, you are not thinking about lifecycles and resources wisely.
So
"is the new'd object deleted at return from loop()?" No, the program is still running and it stays on the heap.
"What happens at power off? Is there a way to clean up?" The moment the supply voltage drops too low, the microcontroller will stop executing instructions. Power supervisor circuitry prevents the controller from doing anything erratic as the voltage drops (should prevent) When the voltage is conpletely drained, all the RAM is lost. Without adding circuitry, you have no way to execute any clean up at power off.
"Do I need to clean up?" No, at power up, everything is reset to a known state. Operation cannot be affected by anything left behind in RAM (presumes you initialize all your variables).
When using a serial port via POSIX, it's recommended to save the original attributes using tcgetattr() before changing them with tcsetattr(), and then restore them before closing the port. What about when a program is terminated by pressing control-C or when the program receives SIGINT? I haven't seen this covered in any of the serial tutorials.
Apparently an atexit() function wouldn't be sufficient, because it's not called by the default SIGINT handler. So it seems installation of a signal handler would be necessary that restores the attributes to any serial ports still open. Is it even safe to call tcsetattr() from a signal handler?
One might simply dismiss this issue as insignificant, but it's common to terminate a program with control-C, especially one that can take tens of seconds to complete operations. If it's OK not to preserve serial port settings in this case, then there seems little reason to preserve them at all. If anything, it might be better not to bother, rather than do it inconsistently.
I found some examples of source code doing the above, but nothing well-documented. I guess I'm interested in some discussion of whether this is a good idea. Thanks.
After further research I think I've answered this to my satisfaction.
First, in the man page for signal I noticed that a signal handler is specifically allowed to call tcsetattr(), along with a few others:
The signal handler routine must be very careful, since processing elsewhere was interrupted at some arbitrary point. POSIX has the concept of "safe function". If a signal interrupts an unsafe function, and handler calls an unsafe function, then the behavior is undefined. Safe functions are listed explicitly in the various standards. The POSIX.1-2003 list is ... `raise()` ... `signal()` ... `tcsetattr()` [trimmed to relevant ones]
This strongly suggests that the POSIX committee had this exact kind of thing in mind, and leads to a straight forward approach where you change the SIGINT handler once you've opened serial and saved its attributes, then in your handler, restore them and the old SIGINT handler, then re-raise the signal:
static void (*prev_sigint)( int );
static termios saved_attr;
static int fd;
static void cleanup( int ignored )
{
tcsetattr( fd, TCSANOW, &saved_attr );
signal( SIGINT, prev_sigint );
raise( SIGINT );
}
int main( void )
{
open_serial_and_save_attrs();
prev_sigint = signal( SIGINT, cleanup );
...
}