Week 1 of 10 of the Making Embedded Systems course.

I’ve signed up for Elicia Whites on-line course Making Embedded Systems. It’s a ten week course with weekly homework and a long-running project of your own choice. You’re supposed to spend 6-10 hours a week on the course, but I expect to at the very least double that.

This week was the introduction and I didn’t spend that much time on the course. It’s been fun hanging on the discord chat and I hope that more people start discussions. I’m very impressed by the careers of the course participants. There’s a lot of experience to tap into there.

The Wokwi simulator

I started off by experimenting with programming a simulated rp2040 on the Wokwi online simulator using the Pico SDK. I was amazed at how usable the simulator was. You can add ~50 different peripherals; hook up an in-simulator logic analyzer that exportc VCD-files; and create custom chips!

I only dipped my toes. Here’s blinky for two leds:

#include <stdio.h>
#include "pico/stdlib.h"

#define HIGH_PIN 2
#define LOW_PIN 3

int main() {
  stdio_init_all();
  
  // Configure a pin that sources current.
  gpio_init(HIGH_PIN);
  gpio_set_dir(HIGH_PIN, GPIO_OUT);

  // Configure a pin that sinks current.
  gpio_init(LOW_PIN);
  gpio_set_dir(LOW_PIN, GPIO_OUT);
  gpio_set_outover(LOW_PIN, GPIO_OVERRIDE_INVERT);

  while (true) {
    printf("Hello world!\n");

    gpio_put(HIGH_PIN, 1);
    gpio_put(LOW_PIN, 1);
    sleep_ms(250);

    gpio_put(HIGH_PIN, 0);
    gpio_put(LOW_PIN, 0);
    sleep_ms(250);
  }
}

And here’s a program that controls two leds using push-buttons, one polling and one interrupt-driven. I’ve set bounce to 0 in the simulators config file so that I don’t have to handle debouncing.

#include <stdio.h>
#include "pico/stdlib.h"

#define PURPLE_LED 2
#define RED_LED 14
#define GREEN_BUTTON 3
#define BLUE_BUTTON 9

#define EDGE_LOW (1UL << 2)
#define EDGE_HIGH (1UL << 3)

void button_pressed(uint gpio, uint32_t events) {
  if (events & EDGE_LOW) {
    gpio_put(RED_LED, 1);
  } else {
    gpio_put(RED_LED, 0);
  }
}

int main() {
  stdio_init_all();

  // Init outputs.
  gpio_init(PURPLE_LED);
  gpio_set_dir(PURPLE_LED, GPIO_OUT);
  gpio_init(RED_LED);
  gpio_set_dir(RED_LED, GPIO_OUT);

  // Init inputs
  gpio_init(GREEN_BUTTON);
  gpio_pull_up(GREEN_BUTTON);
  gpio_init(BLUE_BUTTON);
  gpio_pull_up(BLUE_BUTTON);

  gpio_set_irq_enabled_with_callback(BLUE_BUTTON, EDGE_LOW | EDGE_HIGH, 
      /*enabled=*/true, button_pressed);

  while (true) {
    if (!gpio_get(GREEN_BUTTON)) {
      gpio_put(PURPLE_LED, 1);
    } else {
      gpio_put(PURPLE_LED, 0);
    }
    sleep_ms(1);
  }
}

And finally a program that lights a led using PWM:

#include <stdio.h>
#include "pico/stdlib.h"
#include "hardware/pwm.h"

#define LED 2

int main() {
    stdio_init_all();

    gpio_set_function(LED, GPIO_FUNC_PWM);
    uint slice_num = pwm_gpio_to_slice_num(LED);
    pwm_set_wrap(slice_num, 256);
    pwm_set_chan_level(slice_num, PWM_CHAN_A, 128);
    pwm_set_enabled(slice_num, true);
    
    while (true) {
      sleep_ms(1);
    }
}

I had some problems with the PWM library and the pico-examples repo was very useful as a reference. The documentation for the SDK is a little hard to navigate. I found a dash docset which was quite an improvement.

The STMCubeMX software stack

ST Microelectronics provides their own IDE, STM32CubeIDE based on Eclipse. I followed course mate Dananjaya Ramanayakes instructions for installing the VSCode extension that allows me to import CubeMX projects. This blog post was also helpful : Importing ST projects into Visual Studio Code.

I verified that I could install a CubeMX generated project on a STM32F4xx nucleo board. So far, so good! It’s gonna take quite some time for me to learn the ins and outs of CubeMX and I’m a bit skeptical of all this automatic code generation. But it will be fun to experiment with it!

I asked some questions about how to wrap the generated HAL behind your own interface. You can split the generated code into separate .c/.h files which probably will be useful. And you can also choose whether to generate driver code using HAL or the more low-level LL APIs. I hope I’ll figure it out once I start coding.

Architecture diagrams

This weeks assignment was to create software block diagrams, hierarchical control diagrams and layered software diagrams for a product of your own choosing. I started out by trying to draw the diagrams for the ipod mini and a point-and-shoot camera. I realized that both of them probably relies on Cortex-A5s or similar and not cortex-M microcontrollers. When I started thinking about different products I noticed that it was easier for me to find Cortex-A powered units than Cortex-M ones. I asked around a bit about the performance/cost tradeoffs. Here’s some things I learned:

  • Cortex-M uses bigger process nodes. Means less perf per amp but cheaper production
  • ST has been using 90nm, some low-power devices are built using 40nm.
  • Cortex-M can draw 1uA in sleep mode. A Cortex-A draws astleast 300uA!
  • Cortex-A 32 bit processors are divided into in-order power efficient cores (Cortex-A5, Cortex-A7) and out-of-order speedrunners (Cortex-A15, Cortex-A17).
  • The processors closest in performance and price to Cortex-M parts are Cortex-A5 and Cortex-A7.
  • Cortex-A parts like some Allwinner chips will be in the same price range as the 5-10 USD for a STM32F1xx MCU
  • For SOM chips like an RPI compute module you pay more - about 30 USD.
  • There exists a power efficiency benchmark for Cortex-M parts: https://www.eembc.org/ulpmark/ulp-cp/scores.php

Back to the architecture diagrams: I found them useful but designing things are always hard. I wish there was a large samples of good reference materials for designs and that you could compare your solutions to something that’s considered good by many people. On the other hand, design is a sloppy business, I probably should just get used to “flying blind”.