Been meaning to look at Zephyr for a while and was nudged by reading an article in Elektor magazine to have a go. Had a BBC Micro:bit v1.3 lying around to play with which was handy.
Getting started easy enough, following instructions (had already done this for pico) but the magazine also talked about device trees which was something I had an interest in. Pulled a copy of the standard blinky
example and added pad2
as an ersatz LED for output:
/ {
leds {
compatible = "gpio-leds";
led0: led_0 {
gpios = <&gpio0 1 GPIO_ACTIVE_HIGH>;
};
};
aliases {
led0 = &led0;
};
};
This gets added as boards/bbc_microbit.overlay
in the project source repo. Rather than building with west
decided to figure out out-of-tree building: easy enough as it turns out:
BOARD=bbc_microbit cmake ..
make
Then
cp zephyr/zephyr.hex /Volumes/MICROBIT/
to flash the device. Code simple enough:
#include <stdio.h>
#include <zephyr/drivers/gpio.h>
#include <zephyr/kernel.h>
#define LED0_NODE DT_ALIAS(led0)
static const struct gpio_dt_spec led = GPIO_DT_SPEC_GET(LED0_NODE, gpios);
int main(void) {
int ret;
if (!gpio_is_ready_dt(&led)) {
return 0;
}
ret = gpio_pin_configure_dt(&led, GPIO_OUTPUT_ACTIVE);
if (ret < 0) {
return 0;
}
while (1) {
ret = gpio_pin_set_dt(&led,1);
if (ret < 0) {
return 0;
}
ret = gpio_pin_set_dt(&led,0);
if (ret < 0) {
return 0;
}
}
return 0;
}
which did indeed toggle the output:
but this seems very slow. Wondering if this is just the fact that the CPU is really slow, tried with basic register pokes:
#include <stdio.h>
#include <zephyr/drivers/gpio.h>
#include <zephyr/kernel.h>
#define LED0_NODE DT_ALIAS(led0)
static const struct gpio_dt_spec led = GPIO_DT_SPEC_GET(LED0_NODE, gpios);
int main(void) {
int ret;
volatile uint32_t *gpio_set = (uint32_t *)(0x50000000 | 0x508);
volatile uint32_t *gpio_clr = (uint32_t *)(0x50000000 | 0x50c);
if (!gpio_is_ready_dt(&led)) {
return 0;
}
ret = gpio_pin_configure_dt(&led, GPIO_OUTPUT_ACTIVE);
if (ret < 0) {
return 0;
}
while (1) {
*gpio_set = (0x1 << 1);
*gpio_clr = (0x1 << 1);
}
return 0;
}
N.B. volatile
here is critical: this worked correctly and was much faster:
The timing here is consistent with Cortex M0: load and store are two cycles, branch is three because three stage pipeline. Adding some nop
s with __asm__("nop")
can pad this nicely to give 1MHz-ish output with 8 cycles high and low.
Noteworthy things:
cmake
and make
probably easier in the long gameI expect for less trivial use cases this is probably worthwhile e.g. making USB devices and such.