Skip to content
Snippets Groups Projects
Commit 63926052 authored by rahix's avatar rahix
Browse files

Merge 'WS2812 module (aka Neopixel)'

See merge request !251
parents 668dfffb c20bdbac
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