atmel-samd: Add low level neopixel_write module & function for WS281x/neopixel RGB LEDs.
This commit is contained in:
parent
7e08347d5c
commit
9c67605233
@ -140,11 +140,13 @@ SRC_C = \
|
||||
modmachine_dac.c \
|
||||
modmachine_pin.c \
|
||||
modmachine_pwm.c \
|
||||
modneopixel_write.c \
|
||||
moduos.c \
|
||||
modutime.c \
|
||||
mphalport.c \
|
||||
pin_named_pins.c \
|
||||
rom_fs.c \
|
||||
samdneopixel.c \
|
||||
storage.c \
|
||||
uart.c \
|
||||
asf/common/services/sleepmgr/samd/sleepmgr.c \
|
||||
|
34
atmel-samd/modneopixel_write.c
Normal file
34
atmel-samd/modneopixel_write.c
Normal file
@ -0,0 +1,34 @@
|
||||
#include <stdio.h>
|
||||
|
||||
#include "py/obj.h"
|
||||
#include "py/mphal.h"
|
||||
#include "py/runtime.h"
|
||||
|
||||
#include "modmachine_pin.h"
|
||||
#include "samdneopixel.h"
|
||||
|
||||
extern const mp_obj_type_t pin_type;
|
||||
|
||||
STATIC mp_obj_t neopixel_write_neopixel_write_(mp_obj_t pin_obj, mp_obj_t buf, mp_obj_t is800k) {
|
||||
// Convert parameters into expected types.
|
||||
const pin_obj_t *pin = pin_find(pin_obj);
|
||||
mp_buffer_info_t bufinfo;
|
||||
mp_get_buffer_raise(buf, &bufinfo, MP_BUFFER_READ);
|
||||
// Call platform's neopixel write function with provided buffer and options.
|
||||
samd_neopixel_write(pin->pin, (uint8_t*)bufinfo.buf, bufinfo.len,
|
||||
mp_obj_is_true(is800k));
|
||||
return mp_const_none;
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_3(neopixel_write_neopixel_write_obj, neopixel_write_neopixel_write_);
|
||||
|
||||
STATIC const mp_rom_map_elem_t neopixel_write_module_globals_table[] = {
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_neopixel_write) },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_neopixel_write), (mp_obj_t)&neopixel_write_neopixel_write_obj },
|
||||
};
|
||||
|
||||
STATIC MP_DEFINE_CONST_DICT(neopixel_write_module_globals, neopixel_write_module_globals_table);
|
||||
|
||||
const mp_obj_module_t neopixel_write_module = {
|
||||
.base = { &mp_type_module },
|
||||
.globals = (mp_obj_dict_t*)&neopixel_write_module_globals,
|
||||
};
|
@ -108,11 +108,13 @@ typedef long mp_off_t;
|
||||
extern const struct _mp_obj_module_t machine_module;
|
||||
extern const struct _mp_obj_module_t uos_module;
|
||||
extern const struct _mp_obj_module_t utime_module;
|
||||
extern const struct _mp_obj_module_t neopixel_write_module;
|
||||
|
||||
#define MICROPY_PORT_BUILTIN_MODULES \
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_umachine), (mp_obj_t)&machine_module }, \
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_uos), (mp_obj_t)&uos_module }, \
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_utime), (mp_obj_t)&utime_module } \
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_utime), (mp_obj_t)&utime_module }, \
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_neopixel_write),(mp_obj_t)&neopixel_write_module } \
|
||||
|
||||
#define MICROPY_PORT_BUILTIN_MODULE_WEAK_LINKS \
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_machine), (mp_obj_t)&machine_module }, \
|
||||
|
87
atmel-samd/samdneopixel.c
Normal file
87
atmel-samd/samdneopixel.c
Normal file
@ -0,0 +1,87 @@
|
||||
#include "asf/common2/services/delay/delay.h"
|
||||
#include "asf/sam0/drivers/port/port.h"
|
||||
|
||||
#include "samdneopixel.h"
|
||||
|
||||
void samd_neopixel_write(uint32_t pin, uint8_t *pixels, uint32_t numBytes, bool is800KHz) {
|
||||
// This is adapted directly from the Adafruit NeoPixel library SAMD21G18A code:
|
||||
// https://github.com/adafruit/Adafruit_NeoPixel/blob/master/Adafruit_NeoPixel.cpp
|
||||
uint8_t *ptr, *end, p, bitMask;
|
||||
uint32_t pinMask;
|
||||
PortGroup* port;
|
||||
|
||||
// Turn off interrupts of any kind during timing-sensitive code.
|
||||
irqflags_t flags = cpu_irq_save();
|
||||
|
||||
port = port_get_group_from_gpio_pin(pin);
|
||||
pinMask = (1UL << (pin % 32)); // From port_pin_set_output_level ASF code.
|
||||
ptr = pixels;
|
||||
end = ptr + numBytes;
|
||||
p = *ptr++;
|
||||
bitMask = 0x80;
|
||||
|
||||
volatile uint32_t *set = &(port->OUTSET.reg),
|
||||
*clr = &(port->OUTCLR.reg);
|
||||
|
||||
if(is800KHz) {
|
||||
for(;;) {
|
||||
*set = pinMask;
|
||||
asm("nop; nop; nop; nop; nop; nop; nop; nop;");
|
||||
if(p & bitMask) {
|
||||
asm("nop; nop; nop; nop; nop; nop; nop; nop;"
|
||||
"nop; nop; nop; nop; nop; nop; nop; nop;"
|
||||
"nop; nop; nop; nop;");
|
||||
*clr = pinMask;
|
||||
} else {
|
||||
*clr = pinMask;
|
||||
asm("nop; nop; nop; nop; nop; nop; nop; nop;"
|
||||
"nop; nop; nop; nop; nop; nop; nop; nop;"
|
||||
"nop; nop; nop; nop;");
|
||||
}
|
||||
if(bitMask >>= 1) {
|
||||
asm("nop; nop; nop; nop; nop; nop; nop; nop; nop;");
|
||||
} else {
|
||||
if(ptr >= end) break;
|
||||
p = *ptr++;
|
||||
bitMask = 0x80;
|
||||
}
|
||||
}
|
||||
} else { // 400 KHz bitstream
|
||||
for(;;) {
|
||||
*set = pinMask;
|
||||
asm("nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop;");
|
||||
if(p & bitMask) {
|
||||
asm("nop; nop; nop; nop; nop; nop; nop; nop;"
|
||||
"nop; nop; nop; nop; nop; nop; nop; nop;"
|
||||
"nop; nop; nop; nop; nop; nop; nop; nop;"
|
||||
"nop; nop; nop;");
|
||||
*clr = pinMask;
|
||||
} else {
|
||||
*clr = pinMask;
|
||||
asm("nop; nop; nop; nop; nop; nop; nop; nop;"
|
||||
"nop; nop; nop; nop; nop; nop; nop; nop;"
|
||||
"nop; nop; nop; nop; nop; nop; nop; nop;"
|
||||
"nop; nop; nop;");
|
||||
}
|
||||
asm("nop; nop; nop; nop; nop; nop; nop; nop;"
|
||||
"nop; nop; nop; nop; nop; nop; nop; nop;"
|
||||
"nop; nop; nop; nop; nop; nop; nop; nop;"
|
||||
"nop; nop; nop; nop; nop; nop; nop; nop;");
|
||||
if(bitMask >>= 1) {
|
||||
asm("nop; nop; nop; nop; nop; nop; nop;");
|
||||
} else {
|
||||
if(ptr >= end) break;
|
||||
p = *ptr++;
|
||||
bitMask = 0x80;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Turn on interrupts after timing-sensitive code.
|
||||
cpu_irq_restore(flags);
|
||||
|
||||
// 50ms delay to let pixels latch to the data that was just sent.
|
||||
// This could be optimized to only occur before pixel writes when necessary,
|
||||
// like in the Arduino library.
|
||||
delay_ms(50);
|
||||
}
|
9
atmel-samd/samdneopixel.h
Normal file
9
atmel-samd/samdneopixel.h
Normal file
@ -0,0 +1,9 @@
|
||||
#ifndef SAMD_NEOPIXEL_WRITE_H
|
||||
#define SAMD_NEOPIXEL_WRITE_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
void samd_neopixel_write(uint32_t pin, uint8_t *pixels, uint32_t numBytes, bool is800KHz);
|
||||
|
||||
#endif
|
Loading…
Reference in New Issue
Block a user