@TomKatt
RESOLVED - someone pointed out that the example code I was running included a line to wait for the serial port to be enabled.
Code always does what you tell it, not what you mean lol.
@TomKatt
RESOLVED - someone pointed out that the example code I was running included a line to wait for the serial port to be enabled.
Code always does what you tell it, not what you mean lol.
I've got an M5Stack DinMeter board based on StampS3 ESP32 controller. It works fine while developing and plugged in with usb data cable. If I try to power the board using external power or usb power-only cable, the power led lights on the board but the display remains blank and the code does not run - almost like sleep mode.
I am new to ESP32 and understand that my board has sleep and wake functionality, but I would suspect that default operation would be to start/run when dc power is applied... I looked through demo code but see nothing related to powering board without data cable.
Anyone have experience with M5Stack or similar issues? There must be something in code or flash option that needs to be set that I am missing...
TIA
@ajb2k3
LOL - Silly that I never thought to check out the forums at Arduino proper... Most questions are probably generally related to generic ESP32 discussions, but there also seems to be a fair number of M5Stack users as well ;-)
Perhaps I'll see some of you folks there...
@gleiden
I know this is an old thread, but I just encountered this issue myself tonight. I believe the error is caused by the COM port being either unavailable or busy. In my case, I accidentally created a serial print function for debugging that was writing non-stop to the COM port - this was basically overloading the programmer's ability to get it's data through to begin uploading the new code. I got lucky because my code had a several second initiation routine before it started sending debug data to the COM port - so I unplugged the controller while the compiler was working and plugged in the usb cable just before the compiler was about to upload the code. This allowed the programmer to 'get through' the COM port before the code running on the controller started overwhelming the port.
There must be another way to solve this - I am surprised that pressing the button as you power on the controller to put it into download mode does not work... I would think that is the answer.
At least you know the reasoning for the error.
I'm building a bell controller for a factory that rings for 2 seconds at shift changes and break times. Using a M5Stack DinMeter (StampS3 with RTC, Encoder) with a Mini 3A Relay Unit.
I don't often code in C, so I'm looking for any suggestions to improve my test code - I'm especially interested in the use of string arrays (or not) and identifying if the current time is in the predefined array list... I understand that strings can cause memory issues, but as I am not manipulating them I am hoping what I have is OK.
The RTC is set using internet NTP servers for accuracy over WiFi. I will eventually modify the code to synchronize at least once a day - I think that should be sufficient.
I plan on creating a GUI using the encoder button later, but for now I have defined the bell times in a string array. There are a few serial print calls for debugging that will be removed later. Because the RTC does not seem to provide access to it's IRQ signal, I'm using a while() loop to monitor for changes to the time seconds both to trigger the relay as close to the exact time as possible and also to minimize wasteful refreshing of the time display on the screen.
If you see anything horrible lol or know a better way to accomplish something I'd be grateful for any advice.
EDIT - I live in the East Coast US, so I will have to include code to accommodate DST time changes... Working on that now.
Thanks!
/**
* @file Shift_Bell
* @author TomKatt
* @brief Shift Bell Test
* @version 0.1
* @date 2025-03-21
*
*
* @Hardwares: M5DinMeter
* @Platform Version: Arduino M5Stack Board Manager v2.1.1
* @Dependent Library:
* M5GFX: https://github.com/m5stack/M5GFX
* M5Unified: https://github.com/m5stack/M5Unified
*/
#if defined(ARDUINO)
#define WIFI_SSID "*******"
#define WIFI_PASSWORD "*******"
#define NTP_TIMEZONE "UTC+4"
#define NTP_SERVER1 "0.pool.ntp.org"
#define NTP_SERVER2 "1.pool.ntp.org"
#define NTP_SERVER3 "2.pool.ntp.org"
#include <WiFi.h>
// Different versions of the framework have different SNTP header file names and
// availability.
#if __has_include(<esp_sntp.h>)
#include <esp_sntp.h>
#define SNTP_ENABLED 1
#elif __has_include(<sntp.h>)
#include <sntp.h>
#define SNTP_ENABLED 1
#endif
#endif
#ifndef SNTP_ENABLED
#define SNTP_ENABLED 0
#endif
#include <M5DinMeter.h>
bool Relay = false; // Relay Status
bool NewMinute = false; // New Minute Flag
int LastSecond; // Last Second Placeholder
const int switchPin = 2; // Relay GPIO Pin
char time_string[10]; // String Array of Shift Times
// Shift Bell Time Triggers
String shift_times[9] = {"05:00:00", "05:10:00",
"06:00:00", "06:10:00",
"09:00:00", "09:10:00",
"12:00:00", "12:40:00",
"19:15:00" };
void setup(void) {
DinMeter.begin();
DinMeter.Display.setRotation(1);
DinMeter.Display.setTextColor(GREEN, BLACK);
DinMeter.Display.setTextDatum(middle_center);
DinMeter.Display.setTextFont(&fonts::Orbitron_Light_32);
DinMeter.Display.setTextSize(1);
DinMeter.Display.setBrightness(32);
Serial.begin(115200);
pinMode(switchPin, OUTPUT); // Set pin 2 to output mode for Relay control
if (!DinMeter.Rtc.isEnabled()) {
Serial.println("RTC not found.");
DinMeter.Display.println("RTC not found.");
for (;;) {
vTaskDelay(500);
}
}
DinMeter.Display.setCursor(0, 10);
Serial.println("RTC found.");
DinMeter.Display.print("BOOTING...\r\n");
// It is recommended to set UTC for the RTC and ESP32 internal clocks.
/* /// setup RTC ( direct setting )
// YYYY MM DD hh mm ss
DinMeter.Rtc.setDateTime( { { 2021, 12, 31 }, { 12, 34, 56 } } );
//*/
/// setup RTC ( NTP auto setting )
DinMeter.Display.print("WiFi");
WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
while (WiFi.status() != WL_CONNECTED) {
Serial.print('.');
DinMeter.Display.print(".");
delay(1000);
}
Serial.println("\r\n WiFi Connected.");
DinMeter.Display.print("ON\r\n");
configTzTime(NTP_TIMEZONE, NTP_SERVER1, NTP_SERVER2, NTP_SERVER3);
#if SNTP_ENABLED
DinMeter.Display.print("NTP");
while (sntp_get_sync_status() != SNTP_SYNC_STATUS_COMPLETED) {
Serial.print('.');
DinMeter.Display.print(".");
delay(1000);
}
#else
delay(1600);
struct tm timeInfo;
while (!getLocalTime(&timeInfo, 1000)) {
Serial.print('.');
};
#endif
Serial.println("\r\n NTP Connected.");
DinMeter.Display.print("ON\r\n");
time_t t = time(nullptr) + 1; // Advance one second.
while (t > time(nullptr))
; /// Synchronization in seconds
DinMeter.Rtc.setDateTime(gmtime(&t));
delay(1000);
DinMeter.Display.clear();
auto tm = localtime(&t); // for local timezone.
LastSecond = tm->tm_sec;
}
void loop(void) {
// MAIN LOOP
static constexpr const char* const wd[7] = {"Sun", "Mon", "Tue", "Wed",
"Thr", "Fri", "Sat"};
auto t = time(nullptr);
auto tm = localtime(&t); // for local timezone.
while (LastSecond == tm->tm_sec) {
// loop until next second
t = time(nullptr);
tm = localtime(&t); // for local timezone.
}
LastSecond = tm->tm_sec;
DinMeter.Display.setCursor(20, 35);
DinMeter.Display.printf("%02d/%02d/%02d", tm->tm_mon + 1, tm->tm_mday, (tm->tm_year + 1900) % 100);
DinMeter.Display.setCursor(35, 80);
DinMeter.Display.printf("%02d:%02d:%02d ", tm->tm_hour, tm->tm_min, tm->tm_sec);
strftime(time_string, 10, "%T", tm);
Serial.println(time_string);
if(std::find(std::begin(shift_times), std::end(shift_times), time_string) != std::end(shift_times)) {
// Relay ON
digitalWrite(switchPin, HIGH);
Relay = true;
Serial.println("BELL ON");
}
if((tm->tm_sec>1) && (Relay)) {
// Relay OFF after 2 seconds
digitalWrite(switchPin, LOW);
Relay = false;
Serial.println("BELL OFF");
}
}
I'm almost hesitant to create this thread because I see there are numerous others that mention Partition Schemes - BUT after spending all morning trying to figure out what they all mean, I figured that I might as well ask for a summary.
I was surprised when my small test program appeared to consumer 62% of the available program space on my DinMeter (StampS3)... I understand that the Included library files get compiled with my small 20 line test program, but that's still a little concerning when I think about the big plans I have for this neat little controller.
I see many references to the Expressif tech notes and have just finished reading about OTA firmware space - I think I get the jist of all that and my simple project will not require any OTA updates, so I can choose a partition scheme with NO OTA.
I guess the thing that confuses me the most is that none of the partition schemes add up to the rom size of the M5 controller - supposedly there is 8MB of flash in a StampS3, but the largest partition scheme available appears to be the 'Huge App (3MB No OTA / 1MB SPIFFS). That only adds up to 4MB representing 50% of onboard flash memory on the controller.
Question - I assume that the vast majority of M5Stack users do not use OTA features... What partition scheme are you using and why? Is there any way to utilize more than 3MB for your code?
I'm also guessing that because the ESP-32 chipset was originally intended for consumer wireless products, there are safety nets built into the hardware platform for OTA updates and redundant program code so if something fails the last working backup is rolled back so the device continues working. Perhaps this is just a limitation when we use these chips as general controllers.
Thanks!
@kuriko
Thanks!
I'll check out Discord... Unfortunately, I expressed a few opinions about my governments idiocrasy and have been summarily banned from Reddit lol. Despite appearances, they are a rather sensitive bunch.
Want to better understand if there is a difference between controllers with an RTC and 'software' time of an ESP32. Perhaps I am overthinking this...
I have a DinMeter based on a StampS3 that also includes a BM8563 RTC chip. Looking through example code for NTP sync time, I see the following:
auto dt = DinMeter.Rtc.getDateTime();
Serial.printf("RTC UTC :%04d/%02d/%02d (%s) %02d:%02d:%02d\r\n",
dt.date.year, dt.date.month, dt.date.date,
wd[dt.date.weekDay], dt.time.hours, dt.time.minutes,
dt.time.seconds);
DinMeter.Display.setCursor(0, 0);
DinMeter.Display.printf("RTC UTC :%04d/%02d/%02d (%s) %02d:%02d:%02d",
dt.date.year, dt.date.month, dt.date.date,
wd[dt.date.weekDay], dt.time.hours, dt.time.minutes,
dt.time.seconds);
/// ESP32 internal timer///
auto t = time(nullptr);
{
auto tm = gmtime(&t); // for UTC.
Serial.printf("ESP32 UTC :%04d/%02d/%02d (%s) %02d:%02d:%02d\r\n",
tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday,
wd[tm->tm_wday], tm->tm_hour, tm->tm_min, tm->tm_sec);
DinMeter.Display.setCursor(0, 20);
DinMeter.Display.printf("ESP32 UTC :%04d/%02d/%02d (%s) %02d:%02d:%02d",
tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday,
wd[tm->tm_wday], tm->tm_hour, tm->tm_min,
tm->tm_sec);
}
It looks to me like the first section is getting the time data from the RTC. The comment 'ESP32 Internal Timer' makes me think that perhaps the 2nd section is getting time data from a software clock routine. Is that a correct understanding? Could the software time drift from the RTC time?
I'm not sure how the M5Stack software handles this - it could be that the 'software time' is always sourced from the RTC for controllers that have that option. My project requires time accuracy, so I want to ensure that I'm using the RTC as opposed to any 'software' time driven by the cpu clock.
Thoughts?
@teastain
Found the issue - this was hidden in the Setup routine:
DinMeter.Display.setTextDatum(middle_center);
The default is top left as expected, this line overrides the code below. Problem solved - user error strikes again lol
On the topic of different libraries - I note you have suggested the Canvas API before... Is this preferred over the TFT_eSPI API ?
Thanks!
@teastain
Hello again!
Yes, I've been experimenting and replaced the references to the display width and height with literal values and the result was as expected - the specified xy position is the center of the drawn string. Beyond the confusion of expecting xy to locate the string by upper left corner, the API states this is how drawString() should work...
drawString()
Description:
Draw a character
Syntax:
drawString(const char *string, int32_t poX, int32_t poY, uint8_t font);
drawString(const char *string, int32_t poX, int32_t poY);
drawString(const String& string, int32_t poX, int32_t poY, uint8_t font);
drawString(const String& string, int32_t poX, int32_t poY);
Function argument:
argument type Description
**poX int32_t Coordinate X (upper left)**
**poY int32_t Coordinate Y (upper left)**
string const char * / String & String
font uint8_t 1: If use the loaded font
Function return value:
None
Working through some examples to learn how to use the screen on my DinMeter...
The example code uses the snippet below to display a value manipulated by the encoder knob - the numeric text is always centered on the display...
DinMeter.Display.drawString(String(newPosition),
DinMeter.Display.width() / 2,
DinMeter.Display.height() / 2);
Researching the functions, it seems like drawCentreString() should do that ??? Shouldn't drawString() reference the top left of the current setTextDatum() command? If I need to display text in a specific area, how do you code that?
PS - looks like I'm the only one here lol
Building a project with M5Stack DinMeter that will run 24/7. This is the first time I've given serious thought to power management and battery charging. Doing some research, it seems like it is the responsibility of the programmer to incorporate power management and monitoring battery voltage to enable or disable charging... Is that correct?
My application is driving relay modules and if external DC power is lost I will need to put the controller into Sleep mode so battery can maintain RTC time. Then when external DC power is restored I need to wake controller and resume normal operation.
I found this code to check if external DC power is available - I assume that this is the same as checking if USB power is attached -
// If on battery power the system go to sleep and waiting for the wakeup call by RTC
// If on USB power the system stay awake so undo what shutdown() did and waste some time before repeating the main loop
M5.shutdown(sleepseconds);
M5.enableMainPower();
M5.RTC.clearIRQ();
delay(sleepseconds*1000);
Now I need to find examples of battery management and charging. If anyone has information or links on this topic I would be grateful if you could share them.
Thanks!
@ajb2k3
Thanks for the reply! My Fire v2.7 initially had some difficulty loading with UIFlow V2 - it would just reset with blank screen. Somehow I did manage to get V2 burned and am experimenting with it now.
EDIT - if I accidentally selected Public during initial setup, how do I change that to Private mode ?
EDIT 2 - never mind, figured it out. Wasn't the most intuitive option but I reset as desired.
@ajb2k3
I actually discovered M5Stack on YT and have watched several videos. The issue is that now that I am learning to develop on these devices, I often run into questions and it would be nice to have a forum to post them and seek help from other users.
Thanks for the suggestions - I will check out Hackster and I am already 'stealing' code from GitHub lol.
Setting up my Fire v2.7 and never used UIFlow before... When I go to UIFlow webpage I get the option to enter my device as either Public or Private. What is the difference? Is one type prefrred over the other?
Currently, I am using the UIFlow web compiler, though I may decide to install local UIFlow IDE later on.
Thanks!
I'm new(ish) to the M5Stack environment and while the products seem like fantastic values, the resources seem a bit... lacking.
No disrespect intended, but I'm curious what other resources or forums you folks use? This forum seems a tad sleepy lol. There's a lot more information bouncing around places like Reddit for instance.
Cheers!
Thank you for your help and your list of reference materials. I will review them going forward.
M5Stack is so full of potential and really great value - I don't mind putting in some effort to learn how to use it. At least I have prior experience with microcontrollers (AVR), so I have some general idea what is going on. But I will say M5 would very much benefit from additional reference materials (that are easy to find lol).
PS - I have Dial, Core 2 and Fire controllers. Also AI Unit V2 wifi camera. Just ordered DinMeter coming this week. Plenty of fun if I can figure them all out :-)
@teastain said in M5Stack Arduino IDE Reference (ex Display commands and properties) ?:
@TomKatt The first link is the API
https://docs.m5stack.com/en/arduino/m5dial/display
I did see that - but that's not API documentation as I am familiar with...
For example, where in that link identifies all the display commands? I stumbled upon the fillScreen argument earlier, but even now going back to the first link I cannot locate a command I know exists...
Please pardon my ignorance here ;-)
EDIT - I think I found something along the lines of what I am looking for here:
https://docs.m5stack.com/en/arduino/m5core2/lcd_api
Not complete or Dial specific, but at least lists the commands and arguments with examples. What I would really like is this type of information for the Dial... Perhaps I can just substitute .lcd for .display ?
@teastain said in M5Stack Arduino IDE Reference (ex Display commands and properties) ?:
Try here:
https://docs.m5stack.com/en/arduino/m5dial/display
and here:
https://github.com/m5stack/M5Dial/tree/master/examples/Basic/display
Thanks - but I've been through the example code. What I'm looking for is more of a complete reference, including all the commands not used in the sample code. For example, it took me 30 minutes of Googling to discover how to clear the display screen by using the fillScreen command... It would be very useful if a complete listing of commands and the argument types was available. Sometimes I get lucky and the Arduino IDE editor pops up a list of options as I code, but in many instances you get no pop-ups or the box doesn't show all the options. And of course C is so case sensitive that the first attempt of 'fillscreen' resulted in an error...
This information must exist somewhere - how else are people programming these things if there's no reference of how to do it ?
I'm sure that this information is right in front of me, but somehow I cannot locate it - is there a WIKI or similar reference for the M5Stack libraries? I have a Dial controller and cannot seem to find what commands and properties are available for the M5Dial.Display item... I looked in the Lessons & Guides area but don't see any general references.
Thanks for any links you can provide !!!