Commit 63926052 authored by Rahix's avatar Rahix

Merge 'WS2812 module (aka Neopixel)'

See merge request card10/firmware!251
parents 668dfffb c20bdbac
......@@ -138,6 +138,8 @@ typedef _Bool bool;
#define API_USB_STORAGE 0x111
#define API_USB_CDCACM 0x112
#define API_WS2812_WRITE 0x0120
/* clang-format on */
typedef uint32_t api_int_id_t;
......@@ -1843,4 +1845,20 @@ API(API_USB_STORAGE, int epic_usb_storage(void));
*/
API(API_USB_CDCACM, int epic_usb_cdcacm(void));
/**
* WS2812
* ======
*/
/**
* Takes a gpio pin specified with the gpio module and transmits
* the led data. The format `GG:RR:BB` is expected.
*
* :param uint8_t pin: The gpio pin to be used for data.
* :param uint8_t * pixels: The buffer, in which the pixel data is stored.
* :param uint32_t n_bytes: The size of the buffer.
*/
API(API_WS2812_WRITE, void epic_ws2812_write(uint8_t pin, uint8_t *pixels, uint32_t n_bytes));
#endif /* _EPICARDIUM_H */
......@@ -11,7 +11,7 @@
* Despite what the schematic (currently, 2019-08-18) says these are the correct
* pins for wristband GPIO 1-4 (not 0-3 as the schematic states)
*/
static gpio_cfg_t gpio_configs[] = {
gpio_cfg_t gpio_configs[] = {
[EPIC_GPIO_WRISTBAND_1] = { PORT_0,
PIN_21,
GPIO_FUNC_OUT,
......
......@@ -23,4 +23,5 @@ module_sources = files(
'watchdog.c',
'usb.c',
'config.c',
'ws2812.c'
)
......@@ -3,6 +3,7 @@
#include "FreeRTOS.h"
#include "semphr.h"
#include "gpio.h"
#include <stdint.h>
#include <stdbool.h>
......@@ -106,4 +107,8 @@ void vBhi160Task(void *pvParameters);
void vMAX30001Task(void *pvParameters);
void max30001_mutex_init(void);
/* ---------- GPIO --------------------------------------------------------- */
#define MAX30001_MUTEX_WAIT_MS 50
extern gpio_cfg_t gpio_configs[];
#endif /* MODULES_H */
#include "leds.h"
#include "pmic.h"
#include "FreeRTOS.h"
#include "task.h"
#include "epicardium.h"
#include "max32665.h"
#include "gpio.h"
#include "modules.h"
#include <stdbool.h>
#define OVERHEAD 33
#define EPIC_WS2812_ZERO_HIGH_TICKS 34 - OVERHEAD
#define EPIC_WS2812_ZERO_LOW_TICKS 86 - OVERHEAD
#define EPIC_WS2812_ONE_HIGH_TICKS 86 - OVERHEAD
#define EPIC_WS2812_ONE_LOW_TICKS 34 - OVERHEAD
#define EPIC_WS2812_RESET_TCKS 4800 - OVERHEAD
static volatile uint32_t counter = 0;
static inline __attribute__((always_inline)) void
epic_ws2812_delay_ticks(uint32_t ticks)
{
counter = ticks;
while (--counter) {
};
}
static inline __attribute__((always_inline)) void
epic_ws2812_transmit_bit(uint32_t pin, uint8_t bit)
{
if (bit != 0) {
GPIO_OutSet(pin);
epic_ws2812_delay_ticks(EPIC_WS2812_ONE_HIGH_TICKS);
GPIO_OutClr(pin);
epic_ws2812_delay_ticks(EPIC_WS2812_ONE_LOW_TICKS);
} else {
GPIO_OutSet(pin);
epic_ws2812_delay_ticks(EPIC_WS2812_ZERO_HIGH_TICKS);
GPIO_OutClr(pin);
epic_ws2812_delay_ticks(EPIC_WS2812_ZERO_LOW_TICKS);
}
}
static inline __attribute__((always_inline)) void
epic_ws2812_transmit_byte(uint32_t pin, uint8_t byte)
{
epic_ws2812_transmit_bit(pin, byte & 0b10000000);
epic_ws2812_transmit_bit(pin, byte & 0b01000000);
epic_ws2812_transmit_bit(pin, byte & 0b00100000);
epic_ws2812_transmit_bit(pin, byte & 0b00010000);
epic_ws2812_transmit_bit(pin, byte & 0b00001000);
epic_ws2812_transmit_bit(pin, byte & 0b00000100);
epic_ws2812_transmit_bit(pin, byte & 0b00000010);
epic_ws2812_transmit_bit(pin, byte & 0b00000001);
}
void epic_ws2812_write(uint8_t pin, uint8_t *pixels, uint32_t n_bytes)
{
uint8_t *pixels_end = pixels + n_bytes;
gpio_cfg_t *pin_cfg = &gpio_configs[pin];
taskENTER_CRITICAL();
epic_gpio_set_pin_mode(pin, EPIC_GPIO_MODE_OUT);
do {
epic_ws2812_transmit_byte(pin_cfg, *pixels);
} while (++pixels != pixels_end);
GPIO_OutClr(pin);
epic_ws2812_delay_ticks(EPIC_WS2812_RESET_TCKS);
taskEXIT_CRITICAL();
}
......@@ -16,7 +16,8 @@ modsrc = files(
'modules/sys_display.c',
'modules/utime.c',
'modules/vibra.c',
'modules/bme680.c'
'modules/bme680.c',
'modules/ws2812.c'
)
#################################
......
......@@ -170,3 +170,7 @@ Q(COMMUNICATION)
Q(CAMP)
Q(MAX30001_ECG)
/* ws2812 */
Q(ws2812)
Q(set_all)
#include "epicardium.h"
#include "py/obj.h"
#include <stdlib.h>
#include <stdio.h>
/* Define the pixel set_all function in this module */
static mp_obj_t mp_ws2812_set_all(mp_obj_t pin, mp_obj_t color_in)
{
mp_int_t pin_int = mp_obj_get_int(pin);
mp_int_t len = mp_obj_get_int(mp_obj_len(color_in));
mp_int_t pixels_len = len * 3;
uint8_t *pixels_arr = alloca(pixels_len * sizeof(uint8_t));
for (int i = 0; i < len; i++) {
mp_obj_t color = mp_obj_subscr(
color_in, mp_obj_new_int(i), MP_OBJ_SENTINEL
);
pixels_arr[i * 3] = mp_obj_get_int(mp_obj_subscr(
color, mp_obj_new_int(1), MP_OBJ_SENTINEL)
);
pixels_arr[i * 3 + 1] = mp_obj_get_int(mp_obj_subscr(
color, mp_obj_new_int(0), MP_OBJ_SENTINEL)
);
pixels_arr[i * 3 + 2] = mp_obj_get_int(mp_obj_subscr(
color, mp_obj_new_int(2), MP_OBJ_SENTINEL)
);
}
/* call epicardium to be fast enough */
epic_ws2812_write(pin_int, pixels_arr, pixels_len);
return mp_const_none;
}
static MP_DEFINE_CONST_FUN_OBJ_2(ws2812_set_all_obj, mp_ws2812_set_all);
/* The globals table for this module */
static const mp_rom_map_elem_t ws2812_module_globals_table[] = {
{ MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_ws2812) },
{ MP_ROM_QSTR(MP_QSTR_set_all), MP_ROM_PTR(&ws2812_set_all_obj) },
};
static MP_DEFINE_CONST_DICT(ws2812_module_globals, ws2812_module_globals_table);
const mp_obj_module_t ws2812_module = {
.base = { &mp_type_module },
.globals = (mp_obj_dict_t *)&ws2812_module_globals,
};
/* This is a special macro that will make MicroPython aware of this module */
/* clang-format off */
MP_REGISTER_MODULE(MP_QSTR_ws2812, ws2812_module, MODULE_WS2812_ENABLED);
......@@ -60,6 +60,7 @@ int mp_hal_trng_read_int(void);
#define MODULE_POWER_ENABLED (1)
#define MODULE_UTIME_ENABLED (1)
#define MODULE_VIBRA_ENABLED (1)
#define MODULE_WS2812_ENABLED (1)
/*
* This port is intended to be 32-bit, but unfortunately, int32_t for
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment