Thursday, 25 February 2021

Moving on up from ATMEGA328 & Arduino. The ESP32 "Mexican wave" light chaser.

I've recently been looking at other microcontroller options for some upcoming projects. Arduino and the ATMEGA328 have been wonderful devices, but it's getting on a bit now. 

I've played with the very powerful Teensy range of controllers a little bit, and they're great, just, well, a bit pricey .... The audio functions they perform are, however, wonderful. Probably great "bang for the buck" ... I just really don't need that much bang!

A while ago, I visited the USA, and one guy there gave me a "Blue Pill" , a fast, 32 bit microcontroller, with plenty of IO. Sadly not much in the way of RAM, and support for libraries seems a bit lacking. It is, however, stupid cheap.

I seen & read a bit on the ESP32. Looks good, and is cheaply priced. I've bought a couple. The one thing that (sort of) lets it down is the absence of a simple analogWrite function to control it's myriad of PWM outputs. It does have 2 proper DAC's though. Thankfully there's a function called ledc, which is largely similar, but operates at a higher (5KHz) PWM frequency than Arduino uno (nano etc) 490Hz, which makes filtration a bit easier. It's got wifi, bluetooth, a magnetic hall sensor (why??), and a built in RTC, and probably much more!

A while back I built the Arduino analogue clock , and always intended  to incorporate two large 270 degree meters. I never got round to it. My intention is to modify the code to use the in-built RTC, synchronised by NTP via Wifi, and use that to drive the meters. Seems easy enough, and will be a good project to cut my teeth on. 

In the meantime, I've been playing with ledc to make a mexican-wave style LED chaser, to get the hang of things a bit. It's based on adding more channels to the example supplied in the Arduino IDE for ESP32.

Hang some LED's off the pins as listed in the code, with appropriate current limiting resistors (220Ohm), and enjoy.

  LEDC Software Mexican wave

// use first 8 channels of 16 channels
#define LEDC_CHANNEL_0     0
#define LEDC_CHANNEL_1     1
#define LEDC_CHANNEL_2     2
#define LEDC_CHANNEL_3     3
#define LEDC_CHANNEL_4     4
#define LEDC_CHANNEL_5     5
#define LEDC_CHANNEL_6     6
#define LEDC_CHANNEL_7     7

// use 13 bit precission for LEDC timer
#define LEDC_TIMER_13_BIT  13

// use 5000 Hz as a LEDC base frequency
#define LEDC_BASE_FREQ     5000

// fade LED PIN (replace with LED_BUILTIN constant for built-in LED)
#define LED_PIN_0      23
#define LED_PIN_1      22
#define LED_PIN_2      21
#define LED_PIN_3      19
#define LED_PIN_4      18
#define LED_PIN_5      17
#define LED_PIN_6      16
#define LED_PIN_7      15

int brightness [] = {0, 32, 64, 96, 128, 160, 192, 244, 255}; // how bright the LED is

int fadeAmount[] = {1,1,1,1,1,1,1,1}; // how many points to fade the LED by

// Arduino like analogWrite
// value has to be between 0 and valueMax
void ledcAnalogWrite(uint8_t channel, uint32_t value, uint32_t valueMax = 255) {
  // calculate duty, 8191 from 2 ^ 13 - 1
  uint32_t duty = (8191 / valueMax) * min(value, valueMax);

  // write duty to LEDC
  ledcWrite(channel, duty);

void setup() {
  // Setup timer and attach timer to a led pin
  ledcAttachPin(LED_PIN_0, LEDC_CHANNEL_0);
  ledcAttachPin(LED_PIN_1, LEDC_CHANNEL_1);
  ledcAttachPin(LED_PIN_2, LEDC_CHANNEL_2);
  ledcAttachPin(LED_PIN_3, LEDC_CHANNEL_3);
  ledcAttachPin(LED_PIN_4, LEDC_CHANNEL_4);
  ledcAttachPin(LED_PIN_5, LEDC_CHANNEL_5);
  ledcAttachPin(LED_PIN_6, LEDC_CHANNEL_6);
  ledcAttachPin(LED_PIN_7, LEDC_CHANNEL_7);

void loop() {

  for (int i = 0; i <= 7; i++) {
    ledcAnalogWrite(i, brightness[i]); // set the brightness of each led in the array
    brightness[i] = brightness[i] + fadeAmount[i]; // increase the brightness of each led
    if (brightness[i] <= 0 || brightness[i] >= 255) { // until it gets to 255, then reverse the direction of fade, until it gets to 0, and reverse again
      fadeAmount[i] = -fadeAmount [i];
    delay (1);