a correction to: adafruit esp32 feather v2

In the last post I wrote that you could flash this Adafruit Feather with a version of MicroPython. Unfortunately it did not enable the use of the board’s SPIRAM. The specifications for this board declares that it has 4MiB of non-volatile (FLASH) and 2MiB of RAM (SPIRAM). When I went to check for the amount of free RAM it was far lower than I expected. That’s when I realized I’d use the wrong MicroPython image to flash the Feather. The correct link is: https://micropython.org/download/esp32spiram/ .

One way to test that you are seeing all the RAM is by adding two lines to the blink code, starting at line 13.

import espprint("Flash size {} in bytes".format(esp.flash_size()))import gcprint("Memory free {} in bytes.".format(gc.mem_free()))

When the code executes you’ll see the following (I’m working with Thonny, and this is in Thonny’s shell):

MPY: soft rebootesp32, esp32, 1.18.0, v1.18 on 2022-01-17, ESP32 module (spiram) with ESP32MicroPython-1.18.0-xtensa-IDFv4.2.2-with-newlib3.0.0Flash size 4194304 in bytesMemory free 2046144 in bytes.

Note the second line that contains “…ESP32 module (spiram)…”, and the last line that shows 2MiB of RAM memory.

correction to adding queues, c++ — more esp32-s3-devkitc-1 programming notes

I did something dumb in the referenced programming note. I’ll post the fixed code, and then show the error in the original code.

extern "C" void app_main(void) {static const char *TAG = "DUAL_BLINK_QUEUE";int core = xPortGetCoreID();ESP_LOGI(TAG, "app_main running on core %i", core);ESP_LOGI(TAG, "CONFIG_BLINK_GPIO %i", CONFIG_BLINK_GPIO);TaskHandle_t xHandle1 = NULL;static uint16_t ucParameterToPass1 = 1;TaskHandle_t xHandle2 = NULL;static uint16_t ucParameterToPass2 = 2;qtask = xQueueCreate(10, sizeof(TaskMessage *));if (qtask != NULL) {ESP_LOGI(TAG, "queue created");// Create task 1.//xTaskCreate(task_blink_neo_pixel,"BlinkNeoPixel",// human readable task name.2048,   // stack size in bytes.&ucParameterToPass1,tskIDLE_PRIORITY,&xHandle1);configASSERT(xHandle1);// Create task 2.//xTaskCreate(task_blink_led,"BlinkLED", // human-readable task name.2048,   // stack size in bytes.&ucParameterToPass2,tskIDLE_PRIORITY,&xHandle2);configASSERT(xHandle2);TaskMessage *ptask_message;// Stay in an endless loop. Don't return from this task.//vTaskDelay(1000 / portTICK_PERIOD_MS);while (true) {// vTaskDelay(1000 / portTICK_PERIOD_MS);if (xQueueReceive(qtask, &(ptask_message), (1000/portTICK_PERIOD_MS))) {uint16_t tid = ptask_message->taskid;MsgType msgtype = ptask_message->msgtype;uint32_t msgdata = ptask_message->msgdata;ESP_LOGI(TAG, "Task ID %i, MsgType %i, msg data %i", tid, msgtype, msgdata);}}}}

You should not call xQueueReceive(...) without testing for the return value. If a message is received the call returns true, otherwise it returns because of the timeout (see line 151) AND it returns false. If you blindly accept that the return will always be a message then unpredictable behaviors will result, leading to the occasional application crash.

For example, I decided to stop sending the count message and commented out all the code that managed the message and sent the message. When I tested it again, it was still repeating as if a message was being received, specifically the core message. That made no sense as I only sent that message once, but here it was coming across every second (hint, hint). So I commented out those one time messages, recompiled and reran the result. Now it was crashing every second. When I bothered to look into the code that’s when the light came on and I realized the call was timing out every second, just like I’d originally programmed it. So now I test every return and only process a message when it’s actually received.

Yes, I’m a dummy.