Project Description
The project is a weather station that sends data over Wi-Fi to an MQTT server. The credentials should be input using a serial monitor so the user does not need Arduino software on their computer. The device should utilize the hardware USB peripheral inside the ESP32-C6.
Hardware Description
It's programmed and powered with a USB connection. Apart from the JTAG connector and external crystal, the electrical connections match the peripheral schematic provided by Espressif. Refer to the ESP32-C6-MINI-1U Datasheet (page 32).
Problem Description
I can program the microcontroller whether USB CDC on boot is disabled or enabled. When enabled, I can use the serial monitor in Arduino and PuTTY. However, as soon as I plug the device into a different USB power supply without a connected serial monitor, the code does not run. When I disable USB CDC on boot, I lose the serial monitor functionality over USB, but the code runs when not connected to the computer.
Any chance that you have a while(!Serial) in setup()? On boards with native USB, that will wait for a communication with a PC channel to be established.
Thank you for taking your time for my problem.
I have had it in my code commented (as in the code snippet below) and uncommented but it makes no difference.
//while (!Serial); //Wait for serial communication to be established, ensuring that the Arduino is ready to receive commands or send data
I will try it on a ESP32S3 board and will report back.
That is different...
When I started working, I didn't see anything in the serial monitor. After I enabled USB-CDC on Boot, the module is only working when connected to serial monitor. I mean, whenever I open serial monitor, the module starts working.
This time, I am tried to implement something like, powering it from a power bank or a charger instead of serial monitor in PC and it is not working.
My doubt is, is it possible to make it work in both cases? Such that, the module will be working when i power it from a power source. And if I suddenly remove it and connect it to pc, I directly get serial output. I hope you understood my question?
Yeah I had the same problem today. Tried connecting my Feather ESP32-S2 to a wall supply and it wouldn't run the application. The only way it would run is if it was connected to a computer and the device was enumerated. Disabling USB CDC fixed it for sure. Look forward to understanding why this is.
Just tested that with a Seeed XIAO ESP32C3, and I don't see that problem.
I have print statements in the code, but no while(!Serial) in setup().
Uploaded with CDC enabled. Code runs normally when powered with a USB brick.
Leo..
/*
* Simple HTTP get webclient test
*/
#include <WiFi.h>
#include <HTTPClient.h>
#include <Adafruit_MCP9808.h>
#include <SPI.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SH110X.h>
const char* ssid = "SensorNetwork";
const char* password = "nonsecure";
#define BUTTON_A 9
#define BUTTON_B 6
#define BUTTON_C 5
#define hysteresis 1 //This prevents blasting the basement device with ON/OFF requests
float temp_setpoint=72;
float roomtemp;
bool htreq=false;
bool stopflag=false;
volatile int tstat_timer=50;
volatile int sincelast_timer=30;
volatile int wifi_check_timer=0;
Adafruit_SH1107 display = Adafruit_SH1107(64, 128, &Wire);
Adafruit_MCP9808 tempsensor = Adafruit_MCP9808();
//////////////////////////////////////
/////////////////////PUT ISR HERE
//////////////////////////////////////
hw_timer_t * timer = NULL;
portMUX_TYPE timerMux = portMUX_INITIALIZER_UNLOCKED;
void IRAM_ATTR onTimer() {
portENTER_CRITICAL_ISR(&timerMux);
tstat_timer++;
sincelast_timer++;
wifi_check_timer++;
portEXIT_CRITICAL_ISR(&timerMux);
}
void setup() {
Serial.begin(115200);
while (!Serial) {
; // wait for serial port to connect. Needed for native USB port only
}
//Initialize the display with the I2C addr 0x3C (for the 128x32)
display.begin(0x3C,true);
display.setContrast(0x00);
// init done
Serial.println("OLED begun");
// Show image buffer on the display hardware.
// Since the buffer is intialized with an Adafruit splashscreen
// internally, this will display the splashscreen.
display.display();
for ( int i=0 ; i < 100 ; i++ ) {
yield();
delay( 10 );
}
// Clear the buffer.
display.clearDisplay();
display.display();
display.setRotation(1);
pinMode(BUTTON_A, INPUT_PULLUP);
pinMode(BUTTON_B, INPUT_PULLUP);
pinMode(BUTTON_C, INPUT_PULLUP);
display.setTextSize(1);
display.setTextColor(SH110X_WHITE);
if (!tempsensor.begin()) {
Serial.println("Could not find MCP9808, check wiring!");
display.setCursor(0,0);
display.print("Could not find MCP9808, check wiring!");
display.display();
while (1);
}
// Connect to WiFi network
Serial.println();
Serial.print("Connecting to ");
Serial.println(ssid);
// flush() is needed to print the above (connecting...) message reliably,
// in case the wireless connection doesn't go through
Serial.flush();
display.setCursor(0,0);
display.print("Connecting to:\n");
display.println(ssid);
display.display();
WiFi.begin(ssid, password);
int dots=0;
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print("."); //need watchdog here in case we can't connect
display.print(".");
display.display();
if(++dots>60){
Serial.println("Could not connect WiFi. Exiting...");
display.setCursor(0,0);
display.print("Could not connect WiFi. Exiting...");
display.display();
esp_deep_sleep(1000000);
}
}
Serial.println("");
Serial.println("WiFi connected");
Serial.println(WiFi.localIP());
display.clearDisplay();
display.display();
display.setCursor(0,0);
display.print("WiFi connected:\n");
display.println(WiFi.localIP());
display.display();
////////////////////////////////////////////
//////////Start up the interrupt routine here
/////////////////////////////////////////////
noInterrupts();
// Use 1st timer of 4
// 1 tick take 1/(80MHZ/80) = 1us so we set divider 80 and count up
//timer = timerBegin(0, 80, true);
timer = timerBegin(1000000);
// Attach onTimer function to our timer
// timerAttachInterrupt(timer, &onTimer, true);
timerAttachInterrupt(timer, &onTimer);
// Set alarm to call onTimer function every second 1 tick is 1us
//=> 1 second is 1000000us
// Repeat the alarm (third parameter)
//timerAlarmWrite(timer, 1000000, true);
timerAlarm(timer, 1000000, true, 0);
/* Start an alarm */
//timerAlarmEnable(timer);
interrupts();
}
void loop() {
//Increment temperature setpoint if you press button A
if (! digitalRead(BUTTON_A)){
if(temp_setpoint<85) temp_setpoint++;
for ( int i=0 ; i < 10 ; i++ ) {
yield();
delay( 10 );
}
}
//Decrement temperature setpoint if you press button C
else if (! digitalRead(BUTTON_C)){
if(temp_setpoint>55) temp_setpoint--;
for ( int i=0 ; i < 10 ; i++ ) {
yield();
delay( 10 );
}
}
//Read temp sensor
tempsensor.wake();
delay(250); // MSP9808 takes about 250mS to produce it's first sample
roomtemp = tempsensor.readTempF();
Serial.print(roomtemp);
Serial.print(" ");
tempsensor.shutdown_wake(1);
//update state machine
if(!htreq){
htreq = roomtemp <= (temp_setpoint - hysteresis);
}
else{
if(roomtemp >= (temp_setpoint)){ //assert stopflag immediately upon temp going above setpoint since I will have a heater full of hot water
htreq = false; //even if this is a false assertion, (very unlikely) it will just request heat again when temp falls below
stopflag = true;
}
}
//Press and hold button B for Status routine
if (! digitalRead(BUTTON_B)){
display.clearDisplay();
display.setCursor(0,0);
display.print("WL_CONNECTED: ");
if(WiFi.status() == WL_CONNECTED) display.print("1");
else display.print("0");
display.print("\n");
display.print("IP Addr:");
display.print(WiFi.localIP());
display.print("\n");
display.print("tstat_timer: ");
display.print(tstat_timer);
display.display();
}
else{
//Update display
display.clearDisplay();
display.setCursor(0,0);
display.print("Set Temp: ");
display.print(temp_setpoint);
display.print("\n");
display.print("Curr Temp: ");
display.print(roomtemp);
display.print("\n");
display.print("Heat Req: ");
display.print((htreq)?"yes":" no");
display.print("\n");
display.display();
}
for ( int i=0 ; i < 50 ; i++ ) {
yield();
delay( 10 );
}
// //if it's been more than 60 seconds since the last tstat request update
// //IN OTHER WORDS, PING THE TSTAT IN THE BASEMENT EVERY 60 SECONDS
if((tstat_timer>60 or stopflag) and sincelast_timer >30){
HTTPClient http;
Serial.println("Making tstat request URL");
String s = "http://192.168.0.19/recroom/";
s+= (htreq)?"1":"0";
Serial.println(s);
http.begin(s); //Specify request destination
portENTER_CRITICAL(&timerMux);
sincelast_timer=0;
portEXIT_CRITICAL(&timerMux);
int httpCode = http.GET(); //Send the request
if (httpCode > 0) { //Check the returning code
String payload = http.getString(); //Get the request response payload
Serial.println(payload); //Print the response payload
portENTER_CRITICAL(&timerMux);
tstat_timer =0;
portEXIT_CRITICAL(&timerMux);
stopflag = false; // success so clear flag and timer
}
else Serial.println("wtf... it didnt work");
http.end(); //Close connection
}
// if wifi is down, try reconnecting every 30 seconds
if ((WiFi.status() != WL_CONNECTED) && (wifi_check_timer > 30)) {
Serial.println("Reconnecting to WiFi...");
WiFi.disconnect();
WiFi.begin(ssid, password);
portENTER_CRITICAL(&timerMux);
wifi_check_timer=0;
portEXIT_CRITICAL(&timerMux);
}
}
This will make your program stay in an infinite loop until the serial port is opened in Arduino IDE Serial Monitor (or an equivalent application). The reason that is useful is because on native USB boards like yours, the board is not reset when you open Serial Monitor. That means any serial output printed between the time the program starts running and when you get Serial Monitor open will be lost.
In applications where missing that serial output would be a problem, it's useful to add this code to the sketch in order to make the program wait for the Serial Monitor before running.
However, if you are wanting to run your program when the board is not connected to Serial Monitor, you must remove that while loop to allow the rest of the sketch to run.
I stand corrected. My code contained exactly that. Completely forgot that I copied that from some example code last week and just glossed over it when you asked the question.
Thank you for your thorough observation and explanation!