unexpected maker pros3

Figure 1: Unexpected Maker ProS3 (image via Adafruit)

Two more ESP32-S3-based boards arrived yesterday, the Unexpected Maker ProS3 ( https://esp32s3.com/pros3.html ) I purchased from Adafruit ( https://www.adafruit.com/product/5401 ). At US$25 each, they’re creeping up into the price range of a low-end Raspberry Pi 3 or 4, that is if you could get any Raspberry Pi anywhere. One reason for my interest in the Espressif-based boards is because they’re the only devices available to develop with, except perhaps for the very high end ESP32-S3 Developer Kits and, as bad luck would have it, the Unexpected Maker ProS3. But at least I found these two.

The ProS3 is a well built board with some thought put into what features to include in its build.

Figure 2: Feature highlights (image via Unexpected Maker)

Figure 2 calls out many of the main features on the board. Thankfully it has a USB-C connector on one end, not micro USB. Note that the board edges are castellated, which allows the board to be surface mounted onto a larger PCB for easy inclusion into a larger product. The board is narrow, and all devices are mounted on the upper side. This means that everything is packed, and some work went into solving how to include certain features. For example the STEMMA QT connector is mounted 90° to the board, instead of parallel and on the edge with just about every other board of this type. Unlike every other ESP32-S3 board I’ve worked with, the MCU is in a very-narrow-pitch surface mount device. The board also comes with a very generous 16GB of FLASH and 8GB PSRAM, allowing for some expansive Circuit Python application development. Finally, there is a PicoBlade power connector on the right; the board ships with a PicoBlade-to-JST cable with each board. This allows me to use any of the LiPoly batteries I have, and the board will charge them.

Figure 3: ProS3 pinout (image via Unexpected Maker)

The pinout in Figure 3 shows what features and functions are brought out to the edges of the device. When you purchase a ProS3 you get this exact diagram printed on heavy card stock. It’s a thoughtful touch that enhances the experience of using the ProS3. I appreciate having the pinout next to the device on my bench while I’m wiring up a circuit.

Another nice touch is that these devices came with Circuit Python 7.3.0 alpha installed, complete with two Circuit Python scripts that exercised the RGB LED on the board. I checked the Circuit Python site for the ProS3 ( https://circuitpython.org/board/unexpectedmaker_pros3/ ) to check what version is currently available and discovered it’s now at beta 2. I downloaded the latest and prepared to update the ProS3 and ran into a frustrating, but fixable problem. I found I couldn’t put the board into bootloader mode, and I couldn’t find the directions. I eventually found directions, but for a different board from Unexpected Maker. Here is what you need to do to put the ProS3 into bootloader mode (I’m performing this on a MacBook Pro M1).

  1. Put a finger over the Reset (RST) button and another over BOOT.
  2. Press and release Reset.
  3. Immediately after releasing Reset, press and release Boot.
  4. The RGB LED will go a solid green color, and PROS3BOOT will mount.
  5. Drag the latest Circuit Python UF2 file onto PROS3BOOT. The board will reboot back to Circuit Python on its on.

Once I learned the magic sequence it only took me a single attempt to put the board in bootloader mode. You don’t know how many times I tried the double-click Reset, or the RP2040 boot button sequence. Unexpected Maker has to be different. Of the three methods I know of I prefer the RP2040 boards sequence, because it’s not timing based, it’s sequence based. Unexpected Maker’s method is reasonably doable, as long as it’s clearly documented, especially on the ProS3 page. But no matter. Right now the board is running just fine and I’m beginning to think of what I can build from it.

As for the tools used for developing with Circuit Python, I can confirm that the latest versions of both Thonny and Mu Editor work just fine. And if those two work, I’m certain that just about everything else out there will work as well.

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.