diff --git a/pkg/ucglib/Makefile b/pkg/ucglib/Makefile new file mode 100644 index 0000000000..d6f76fe3cf --- /dev/null +++ b/pkg/ucglib/Makefile @@ -0,0 +1,15 @@ +PKG_NAME=ucglib +PKG_URL=https://github.com/olikraus/ucglib +PKG_VERSION=bf48515702dd7c87cbacdd17989738f33f003df2 +PKG_LICENSE=BSD-2-Clause + +.PHONY: all + +all: git-download + cp $(RIOTBASE)/pkg/ucglib/src/Makefile $(PKG_BUILDDIR)/Makefile + cp $(RIOTBASE)/pkg/ucglib/src/csrc/Makefile $(PKG_BUILDDIR)/csrc/Makefile + cp $(RIOTBASE)/pkg/ucglib/src/csrc/ucg_riotos.c $(PKG_BUILDDIR)/csrc/ucg_riotos.c + cp $(RIOTBASE)/pkg/ucglib/src/sys/sdl/dev/Makefile $(PKG_BUILDDIR)/sys/sdl/dev/Makefile + "$(MAKE)" -C $(PKG_BUILDDIR) + +include $(RIOTBASE)/pkg/pkg.mk diff --git a/pkg/ucglib/Makefile.include b/pkg/ucglib/Makefile.include new file mode 100644 index 0000000000..d6afc52d69 --- /dev/null +++ b/pkg/ucglib/Makefile.include @@ -0,0 +1,6 @@ +INCLUDES += -I$(PKGDIRBASE)/ucglib/csrc + +# Link SDL if enabled. +ifneq (,$(filter ucglib_sdl,$(USEMODULE))) + LINKFLAGS += `sdl2-config --libs` +endif diff --git a/pkg/ucglib/README.md b/pkg/ucglib/README.md new file mode 100644 index 0000000000..263ec40ff2 --- /dev/null +++ b/pkg/ucglib/README.md @@ -0,0 +1,57 @@ +# Ucglib + +## Introduction +[Ucglib](https://github.com/olikraus/ucglib) is a color graphics library for LCDs and OLEDs. It contains both drivers and high-level drawing routines. + +The library is originally written for Arduino boards, but it runs just fine on other platforms, as long as the right drivers are available. + +## Usage +Just put `USEPKG += ucglib` in your Makefile and `#include "ucg.h"` to your code. Refer to the [Ucglib wiki](https://github.com/olikraus/ucglib/wiki) for more information on the API. + +## RIOT-OS interface +This package patches the original source to add an interface for RIOT-OS. + +Only the callback for SPI peripherals is supported: + +* `ucg_com_riotos_hw_spi` + +Ucglib needs to map pin numbers to RIOT-OS pin numbers. It also needs to know which peripheral to use. The following two methods can be used to set this information. + +* `ucg_SetPins(ucg_dev, pins, bitmap)` +* `ucg_SetDevice(ucg_dev, dev)` + +Note: `pins` should point to `gpio_t` array of Ucglib pin numbers to RIOT-OS pins. Due to this, `pins` can take up an additional 100 bytes, because it will use memory for the pins you do not map. You can overcome this limitation by implementing `ucg_com_riotos_hw_spi` yourself and hardcode the pins. + +### Example +``` +ucg_t ucg; + +gpio_t pins[] = { + [UCG_PIN_CS] = GPIO(PA, 0), + [UCG_PIN_CD] = GPIO(PA, 1), + [UCG_PIN_RESET] = GPIO(PA, 2) +}; + +uint32_t bitmap = ( + (1 << UCG_PIN_CS) + + (1 << UCG_PIN_CD) + + (1 << UCG_PIN_RESET) +); + +ucg_SetPins(&ucg, pins, bitmap); +ucg_SetDevice(&ucg, SPI_DEV(0)); + +ucg_Init(&ucg, ucg_dev_ssd1331_18x96x64_univision, ucg_ext_ssd1331_18, ucg_com_riotos_hw_spi); +``` + +## Virtual displays +For targets without an I2C or SPI, a virtual display is available. Support for a virtual display is not compiled in by default. + +* By adding `USEMODULE += ucglib_sdl`, a SDL virtual display will be used. This is only available on native targets that have SDL2 installed. It uses `sdl2-config` to find the headers and libraries. Note that RIOT-OS builds 32-bit binaries and requires 32-bit SDL2 libraries. + +### Example +``` +ucg_t ucg; + +ucg_Init(&ucg, ucg_sdl_dev_cb, ucg_ext_none, NULL); +``` diff --git a/pkg/ucglib/doc.txt b/pkg/ucglib/doc.txt new file mode 100644 index 0000000000..e5d37b91d5 --- /dev/null +++ b/pkg/ucglib/doc.txt @@ -0,0 +1,6 @@ +/** + * @defgroup pkg_ucglib Color graphics library for embedded systems + * @ingroup pkg + * @brief Provides a color graphics library for OLED and LCD displays + * @see https://github.com/olikraus/ucglib + */ \ No newline at end of file diff --git a/pkg/ucglib/patches/0001-add-RIOT-OS-interface.patch b/pkg/ucglib/patches/0001-add-RIOT-OS-interface.patch new file mode 100644 index 0000000000..0dccbf1ba6 --- /dev/null +++ b/pkg/ucglib/patches/0001-add-RIOT-OS-interface.patch @@ -0,0 +1,88 @@ +From a3187bd1bbf0d11f73d6108daff89f7ab009dd35 Mon Sep 17 00:00:00 2001 +From: Bas Stottelaar +Date: Fri, 2 Mar 2018 00:16:43 +0100 +Subject: [PATCH 1/1] add RIOT-OS interface. + +--- + csrc/ucg.h | 29 +++++++++++++++++++---------- + 1 file changed, 19 insertions(+), 10 deletions(-) + +diff --git a/csrc/ucg.h b/csrc/ucg.h +index c070a77..553562c 100644 +--- a/csrc/ucg.h ++++ b/csrc/ucg.h +@@ -84,17 +84,19 @@ + #include + #include + ++#include "periph/gpio.h" ++ + + #ifdef __cplusplus + extern "C" + { + #endif + +-#if defined(ARDUINO) +-#ifndef USE_PIN_LIST ++//#if defined(ARDUINO) ++//#ifndef USE_PIN_LIST + #define USE_PIN_LIST +-#endif +-#endif ++//#endif ++//#endif + + #ifdef __GNUC__ + # define UCG_NOINLINE __attribute__((noinline)) +@@ -413,12 +415,14 @@ struct _ucg_t + + /* only for Arduino/C++ Interface */ + #ifdef USE_PIN_LIST +- uint8_t pin_list[UCG_PIN_COUNT]; ++ gpio_t* pin_list; ++ uint32_t pins_enabled; ++ uint32_t dev; + +-#ifdef __AVR__ +- volatile uint8_t *data_port[UCG_PIN_COUNT]; +- uint8_t data_mask[UCG_PIN_COUNT]; +-#endif ++//#ifdef __AVR__ ++// volatile uint8_t *data_port[UCG_PIN_COUNT]; ++// uint8_t data_mask[UCG_PIN_COUNT]; ++//#endif + + #endif + +@@ -434,6 +438,9 @@ struct _ucg_t + + }; + ++#define ucg_SetPins(ucg,pins,pins_enabled) {(ucg)->pin_list = (pins); (ucg)->pins_enabled = (pins_enabled);} ++#define ucg_SetDevice(ucg,device) ((ucg)->dev = device) ++ + #define ucg_GetWidth(ucg) ((ucg)->dimension.w) + #define ucg_GetHeight(ucg) ((ucg)->dimension.h) + +@@ -574,6 +581,7 @@ ucg_int_t ucg_Init(ucg_t *ucg, ucg_dev_fnptr device_cb, ucg_dev_fnptr ext_cb, uc + /*================================================*/ + /* ucg_dev_sdl.c */ + ucg_int_t ucg_sdl_dev_cb(ucg_t *ucg, ucg_int_t msg, void *data); ++int ucg_sdl_get_key(void); + + /*================================================*/ + /* ucg_pixel.c */ +@@ -2172,7 +2180,8 @@ extern const ucg_fntpgm_uint8_t ucg_font_osr41_tr[] UCG_FONT_SECTION("ucg_font_o + + #endif + +- ++int16_t ucg_com_riotos_hw_spi(ucg_t *ucg, int16_t msg, uint16_t arg, uint8_t *data); ++ucg_int_t ucg_dev_dummy_cb(ucg_t *ucg, ucg_int_t msg, void *data); + + #ifdef __cplusplus + } +-- +2.14.2 + diff --git a/pkg/ucglib/src/Makefile b/pkg/ucglib/src/Makefile new file mode 100644 index 0000000000..62a8d91056 --- /dev/null +++ b/pkg/ucglib/src/Makefile @@ -0,0 +1,19 @@ +MODULE = pkg-ucglib + +DIRS += csrc + +# SDL can be used as a virtual display, but is for native target only. +ifneq (,$(filter ucglib_sdl,$(USEMODULE))) + DIRS += sys/sdl/dev +endif + +# Compiling Ucglib will generate a lot of compiler warnings, which are treated +# as errors. For the sake of simplicity, ignore them. +CFLAGS += -Wno-empty-translation-unit \ + -Wno-newline-eof \ + -Wno-unused-parameter \ + -Wno-unused \ + -Wno-overlength-strings \ + -Wno-pointer-arith + +include $(RIOTBASE)/Makefile.base diff --git a/pkg/ucglib/src/csrc/Makefile b/pkg/ucglib/src/csrc/Makefile new file mode 100644 index 0000000000..8a930a696d --- /dev/null +++ b/pkg/ucglib/src/csrc/Makefile @@ -0,0 +1,3 @@ +MODULE = ucglib + +include $(RIOTBASE)/Makefile.base diff --git a/pkg/ucglib/src/csrc/ucg_riotos.c b/pkg/ucglib/src/csrc/ucg_riotos.c new file mode 100644 index 0000000000..892847b876 --- /dev/null +++ b/pkg/ucglib/src/csrc/ucg_riotos.c @@ -0,0 +1,173 @@ +/* + * Copyright (C) 2018 Bas Stottelaar + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ + +/** + * @ingroup pkg_ucglib + * @{ + * + * @file + * @brief Ucglib driver to interact with RIOT-OS drivers. + * + * @author Bas Stottelaar + * + * @} + */ + +#include "ucg.h" + +#include "xtimer.h" + +#include "periph/spi.h" +#include "periph/i2c.h" +#include "periph/gpio.h" + +#include + +#ifdef SPI_NUMOF +static spi_clk_t ucg_serial_clk_speed_to_spi_speed(uint32_t serial_clk_speed) +{ + if (serial_clk_speed < 100) { + return SPI_CLK_10MHZ; + } + else if (serial_clk_speed < 200) { + return SPI_CLK_5MHZ; + } + else if (serial_clk_speed < 1000) { + return SPI_CLK_1MHZ; + } + else if (serial_clk_speed < 2500) { + return SPI_CLK_400KHZ; + } + + return SPI_CLK_100KHZ; +} +#endif /* SPI_NUMOF */ + +static void ucg_enable_pins(gpio_t *pins, uint32_t pins_enabled) +{ + uint8_t i; + + for (i = 0; i < 32; i++) { + if (pins_enabled & (1 << i)) { + if (pins[i] != GPIO_UNDEF) { + if (i < UCG_PIN_COUNT) { + gpio_init(pins[i], GPIO_OUT); + } + else { + gpio_init(pins[i], GPIO_IN); + } + } + } + } +} + +#ifdef SPI_NUMOF +int16_t ucg_com_riotos_hw_spi(ucg_t *ucg, int16_t msg, uint16_t arg, uint8_t *data) +{ + spi_t dev = (spi_t) ucg->dev; + + switch (msg) { + case UCG_COM_MSG_POWER_UP: + /* setup pins */ + ucg_enable_pins(ucg->pin_list, ucg->pins_enabled); + + /* setup Arduino SPI */ + spi_init_pins(dev); + spi_acquire(dev, GPIO_UNDEF, SPI_MODE_0, + ucg_serial_clk_speed_to_spi_speed(((ucg_com_info_t *)data)->serial_clk_speed)); + + break; + case UCG_COM_MSG_POWER_DOWN: + spi_release(dev); + break; + case UCG_COM_MSG_DELAY: + xtimer_usleep(arg); + break; + case UCG_COM_MSG_CHANGE_RESET_LINE: + if (ucg->pins_enabled & (1 << UCG_PIN_RST)) { + gpio_write(ucg->pin_list[UCG_PIN_RST], arg); + } + break; + case UCG_COM_MSG_CHANGE_CS_LINE: + if (ucg->pins_enabled & (1 << UCG_PIN_CS)) { + gpio_write(ucg->pin_list[UCG_PIN_CS], arg); + } + break; + case UCG_COM_MSG_CHANGE_CD_LINE: + if (ucg->pins_enabled & (1 << UCG_PIN_CD)) { + gpio_write(ucg->pin_list[UCG_PIN_CD], arg); + } + break; + case UCG_COM_MSG_SEND_BYTE: + spi_transfer_byte(dev, GPIO_UNDEF, true, (uint8_t) arg); + break; + case UCG_COM_MSG_REPEAT_1_BYTE: + while (arg--) { + spi_transfer_byte(dev, GPIO_UNDEF, true, ((uint8_t *) data)[0]); + } + break; + case UCG_COM_MSG_REPEAT_2_BYTES: + while (arg--) { + spi_transfer_bytes(dev, GPIO_UNDEF, true, data, NULL, 2); + } + break; + case UCG_COM_MSG_REPEAT_3_BYTES: + while (arg--) { + spi_transfer_bytes(dev, GPIO_UNDEF, true, data, NULL, 3); + } + break; + case UCG_COM_MSG_SEND_STR: + spi_transfer_bytes(dev, GPIO_UNDEF, true, data, NULL, arg); + break; + case UCG_COM_MSG_SEND_CD_DATA_SEQUENCE: + while (arg--) { + if (*data != 0) { + if (ucg->pins_enabled & (1 << UCG_PIN_CD)) { + gpio_write(ucg->pin_list[UCG_PIN_CD], *data); + } + } + + data++; + spi_transfer_bytes(dev, GPIO_UNDEF, true, data, NULL, 1); + data++; + } + break; + } + + return 1; +} +#endif /* SPI_NUMOF */ + +ucg_int_t ucg_dev_dummy_cb(ucg_t *ucg, ucg_int_t msg, void *data) +{ + static uint32_t pixels; + + switch (msg) { + case UCG_MSG_DEV_POWER_UP: + puts("ucg: UCG_MSG_DEV_POWER_UP"); + return 1; + case UCG_MSG_DEV_POWER_DOWN: + puts("ucg: UCG_MSG_DEV_POWER_DOWN"); + return 1; + case UCG_MSG_GET_DIMENSION: + puts("ucg: UCG_MSG_GET_DIMENSION"); + ((ucg_wh_t *)data)->w = 128; + ((ucg_wh_t *)data)->h = 128; + return 1; + case UCG_MSG_DRAW_PIXEL: + pixels++; + + /* log each 128th draw */ + if (pixels % 128 == 0) { + printf("ucg: UCG_MSG_DRAW_PIXEL (%" PRIu32 ")\n", pixels); + } + + return 1; + } + return ucg_dev_default_cb(ucg, msg, data); +} diff --git a/pkg/ucglib/src/sys/sdl/dev/Makefile b/pkg/ucglib/src/sys/sdl/dev/Makefile new file mode 100644 index 0000000000..bc6842cac7 --- /dev/null +++ b/pkg/ucglib/src/sys/sdl/dev/Makefile @@ -0,0 +1,5 @@ +MODULE = ucglib_sdl + +CFLAGS += `sdl2-config --cflags` + +include $(RIOTBASE)/Makefile.base