10. Output Devices - Week 10


10.1. Assignments

Input Devices

group assignment

  • measure the power consumption of an output device

individual assignment

  • add an output device to a microcontroller board you’ve designed, and program it to do something

10.2. Group Assignment

I wanted to work with the addressable LEDs (‘NeoPixel’) for my final project, so I looked a bit more into them.

10.2.1. General about ‘NeoPixel’

WS2812B Datasheet

Those LEDs are special because they have an Integrated Circuit (IC) for adresssing the LED, and all in a 5050 package (5mmx5mm). Addressable means in this case that the LEDs are controllable via an address via a specific protocol.

10.2.1.1. Inner Structure

../_images/leds_neo-closeup.jpg

Source

They have 4 connectors:

  • VCC (in this case 3-5V)

  • Ground (VSS)

  • Data Input (DIN)

  • Data Out (DOUT)

In the above case are the top and bottom ones VCC or Ground and connected horizontally. Then are the DIN and DOUT pins the middle ones.

10.2.1.2. How they work

To control/use them, the need a voltage and they also need to be programmed/need to have a value.
The DIN and DOUT Pins are SPI pins of the IC and receive output from another IC (e.g. the one controlling it OR another NeoPixel).

And the usual way they are used is to daisy chain the LEDs (DIN to DOUT) and only connect one DIN pin to a MCU.
That means, there is only one pin of the MCU needed to control many of those LEDs. And the amount of LED is actually only limited by your power supply and your needed frequency to change the LEDs.

This is because of how they are addressed, they use the data-in pin to receive 24 bits (3 bytes, one byte for each color). The rest is just forwarded to DOUT and the next LEDs. This way you can easily control every pixel in a stripe with only needing one wire! :D

10.2.2. Measuring Power Consumption

Group Page

For the Power Consumption I measured the current of one WS2812B LED to calculate, how much Ampere would run on my board below. There I limited the current to 100mA and set the Voltage to 3.3V which I wanted to operate them with in my board below. In this case, the led was used previously and pre-programmed.

IMAGE_WS_current

There I measured:

0.02A @ 3.3V

for one LED with color white.

I wanted to build 12 of those LEDs in my board and I wanted to use 2 of the Super Capacitors to power the board, here the energy and time calculation:

2x Super Conductors
each:
    - 10F
    - 3.8V

12x WS2812B
each:
    - 0.02A
    - 3.3V

Q = C * V = 10F * 3.8V
=> 38C == 38 As

For 1 LED:

2 * 38 As / 0.02A = 3800s == ca. 63min (-> a small pomodoro cycle :D)

For 12 LEDs:

2 * 38As / (12 * 0.02A) = 317s == ca. 5min

Also note that this is with full brightness and white color, meaning if I change to another color and decrease the brightness, I should get more time :].

10.3. Individual Assignment

10.3.2. Final Project POC

Now I used my proof of concept device from the last weeks to control the LED-Matrix with my touchpads, therefore I used the example-code for the Qtouch pins of the esp-idf. Unfortunately I did not choose the Charlieplexing for my matrix control because when I designed it, I didn’t know about such a thing.

IMAGE_BOARD

I only changed the callback for the threading-abstraction to check for the pad pressed and then blink one LED in the Matrix and some pragma-stuff.

/*
 * SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD
 *
 * SPDX-License-Identifier: CC0-1.0
 */

#include "driver/gpio.h"
#include "driver/touch_pad.h"
#include "esp_log.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include <inttypes.h>
#include <stdio.h>

#define TOUCH_BUTTON_NUM 3
#define TOUCH_CHANGE_CONFIG 0

#define LED_V0 1
#define LED_V1 2
#define LED_V2 3

#define LED_G0 6
#define LED_G1 5
#define LED_G2 4
static const char *TAG = "touch read";
static const touch_pad_t button[TOUCH_BUTTON_NUM] = {
    /*TOUCH_PAD_NUM1,*/
    /*TOUCH_PAD_NUM2,*/
    /*TOUCH_PAD_NUM3,*/
    /*TOUCH_PAD_NUM4,*/
    /*TOUCH_PAD_NUM5,*/
    /*TOUCH_PAD_NUM6,*/
    TOUCH_PAD_NUM7, TOUCH_PAD_NUM8, TOUCH_PAD_NUM9,
    /*TOUCH_PAD_NUM10,*/
    /*TOUCH_PAD_NUM11,*/
    /*TOUCH_PAD_NUM12,*/
    /*TOUCH_PAD_NUM13,*/
    /*TOUCH_PAD_NUM14*/
};

/*
  Read values sensed at all available touch pads.
 Print out values in a loop on a serial monitor.
 */

//
// MY CHANGES
//
static void tp_example_read_task(void *pvParameter) {
  uint32_t touch_value;

  /* Wait touch sensor init done */
  vTaskDelay(100 / portTICK_PERIOD_MS);
  printf(
      "Touch Sensor read, the output format is: \nTouchpad num:[raw data]\n\n");

  while (1) {
    for (int i = 0; i < TOUCH_BUTTON_NUM; i++) {
      touch_pad_read_raw_data(button[i], &touch_value); // read raw data.
      printf("T%d: [%4" PRIu32 "] ", button[i], touch_value);
      if (i == 0) {
        if (touch_value > 30000) {
          gpio_set_level(LED_V1, 1);
        } else {
          gpio_set_level(LED_V1, 0);
        }
      }
      if (i == 1) {
        if (touch_value > 30000) {
          gpio_set_level(LED_V2, 1);
        } else {
          gpio_set_level(LED_V2, 0);
        }
      }
      if (i == 2) {
        if (touch_value > 30000) {
          gpio_set_level(LED_V0, 1);
        } else {
          gpio_set_level(LED_V0, 0);
        }
      }
    }
    printf("\n");
    vTaskDelay(200 / portTICK_PERIOD_MS);
  }
}

//
// END MY CHANGES
//

void app_main(void) {
  /* Initialize touch pad peripheral. */
  touch_pad_init();
  for (int i = 0; i < TOUCH_BUTTON_NUM; i++) {
    touch_pad_config(button[i]);
  }
  gpio_reset_pin(LED_V0);
  gpio_reset_pin(LED_V1);
  gpio_reset_pin(LED_V2);
  gpio_reset_pin(LED_G0);
  gpio_reset_pin(LED_G1);
  gpio_reset_pin(LED_G2);
  /* Set the GPIO as a push/pull output */
  gpio_set_direction(LED_V0, GPIO_MODE_OUTPUT);
  gpio_set_direction(LED_V1, GPIO_MODE_OUTPUT);
  gpio_set_direction(LED_V2, GPIO_MODE_OUTPUT);
  gpio_set_direction(LED_G0, GPIO_MODE_OUTPUT);
  gpio_set_direction(LED_G1, GPIO_MODE_OUTPUT);
  gpio_set_direction(LED_G2, GPIO_MODE_OUTPUT);
  gpio_set_level(LED_G0, 0);
  gpio_set_level(LED_G1, 1);
  gpio_set_level(LED_G2, 1);
#if TOUCH_CHANGE_CONFIG
  /* If you want change the touch sensor default setting, please write
   * here(after initialize). There are examples: */
  touch_pad_set_measurement_interval(TOUCH_PAD_SLEEP_CYCLE_DEFAULT);
  touch_pad_set_charge_discharge_times(TOUCH_PAD_MEASURE_CYCLE_DEFAULT);
  touch_pad_set_voltage(TOUCH_PAD_HIGH_VOLTAGE_THRESHOLD,
                        TOUCH_PAD_LOW_VOLTAGE_THRESHOLD,
                        TOUCH_PAD_ATTEN_VOLTAGE_THRESHOLD);
  touch_pad_set_idle_channel_connect(TOUCH_PAD_IDLE_CH_CONNECT_DEFAULT);
  for (int i = 0; i < TOUCH_BUTTON_NUM; i++) {
    touch_pad_set_cnt_mode(button[i], TOUCH_PAD_SLOPE_DEFAULT,
                           TOUCH_PAD_TIE_OPT_DEFAULT);
  }
#endif
  /* Denoise setting at TouchSensor 0. */
  touch_pad_denoise_t denoise = {
      /* The bits to be cancelled are determined according to the noise level.
       */
      .grade = TOUCH_PAD_DENOISE_BIT4,
      .cap_level = TOUCH_PAD_DENOISE_CAP_L4,
  };
  touch_pad_denoise_set_config(&denoise);
  touch_pad_denoise_enable();
  ESP_LOGI(TAG, "Denoise function init");

  /* Enable touch sensor clock. Work mode is "timer trigger". */
  touch_pad_set_fsm_mode(TOUCH_FSM_MODE_TIMER);
  touch_pad_fsm_start();

  /* Start task to read values by pads. */
  xTaskCreate(&tp_example_read_task, "touch_pad_read_task", 4096, NULL, 5,
              NULL);
}

There I first mixed the pin-direction up in my schematics, where I then tested the LEDs manual:

IMAGE_TEST_LEDs

But then I corrected the code and it worked :D

Also I tested out the NeoPixel LEDs in the next week.

10.3.3. Pomodoro Timer

IMAGE IMAGE IMAGE IMAGE

10.4. Notes