Merge pull request #393 from tannewt/m4_neopixel
Now with more blinky!!!
This commit is contained in:
commit
0076a3c868
2
main.c
2
main.c
@ -146,7 +146,7 @@ bool start_mp(safe_mode_t safe_mode) {
|
||||
// Wait for connection or character.
|
||||
bool serial_connected_before_animation = false;
|
||||
rgb_status_animation_t animation;
|
||||
prep_rgb_status_animation(&result, found_main, &animation);
|
||||
prep_rgb_status_animation(&result, found_main, safe_mode, &animation);
|
||||
while (true) {
|
||||
#ifdef MICROPY_VM_HOOK_LOOP
|
||||
MICROPY_VM_HOOK_LOOP
|
||||
|
@ -251,6 +251,7 @@ SRC_COMMON_HAL = \
|
||||
microcontroller/__init__.c \
|
||||
microcontroller/Pin.c \
|
||||
microcontroller/Processor.c \
|
||||
neopixel_write/__init__.c \
|
||||
os/__init__.c \
|
||||
time/__init__.c
|
||||
# analogio/__init__.c \
|
||||
|
@ -61,6 +61,6 @@ void reset_board(void) {
|
||||
common_hal_digitalio_digitalinout_construct(&neopixel_pin, &pin_PB23);
|
||||
common_hal_digitalio_digitalinout_switch_to_output(&neopixel_pin, false,
|
||||
DRIVE_MODE_PUSH_PULL);
|
||||
// common_hal_neopixel_write(&neopixel_pin, empty, 30);
|
||||
common_hal_neopixel_write(&neopixel_pin, empty, 30);
|
||||
common_hal_digitalio_digitalinout_deinit(&neopixel_pin);
|
||||
}
|
||||
|
@ -26,8 +26,16 @@
|
||||
|
||||
#include "boards/board.h"
|
||||
#include "mpconfigboard.h"
|
||||
#include "hal/include/hal_gpio.h"
|
||||
|
||||
void board_init(void) {
|
||||
gpio_set_pin_function(MICROPY_HW_LED_TX, GPIO_PIN_FUNCTION_OFF);
|
||||
gpio_set_pin_direction(MICROPY_HW_LED_TX, GPIO_DIRECTION_OUT);
|
||||
gpio_set_pin_level(MICROPY_HW_LED_TX, true);
|
||||
|
||||
gpio_set_pin_function(MICROPY_HW_LED_RX, GPIO_PIN_FUNCTION_OFF);
|
||||
gpio_set_pin_direction(MICROPY_HW_LED_RX, GPIO_DIRECTION_OUT);
|
||||
gpio_set_pin_level(MICROPY_HW_LED_RX, true);
|
||||
}
|
||||
|
||||
bool board_requests_safe_mode(void) {
|
||||
|
@ -6,7 +6,7 @@
|
||||
#define MICROPY_HW_LED_TX PIN_PA27
|
||||
#define MICROPY_HW_LED_RX PIN_PB06
|
||||
|
||||
// #define MICROPY_HW_NEOPIXEL (&pin_PB17)
|
||||
#define MICROPY_HW_NEOPIXEL (&pin_PB17)
|
||||
|
||||
#define SPI_FLASH_BAUDRATE (1000000)
|
||||
|
||||
|
@ -23,13 +23,27 @@
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
#include "hpl_gpio.h"
|
||||
|
||||
#include "mphalport.h"
|
||||
#include "py/mphal.h"
|
||||
|
||||
#include "shared-bindings/neopixel_write/__init__.h"
|
||||
|
||||
#include "asf/common2/services/delay/delay.h"
|
||||
#include "asf/sam0/drivers/port/port.h"
|
||||
#include "tick.h"
|
||||
|
||||
#ifdef SAMD51
|
||||
static inline void delay_cycles(uint8_t cycles) {
|
||||
uint32_t start = SysTick->VAL;
|
||||
uint32_t stop = start - cycles;
|
||||
if (start < cycles) {
|
||||
stop = 0xffffff + start - cycles;
|
||||
}
|
||||
while (SysTick->VAL > stop) {}
|
||||
}
|
||||
#endif
|
||||
|
||||
uint64_t next_start_tick_ms = 0;
|
||||
uint32_t next_start_tick_us = 1000;
|
||||
|
||||
void common_hal_neopixel_write(const digitalio_digitalinout_obj_t* digitalinout, uint8_t *pixels, uint32_t numBytes) {
|
||||
// This is adapted directly from the Adafruit NeoPixel library SAMD21G18A code:
|
||||
@ -38,14 +52,21 @@ void common_hal_neopixel_write(const digitalio_digitalinout_obj_t* digitalinout,
|
||||
uint32_t pinMask;
|
||||
PortGroup* port;
|
||||
|
||||
// This must be called while interrupts are on in case we're waiting for a
|
||||
// future ms tick.
|
||||
wait_until(next_start_tick_ms, next_start_tick_us);
|
||||
|
||||
// Turn off interrupts of any kind during timing-sensitive code.
|
||||
mp_hal_disable_all_interrupts();
|
||||
|
||||
#ifdef SAMD21
|
||||
// Make sure the NVM cache is consistently timed.
|
||||
NVMCTRL->CTRLB.bit.READMODE = NVMCTRL_CTRLB_READMODE_DETERMINISTIC_Val;
|
||||
#endif
|
||||
|
||||
|
||||
uint32_t pin = digitalinout->pin->pin;
|
||||
port = port_get_group_from_gpio_pin(pin);
|
||||
port = &PORT->Group[GPIO_PORT(pin)]; // Convert GPIO # to port register
|
||||
pinMask = (1UL << (pin % 32)); // From port_pin_set_output_level ASF code.
|
||||
ptr = pixels;
|
||||
end = ptr + numBytes;
|
||||
@ -57,31 +78,75 @@ void common_hal_neopixel_write(const digitalio_digitalinout_obj_t* digitalinout,
|
||||
|
||||
for(;;) {
|
||||
*set = pinMask;
|
||||
// This is the time where the line is always high regardless of the bit.
|
||||
// For the SK6812 its 0.3us +- 0.15us
|
||||
#ifdef SAMD21
|
||||
asm("nop; nop;");
|
||||
#endif
|
||||
#ifdef SAMD51
|
||||
delay_cycles(18);
|
||||
#endif
|
||||
if(p & bitMask) {
|
||||
// This is the high delay unique to a one bit.
|
||||
// For the SK6812 its 0.3us
|
||||
#ifdef SAMD21
|
||||
asm("nop; nop; nop; nop; nop; nop; nop;");
|
||||
#endif
|
||||
#ifdef SAMD51
|
||||
delay_cycles(25);
|
||||
#endif
|
||||
*clr = pinMask;
|
||||
} else {
|
||||
*clr = pinMask;
|
||||
// This is the low delay unique to a zero bit.
|
||||
// For the SK6812 its 0.3us
|
||||
#ifdef SAMD21
|
||||
asm("nop; nop;");
|
||||
#endif
|
||||
#ifdef SAMD51
|
||||
delay_cycles(25);
|
||||
#endif
|
||||
}
|
||||
if((bitMask >>= 1) != 0) {
|
||||
// This is the delay between bits in a byte and is the 1 code low
|
||||
// level time from the datasheet.
|
||||
// For the SK6812 its 0.6us +- 0.15us
|
||||
#ifdef SAMD21
|
||||
asm("nop; nop; nop; nop; nop;");
|
||||
#endif
|
||||
#ifdef SAMD51
|
||||
delay_cycles(44);
|
||||
#endif
|
||||
} else {
|
||||
if(ptr >= end) break;
|
||||
p = *ptr++;
|
||||
bitMask = 0x80;
|
||||
// This is the delay between bytes. Its similar to the other branch
|
||||
// in the if statement except its tuned to account for the time the
|
||||
// above operations take.
|
||||
// For the SK6812 its 0.6us +- 0.15us
|
||||
#ifdef SAMD51
|
||||
delay_cycles(50);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef SAMD21
|
||||
// Speed up! (But inconsistent timing.)
|
||||
NVMCTRL->CTRLB.bit.READMODE = NVMCTRL_CTRLB_READMODE_NO_MISS_PENALTY_Val;
|
||||
#endif
|
||||
|
||||
// ticks_ms may be out of date at this point because we stopped the
|
||||
// interrupt. We'll risk it anyway.
|
||||
current_tick(&next_start_tick_ms, &next_start_tick_us);
|
||||
if (next_start_tick_us < 100) {
|
||||
next_start_tick_ms += 1;
|
||||
next_start_tick_us = 100 - next_start_tick_us;
|
||||
} else {
|
||||
next_start_tick_us -= 100;
|
||||
}
|
||||
|
||||
// Turn on interrupts after timing-sensitive code.
|
||||
mp_hal_enable_all_interrupts();
|
||||
|
||||
// 50us 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_us(50);
|
||||
}
|
||||
|
@ -215,7 +215,6 @@ extern const struct _mp_obj_module_t usb_hid_module;
|
||||
// { MP_OBJ_NEW_QSTR(MP_QSTR_analogio), (mp_obj_t)&analogio_module },
|
||||
// { MP_OBJ_NEW_QSTR(MP_QSTR_busio), (mp_obj_t)&busio_module },
|
||||
// { MP_OBJ_NEW_QSTR(MP_QSTR_gamepad),(mp_obj_t)&gamepad_module },
|
||||
// { MP_OBJ_NEW_QSTR(MP_QSTR_neopixel_write),(mp_obj_t)&neopixel_write_module },
|
||||
// { MP_OBJ_NEW_QSTR(MP_QSTR_usb_hid),(mp_obj_t)&usb_hid_module },
|
||||
// { MP_OBJ_NEW_QSTR(MP_QSTR_storage), (mp_obj_t)&storage_module },
|
||||
// { MP_OBJ_NEW_QSTR(MP_QSTR_samd),(mp_obj_t)&samd_module },
|
||||
@ -225,6 +224,7 @@ extern const struct _mp_obj_module_t usb_hid_module;
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_board), (mp_obj_t)&board_module }, \
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_digitalio), (mp_obj_t)&digitalio_module }, \
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_microcontroller), (mp_obj_t)µcontroller_module }, \
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_neopixel_write),(mp_obj_t)&neopixel_write_module }, \
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_os), (mp_obj_t)&os_module }, \
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_random), (mp_obj_t)&random_module }, \
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_struct), (mp_obj_t)&struct_module }, \
|
||||
|
@ -66,5 +66,17 @@ void tick_delay(uint32_t us) {
|
||||
start_ms = ticks_ms;
|
||||
us_between_ticks = 1000;
|
||||
}
|
||||
while (SysTick->VAL > ((1000 - us) * ticks_per_us)) {}
|
||||
while (SysTick->VAL > ((us_between_ticks - us) * ticks_per_us)) {}
|
||||
}
|
||||
|
||||
// us counts down!
|
||||
void current_tick(uint64_t* ms, uint32_t* us_until_ms) {
|
||||
uint32_t ticks_per_us = common_hal_mcu_processor_get_frequency() / 1000 / 1000;
|
||||
*ms = ticks_ms;
|
||||
*us_until_ms = SysTick->VAL / ticks_per_us;
|
||||
}
|
||||
|
||||
void wait_until(uint64_t ms, uint32_t us_until_ms) {
|
||||
uint32_t ticks_per_us = common_hal_mcu_processor_get_frequency() / 1000 / 1000;
|
||||
while(ticks_ms <= ms && SysTick->VAL / ticks_per_us >= us_until_ms) {}
|
||||
}
|
||||
|
@ -36,4 +36,9 @@ void tick_init(void);
|
||||
|
||||
void tick_delay(uint32_t us);
|
||||
|
||||
void current_tick(uint64_t* ms, uint32_t* us_until_ms);
|
||||
// Do not call this with interrupts disabled because it may be waiting for
|
||||
// ticks_ms to increment.
|
||||
void wait_until(uint64_t ms, uint32_t us_until_ms);
|
||||
|
||||
#endif // MICROPY_INCLUDED_ATMEL_SAMD_TICK_H
|
||||
|
@ -309,8 +309,7 @@ void usb_msc_background(void) {
|
||||
// Load more blocks from USB if they are needed.
|
||||
if (active_nblocks > 0) {
|
||||
int32_t result = mscdf_xfer_blocks(false, sector_buffer, 1);
|
||||
while (result != ERR_NONE) {}
|
||||
usb_busy = true;
|
||||
usb_busy = result != ERR_NONE;
|
||||
} else {
|
||||
mscdf_xfer_blocks(false, NULL, 0);
|
||||
active_write = false;
|
||||
|
@ -199,12 +199,15 @@ void set_rgb_status_brightness(uint8_t level){
|
||||
rgb_status_brightness = level;
|
||||
}
|
||||
|
||||
void prep_rgb_status_animation(const pyexec_result_t* result, bool found_main, rgb_status_animation_t* status) {
|
||||
void prep_rgb_status_animation(const pyexec_result_t* result,
|
||||
bool found_main,
|
||||
safe_mode_t safe_mode,
|
||||
rgb_status_animation_t* status) {
|
||||
#if defined(MICROPY_HW_NEOPIXEL) || (defined(MICROPY_HW_APA102_MOSI) && defined(MICROPY_HW_APA102_SCK))
|
||||
new_status_color(ALL_DONE);
|
||||
status->pattern_start = ticks_ms;
|
||||
|
||||
uint32_t total_exception_cycle = 0;
|
||||
status->safe_mode = safe_mode;
|
||||
status->total_exception_cycle = 0;
|
||||
status->ones = result->exception_line % 10;
|
||||
status->ones += status->ones > 0 ? 1 : 0;
|
||||
status->tens = (result->exception_line / 10) % 10;
|
||||
@ -224,7 +227,7 @@ void prep_rgb_status_animation(const pyexec_result_t* result, bool found_main, r
|
||||
}
|
||||
status->ok = result->return_code != PYEXEC_EXCEPTION;
|
||||
if (!status->ok) {
|
||||
status->total_exception_cycle = EXCEPTION_TYPE_LENGTH_MS * 3 + LINE_NUMBER_TOGGLE_LENGTH * digit_sum + LINE_NUMBER_TOGGLE_LENGTH * num_places;
|
||||
status->total_exception_cycle = EXCEPTION_TYPE_LENGTH_MS * 3 + LINE_NUMBER_TOGGLE_LENGTH * status->digit_sum + LINE_NUMBER_TOGGLE_LENGTH * num_places;
|
||||
}
|
||||
if (mp_obj_is_subclass_fast(result->exception_type, &mp_type_IndentationError)) {
|
||||
status->exception_color = INDENTATION_ERROR;
|
||||
@ -244,11 +247,11 @@ void prep_rgb_status_animation(const pyexec_result_t* result, bool found_main, r
|
||||
|
||||
void tick_rgb_status_animation(rgb_status_animation_t* status) {
|
||||
#if defined(MICROPY_HW_NEOPIXEL) || (defined(MICROPY_HW_APA102_MOSI) && defined(MICROPY_HW_APA102_SCK))
|
||||
uint32_t tick_diff = ticks_ms - pattern_start;
|
||||
uint32_t tick_diff = ticks_ms - status->pattern_start;
|
||||
if (status->ok) {
|
||||
// All is good. Ramp ALL_DONE up and down.
|
||||
if (tick_diff > ALL_GOOD_CYCLE_MS) {
|
||||
pattern_start = ticks_ms;
|
||||
status->pattern_start = ticks_ms;
|
||||
tick_diff = 0;
|
||||
}
|
||||
|
||||
@ -256,14 +259,14 @@ void tick_rgb_status_animation(rgb_status_animation_t* status) {
|
||||
if (brightness > 255) {
|
||||
brightness = 511 - brightness;
|
||||
}
|
||||
if (safe_mode == NO_SAFE_MODE) {
|
||||
if (status->safe_mode == NO_SAFE_MODE) {
|
||||
new_status_color(color_brightness(ALL_DONE, brightness));
|
||||
} else {
|
||||
new_status_color(color_brightness(SAFE_MODE, brightness));
|
||||
}
|
||||
} else {
|
||||
if (tick_diff > total_exception_cycle) {
|
||||
pattern_start = ticks_ms;
|
||||
if (tick_diff > status->total_exception_cycle) {
|
||||
status->pattern_start = ticks_ms;
|
||||
tick_diff = 0;
|
||||
}
|
||||
// First flash the file color.
|
||||
@ -275,34 +278,34 @@ void tick_rgb_status_animation(rgb_status_animation_t* status) {
|
||||
}
|
||||
// Next flash the exception color.
|
||||
} else if (tick_diff < EXCEPTION_TYPE_LENGTH_MS * 2) {
|
||||
new_status_color(exception_color);
|
||||
new_status_color(status->exception_color);
|
||||
// Finally flash the line number digits from highest to lowest.
|
||||
// Zeroes will not produce a flash but can be read by the absence of
|
||||
// a color from the sequence.
|
||||
} else if (tick_diff < (EXCEPTION_TYPE_LENGTH_MS * 2 + LINE_NUMBER_TOGGLE_LENGTH * digit_sum)) {
|
||||
} else if (tick_diff < (EXCEPTION_TYPE_LENGTH_MS * 2 + LINE_NUMBER_TOGGLE_LENGTH * status->digit_sum)) {
|
||||
uint32_t digit_diff = tick_diff - EXCEPTION_TYPE_LENGTH_MS * 2;
|
||||
if ((digit_diff % LINE_NUMBER_TOGGLE_LENGTH) < (LINE_NUMBER_TOGGLE_LENGTH / 2)) {
|
||||
new_status_color(BLACK);
|
||||
} else if (digit_diff < LINE_NUMBER_TOGGLE_LENGTH * thousands) {
|
||||
} else if (digit_diff < LINE_NUMBER_TOGGLE_LENGTH * status->thousands) {
|
||||
if (digit_diff < LINE_NUMBER_TOGGLE_LENGTH) {
|
||||
new_status_color(BLACK);
|
||||
} else {
|
||||
new_status_color(THOUSANDS);
|
||||
}
|
||||
} else if (digit_diff < LINE_NUMBER_TOGGLE_LENGTH * (thousands + hundreds)) {
|
||||
if (digit_diff < LINE_NUMBER_TOGGLE_LENGTH * (thousands + 1)) {
|
||||
} else if (digit_diff < LINE_NUMBER_TOGGLE_LENGTH * (status->thousands + status->hundreds)) {
|
||||
if (digit_diff < LINE_NUMBER_TOGGLE_LENGTH * (status->thousands + 1)) {
|
||||
new_status_color(BLACK);
|
||||
} else {
|
||||
new_status_color(HUNDREDS);
|
||||
}
|
||||
} else if (digit_diff < LINE_NUMBER_TOGGLE_LENGTH * (thousands + hundreds + tens)) {
|
||||
if (digit_diff < LINE_NUMBER_TOGGLE_LENGTH * (thousands + hundreds + 1)) {
|
||||
} else if (digit_diff < LINE_NUMBER_TOGGLE_LENGTH * (status->thousands + status->hundreds + status->tens)) {
|
||||
if (digit_diff < LINE_NUMBER_TOGGLE_LENGTH * (status->thousands + status->hundreds + 1)) {
|
||||
new_status_color(BLACK);
|
||||
} else {
|
||||
new_status_color(TENS);
|
||||
}
|
||||
} else {
|
||||
if (digit_diff < LINE_NUMBER_TOGGLE_LENGTH * (thousands + hundreds + tens + 1)) {
|
||||
if (digit_diff < LINE_NUMBER_TOGGLE_LENGTH * (status->thousands + status->hundreds + status->tens + 1)) {
|
||||
new_status_color(BLACK);
|
||||
} else {
|
||||
new_status_color(ONES);
|
||||
|
@ -31,6 +31,7 @@
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "lib/utils/pyexec.h"
|
||||
#include "supervisor/port.h"
|
||||
|
||||
#include "mpconfigport.h"
|
||||
#include "rgb_led_colors.h"
|
||||
@ -59,6 +60,8 @@ typedef struct {
|
||||
bool ok;
|
||||
uint32_t pattern_start;
|
||||
uint32_t total_exception_cycle;
|
||||
safe_mode_t safe_mode;
|
||||
uint8_t digit_sum;
|
||||
uint8_t ones;
|
||||
uint8_t tens;
|
||||
uint8_t hundreds;
|
||||
@ -67,7 +70,10 @@ typedef struct {
|
||||
bool found_main;
|
||||
} rgb_status_animation_t;
|
||||
|
||||
void prep_rgb_status_animation(const pyexec_result_t* result, bool found_main, rgb_status_animation_t* status);
|
||||
void prep_rgb_status_animation(const pyexec_result_t* result,
|
||||
bool found_main,
|
||||
safe_mode_t safe_mode,
|
||||
rgb_status_animation_t* status);
|
||||
void tick_rgb_status_animation(rgb_status_animation_t* status);
|
||||
|
||||
#endif // MICROPY_INCLUDED_SUPERVISOR_RGB_LED_STATUS_H
|
||||
|
Loading…
Reference in New Issue
Block a user