simple programming of the esp32-s3-devkitc-1 using esp-idf, version 2

ESP32-S3-DevKitC-1 with externally wired LED — drawn with KiCad 6

I’ve been cleaning up some code, and I decided to go back and do a smidge of refactoring of the original post. So here’s the new code. Comments on what changed and why follows.

#include <stdio.h>#include "freertos/FreeRTOS.h"#include "freertos/task.h"#include "driver/gpio.h"#include "esp_log.h"#include "led_strip.h"#include "sdkconfig.h"#include <vector>#include <tuple>typedef std::tuple<int, int, int, int> led_color;const std::vector <led_color> colors {{0,32,0,0},  // red{0,0,32,0},  // green{0,0,0,32},  // blue{0,0,32,32}, // cyan{0,32,0,32}, // magenta{0,32,16,0}, // yellow{0,0,0,0}// black};// Task 1.//static void task_blink_neo_pixel(void * pvParameters) {static led_strip_t *pStrip_a;pStrip_a = led_strip_init(CONFIG_BLINK_LED_RMT_CHANNEL, CONFIG_BLINK_GPIO, 1);pStrip_a->clear(pStrip_a, 50);// Stay in an endless loop. Don't return from this task.//while(true) {for(led_color c : colors) {pStrip_a->set_pixel(pStrip_a,std::get<0>(c), std::get<1>(c), std::get<2>(c), std::get<3>(c));pStrip_a->refresh(pStrip_a, 100);vTaskDelay(500 / portTICK_PERIOD_MS);// Set NeoPixel LED dark by clearing all its individual LEDs.pStrip_a->clear(pStrip_a, 50);vTaskDelay(500 / portTICK_PERIOD_MS);}}}// Task 2.//static void task_blink_led(void * pvParameters) {gpio_reset_pin(GPIO_NUM_46);// Set the GPIO as a push/pull output//gpio_set_direction(GPIO_NUM_46, GPIO_MODE_OUTPUT);// Stay in an endless loop. Don't return from this task.//while (true) {gpio_set_level(GPIO_NUM_46, true);   // LED onvTaskDelay(100 / portTICK_PERIOD_MS);gpio_set_level(GPIO_NUM_46, false);  // LED offvTaskDelay(100 / portTICK_PERIOD_MS);gpio_set_level(GPIO_NUM_46, true);   // LED onvTaskDelay(100 / portTICK_PERIOD_MS);gpio_set_level(GPIO_NUM_46, false);  // LED offvTaskDelay(2700 / portTICK_PERIOD_MS);}}extern "C" void app_main(void) {static const char *TAG = "DUAL_BLINK";int core = xPortGetCoreID();ESP_LOGI(TAG, "app_main running on core %i", core);ESP_LOGI(TAG, "CONFIG_BLINK_GPIO %i", CONFIG_BLINK_GPIO);// Create task 1.//TaskHandle_t xHandle1 = NULL;static uint8_t ucParameterToPass1 = 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.//TaskHandle_t xHandle2 = NULL;static uint8_t ucParameterToPass2 = 1;xTaskCreate(task_blink_led,"BlinkLED", // human-readable task name.2048,   // stack size in bytes.&ucParameterToPass2,tskIDLE_PRIORITY,&xHandle2);configASSERT(xHandle2);// Stay in an endless loop. Don't return from this task.//while (true) {vTaskDelay(1000 / portTICK_PERIOD_MS);}}

Here’s what changed.

  • ESP-IDF was updated to version 4.4.3. I’m using that now, waiting in anticipation of the version 5.0.0 drop. Version 5 is now a release candidate, but I’m holding off stepping up to that until there’s a full formal release.
  • The source file was renamed to dualblink.cpp. That cpp extension signals to the tool chain to treat this as a C++ source file, with all that implies. This allowed me to include vector and tuple (lines 18 and 19), which then provided me with a better way to define the collection of colors to cycle through in the task_blink_neo_pixel task. This eliminates having to explicitly define a size of the data structure.
  • I was able to combine the new way of creating my collection of colors (line 26) with the C++ foreach loop (line 46) and clearly and simply iterate through the collection. You’ll note that I did not have to explicitly declare an iterator nor manipulate it anywhere in the foreach block. My only annoyance is syntax for how to reference each individual tuple element for the call to set the neopixel color (line 48).
  • I had to declare the app_main entry point as extern “C” in order for the linker to properly link with FreeRTOS.

The link to the older post is here: /2022/03/23/simple-programming-of-the-esp32-s3-devkitc-1-using-esp-idf/

silly safe coding with c++

Being anti-C++ is all the rage these days, with the programming hoi polloi singing hosannas to Rust ( https://www.rust-lang.org ) in particular. While I’ve worked a bit with Rust (and Google Go), I’m coming back around again to C++, specifically C++11 (the standard passed in 2011) or later, such as C++14 and C++17. For this coding experiment I’m using GCC/G++ 11.2 (a part of Mint Linux 21) and Boost 1.80 ( https://www.boost.org ). I also created this to try out using big numbers, which you can do natively within Python and Julia. Anyway, here’s the code.

#include <boost/multiprecision/cpp_int.hpp>#include <algorithm>#include <iostream>#include <iomanip>using boost::multiprecision::cpp_int;void factorial(cpp_int n) {cpp_int a = 1;std::cout << std::right << std::setw(4) << std::fixed << n;while ( n > 0 ) {a = a * n;n--;}std::cout << std::left << "! = " << a << std::endl;}int main(int argc, char *argv[]) {// Uncomment the following line to debug cli input.// std::copy(argv, argv + argc, std::ostream_iterator<char *>(std::cout, "\n"));for (int i = 1; i < argc; factorial(std::stoi(argv[i++])));return 0;}

And here’s a run.

I patterned this after another post where I wrote the equivalent simple factorial program in Julia and Python ( /2022/01/15/silly-coding/ ). What made the Python and Julia programs work is that both will work with arbitrarily sized integers. I had thought I might write something equivalent in C++, but then it quickly dawned on me that this arbitrarily sized integers are a common need, which is why they’re in Python and Julia. Sure enough, I quickly found support in Boost, using the Multiprecision data type cpp_int. What’s more the math and comparison operators are all overloaded so that the code looks no different using the big integer type as for a regular integer data type.

I call this safe because I’ve used as much pre-coded software as possible, knowing that all of it has been properly designed, coded, and tested. Yes, I could write it all myself, but it wouldn’t be as safe or trustworthy as it is now. Yes, it’s still fragile. For example I can pass bad values on the command line that don’t convert to an int and it will core dump (I know, I tried it out). But for basic testing, and as an example, I’m quite pleased how little I did code in order to make this work.

I know that working with C and C++ aren’t cool right now, but I’ll say what I’ve always said in the past. Learn the language, no matter what it is, and learn the best idiomatic way to program in that language.