SAMD21 doesn't wake up after deep sleep - c++

I'am working on a personnal board build with an atsamd21e18a. I'am actually working on sleep mode. I make a function to put samd21 in sleep mode like that. I use RTCZero library.
So in my setup function I've something like this
RTCZero rtc;
void setup(){
// Set the XOSC32K to run in standby
SYSCTRL->XOSC32K.bit.RUNSTDBY = 1;
rtc.begin();
.... other line code ....
attachInterrupt(digitalPinToInterrupt(PIN_USER_BUTTON), wakeUpButtonUser, CHANGE);
...other line....
}
So in my setup I intialise rtc and I attach an interrupt in my user button. This button is used to power on or power off my board.
My function goTosleep() :
SCB->SCR |= SCB_SCR_SLEEPDEEP_Msk;
__DSB();
__WFI();
In my function wakeUpButtonUser I have a simple if/else statement. If the user pressed the button more than 3 seconds samd21 go to sleep with goToSleep() function, else if it's less than 3 seconds I want wake up the board and light up my led but it's doesn't work.
Here my wakeUpButtonUser function, user_button is object create from C++ for my button.
void wakeUpButtonUser(){
if (userButton.isPressed())
{
userButton.setTimeStartPressed(millis());
PRINT_DEBUG_LN("Pressed");
}
else
{
userButton.setTimeEndPressed(millis());
PRINT_DEBUG_LN("Released");
uint32_t time_pressed = userButton.getTimePressed();
if (time_pressed >= temps_on && time_pressed < temps_off)
{
PRINT_DEBUG_LN("ON");
//here I have code to light up a led
}
else
{
PRINT_DEBUG_LN("STOP");
goSleepMode();
}
}
}
This fuction works because if I comment the line goToSleep(), I can read on my serial ON or OFF depending the time I pressed my button and the led works also because I can light up led before going to sleep. But when my board go to sleep, she's never wake up I don't understand why, I missed something?

Related

QT: Run a function as long as button is toggled

I want to implement a GUI that receives messages from an external device. The "advancedReceiveExample" is waiting for messages. Once it has received one, it does stuff with it, saves it and terminates.
I want to make my function wait for new messages after receiving one as long as the button is toggled.
I have tried this so far:
void MainWindow::on_pushButton_clicked()
{
if (ui.pushButton->isChecked()) {
ui.pushButton->setText("Stop Receiving");
ui.label_3->setText("Receiving...");
advancedReceiveExample(ui.comboBox->currentIndex() + 1);
}
else
{
ui.pushButton->setText("Start Receiving");
ui.label_3->setText("Not Receiving");
}
}
This works perfectly fine but as mentioned above it only receives one message. If I do that:
void MainWindow::on_pushButton_clicked()
{
if (ui.pushButton->isChecked()) {
ui.pushButton->setText("Stop Receiving");
ui.label_3->setText("Receiving...");
while (1)
{
advancedReceiveExample(ui.comboBox->currentIndex() + 1);
}
}
else
{
ui.pushButton->setText("Start Receiving");
ui.label_3->setText("Not Receiving");
}
}
it blocks the function because the state of the button can only be change after the function "on_pushButton_clicked()" has terminated.
Visual Studio 2019
C/C++
EDIT: Okay, I have understood the problem of blocking the thread. Multithreading might be the right option but I am very unexperienced regarding this topic. The <QThread> could be possible. How would you use it?
Do you have suggestions which other library could be used?
Note QT is event-based. If you keep your computer busy inside some function without returning to the main loop frequently, your GUI will freeze.
What you need to do is slice your action that you want to do into small bits that can repeatedly return to the main loop in order to keep the GUI responsive. (Another method yould be to swap out your action into a separate thread and handle it in parallel, killing the thread when the button is released)
Probably the simplest method to do what you want is with timers that you arm in the PushButton::clicked slot, and then check in the timer event whether the button is still pressed, and, if yes, do a bit of your action, save state and re-arm the timer to have you return.
Something along the lines of the following pseudo code should work and execute what you want to do in slices every 10ms:
MainWindow::onPushButtonClicked () {
// do the action, or, alternatively, start a
// parallel thread that does it
do_a_bit_of_action();
// sets up a timer to call onTimer after 10ms
QTimer::singleShot (10, this, SLOT(onTimer()));
}
MainWindow::onTimer () {
// check if button is still held down
if (pushButton.down) {
// re-arm timer
Timer::singleShot (10, this, SLOT(onTimer()));
// do some more action bits
do_a_bit_of_action();
}
else {
// kill optional background thread here
}
}
You can try it with:
while(ui.pushButton->isChecked()){
*your function*
}

Button Push turning on an OLED ESP32

I am working on getting a DHT22 sensor which displays a reading onto an OLED when a button is pushed. I am using Arduino IDE. Right now I have the sensor working and displaying on the screen, but I am having difficulty getting it to only turn on when the button is pushed. GPIO 13 is currently getting the signal from the sensor, and GPIO 26 is connected to the physical button along with power and ground. All of the code with "//added" is the new code I added in order to get the button to work. Any help is greatly appreciated!
At the top I added:
const int ButtonPin = 26; //added
const int PushButton; //added
I am getting the error:
exit status 1
uninitialized const 'PushButton' [-fpermissive]
In setup function I added:
pinMode(ButtonPin, OUTPUT); //added
pinMode(PushButton, INPUT)://added
And in loop function I added:
int Push_button_state = digitalRead(PushButton); //added
if (Push_button_state == HIGH) //added
float h = dht.readHumidity();
// Read temperature as Celsius
float t = dht.readTemperature();
u8g2.firstPage();
do {
draw();
} while ( u8g2.nextPage() );
delay(1000);
}
else { //added
I think you are not clear about what you want to achieve. First of all, you only need ButtonPin variable to work with the button. As your button is connected to GPIO 26, you must declare this pin as an INPUT.
Later, you shoould use the digitalWrite function to get the state of the pin. Depending on how you connect your button, you will receive a '0' or a '1' when it is pressed. Anyways, I have been using a really comfortable library to work with buttons on Arduino, check it here. I hope this could help

Arduino, Run Time Code Error in Debouncing Voltage Time Delay Code

I am Ansh Goel, I was learning Arduino from Udemy. I am beginner to this field. I was creating a code for Debouncing the button to solve the issues of bouncing voltage. But there is error in the code. There is no Compile time error but it is run time error.
I also tried to check the code using the Serial.print() to find the where the error is, then I found that the error is in the second nested if condition. I have also mention where there is the error in the code for ease. There I am not able to get the Serial.print("A") function too to the Serial Monitor.
My main motive is to run the code so that I am able to stop bouncing voltages when a button is pressed using some delay.
It is from line 41
This is the code I used to debounce the button
const int btn_pin = 2;
const int debounce_delay = 50; //ms
// We need to remember the previous button state between loops
int btn_prev = HIGH;
int btn_state = HIGH;
unsigned long last_debounce_time = 0;
// Counter
int counter = 0;
void setup() {
Serial.begin(9600);
// Set up pins
pinMode(btn_pin, INPUT_PULLUP);
pinMode(13, OUTPUT);
}
void loop() {
int btn_read;
// Read current button state
btn_read = digitalRead(btn_pin);
//Remember when the button change state
// If the button was previously HIGH and now LOW, it's been pressed
if ( (btn_prev == HIGH) && (btn_read == LOW )) {
//Store the time it took to take the action for button press
last_debounce_time = millis();
}
//Wait before changing the state of the button
// IN THIS CONDITION THERE IS ERROR SOMEWHERE I AM NOT GETTING IT
if(millis() > (last_debounce_time + debounce_delay)){
if(btn_read != btn_state) {
Serial.println("A");
// Then store the button change value to the global variable
btn_state = btn_read;
if(btn_state == LOW) {
// Increment and print counter
counter++;
Serial.println(counter);
digitalWrite(13,HIGH);
delay(500);
digitalWrite(13,LOW);
delay(500);
}
}
}
// Remember the previous button state for the next loop iteration
btn_prev = btn_state;
}
For testing purposes, this is the circuit design on TinkerCad, that you can check online.
TinkerCad Circuit Design
Please Help me solve the issue, it will be a great help from your side for me.
There are several locations where your code could malfunction:
you're not looping properly for loop
your logic doesn't work
digitalRead doesn't work
print doesn't work
first, remove the debounce check and see if this works:
//if(millis() > (last_debounce_time + debounce_delay)){
to check all other issues, add the following right before the remaining if:
delay so you don't get endless data
print millis, last_debounce_time, debounce_delay and btn_read
end line
then run and press the button. The output will let you know what's the issue

ESP8266-01 does not react to AT Commands over UART with TM4C123GH6PM

I am trying to connect my TM4C123GH6PM Microcontroller from Texas Instruments with my Smartphone and use it to control an alarm clock and LED Lights. (the LEDs are controlled over a Transistor, which is controlled over an GPIO Pin).
I have some experience with coding in C++ and the TM4C123GH6PM, but I am still learning a lot. So please excuse some foolish mistakes I might have made.
I want to connect the ESP8266 with the Microcontroller using UART and the TivaWare Framework.
I have written some code and my UART works correctly (I tested it by sending chars from UART 4 to 3).
According to the AT commands of ESP8266 It should respond to "AT" with "OK". But whenever I send something to the ESP it responds with exactly what I sent to it. I checked the wiring, and that's not The Issue. Or at least I think so. Please correct me, if the wiring is wrong.
ESP -> TM4C123GH6PM:
GND -> GND
VCC -> 3.3V
Tx -> Rx (UART3 / PC6)
Rx -> Tx (UART4 / PC5)
CH_PD -> 3.3V
I also checked for the power consumption of the ESP. Everything is powered by the USB-port of my laptop, since that helps keep the cable mess down. I monitor the power consumption with (https://www.amazon.de/gp/product/B07C8CM5TG/ref=ppx_yo_dt_b_asin_title_o08_s00?ie=UTF8&psc=1). The ESP is drawing about 150mA from the computer, but the port can provide a lot more. I checked with some LEDs and 400mA is not a problem.
Can anyone help me? I am working on this now for over two days and can't find a Solution. What is the Problem with the ESP not responding correctly to the AT command? The blue light is one, when the code is running.
PS: The attached code contains also code for the alarm clock control and LEDs. I attached it, since it could be part of the problem, but some of it is commented out and most of it is not used.
#include<stdint.h>
#include<stdbool.h>
#include"inc/hw_ints.h"
#include"inc/hw_memmap.h"
#include"inc/hw_types.h"
#include"driverlib/gpio.h"
#include"driverlib/sysctl.h"
#include"driverlib/timer.h"
#include"driverlib/interrupt.h"
#include"driverlib/uart.h"
#include"driverlib/pin_map.h"
#include "driverlib/rom.h"
// stores the time since system start in ms
uint32_t systemTime_ms;
//bools or controling the alarm clock and LEDS
bool an_aus = false;
bool alarm_clock = false;
void InterruptHandlerTimer0A (void)
{
// Clear the timer interrupt flag to avoid calling it up again directly
TimerIntClear(TIMER0_BASE, TIMER_TIMA_TIMEOUT);
// increase the ms counter by 1 ms
systemTime_ms++;
}
void clockSetup(void)
{
uint32_t timerPeriod;
//configure clock
SysCtlClockSet(SYSCTL_SYSDIV_5|SYSCTL_USE_PLL|SYSCTL_XTAL_16MHZ| SYSCTL_OSC_MAIN);
//activate peripherals for the timer
SysCtlPeripheralEnable(SYSCTL_PERIPH_TIMER0);
// configure timers as 32 bit timers in periodic mode
TimerConfigure(TIMER0_BASE, TIMER_CFG_PERIODIC);
// set the variable timerPeriod to the number of periods to generate a timeout every ms
timerPeriod = (SysCtlClockGet()/1000);
// pass the variable timerPeriod to the TIMER-0-A
TimerLoadSet(TIMER0_BASE, TIMER_A, timerPeriod-1);
// register the InterruptHandlerTimer0A function as an interrupt service routine
TimerIntRegister(TIMER0_BASE, TIMER_A, &(InterruptHandlerTimer0A));
// activate the interrupt on TIMER-0-A
IntEnable(INT_TIMER0A);
// generate an interrupt when TIMER-0-A generates a timeout
TimerIntEnable(TIMER0_BASE, TIMER_TIMA_TIMEOUT);
// all interrupts are activated
IntMasterEnable();
// start the timer
TimerEnable(TIMER0_BASE, TIMER_A);
}
void UART (void)
{
//configure UART 4:
SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOC);
SysCtlPeripheralEnable(SYSCTL_PERIPH_UART4);
while(!SysCtlPeripheralReady(SYSCTL_PERIPH_UART4));
//GPIO pins for transmitting and receiving
GPIOPinConfigure(GPIO_PC4_U4RX);
GPIOPinConfigure(GPIO_PC5_U4TX);
GPIOPinTypeUART(GPIO_PORTC_BASE, GPIO_PIN_4 | GPIO_PIN_5);
//configure UART 8Bit, no parity, baudrat 38400
UARTConfigSetExpClk(UART4_BASE, SysCtlClockGet(), 38400, (UART_CONFIG_WLEN_8 | UART_CONFIG_STOP_ONE | UART_CONFIG_PAR_NONE));
//configure UART 3:
SysCtlPeripheralEnable(SYSCTL_PERIPH_UART3);
while(!SysCtlPeripheralReady(SYSCTL_PERIPH_UART3));
GPIOPinConfigure(GPIO_PC6_U3RX);
GPIOPinConfigure(GPIO_PC7_U3TX);
GPIOPinTypeUART(GPIO_PORTC_BASE, GPIO_PIN_6 | GPIO_PIN_7);
UARTConfigSetExpClk(UART3_BASE, SysCtlClockGet(), 38400, (UART_CONFIG_WLEN_8 | UART_CONFIG_STOP_ONE | UART_CONFIG_PAR_NONE));
}
void delay_ms(uint32_t waitTime)
{
// Saves the current system time in ms
uint32_t aktuell = systemTime_ms;
// Wait until the current system time corresponds to the sum of the time at the start of the delay and the waiting time
while(aktuell + waitTime > systemTime_ms);
}
void ex_int_handler(void)
{
// press the button to start timer for alarm clock
alarm_clock = true;
GPIOIntClear(GPIO_PORTF_BASE,GPIO_PIN_4);
}
int main(void)
{
//Peripherals for LED and GPIO
SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOB);
SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOF);
//UART
UART();
//Timer
clockSetup();
// button
GPIOPinTypeGPIOInput(GPIO_PORTF_BASE,GPIO_PIN_4);
GPIOPadConfigSet(GPIO_PORTF_BASE,GPIO_PIN_4,GPIO_STRENGTH_2MA,GPIO_PIN_TYPE_STD_WPU);
//OnboardLED
GPIOPinTypeGPIOOutput(GPIO_PORTF_BASE,GPIO_PIN_1);
GPIOPinTypeGPIOOutput(GPIO_PORTF_BASE,GPIO_PIN_3);
//Interrupt Timer
GPIOIntDisable(GPIO_PORTF_BASE,GPIO_PIN_4);
GPIOIntClear(GPIO_PORTF_BASE,GPIO_PIN_4);
GPIOIntTypeSet(GPIO_PORTF_BASE,GPIO_PIN_4,GPIO_FALLING_EDGE);
GPIOIntRegister(GPIO_PORTF_BASE,ex_int_handler);
GPIOIntEnable(GPIO_PORTF_BASE,GPIO_PIN_4);
//Transistor Gate
GPIOPinTypeGPIOOutput(GPIO_PORTB_BASE,GPIO_PIN_0);
//GPIOPadConfigSet(GPIO_PORTB_BASE,GPIO_PIN_0,GPIO_STRENGTH_6MA,GPIO_PIN_TYPE_STD_WPU);
//debugging only: save all the received data from the ESP in an array to look at while debugging
int32_t data[20] = {0};
int32_t j = 0;
//Code for debugging the UART and ESP8266
while(1){
//Checks for Data in the FIFO
while(!UARTCharsAvail(UART4_BASE));
//send AT-command to ESP8266
UARTCharPut(UART4_BASE, 'A');
while(UARTBusy(UART4_BASE));
UARTCharPut(UART4_BASE, 'T');
while(UARTBusy(UART4_BASE));
if(UARTCharsAvail(UART3_BASE))
{
while(UARTCharsAvail(UART3_BASE))
{
//Read data from the FIFO in UART3 -> received from ESP8266
data[j] = UARTCharGet(UART3_BASE);
j++;
}
}
//clear array when its full
if (j >= 20)
{
j = 0;
for(int32_t a = 0; a <21; a++)
{
data[a] = 0;
}
}
}
//code to run the alarm clock and leds
/*
while(1)
{
if (alarm_clock)
{
GPIOPinWrite(GPIO_PORTF_BASE,GPIO_PIN_3,GPIO_PIN_3);
//Wait
delay_ms(30600000);
GPIOPinWrite(GPIO_PORTB_BASE,GPIO_PIN_0,GPIO_PIN_0);
alarm_clock = false;
GPIOPinWrite(GPIO_PORTF_BASE,GPIO_PIN_3,0x00);
//Start Red LED blinking when it is finished
while(1)
{
GPIOPinWrite(GPIO_PORTF_BASE,GPIO_PIN_1,GPIO_PIN_1);
delay_ms(1000);
GPIOPinWrite(GPIO_PORTF_BASE,GPIO_PIN_1,0x00);
delay_ms(1000);
}
}
}
*/
}
According to the AT commands of ESP8266 It should respond to "AT" with
"OK". But whenever I send something to the ESP it responds with
exactly what I sent to it
Modems with AT Commands commonly ship with the echo mode turned on, so that when you are interacting with it manually through serial port, it will echo the characters you sent first, and then send the reply.
So, when you are automating the process, you first send the characters, then wait for the reply until you reach a '\r'. Well, you are reaching a '\r', but its the one from the echo. You might have some other characters next. You send AT, you should receive AT first, then you have the OK.
To solve this problem, you should turn echo mode off.
The command to turn off echo is ATE0.

How to break the loop in an Arduino?

I'm trying to write a simple program in Arduino, blinking of a LED.
Program is as shown below.
#define red1 13
#define amber1 12
#define green1 11
void setup() {
// put your setup code here, to run once:
Serial.begin(9600);
pinMode(red1, OUTPUT);
pinMode(amber1, OUTPUT);
pinMode(green1, OUTPUT);
}
void Delay(int sec) {
for(int i=0;i<sec;i++){
if (Serial.available())
{
Button();
break;
}
delay(1);
}
}
void Light()
{
digitalWrite(red1,HIGH);
Delay(5000);
digitalWrite(red1,LOW);
digitalWrite(amber1,HIGH);
Delay(5000);
digitalWrite(amber1,LOW);
}
void Button()
{
digitalWrite(red1,LOW);
digitalWrite(amber1,LOW);
digitalWrite(green1,HIGH);
delay(1000);
digitalWrite(green1,LOW);
}
void loop()
{
Light();
}
When ever I enter a value in serial monitor Button() function is executed, it should end as soon as function completes due to a break, but this function keeps repeating continuously? How can I fix this such that whenever a serial monitor is interrupted, Button() is executed onetime and then continues with Light().
Try to replace
break;
with
return;
This will terminate the function instantly since you won't be executing other statements after the loop.
You can look at https://www.arduino.cc/reference/en/language/structure/control-structure/return/ for more info about return
As some others have briefly alluded to, you call Button many times due to the fact that you don't clear the serial interface.
Right now what happens is Delay is called, and let's say there's information available on the interface, then you call Button and break as expected, but since you don't clear the interface by reading the available information, you call Button again on the next call to Delay.
To fix this, you need to read the information from the serial interface either in the Button function or in the if statement before calling Button.