Skip to content
Snippets Groups Projects
Commit c20bdbac authored by danb's avatar danb Committed by rahix
Browse files

feat(ws2812): Add WS2812 module (aka Neopixel)

parent 668dfffb
No related branches found
No related tags found
No related merge requests found
...@@ -138,6 +138,8 @@ typedef _Bool bool; ...@@ -138,6 +138,8 @@ typedef _Bool bool;
#define API_USB_STORAGE 0x111 #define API_USB_STORAGE 0x111
#define API_USB_CDCACM 0x112 #define API_USB_CDCACM 0x112
#define API_WS2812_WRITE 0x0120
/* clang-format on */ /* clang-format on */
typedef uint32_t api_int_id_t; typedef uint32_t api_int_id_t;
...@@ -1843,4 +1845,20 @@ API(API_USB_STORAGE, int epic_usb_storage(void)); ...@@ -1843,4 +1845,20 @@ API(API_USB_STORAGE, int epic_usb_storage(void));
*/ */
API(API_USB_CDCACM, int epic_usb_cdcacm(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 */ #endif /* _EPICARDIUM_H */
...@@ -11,7 +11,7 @@ ...@@ -11,7 +11,7 @@
* Despite what the schematic (currently, 2019-08-18) says these are the correct * 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) * 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, [EPIC_GPIO_WRISTBAND_1] = { PORT_0,
PIN_21, PIN_21,
GPIO_FUNC_OUT, GPIO_FUNC_OUT,
......
...@@ -23,4 +23,5 @@ module_sources = files( ...@@ -23,4 +23,5 @@ module_sources = files(
'watchdog.c', 'watchdog.c',
'usb.c', 'usb.c',
'config.c', 'config.c',
'ws2812.c'
) )
...@@ -3,6 +3,7 @@ ...@@ -3,6 +3,7 @@
#include "FreeRTOS.h" #include "FreeRTOS.h"
#include "semphr.h" #include "semphr.h"
#include "gpio.h"
#include <stdint.h> #include <stdint.h>
#include <stdbool.h> #include <stdbool.h>
...@@ -106,4 +107,8 @@ void vBhi160Task(void *pvParameters); ...@@ -106,4 +107,8 @@ void vBhi160Task(void *pvParameters);
void vMAX30001Task(void *pvParameters); void vMAX30001Task(void *pvParameters);
void max30001_mutex_init(void); void max30001_mutex_init(void);
/* ---------- GPIO --------------------------------------------------------- */
#define MAX30001_MUTEX_WAIT_MS 50
extern gpio_cfg_t gpio_configs[];
#endif /* MODULES_H */ #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( ...@@ -16,7 +16,8 @@ modsrc = files(
'modules/sys_display.c', 'modules/sys_display.c',
'modules/utime.c', 'modules/utime.c',
'modules/vibra.c', 'modules/vibra.c',
'modules/bme680.c' 'modules/bme680.c',
'modules/ws2812.c'
) )
################################# #################################
......
...@@ -170,3 +170,7 @@ Q(COMMUNICATION) ...@@ -170,3 +170,7 @@ Q(COMMUNICATION)
Q(CAMP) Q(CAMP)
Q(MAX30001_ECG) 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); ...@@ -60,6 +60,7 @@ int mp_hal_trng_read_int(void);
#define MODULE_POWER_ENABLED (1) #define MODULE_POWER_ENABLED (1)
#define MODULE_UTIME_ENABLED (1) #define MODULE_UTIME_ENABLED (1)
#define MODULE_VIBRA_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 * This port is intended to be 32-bit, but unfortunately, int32_t for
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment