drivers: Add support for BBC micro:bit LED display

Adds a simple driver to access the 5x5 LED display found on BBC
micro:bit boards. The display is so limited that no effort is done to
try to integrate with the existing console (which would likely make
the display unusable). Instead, dedicated mb_display_* APIs are added
that are specific to this display.

References:

 https://www.microbit.co.uk/device/screen
 https://lancaster-university.github.io/microbit-docs/ubit/display/

Jira: ZEP-1990
Change-Id: I431b5b358b5f07592a60d3aed87eaab6ac20ce25
Signed-off-by: Johan Hedberg <johan.hedberg@intel.com>
This commit is contained in:
Johan Hedberg 2017-04-02 20:54:23 +03:00
commit 380d24de1d
17 changed files with 1068 additions and 0 deletions

View file

@ -71,4 +71,7 @@ source "drivers/dma/Kconfig"
source "drivers/usb/Kconfig"
source "drivers/crypto/Kconfig"
source "drivers/display/Kconfig"
endmenu

View file

@ -3,6 +3,7 @@ subdir-ccflags-y += -I$(srctree)/include/drivers
obj-y = console/
obj-y += random/
obj-y += serial/
obj-y += display/
obj-$(CONFIG_SYS_CLOCK_EXISTS) += timer/
obj-y += interrupt_controller/
obj-$(CONFIG_GROVE) += grove/

26
drivers/display/Kconfig Normal file
View file

@ -0,0 +1,26 @@
# Kconfig - Display drivers
#
# Copyright (c) 2017 Intel Corporation
#
# SPDX-License-Identifier: Apache-2.0
#
config MICROBIT_DISPLAY
bool "BBC micro:bit 5x5 LED Display support"
depends on BOARD_BBC_MICROBIT
depends on GPIO
help
Enable this to be able to display images and text on the 5x5
LED matrix display on the BBC micro:bit.
config MICROBIT_DISPLAY_PIN_GRANULARITY
bool "Access the GPIO on a per-pin instead of per-port basis"
depends on MICROBIT_DISPLAY
help
By default, the micro:bit display driver will update the GPIO
pins of the display (pins 4 through 15) by accessing the entire
GPIO port. This is done for efficiency, however it may interfere
with other peripherals connected to the same GPIO port. Select
this option if other peripherals are connected to the same GPIO
port.

1
drivers/display/Makefile Normal file
View file

@ -0,0 +1 @@
obj-$(CONFIG_MICROBIT_DISPLAY) += mb_display.o mb_font.o

View file

@ -0,0 +1,206 @@
/*
* Copyright (c) 2017 Intel Corporation
*
* SPDX-License-Identifier: Apache-2.0
*/
/*
* References:
*
* https://www.microbit.co.uk/device/screen
* https://lancaster-university.github.io/microbit-docs/ubit/display/
*/
#include <zephyr.h>
#include <init.h>
#include <board.h>
#include <gpio.h>
#include <device.h>
#include <display/mb_display.h>
#include "mb_font.h"
#define DISPLAY_ROWS 3
#define DISPLAY_COLS 9
struct mb_display {
struct device *dev; /* GPIO device */
struct k_timer timer; /* Rendering timer */
/* The following variables track the currently shown image */
int cur; /* Currently rendered row */
uint32_t row[3]; /* Content (columns) for each row */
int64_t expiry; /* When to stop showing the current image */
int32_t duration; /* Duration for each shown image */
const char *str; /* String to be shown */
};
struct x_y {
uint8_t x:4,
y:4;
};
/* Where the X,Y coordinates of each row/col are found.
* The top left corner has the coordinates 0,0.
*/
static const struct x_y map[DISPLAY_ROWS][DISPLAY_COLS] = {
{{0, 0}, {2, 0}, {4, 0}, {4, 3}, {3, 3}, {2, 3}, {1, 3}, {0, 3}, {1, 2} },
{{4, 2}, {0, 2}, {2, 2}, {1, 0}, {3, 0}, {3, 4}, {1, 4}, {0, 0}, {0, 0} },
{{2, 4}, {4, 4}, {0, 4}, {0, 1}, {1, 1}, {2, 1}, {3, 1}, {4, 1}, {3, 2} },
};
/* Mask of all the column bits */
static const uint32_t col_mask = (((~0UL) << LED_COL1_GPIO_PIN) &
((~0UL) >> (31 - LED_COL9_GPIO_PIN)));
#define GET_PIXEL(img, x, y) ((img)->row[y] & BIT(x))
/* Precalculate all three rows of an image */
static void set_img(struct mb_display *disp, const struct mb_image *img)
{
int row, col;
for (row = 0; row < DISPLAY_ROWS; row++) {
disp->row[row] = 0;
for (col = 0; col < DISPLAY_COLS; col++) {
if (GET_PIXEL(img, map[row][col].x, map[row][col].y)) {
disp->row[row] |= BIT(LED_COL1_GPIO_PIN + col);
}
}
disp->row[row] = ~disp->row[row] & col_mask;
disp->row[row] |= BIT(LED_ROW1_GPIO_PIN + row);
}
disp->cur = 0;
}
#define ROW_PIN(n) (LED_ROW1_GPIO_PIN + (n))
static inline void update_pins(struct mb_display *disp, uint32_t val)
{
if (IS_ENABLED(CONFIG_MICROBIT_DISPLAY_PIN_GRANULARITY)) {
uint32_t pin, prev = (disp->cur + 2) % 3;
/* Disable the previous row */
gpio_pin_write(disp->dev, ROW_PIN(prev), 0);
/* Set the column pins to their correct values */
for (pin = LED_COL1_GPIO_PIN; pin <= LED_COL9_GPIO_PIN; pin++) {
gpio_pin_write(disp->dev, pin, !!(val & BIT(pin)));
}
/* Enable the new row */
gpio_pin_write(disp->dev, ROW_PIN(disp->cur), 1);
} else {
gpio_port_write(disp->dev, val);
}
}
static void show_row(struct k_timer *timer)
{
struct mb_display *disp = CONTAINER_OF(timer, struct mb_display, timer);
update_pins(disp, disp->row[disp->cur]);
disp->cur = (disp->cur + 1) % DISPLAY_ROWS;
if (disp->cur == 0 && disp->expiry != K_FOREVER &&
k_uptime_get() > disp->expiry) {
k_timer_stop(&disp->timer);
if (disp->str && disp->str[0]) {
mb_display_char(disp, disp->str[0], disp->duration);
disp->str++;
}
}
}
static void clear_display(struct k_timer *timer)
{
struct mb_display *disp = CONTAINER_OF(timer, struct mb_display, timer);
update_pins(disp, col_mask);
}
static struct mb_display display = {
.timer = K_TIMER_INITIALIZER(display.timer, show_row, clear_display),
};
void mb_display_image(struct mb_display *disp, const struct mb_image *img,
int32_t duration)
{
set_img(disp, img);
if (duration == K_FOREVER) {
disp->expiry = K_FOREVER;
} else {
disp->expiry = k_uptime_get() + duration;
}
k_timer_start(&disp->timer, K_NO_WAIT, K_MSEC(5));
}
void mb_display_stop(struct mb_display *disp)
{
k_timer_stop(&disp->timer);
disp->str = NULL;
}
void mb_display_char(struct mb_display *disp, char chr, int32_t duration)
{
if (chr < MB_FONT_START || chr > MB_FONT_END) {
chr = ' ';
}
mb_display_image(disp, &mb_font[chr - MB_FONT_START], duration);
}
void mb_display_str(struct mb_display *disp, const char *str, int32_t duration)
{
__ASSERT(str, "NULL string");
if (*str == '\0') {
return;
}
disp->str = &str[1];
disp->duration = duration;
mb_display_char(disp, *str, duration);
}
struct mb_display *mb_display_get(void)
{
return &display;
}
static int mb_display_init(struct device *dev)
{
ARG_UNUSED(dev);
display.dev = device_get_binding(CONFIG_GPIO_NRF5_P0_DEV_NAME);
__ASSERT(dev, "No GPIO device found");
gpio_pin_configure(display.dev, LED_ROW1_GPIO_PIN, GPIO_DIR_OUT);
gpio_pin_configure(display.dev, LED_ROW2_GPIO_PIN, GPIO_DIR_OUT);
gpio_pin_configure(display.dev, LED_ROW3_GPIO_PIN, GPIO_DIR_OUT);
gpio_pin_configure(display.dev, LED_COL1_GPIO_PIN, GPIO_DIR_OUT);
gpio_pin_configure(display.dev, LED_COL2_GPIO_PIN, GPIO_DIR_OUT);
gpio_pin_configure(display.dev, LED_COL3_GPIO_PIN, GPIO_DIR_OUT);
gpio_pin_configure(display.dev, LED_COL4_GPIO_PIN, GPIO_DIR_OUT);
gpio_pin_configure(display.dev, LED_COL5_GPIO_PIN, GPIO_DIR_OUT);
gpio_pin_configure(display.dev, LED_COL6_GPIO_PIN, GPIO_DIR_OUT);
gpio_pin_configure(display.dev, LED_COL7_GPIO_PIN, GPIO_DIR_OUT);
gpio_pin_configure(display.dev, LED_COL8_GPIO_PIN, GPIO_DIR_OUT);
gpio_pin_configure(display.dev, LED_COL9_GPIO_PIN, GPIO_DIR_OUT);
return 0;
}
SYS_INIT(mb_display_init, POST_KERNEL, CONFIG_KERNEL_INIT_PRIORITY_DEVICE);

582
drivers/display/mb_font.c Normal file
View file

@ -0,0 +1,582 @@
/*
* Copyright (c) 2017 Intel Corporation
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <display/mb_display.h>
#include "mb_font.h"
const struct mb_image mb_font[MB_FONT_COUNT] = {
/* ' ' */
MB_IMAGE({ 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0 }),
/* '!' */
MB_IMAGE({ 0, 1, 0, 0, 0 },
{ 0, 1, 0, 0, 0 },
{ 0, 1, 0, 0, 0 },
{ 0, 0, 0, 0, 0 },
{ 0, 1, 0, 0, 0 }),
/* '"' */
MB_IMAGE({ 0, 1, 0, 1, 0 },
{ 0, 1, 0, 1, 0 },
{ 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0 }),
/* '#' */
MB_IMAGE({ 0, 1, 0, 1, 0 },
{ 1, 1, 1, 1, 1 },
{ 0, 1, 0, 1, 0 },
{ 1, 1, 1, 1, 1 },
{ 0, 1, 0, 1, 0 }),
/* '$' */
MB_IMAGE({ 0, 1, 1, 1, 0 },
{ 1, 1, 0, 0, 1 },
{ 0, 1, 1, 1, 0 },
{ 1, 0, 0, 1, 1 },
{ 0, 1, 1, 1, 0 }),
/* '%' */
MB_IMAGE({ 1, 1, 0, 0, 1 },
{ 1, 0, 0, 1, 0 },
{ 0, 0, 1, 0, 0 },
{ 0, 1, 0, 0, 1 },
{ 1, 0, 0, 1, 1 }),
/* '&' */
MB_IMAGE({ 0, 1, 1, 0, 0 },
{ 1, 0, 0, 1, 0 },
{ 0, 1, 1, 0, 0 },
{ 1, 0, 0, 1, 0 },
{ 0, 1, 1, 0, 1 }),
/* ''' */
MB_IMAGE({ 0, 1, 0, 0, 0 },
{ 0, 1, 0, 0, 0 },
{ 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0 }),
/* '(' */
MB_IMAGE({ 0, 0, 1, 0, 0 },
{ 0, 1, 0, 0, 0 },
{ 0, 1, 0, 0, 0 },
{ 0, 1, 0, 0, 0 },
{ 0, 0, 1, 0, 0 }),
/* ')' */
MB_IMAGE({ 0, 1, 0, 0, 0 },
{ 0, 0, 1, 0, 0 },
{ 0, 0, 1, 0, 0 },
{ 0, 0, 1, 0, 0 },
{ 0, 1, 0, 0, 0 }),
/* '*' */
MB_IMAGE({ 0, 0, 0, 0, 0 },
{ 0, 1, 0, 1, 0 },
{ 0, 0, 1, 0, 0 },
{ 0, 1, 0, 1, 0 },
{ 0, 0, 0, 0, 0 }),
/* '+' */
MB_IMAGE({ 0, 0, 0, 0, 0 },
{ 0, 0, 1, 0, 0 },
{ 0, 1, 1, 1, 0 },
{ 0, 0, 1, 0, 0 },
{ 0, 0, 0, 0, 0 }),
/* ',' */
MB_IMAGE({ 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0 },
{ 0, 0, 1, 0, 0 },
{ 0, 1, 0, 0, 0 }),
/* '-' */
MB_IMAGE({ 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0 },
{ 0, 1, 1, 1, 0 },
{ 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0 }),
/* '.' */
MB_IMAGE({ 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0 },
{ 0, 1, 0, 0, 0 },
{ 0, 0, 0, 0, 0 }),
/* '/' */
MB_IMAGE({ 0, 0, 0, 0, 1 },
{ 0, 0, 0, 1, 0 },
{ 0, 0, 1, 0, 0 },
{ 0, 1, 0, 0, 0 },
{ 1, 0, 0, 0, 0 }),
/* '0' */
MB_IMAGE({ 0, 1, 1, 0, 0 },
{ 1, 0, 0, 1, 0 },
{ 1, 0, 0, 1, 0 },
{ 1, 0, 0, 1, 0 },
{ 0, 1, 1, 0, 0 }),
/* '1' */
MB_IMAGE({ 0, 0, 1, 0, 0 },
{ 0, 1, 1, 0, 0 },
{ 0, 0, 1, 0, 0 },
{ 0, 0, 1, 0, 0 },
{ 0, 1, 1, 1, 0 }),
/* '2' */
MB_IMAGE({ 1, 1, 1, 0, 0 },
{ 0, 0, 0, 1, 0 },
{ 0, 1, 1, 0, 0 },
{ 1, 0, 0, 0, 0 },
{ 1, 1, 1, 1, 0 }),
/* '3' */
MB_IMAGE({ 1, 1, 1, 1, 0 },
{ 0, 0, 0, 1, 0 },
{ 0, 0, 1, 0, 0 },
{ 1, 0, 0, 1, 0 },
{ 0, 1, 1, 0, 0 }),
/* '4' */
MB_IMAGE({ 0, 0, 1, 1, 0 },
{ 0, 1, 0, 1, 0 },
{ 1, 0, 0, 1, 0 },
{ 1, 1, 1, 1, 1 },
{ 0, 0, 0, 1, 0 }),
/* '5' */
MB_IMAGE({ 1, 1, 1, 1, 1 },
{ 1, 0, 0, 0, 0 },
{ 1, 1, 1, 1, 0 },
{ 0, 0, 0, 0, 1 },
{ 1, 1, 1, 1, 0 }),
/* '6' */
MB_IMAGE({ 0, 0, 0, 1, 0 },
{ 0, 0, 1, 0, 0 },
{ 0, 1, 1, 1, 0 },
{ 1, 0, 0, 0, 1 },
{ 0, 1, 1, 1, 0 }),
/* '7' */
MB_IMAGE({ 1, 1, 1, 1, 1 },
{ 0, 0, 0, 1, 0 },
{ 0, 0, 1, 0, 0 },
{ 0, 1, 0, 0, 0 },
{ 1, 0, 0, 0, 0 }),
/* '8' */
MB_IMAGE({ 0, 1, 1, 1, 0 },
{ 1, 0, 0, 0, 1 },
{ 0, 1, 1, 1, 0 },
{ 1, 0, 0, 0, 1 },
{ 0, 1, 1, 1, 0 }),
/* '9' */
MB_IMAGE({ 0, 1, 1, 1, 0 },
{ 1, 0, 0, 0, 1 },
{ 0, 1, 1, 1, 0 },
{ 0, 0, 1, 0, 0 },
{ 0, 1, 0, 0, 0 }),
/* ':' */
MB_IMAGE({ 0, 0, 0, 0, 0 },
{ 0, 1, 0, 0, 0 },
{ 0, 0, 0, 0, 0 },
{ 0, 1, 0, 0, 0 },
{ 0, 0, 0, 0, 0 }),
/* ';' */
MB_IMAGE({ 0, 0, 0, 0, 0 },
{ 0, 0, 1, 0, 0 },
{ 0, 0, 0, 0, 0 },
{ 0, 0, 1, 0, 0 },
{ 0, 1, 0, 0, 0 }),
/* '<' */
MB_IMAGE({ 0, 0, 0, 1, 0 },
{ 0, 0, 1, 0, 0 },
{ 0, 1, 0, 0, 0 },
{ 0, 0, 1, 0, 0 },
{ 0, 0, 0, 1, 0 }),
/* '=' */
MB_IMAGE({ 0, 0, 0, 0, 0 },
{ 0, 1, 1, 1, 0 },
{ 0, 0, 0, 0, 0 },
{ 0, 1, 1, 1, 0 },
{ 0, 0, 0, 0, 0 }),
/* '>' */
MB_IMAGE({ 0, 1, 0, 0, 0 },
{ 0, 0, 1, 0, 0 },
{ 0, 0, 0, 1, 0 },
{ 0, 0, 1, 0, 0 },
{ 0, 1, 0, 0, 0 }),
/* '?' */
MB_IMAGE({ 0, 1, 1, 1, 0 },
{ 1, 0, 0, 0, 1 },
{ 0, 0, 1, 1, 0 },
{ 0, 0, 0, 0, 0 },
{ 0, 0, 1, 0, 0 }),
/* '@' */
MB_IMAGE({ 0, 1, 1, 1, 0 },
{ 1, 0, 0, 0, 1 },
{ 1, 0, 1, 0, 1 },
{ 1, 0, 0, 1, 1 },
{ 0, 1, 1, 0, 0 }),
/* 'A' */
MB_IMAGE({ 0, 1, 1, 0, 0 },
{ 1, 0, 0, 1, 0 },
{ 1, 1, 1, 1, 0 },
{ 1, 0, 0, 1, 0 },
{ 1, 0, 0, 1, 0 }),
/* 'B' */
MB_IMAGE({ 1, 1, 1, 0, 0 },
{ 1, 0, 0, 1, 0 },
{ 1, 1, 1, 0, 0 },
{ 1, 0, 0, 1, 0 },
{ 1, 1, 1, 0, 0 }),
/* 'C' */
MB_IMAGE({ 0, 1, 1, 1, 0 },
{ 1, 0, 0, 0, 0 },
{ 1, 0, 0, 0, 0 },
{ 1, 0, 0, 0, 0 },
{ 0, 1, 1, 1, 0 }),
/* 'D' */
MB_IMAGE({ 1, 1, 1, 0, 0 },
{ 1, 0, 0, 1, 0 },
{ 1, 0, 0, 1, 0 },
{ 1, 0, 0, 1, 0 },
{ 1, 1, 1, 0, 0 }),
/* 'E' */
MB_IMAGE({ 1, 1, 1, 1, 0 },
{ 1, 0, 0, 0, 0 },
{ 1, 1, 1, 0, 0 },
{ 1, 0, 0, 0, 0 },
{ 1, 1, 1, 1, 0 }),
/* 'F' */
MB_IMAGE({ 1, 1, 1, 1, 0 },
{ 1, 0, 0, 0, 0 },
{ 1, 1, 1, 0, 0 },
{ 1, 0, 0, 0, 0 },
{ 1, 0, 0, 0, 0 }),
/* 'G' */
MB_IMAGE({ 0, 1, 1, 1, 0 },
{ 1, 0, 0, 0, 0 },
{ 1, 0, 0, 1, 1 },
{ 1, 0, 0, 0, 1 },
{ 0, 1, 1, 1, 0 }),
/* 'H' */
MB_IMAGE({ 1, 0, 0, 1, 0 },
{ 1, 0, 0, 1, 0 },
{ 1, 1, 1, 1, 0 },
{ 1, 0, 0, 1, 0 },
{ 1, 0, 0, 1, 0 }),
/* 'I' */
MB_IMAGE({ 1, 1, 1, 0, 0 },
{ 0, 1, 0, 0, 0 },
{ 0, 1, 0, 0, 0 },
{ 0, 1, 0, 0, 0 },
{ 1, 1, 1, 0, 0 }),
/* 'J' */
MB_IMAGE({ 1, 1, 1, 1, 1 },
{ 0, 0, 0, 1, 0 },
{ 0, 0, 0, 1, 0 },
{ 1, 0, 0, 1, 0 },
{ 0, 1, 1, 0, 0 }),
/* 'K' */
MB_IMAGE({ 1, 0, 0, 1, 0 },
{ 1, 0, 1, 0, 0 },
{ 1, 1, 0, 0, 0 },
{ 1, 0, 1, 0, 0 },
{ 1, 0, 0, 1, 0 }),
/* 'L' */
MB_IMAGE({ 1, 0, 0, 0, 0 },
{ 1, 0, 0, 0, 0 },
{ 1, 0, 0, 0, 0 },
{ 1, 0, 0, 0, 0 },
{ 1, 1, 1, 1, 0 }),
/* 'M' */
MB_IMAGE({ 1, 0, 0, 0, 1 },
{ 1, 1, 0, 1, 1 },
{ 1, 0, 1, 0, 1 },
{ 1, 0, 0, 0, 1 },
{ 1, 0, 0, 0, 1 }),
/* 'N' */
MB_IMAGE({ 1, 0, 0, 0, 1 },
{ 1, 1, 0, 0, 1 },
{ 1, 0, 1, 0, 1 },
{ 1, 0, 0, 1, 1 },
{ 1, 0, 0, 0, 1 }),
/* 'O' */
MB_IMAGE({ 0, 1, 1, 0, 0 },
{ 1, 0, 0, 1, 0 },
{ 1, 0, 0, 1, 0 },
{ 1, 0, 0, 1, 0 },
{ 0, 1, 1, 0, 0 }),
/* 'P' */
MB_IMAGE({ 1, 1, 1, 0, 0 },
{ 1, 0, 0, 1, 0 },
{ 1, 1, 1, 0, 0 },
{ 1, 0, 0, 0, 0 },
{ 1, 0, 0, 0, 0 }),
/* 'Q' */
MB_IMAGE({ 0, 1, 1, 0, 0 },
{ 1, 0, 0, 1, 0 },
{ 1, 0, 0, 1, 0 },
{ 0, 1, 1, 0, 0 },
{ 0, 0, 1, 1, 0 }),
/* 'R' */
MB_IMAGE({ 1, 1, 1, 0, 0 },
{ 1, 0, 0, 1, 0 },
{ 1, 1, 1, 0, 0 },
{ 1, 0, 0, 1, 0 },
{ 1, 0, 0, 0, 1 }),
/* 'S' */
MB_IMAGE({ 0, 1, 1, 1, 0 },
{ 1, 0, 0, 0, 0 },
{ 0, 1, 1, 0, 0 },
{ 0, 0, 0, 1, 0 },
{ 1, 1, 1, 0, 0 }),
/* 'T' */
MB_IMAGE({ 1, 1, 1, 1, 1 },
{ 0, 0, 1, 0, 0 },
{ 0, 0, 1, 0, 0 },
{ 0, 0, 1, 0, 0 },
{ 0, 0, 1, 0, 0 }),
/* 'U' */
MB_IMAGE({ 1, 0, 0, 1, 0 },
{ 1, 0, 0, 1, 0 },
{ 1, 0, 0, 1, 0 },
{ 1, 0, 0, 1, 0 },
{ 0, 1, 1, 0, 0 }),
/* 'V' */
MB_IMAGE({ 1, 0, 0, 0, 1 },
{ 1, 0, 0, 0, 1 },
{ 1, 0, 0, 0, 1 },
{ 0, 1, 0, 1, 0 },
{ 0, 0, 1, 0, 0 }),
/* 'W' */
MB_IMAGE({ 1, 0, 0, 0, 1 },
{ 1, 0, 0, 0, 1 },
{ 1, 0, 1, 0, 1 },
{ 1, 1, 0, 1, 1 },
{ 1, 0, 0, 0, 1 }),
/* 'X' */
MB_IMAGE({ 1, 0, 0, 1, 0 },
{ 1, 0, 0, 1, 0 },
{ 0, 1, 1, 0, 0 },
{ 1, 0, 0, 1, 0 },
{ 1, 0, 0, 1, 0 }),
/* 'Y' */
MB_IMAGE({ 1, 0, 0, 0, 1 },
{ 0, 1, 0, 1, 0 },
{ 0, 0, 1, 0, 0 },
{ 0, 0, 1, 0, 0 },
{ 0, 0, 1, 0, 0 }),
/* 'Z' */
MB_IMAGE({ 1, 1, 1, 1, 0 },
{ 0, 0, 1, 0, 0 },
{ 0, 1, 0, 0, 0 },
{ 1, 0, 0, 0, 0 },
{ 1, 1, 1, 1, 0 }),
/* '[' */
MB_IMAGE({ 0, 1, 1, 1, 0 },
{ 0, 1, 0, 0, 0 },
{ 0, 1, 0, 0, 0 },
{ 0, 1, 0, 0, 0 },
{ 0, 1, 1, 1, 0 }),
/* '\' */
MB_IMAGE({ 1, 0, 0, 0, 0 },
{ 0, 1, 0, 0, 0 },
{ 0, 0, 1, 0, 0 },
{ 0, 0, 0, 1, 0 },
{ 0, 0, 0, 0, 1 }),
/* ']' */
MB_IMAGE({ 0, 1, 1, 1, 0 },
{ 0, 0, 0, 1, 0 },
{ 0, 0, 0, 1, 0 },
{ 0, 0, 0, 1, 0 },
{ 0, 1, 1, 1, 0 }),
/* '^' */
MB_IMAGE({ 0, 0, 1, 0, 0 },
{ 0, 1, 0, 1, 0 },
{ 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0 }),
/* '_' */
MB_IMAGE({ 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0 },
{ 1, 1, 1, 1, 1 }),
/* '`' */
MB_IMAGE({ 0, 1, 0, 0, 0 },
{ 0, 0, 1, 0, 0 },
{ 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0 }),
/* 'a' */
MB_IMAGE({ 0, 0, 0, 0, 0 },
{ 0, 1, 1, 1, 0 },
{ 1, 0, 0, 1, 0 },
{ 1, 0, 0, 1, 0 },
{ 0, 1, 1, 1, 1 }),
/* 'b' */
MB_IMAGE({ 1, 0, 0, 0, 0 },
{ 1, 0, 0, 0, 0 },
{ 1, 1, 1, 0, 0 },
{ 1, 0, 0, 1, 0 },
{ 1, 1, 1, 0, 0 }),
/* 'c' */
MB_IMAGE({ 0, 0, 0, 0, 0 },
{ 0, 1, 1, 1, 0 },
{ 1, 0, 0, 0, 0 },
{ 1, 0, 0, 0, 0 },
{ 0, 1, 1, 1, 0 }),
/* 'd' */
MB_IMAGE({ 0, 0, 0, 1, 0 },
{ 0, 0, 0, 1, 0 },
{ 0, 1, 1, 1, 0 },
{ 1, 0, 0, 1, 0 },
{ 0, 1, 1, 1, 0 }),
/* 'e' */
MB_IMAGE({ 0, 1, 1, 0, 0 },
{ 1, 0, 0, 1, 0 },
{ 1, 1, 1, 0, 0 },
{ 1, 0, 0, 0, 0 },
{ 0, 1, 1, 1, 0 }),
/* 'f' */
MB_IMAGE({ 0, 0, 1, 1, 0 },
{ 0, 1, 0, 0, 0 },
{ 1, 1, 1, 0, 0 },
{ 0, 1, 0, 0, 0 },
{ 0, 1, 0, 0, 0 }),
/* 'g' */
MB_IMAGE({ 0, 1, 1, 1, 0 },
{ 1, 0, 0, 1, 0 },
{ 0, 1, 1, 1, 0 },
{ 0, 0, 0, 1, 0 },
{ 0, 1, 1, 0, 0 }),
/* 'h' */
MB_IMAGE({ 1, 0, 0, 0, 0 },
{ 1, 0, 0, 0, 0 },
{ 1, 1, 1, 0, 0 },
{ 1, 0, 0, 1, 0 },
{ 1, 0, 0, 1, 0 }),
/* 'i' */
MB_IMAGE({ 0, 1, 0, 0, 0 },
{ 0, 0, 0, 0, 0 },
{ 0, 1, 0, 0, 0 },
{ 0, 1, 0, 0, 0 },
{ 0, 1, 0, 0, 0 }),
/* 'j' */
MB_IMAGE({ 0, 0, 0, 1, 0 },
{ 0, 0, 0, 0, 0 },
{ 0, 0, 0, 1, 0 },
{ 0, 0, 0, 1, 0 },
{ 0, 1, 1, 0, 0 }),
/* 'k' */
MB_IMAGE({ 1, 0, 0, 0, 0 },
{ 1, 0, 1, 0, 0 },
{ 1, 1, 0, 0, 0 },
{ 1, 0, 1, 0, 0 },
{ 1, 0, 0, 1, 0 }),
/* 'l' */
MB_IMAGE({ 0, 1, 0, 0, 0 },
{ 0, 1, 0, 0, 0 },
{ 0, 1, 0, 0, 0 },
{ 0, 1, 0, 0, 0 },
{ 0, 0, 1, 1, 0 }),
/* 'm' */
MB_IMAGE({ 0, 0, 0, 0, 0 },
{ 1, 1, 0, 1, 1 },
{ 1, 0, 1, 0, 1 },
{ 1, 0, 0, 0, 1 },
{ 1, 0, 0, 0, 1 }),
/* 'n' */
MB_IMAGE({ 0, 0, 0, 0, 0 },
{ 1, 1, 1, 0, 0 },
{ 1, 0, 0, 1, 0 },
{ 1, 0, 0, 1, 0 },
{ 1, 0, 0, 1, 0 }),
/* 'o' */
MB_IMAGE({ 0, 0, 0, 0, 0 },
{ 0, 1, 1, 0, 0 },
{ 1, 0, 0, 1, 0 },
{ 1, 0, 0, 1, 0 },
{ 0, 1, 1, 0, 0 }),
/* 'p' */
MB_IMAGE({ 0, 0, 0, 0, 0 },
{ 1, 1, 1, 0, 0 },
{ 1, 0, 0, 1, 0 },
{ 1, 1, 1, 0, 0 },
{ 1, 0, 0, 0, 0 }),
/* 'q' */
MB_IMAGE({ 0, 0, 0, 0, 0 },
{ 0, 1, 1, 1, 0 },
{ 1, 0, 0, 1, 0 },
{ 0, 1, 1, 1, 0 },
{ 0, 0, 0, 1, 0 }),
/* 'r' */
MB_IMAGE({ 0, 0, 0, 0, 0 },
{ 0, 1, 1, 1, 0 },
{ 1, 0, 0, 0, 0 },
{ 1, 0, 0, 0, 0 },
{ 1, 0, 0, 0, 0 }),
/* 's' */
MB_IMAGE({ 0, 0, 0, 0, 0 },
{ 0, 0, 1, 1, 0 },
{ 0, 1, 0, 0, 0 },
{ 0, 0, 1, 0, 0 },
{ 1, 1, 0, 0, 0 }),
/* 't' */
MB_IMAGE({ 0, 1, 0, 0, 0 },
{ 0, 1, 0, 0, 0 },
{ 0, 1, 1, 1, 0 },
{ 0, 1, 0, 0, 0 },
{ 0, 0, 1, 1, 1 }),
/* 'u' */
MB_IMAGE({ 0, 0, 0, 0, 0 },
{ 1, 0, 0, 1, 0 },
{ 1, 0, 0, 1, 0 },
{ 1, 0, 0, 1, 0 },
{ 0, 1, 1, 1, 1 }),
/* 'v' */
MB_IMAGE({ 0, 0, 0, 0, 0 },
{ 1, 0, 0, 0, 1 },
{ 1, 0, 0, 0, 1 },
{ 0, 1, 0, 1, 0 },
{ 0, 0, 1, 0, 0 }),
/* 'w' */
MB_IMAGE({ 0, 0, 0, 0, 0 },
{ 1, 0, 0, 0, 1 },
{ 1, 0, 0, 0, 1 },
{ 1, 0, 1, 0, 1 },
{ 1, 1, 0, 1, 1 }),
/* 'x' */
MB_IMAGE({ 0, 0, 0, 0, 0 },
{ 1, 0, 0, 1, 0 },
{ 0, 1, 1, 0, 0 },
{ 0, 1, 1, 0, 0 },
{ 1, 0, 0, 1, 0 }),
/* 'y' */
MB_IMAGE({ 0, 0, 0, 0, 0 },
{ 1, 0, 0, 0, 1 },
{ 0, 1, 0, 1, 0 },
{ 0, 0, 1, 0, 0 },
{ 1, 1, 0, 0, 0 }),
/* 'z' */
MB_IMAGE({ 0, 0, 0, 0, 0 },
{ 1, 1, 1, 1, 0 },
{ 0, 0, 1, 0, 0 },
{ 0, 1, 0, 0, 0 },
{ 1, 1, 1, 1, 0 }),
/* '{' */
MB_IMAGE({ 0, 0, 1, 1, 0 },
{ 0, 0, 1, 0, 0 },
{ 0, 1, 1, 0, 0 },
{ 0, 0, 1, 0, 0 },
{ 0, 0, 1, 1, 0 }),
/* '|' */
MB_IMAGE({ 0, 1, 0, 0, 0 },
{ 0, 1, 0, 0, 0 },
{ 0, 1, 0, 0, 0 },
{ 0, 1, 0, 0, 0 },
{ 0, 1, 0, 0, 0 }),
/* '}' */
MB_IMAGE({ 1, 1, 0, 0, 0 },
{ 0, 1, 0, 0, 0 },
{ 0, 1, 1, 0, 0 },
{ 0, 1, 0, 0, 0 },
{ 1, 1, 0, 0, 0 }),
/* '~' */
MB_IMAGE({ 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0 },
{ 0, 1, 1, 0, 0 },
{ 0, 0, 0, 1, 1 },
{ 0, 0, 0, 0, 0 }),
};

11
drivers/display/mb_font.h Normal file
View file

@ -0,0 +1,11 @@
/*
* Copyright (c) 2017 Intel Corporation
*
* SPDX-License-Identifier: Apache-2.0
*/
#define MB_FONT_COUNT 95
#define MB_FONT_START ' '
#define MB_FONT_END '~'
extern const struct mb_image mb_font[MB_FONT_COUNT];

View file

@ -0,0 +1,134 @@
/** @file
* @brief BBC micro:bit display APIs.
*/
/*
* Copyright (c) 2017 Intel Corporation
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef __MB_DISPLAY_H
#define __MB_DISPLAY_H
/**
* @brief BBC micro:bit display APIs
* @defgroup mb_display BBC micro:bit display APIs
* @{
*/
#include <stdint.h>
#include <misc/util.h>
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief Representation of a BBC micro:bit display image.
*
* This struct should normally not be used directly, rather created
* using the MB_IMAGE() macro.
*/
struct mb_image {
union {
struct {
uint8_t c1:1,
c2:1,
c3:1,
c4:1,
c5:1;
} r[5];
uint8_t row[5];
};
};
/**
* @def MB_IMAGE
* @brief Generate an image object from a given array rows/columns.
*
* This helper takes an array of 5 rows, each consisting of 5 0/1 values which
* correspond to the columns of that row. The value 0 means the pixel is
* disabled whereas a 1 means the pixel is enabled.
*
* The pixels go from left to right and top to bottom, i.e. top-left corner
* is the first row's first value, top-right is the first rows last value,
* and bottom-right corner is the last value of the last (5th) row. As an
* example, the following would create a smiley face image:
*
* <pre>
* static const struct mb_image smiley = MB_IMAGE({ 0, 1, 0, 1, 0 },
* { 0, 1, 0, 1, 0 },
* { 0, 0, 0, 0, 0 },
* { 1, 0, 0, 0, 1 },
* { 0, 1, 1, 1, 0 });
* </pre>
*
* @param _rows Each of the 5 rows represented as a 5-value column array.
*
* @return Image bitmap that can be passed e.g. to mb_display_image().
*/
#define MB_IMAGE(_rows...) { .r = { _rows } }
/**
* @brief Opaque struct representing the BBC micro:bit display.
*
* For more information see the following links:
*
* https://www.microbit.co.uk/device/screen
*
* https://lancaster-university.github.io/microbit-docs/ubit/display/
*/
struct mb_display;
/**
* @brief Get a pointer to the BBC micro:bit display object.
*
* @return Pointer to display object.
*/
struct mb_display *mb_display_get(void);
/**
* @brief Display an image on the BBC micro:bit LED display.
*
* @param disp Display object.
* @param img Bitmap of pixels.
* @param duration Duration how long to show the image (in milliseconds).
*/
void mb_display_image(struct mb_display *disp, const struct mb_image *img,
int32_t duration);
/**
* @brief Display a character on the BBC micro:bit LED display.
*
* @param disp Display object.
* @param chr Character to display.
* @param duration Duration how long to show the character (in milliseconds).
*/
void mb_display_char(struct mb_display *disp, char chr, int32_t duration);
/**
* @brief Display a string of characters on the BBC micro:bit LED display.
*
* @param disp Display object.
* @param str String to display.
* @param duration Duration how long to show each character (in milliseconds).
*/
void mb_display_str(struct mb_display *disp, const char *str, int32_t duration);
/**
* @brief Stop the ongoing display of an image.
*
* @param disp Display object.
*/
void mb_display_stop(struct mb_display *disp);
#ifdef __cplusplus
}
#endif
/**
* @}
*/
#endif /* __MB_DISPLAY_H */

View file

@ -0,0 +1,8 @@
Board-specific samples
######################
.. toctree::
:maxdepth: 1
:glob:
*/*

View file

@ -0,0 +1,4 @@
BOARD ?= bbc_microbit
CONF_FILE = prj.conf
include ${ZEPHYR_BASE}/Makefile.test

View file

@ -0,0 +1,27 @@
.. _microbit_display:
BBC micro:bit display
#####################
Overview
********
A simple example that demonstrates how to use the 5x5 LED matrix display
on the BBC micro:bit board.
Building
********
This project outputs various things on the BBC micro:bit display. It can
be built as follows:
.. code-block:: console
$ cd samples/boards/microbit/display
$ make
Sample Output
=============
The sample app displays a countdown of the characters 9-0, iterates
through all pixels one-by-one, displays a smiley face, displays the text
"Zephyr!", and then stops.

View file

@ -0,0 +1,4 @@
# nothing here
CONFIG_GPIO=y
CONFIG_MICROBIT_DISPLAY=y
#CONFIG_MICROBIT_DISPLAY_PIN_GRANULARITY=y

View file

@ -0,0 +1 @@
obj-y = main.o

View file

@ -0,0 +1,47 @@
/*
* Copyright (c) 2017 Intel Corporation
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <zephyr.h>
#include <misc/printk.h>
#include <board.h>
#include <gpio.h>
#include <device.h>
#include <display/mb_display.h>
static struct mb_image smiley = MB_IMAGE({ 0, 1, 0, 1, 0 },
{ 0, 1, 0, 1, 0 },
{ 0, 0, 0, 0, 0 },
{ 1, 0, 0, 0, 1 },
{ 0, 1, 1, 1, 0 });
void main(void)
{
struct mb_display *disp = mb_display_get();
int x, y;
/* Display countdown from '9' to '0' */
mb_display_str(disp, "9876543210", K_SECONDS(1));
k_sleep(K_SECONDS(11));
/* Iterate through all pixels one-by-one */
for (y = 0; y < 5; y++) {
for (x = 0; x < 5; x++) {
struct mb_image pixel = {};
pixel.row[y] = BIT(x);
mb_display_image(disp, &pixel, K_MSEC(250));
k_sleep(K_MSEC(300));
}
}
/* Show a smiley-face */
mb_display_image(disp, &smiley, K_SECONDS(2));
k_sleep(K_SECONDS(2));
/* Show some text ("Zephyr!") */
mb_display_str(disp, "Zephyr!", K_SECONDS(1));
}

View file

@ -0,0 +1,4 @@
[test]
build_only = true
tags = samples
platform_whitelist = bbc_microbit

View file

@ -0,0 +1,8 @@
BBC micro:bit Samples
#####################
.. toctree::
:maxdepth: 1
:glob:
**/*

View file

@ -15,6 +15,7 @@ Samples and Demos
grove/*
advanced
power/power.rst
boards/*