atmel-samd: Add APA102 support and flash more advanced status.
The new sequence is as follows: * Solid blue during the boot/settings script. * Solid green during the main/code script. * After main while waiting to enter repl or reset: * Fading green once main is done successfully. * On error produce a series of flashes: * Long flash color of script. * Long flash color of error: * Green = IndentationError * Cyan = SyntaxError * White = NameError * Orange = OSError * Yellow = Other error * Line number of the exception by digit. Number of flashes represents value. * Thousands = White * Hundreds = Blue * Tens = Yellow * Ones = Cyan * Off for a period and then repeats. At any point a write to the flash storage will flicker red. Fixes #63
This commit is contained in:
parent
6225b89c76
commit
b6f1eebab3
@ -178,7 +178,7 @@ SRC_C = \
|
||||
moduos.c \
|
||||
mphalport.c \
|
||||
samd21_pins.c \
|
||||
neopixel_status.c \
|
||||
rgb_led_status.c \
|
||||
tick.c \
|
||||
$(FLASH_IMPL) \
|
||||
asf/common/services/sleepmgr/samd/sleepmgr.c \
|
||||
|
@ -3,7 +3,6 @@
|
||||
#define MICROPY_HW_BOARD_NAME "Adafruit Gemma M0 (Experimental)"
|
||||
#define MICROPY_HW_MCU_NAME "samd21e18"
|
||||
|
||||
#define MICROPY_HW_APA102_SERCOM SERCOM0
|
||||
#define MICROPY_HW_APA102_MOSI &pin_PA04
|
||||
#define MICROPY_HW_APA102_SCK &pin_PA05
|
||||
|
||||
|
@ -3,7 +3,6 @@
|
||||
#define MICROPY_HW_BOARD_NAME "Adafruit Trinket M0 (Experimental)"
|
||||
#define MICROPY_HW_MCU_NAME "samd21e18"
|
||||
|
||||
#define MICROPY_HW_APA102_SERCOM SERCOM0
|
||||
#define MICROPY_HW_APA102_MOSI &pin_PA04
|
||||
#define MICROPY_HW_APA102_SCK &pin_PA05
|
||||
|
||||
|
@ -37,7 +37,7 @@
|
||||
#include "asf/sam0/drivers/nvm/nvm.h"
|
||||
#include "asf/sam0/drivers/port/port.h"
|
||||
|
||||
#include "neopixel_status.h"
|
||||
#include "rgb_led_status.h"
|
||||
|
||||
#define TOTAL_INTERNAL_FLASH_SIZE 0x010000
|
||||
|
||||
@ -174,9 +174,7 @@ bool internal_flash_write_block(const uint8_t *src, uint32_t block) {
|
||||
#ifdef MICROPY_HW_LED_MSC
|
||||
port_pin_set_output_level(MICROPY_HW_LED_MSC, true);
|
||||
#endif
|
||||
#ifdef MICROPY_HW_NEOPIXEL
|
||||
temp_status_color(0x8f, 0x00, 0x00);
|
||||
#endif
|
||||
temp_status_color(ACTIVE_WRITE);
|
||||
// non-MBR block, copy to cache
|
||||
int32_t dest = convert_block_to_flash_addr(block);
|
||||
if (dest == -1) {
|
||||
@ -214,9 +212,7 @@ bool internal_flash_write_block(const uint8_t *src, uint32_t block) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
#ifdef MICROPY_HW_NEOPIXEL
|
||||
clear_temp_status();
|
||||
#endif
|
||||
clear_temp_status();
|
||||
#ifdef MICROPY_HW_LED_MSC
|
||||
port_pin_set_output_level(MICROPY_HW_LED_MSC, false);
|
||||
#endif
|
||||
|
@ -10,6 +10,7 @@
|
||||
|
||||
#include "lib/fatfs/ff.h"
|
||||
#include "lib/fatfs/diskio.h"
|
||||
#include "lib/mp-readline/readline.h"
|
||||
#include "lib/utils/pyexec.h"
|
||||
#include "extmod/fsusermount.h"
|
||||
|
||||
@ -23,7 +24,7 @@
|
||||
|
||||
#include "autoreset.h"
|
||||
#include "mpconfigboard.h"
|
||||
#include "neopixel_status.h"
|
||||
#include "rgb_led_status.h"
|
||||
#include "tick.h"
|
||||
|
||||
fs_user_mount_t fs_user_mount_flash;
|
||||
@ -131,7 +132,7 @@ static char *stack_top;
|
||||
static char heap[16384];
|
||||
|
||||
void reset_mp(void) {
|
||||
new_status_color(0x8f, 0x00, 0x8f);
|
||||
new_status_color(0x8f008f);
|
||||
autoreset_stop();
|
||||
autoreset_enable();
|
||||
|
||||
@ -181,7 +182,7 @@ void reset_samd21(void) {
|
||||
system_pinmux_group_set_config(&(PORT->Group[1]), pin_mask[1] & ~MICROPY_PORT_B, &config);
|
||||
}
|
||||
|
||||
bool maybe_run(const char* filename, int* ret) {
|
||||
bool maybe_run(const char* filename, pyexec_result_t* exec_result) {
|
||||
FILINFO fno;
|
||||
#if _USE_LFN
|
||||
fno.lfname = NULL;
|
||||
@ -193,32 +194,171 @@ bool maybe_run(const char* filename, int* ret) {
|
||||
}
|
||||
mp_hal_stdout_tx_str(filename);
|
||||
mp_hal_stdout_tx_str(" output:\r\n");
|
||||
*ret = pyexec_file(filename);
|
||||
pyexec_file(filename, exec_result);
|
||||
return true;
|
||||
}
|
||||
|
||||
void start_mp(void) {
|
||||
bool start_mp(void) {
|
||||
bool cdc_enabled_at_start = mp_cdc_enabled;
|
||||
#ifdef AUTORESET_DELAY_MS
|
||||
if (cdc_enabled_at_start) {
|
||||
mp_hal_stdout_tx_str("\r\n");
|
||||
mp_hal_stdout_tx_str("Auto-soft reset is on. Simply save files over USB to run them.\r\n");
|
||||
mp_hal_stdout_tx_str("Type anything into the REPL to disable and manually reset (CTRL-D) to re-enable.\r\n");
|
||||
}
|
||||
#endif
|
||||
|
||||
new_status_color(0x00, 0x00, 0x8f);
|
||||
int ret = 0;
|
||||
bool found_boot = maybe_run("settings.txt", &ret) ||
|
||||
maybe_run("settings.py", &ret) ||
|
||||
maybe_run("boot.py", &ret) ||
|
||||
maybe_run("boot.txt", &ret);
|
||||
if (found_boot && ret & PYEXEC_FORCED_EXIT) {
|
||||
return;
|
||||
new_status_color(BOOT_RUNNING);
|
||||
pyexec_result_t result;
|
||||
bool found_boot = maybe_run("settings.txt", &result) ||
|
||||
maybe_run("settings.py", &result) ||
|
||||
maybe_run("boot.py", &result) ||
|
||||
maybe_run("boot.txt", &result);
|
||||
bool found_main = false;
|
||||
if (!found_boot || !(result.return_code & PYEXEC_FORCED_EXIT)) {
|
||||
new_status_color(MAIN_RUNNING);
|
||||
found_main = maybe_run("code.txt", &result) ||
|
||||
maybe_run("code.py", &result) ||
|
||||
maybe_run("main.py", &result) ||
|
||||
maybe_run("main.txt", &result);
|
||||
}
|
||||
|
||||
new_status_color(0x00, 0x8f, 0x00);
|
||||
maybe_run("code.txt", &ret) ||
|
||||
maybe_run("code.py", &ret) ||
|
||||
maybe_run("main.py", &ret) ||
|
||||
maybe_run("main.txt", &ret);
|
||||
if (result.return_code & PYEXEC_FORCED_EXIT) {
|
||||
return reset_next_character;
|
||||
}
|
||||
|
||||
// If not is USB mode then do not skip the repl.
|
||||
#ifndef USB_REPL
|
||||
return false;
|
||||
#endif
|
||||
|
||||
// Wait for connection or character.
|
||||
new_status_color(ALL_DONE);
|
||||
bool cdc_enabled_before = false;
|
||||
uint32_t pattern_start = ticks_ms;
|
||||
|
||||
printf("result code %d %d.\r\n", result.return_code, result.exception_line);
|
||||
uint32_t total_exception_cycle = 0;
|
||||
uint8_t ones = result.exception_line % 10;
|
||||
ones += ones > 0 ? 1 : 0;
|
||||
uint8_t tens = (result.exception_line / 10) % 10;
|
||||
tens += tens > 0 ? 1 : 0;
|
||||
uint8_t hundreds = (result.exception_line / 100) % 10;
|
||||
hundreds += hundreds > 0 ? 1 : 0;
|
||||
uint8_t thousands = (result.exception_line / 1000) % 10;
|
||||
thousands += thousands > 0 ? 1 : 0;
|
||||
uint8_t digit_sum = ones + tens + hundreds + thousands;
|
||||
uint8_t num_places = 0;
|
||||
uint16_t line = result.exception_line;
|
||||
for (int i = 0; i < 4; i++) {
|
||||
if ((line % 10) > 0) {
|
||||
num_places++;
|
||||
}
|
||||
line /= 10;
|
||||
}
|
||||
if (result.return_code == PYEXEC_EXCEPTION) {
|
||||
total_exception_cycle = EXCEPTION_TYPE_LENGTH_MS * 3 + LINE_NUMBER_TOGGLE_LENGTH * digit_sum + LINE_NUMBER_TOGGLE_LENGTH * num_places;
|
||||
}
|
||||
while (true) {
|
||||
#ifdef MICROPY_VM_HOOK_LOOP
|
||||
MICROPY_VM_HOOK_LOOP
|
||||
#endif
|
||||
if (reset_next_character) {
|
||||
return true;
|
||||
}
|
||||
if (usb_rx_count > 0) {
|
||||
// Skip REPL if reset was requested.
|
||||
return receive_usb() == CHAR_CTRL_D;
|
||||
}
|
||||
|
||||
if (!cdc_enabled_before && mp_cdc_enabled) {
|
||||
if (cdc_enabled_at_start) {
|
||||
mp_hal_stdout_tx_str("\r\n\r\n");
|
||||
} else {
|
||||
printf("result code %d %d.\r\n", result.return_code, result.exception_line);
|
||||
mp_hal_stdout_tx_str("Auto-soft reset is on. Simply save files over USB to run them.\r\n");
|
||||
}
|
||||
mp_hal_stdout_tx_str("Press any key to enter the REPL and disable auto-reset. Use CTRL-D to soft reset.\r\n");
|
||||
}
|
||||
if (cdc_enabled_before && !mp_cdc_enabled) {
|
||||
cdc_enabled_at_start = false;
|
||||
}
|
||||
cdc_enabled_before = mp_cdc_enabled;
|
||||
|
||||
uint32_t tick_diff = ticks_ms - pattern_start;
|
||||
if (result.return_code != PYEXEC_EXCEPTION) {
|
||||
// All is good. Ramp ALL_DONE up and down.
|
||||
if (tick_diff > ALL_GOOD_CYCLE_MS) {
|
||||
pattern_start = ticks_ms;
|
||||
tick_diff = 0;
|
||||
}
|
||||
|
||||
uint16_t brightness = tick_diff * 255 / (ALL_GOOD_CYCLE_MS / 2);
|
||||
if (brightness > 255) {
|
||||
brightness = 511 - brightness;
|
||||
}
|
||||
new_status_color(color_brightness(ALL_DONE, brightness));
|
||||
} else {
|
||||
if (tick_diff > total_exception_cycle) {
|
||||
pattern_start = ticks_ms;
|
||||
tick_diff = 0;
|
||||
}
|
||||
// First flash the file color.
|
||||
if (tick_diff < EXCEPTION_TYPE_LENGTH_MS) {
|
||||
if (found_main) {
|
||||
new_status_color(MAIN_RUNNING);
|
||||
} else {
|
||||
new_status_color(BOOT_RUNNING);
|
||||
}
|
||||
// Next flash the exception color.
|
||||
} else if (tick_diff < EXCEPTION_TYPE_LENGTH_MS * 2) {
|
||||
if (mp_obj_is_subclass_fast(result.exception_type, &mp_type_IndentationError)) {
|
||||
new_status_color(INDENTATION_ERROR);
|
||||
} else if (mp_obj_is_subclass_fast(result.exception_type, &mp_type_SyntaxError)) {
|
||||
new_status_color(SYNTAX_ERROR);
|
||||
} else if (mp_obj_is_subclass_fast(result.exception_type, &mp_type_NameError)) {
|
||||
new_status_color(NAME_ERROR);
|
||||
} else if (mp_obj_is_subclass_fast(result.exception_type, &mp_type_OSError)) {
|
||||
new_status_color(OS_ERROR);
|
||||
} else {
|
||||
new_status_color(OTHER_ERROR);
|
||||
}
|
||||
// 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)) {
|
||||
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) {
|
||||
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)) {
|
||||
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)) {
|
||||
new_status_color(BLACK);
|
||||
} else {
|
||||
new_status_color(TENS);
|
||||
}
|
||||
} else {
|
||||
if (digit_diff < LINE_NUMBER_TOGGLE_LENGTH * (thousands + hundreds + tens + 1)) {
|
||||
new_status_color(BLACK);
|
||||
} else {
|
||||
new_status_color(ONES);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
new_status_color(BLACK);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef UART_REPL
|
||||
@ -283,7 +423,7 @@ void samd21_init(void) {
|
||||
// port_pin_set_config(MICROPY_HW_LED1, &pin_conf);
|
||||
// port_pin_set_output_level(MICROPY_HW_LED1, false);
|
||||
|
||||
neopixel_status_init();
|
||||
rgb_led_status_init();
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
@ -307,24 +447,29 @@ int main(int argc, char **argv) {
|
||||
udc_start();
|
||||
#endif
|
||||
|
||||
// Run boot and main.
|
||||
start_mp();
|
||||
|
||||
// Main script is finished, so now go into REPL mode.
|
||||
// The REPL mode can change, or it can request a soft reset.
|
||||
int exit_code = 0;
|
||||
int exit_code = PYEXEC_FORCED_EXIT;
|
||||
bool skip_repl = true;
|
||||
bool first_run = true;
|
||||
for (;;) {
|
||||
new_status_color(0x3f, 0x3f, 0x3f);
|
||||
if (pyexec_mode_kind == PYEXEC_MODE_RAW_REPL) {
|
||||
exit_code = pyexec_raw_repl();
|
||||
} else {
|
||||
exit_code = pyexec_friendly_repl();
|
||||
if (!skip_repl) {
|
||||
autoreset_disable();
|
||||
new_status_color(REPL_RUNNING);
|
||||
if (pyexec_mode_kind == PYEXEC_MODE_RAW_REPL) {
|
||||
exit_code = pyexec_raw_repl();
|
||||
} else {
|
||||
exit_code = pyexec_friendly_repl();
|
||||
}
|
||||
}
|
||||
if (exit_code == PYEXEC_FORCED_EXIT) {
|
||||
mp_hal_stdout_tx_str("soft reboot\r\n");
|
||||
reset_samd21();
|
||||
reset_mp();
|
||||
start_mp();
|
||||
if (!first_run) {
|
||||
mp_hal_stdout_tx_str("soft reboot\r\n");
|
||||
reset_samd21();
|
||||
reset_mp();
|
||||
}
|
||||
first_run = false;
|
||||
skip_repl = start_mp();
|
||||
} else if (exit_code != 0) {
|
||||
break;
|
||||
}
|
||||
|
@ -30,9 +30,9 @@ static volatile uint8_t usb_rx_buf_head;
|
||||
static volatile uint8_t usb_rx_buf_tail;
|
||||
|
||||
// Number of bytes in receive buffer
|
||||
static volatile uint8_t usb_rx_count;
|
||||
volatile uint8_t usb_rx_count;
|
||||
|
||||
static volatile bool mp_cdc_enabled = false;
|
||||
volatile bool mp_cdc_enabled = false;
|
||||
|
||||
void mp_keyboard_interrupt(void);
|
||||
int interrupt_char;
|
||||
|
@ -37,6 +37,11 @@ extern volatile uint64_t ticks_ms;
|
||||
static inline mp_uint_t mp_hal_ticks_ms(void) {
|
||||
return ticks_ms;
|
||||
}
|
||||
// Number of bytes in receive buffer
|
||||
volatile uint8_t usb_rx_count;
|
||||
volatile bool mp_cdc_enabled;
|
||||
|
||||
int receive_usb(void);
|
||||
|
||||
void mp_hal_set_interrupt_char(int c);
|
||||
|
||||
|
@ -1,43 +0,0 @@
|
||||
#include "asf/common2/services/delay/delay.h"
|
||||
#include "asf/sam0/drivers/port/port.h"
|
||||
|
||||
#include "mphalport.h"
|
||||
|
||||
#include "shared-bindings/nativeio/DigitalInOut.h"
|
||||
#include "shared-bindings/neopixel_write/__init__.h"
|
||||
#include "neopixel_status.h"
|
||||
#include "samd21_pins.h"
|
||||
|
||||
#ifdef MICROPY_HW_NEOPIXEL
|
||||
static uint8_t status_neopixel_color[3];
|
||||
static nativeio_digitalinout_obj_t status_neopixel;
|
||||
#endif
|
||||
|
||||
void neopixel_status_init() {
|
||||
#ifdef MICROPY_HW_NEOPIXEL
|
||||
common_hal_nativeio_digitalinout_construct(&status_neopixel, MICROPY_HW_NEOPIXEL);
|
||||
common_hal_nativeio_digitalinout_switch_to_output(&status_neopixel, false, DRIVE_MODE_PUSH_PULL);
|
||||
#endif
|
||||
}
|
||||
|
||||
void new_status_color(uint8_t r, uint8_t g, uint8_t b) {
|
||||
#ifdef MICROPY_HW_NEOPIXEL
|
||||
status_neopixel_color[0] = g;
|
||||
status_neopixel_color[1] = r;
|
||||
status_neopixel_color[2] = b;
|
||||
common_hal_neopixel_write(&status_neopixel, status_neopixel_color, 3, true);
|
||||
#endif
|
||||
}
|
||||
|
||||
void temp_status_color(uint8_t r, uint8_t g, uint8_t b) {
|
||||
#ifdef MICROPY_HW_NEOPIXEL
|
||||
uint8_t colors[3] = {g, r, b};
|
||||
common_hal_neopixel_write(&status_neopixel, colors, 3, true);
|
||||
#endif
|
||||
}
|
||||
|
||||
void clear_temp_status() {
|
||||
#ifdef MICROPY_HW_NEOPIXEL
|
||||
common_hal_neopixel_write(&status_neopixel, status_neopixel_color, 3, true);
|
||||
#endif
|
||||
}
|
@ -1,12 +0,0 @@
|
||||
#ifndef __MICROPY_INCLUDED_ATMEL_SAMD_NEOPIXEL_STATUS_H
|
||||
#define __MICROPY_INCLUDED_ATMEL_SAMD_NEOPIXEL_STATUS_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
extern void neopixel_status_init(void);
|
||||
extern void new_status_color(uint8_t r, uint8_t g, uint8_t b);
|
||||
extern void temp_status_color(uint8_t r, uint8_t g, uint8_t b);
|
||||
extern void clear_temp_status(void);
|
||||
|
||||
#endif // __MICROPY_INCLUDED_ATMEL_SAMD_NEOPIXEL_STATUS_H
|
32
atmel-samd/rgb_led_colors.h
Normal file
32
atmel-samd/rgb_led_colors.h
Normal file
@ -0,0 +1,32 @@
|
||||
#define BLACK 0x000000
|
||||
#define GREEN 0x003f00
|
||||
#define BLUE 0x00003f
|
||||
#define CYAN 0x003f3f
|
||||
#define RED 0x3f0000
|
||||
#define ORANGE 0x3f1f00
|
||||
#define YELLOW 0x3f3f00
|
||||
#define PURPLE 0x3f003f
|
||||
#define WHITE 0x3f3f3f
|
||||
|
||||
#define BOOT_RUNNING BLUE
|
||||
#define MAIN_RUNNING GREEN
|
||||
#define ALL_DONE GREEN
|
||||
#define REPL_RUNNING WHITE
|
||||
|
||||
#define ACTIVE_WRITE 0x8f0000
|
||||
|
||||
#define ALL_GOOD_CYCLE_MS 2000u
|
||||
|
||||
#define LINE_NUMBER_TOGGLE_LENGTH 300u
|
||||
#define EXCEPTION_TYPE_LENGTH_MS 1000u
|
||||
|
||||
#define THOUSANDS WHITE
|
||||
#define HUNDREDS BLUE
|
||||
#define TENS YELLOW
|
||||
#define ONES CYAN
|
||||
|
||||
#define INDENTATION_ERROR GREEN
|
||||
#define SYNTAX_ERROR CYAN
|
||||
#define NAME_ERROR WHITE
|
||||
#define OS_ERROR ORANGE
|
||||
#define OTHER_ERROR YELLOW
|
93
atmel-samd/rgb_led_status.c
Normal file
93
atmel-samd/rgb_led_status.c
Normal file
@ -0,0 +1,93 @@
|
||||
#include "asf/common2/services/delay/delay.h"
|
||||
#include "asf/sam0/drivers/port/port.h"
|
||||
|
||||
#include "mphalport.h"
|
||||
|
||||
#include "shared-bindings/bitbangio/SPI.h"
|
||||
#include "shared-bindings/nativeio/DigitalInOut.h"
|
||||
#include "shared-bindings/neopixel_write/__init__.h"
|
||||
#include "shared-module/bitbangio/types.h"
|
||||
#include "rgb_led_status.h"
|
||||
#include "samd21_pins.h"
|
||||
|
||||
#ifdef MICROPY_HW_NEOPIXEL
|
||||
static uint8_t status_neopixel_color[3];
|
||||
static nativeio_digitalinout_obj_t status_neopixel;
|
||||
#endif
|
||||
|
||||
#if defined(MICROPY_HW_APA102_MOSI) && defined(MICROPY_HW_APA102_SCK)
|
||||
static uint8_t status_apa102_color[12] = {0, 0, 0, 0, 0xff, 0, 0, 0};
|
||||
static bitbangio_spi_obj_t status_apa102;
|
||||
#endif
|
||||
|
||||
#if defined(MICROPY_HW_NEOPIXEL) || (defined(MICROPY_HW_APA102_MOSI) && defined(MICROPY_HW_APA102_SCK))
|
||||
static uint32_t current_status_color = 0;
|
||||
#endif
|
||||
|
||||
void rgb_led_status_init() {
|
||||
#ifdef MICROPY_HW_NEOPIXEL
|
||||
common_hal_nativeio_digitalinout_construct(&status_neopixel, MICROPY_HW_NEOPIXEL);
|
||||
common_hal_nativeio_digitalinout_switch_to_output(&status_neopixel, false, DRIVE_MODE_PUSH_PULL);
|
||||
#endif
|
||||
#if defined(MICROPY_HW_APA102_MOSI) && defined(MICROPY_HW_APA102_SCK)
|
||||
shared_module_bitbangio_spi_construct(&status_apa102,
|
||||
MICROPY_HW_APA102_SCK,
|
||||
MICROPY_HW_APA102_MOSI,
|
||||
NULL);
|
||||
shared_module_bitbangio_spi_try_lock(&status_apa102);
|
||||
shared_module_bitbangio_spi_configure(&status_apa102, 100000, 0, 1, 8);
|
||||
#endif
|
||||
}
|
||||
|
||||
void new_status_color(uint32_t rgb) {
|
||||
#if defined(MICROPY_HW_NEOPIXEL) || (defined(MICROPY_HW_APA102_MOSI) && defined(MICROPY_HW_APA102_SCK))
|
||||
if (current_status_color == rgb) {
|
||||
return;
|
||||
}
|
||||
current_status_color = rgb;
|
||||
#endif
|
||||
|
||||
#ifdef MICROPY_HW_NEOPIXEL
|
||||
status_neopixel_color[0] = (rgb >> 8) & 0xff;
|
||||
status_neopixel_color[1] = (rgb >> 16) & 0xff;
|
||||
status_neopixel_color[2] = rgb & 0xff;
|
||||
common_hal_neopixel_write(&status_neopixel, status_neopixel_color, 3, true);
|
||||
#endif
|
||||
#if defined(MICROPY_HW_APA102_MOSI) && defined(MICROPY_HW_APA102_SCK)
|
||||
status_apa102_color[5] = rgb & 0xff;
|
||||
status_apa102_color[6] = (rgb >> 8) & 0xff;
|
||||
status_apa102_color[7] = (rgb >> 16) & 0xff;
|
||||
shared_module_bitbangio_spi_write(&status_apa102, status_apa102_color, 8);
|
||||
#endif
|
||||
}
|
||||
|
||||
void temp_status_color(uint32_t rgb) {
|
||||
#ifdef MICROPY_HW_NEOPIXEL
|
||||
uint8_t colors[3] = {(rgb >> 8) & 0xff, (rgb >> 16) & 0xff, rgb & 0xff};
|
||||
common_hal_neopixel_write(&status_neopixel, colors, 3, true);
|
||||
#endif
|
||||
#if defined(MICROPY_HW_APA102_MOSI) && defined(MICROPY_HW_APA102_SCK)
|
||||
uint8_t colors[12] = {0, 0, 0, 0, 0xff, rgb & 0xff, (rgb >> 8) & 0xff, (rgb >> 16) & 0xff, 0x0, 0x0, 0x0, 0x0};
|
||||
shared_module_bitbangio_spi_write(&status_apa102, colors, 8);
|
||||
#endif
|
||||
}
|
||||
|
||||
void clear_temp_status() {
|
||||
#ifdef MICROPY_HW_NEOPIXEL
|
||||
common_hal_neopixel_write(&status_neopixel, status_neopixel_color, 3, true);
|
||||
#endif
|
||||
#if defined(MICROPY_HW_APA102_MOSI) && defined(MICROPY_HW_APA102_SCK)
|
||||
shared_module_bitbangio_spi_write(&status_apa102, status_apa102_color, 12);
|
||||
#endif
|
||||
}
|
||||
|
||||
uint32_t color_brightness(uint32_t color, uint8_t brightness) {
|
||||
#if defined(MICROPY_HW_NEOPIXEL) || (defined(MICROPY_HW_APA102_MOSI) && defined(MICROPY_HW_APA102_SCK))
|
||||
uint32_t result = ((color & 0xff0000) * brightness / 255) & 0xff0000;
|
||||
result += ((color & 0xff00) * brightness / 255) & 0xff00;
|
||||
result += ((color & 0xff) * brightness / 255) & 0xff;
|
||||
return result;
|
||||
#else
|
||||
return color;
|
||||
#endif
|
||||
}
|
16
atmel-samd/rgb_led_status.h
Normal file
16
atmel-samd/rgb_led_status.h
Normal file
@ -0,0 +1,16 @@
|
||||
#ifndef __MICROPY_INCLUDED_ATMEL_SAMD_RGB_LED_STATUS_H
|
||||
#define __MICROPY_INCLUDED_ATMEL_SAMD_RGB_LED_STATUS_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "rgb_led_colors.h"
|
||||
|
||||
extern void rgb_led_status_init(void);
|
||||
extern void new_status_color(uint32_t rgb);
|
||||
extern void temp_status_color(uint32_t rgb);
|
||||
extern void clear_temp_status(void);
|
||||
|
||||
uint32_t color_brightness(uint32_t color, uint8_t brightness);
|
||||
|
||||
#endif // __MICROPY_INCLUDED_ATMEL_SAMD_RGB_LED_STATUS_H
|
@ -36,7 +36,7 @@
|
||||
#include "lib/fatfs/ff.h"
|
||||
#include "extmod/fsusermount.h"
|
||||
|
||||
#include "neopixel_status.h"
|
||||
#include "rgb_led_status.h"
|
||||
|
||||
#define SPI_FLASH_PART1_START_BLOCK (0x1)
|
||||
|
||||
@ -384,9 +384,7 @@ static void spi_flash_flush_keep_cache(bool keep_cache) {
|
||||
#ifdef MICROPY_HW_LED_MSC
|
||||
port_pin_set_output_level(MICROPY_HW_LED_MSC, true);
|
||||
#endif
|
||||
#ifdef MICROPY_HW_NEOPIXEL
|
||||
temp_status_color(0x8f, 0x00, 0x00);
|
||||
#endif
|
||||
temp_status_color(ACTIVE_WRITE);
|
||||
// If we've cached to the flash itself flush from there.
|
||||
if (MP_STATE_VM(flash_ram_cache) == NULL) {
|
||||
flush_scratch_flash();
|
||||
@ -394,9 +392,7 @@ static void spi_flash_flush_keep_cache(bool keep_cache) {
|
||||
flush_ram_cache(keep_cache);
|
||||
}
|
||||
current_sector = NO_SECTOR_LOADED;
|
||||
#ifdef MICROPY_HW_NEOPIXEL
|
||||
clear_temp_status();
|
||||
#endif
|
||||
clear_temp_status();
|
||||
#ifdef MICROPY_HW_LED_MSC
|
||||
port_pin_set_output_level(MICROPY_HW_LED_MSC, false);
|
||||
#endif
|
||||
|
@ -58,7 +58,7 @@ STATIC bool repl_display_debugging_info = 0;
|
||||
// EXEC_FLAG_PRINT_EOF prints 2 EOF chars: 1 after normal output, 1 after exception output
|
||||
// EXEC_FLAG_ALLOW_DEBUGGING allows debugging info to be printed after executing the code
|
||||
// EXEC_FLAG_IS_REPL is used for REPL inputs (flag passed on to mp_compile)
|
||||
STATIC int parse_compile_execute(void *source, mp_parse_input_kind_t input_kind, int exec_flags) {
|
||||
STATIC int parse_compile_execute(void *source, mp_parse_input_kind_t input_kind, int exec_flags, pyexec_result_t *result) {
|
||||
int ret = 0;
|
||||
uint32_t start = 0;
|
||||
|
||||
@ -88,7 +88,7 @@ STATIC int parse_compile_execute(void *source, mp_parse_input_kind_t input_kind,
|
||||
mp_call_function_0(module_fun);
|
||||
mp_hal_set_interrupt_char(-1); // disable interrupt
|
||||
nlr_pop();
|
||||
ret = 1;
|
||||
ret = 0;
|
||||
if (exec_flags & EXEC_FLAG_PRINT_EOF) {
|
||||
mp_hal_stdout_tx_strn("\x04", 1);
|
||||
}
|
||||
@ -108,7 +108,21 @@ STATIC int parse_compile_execute(void *source, mp_parse_input_kind_t input_kind,
|
||||
ret = PYEXEC_FORCED_EXIT;
|
||||
} else {
|
||||
mp_obj_print_exception(&mp_plat_print, (mp_obj_t)nlr.ret_val);
|
||||
ret = 0;
|
||||
ret = PYEXEC_EXCEPTION;
|
||||
}
|
||||
}
|
||||
if (result != NULL) {
|
||||
result->return_code = ret;
|
||||
if (ret != 0) {
|
||||
mp_obj_t return_value = (mp_obj_t)nlr.ret_val;
|
||||
result->exception_type = mp_obj_get_type(return_value);
|
||||
result->exception_line = -1;
|
||||
|
||||
if (mp_obj_is_exception_instance(return_value)) {
|
||||
size_t n, *values;
|
||||
mp_obj_exception_get_traceback(return_value, &n, &values);
|
||||
result->exception_line = values[n - 2];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -203,7 +217,7 @@ STATIC int pyexec_raw_repl_process_char(int c) {
|
||||
if (lex == NULL) {
|
||||
mp_hal_stdout_tx_str("\x04MemoryError\r\n\x04");
|
||||
} else {
|
||||
int ret = parse_compile_execute(lex, MP_PARSE_FILE_INPUT, EXEC_FLAG_PRINT_EOF);
|
||||
int ret = parse_compile_execute(lex, MP_PARSE_FILE_INPUT, EXEC_FLAG_PRINT_EOF, NULL);
|
||||
if (ret & PYEXEC_FORCED_EXIT) {
|
||||
return ret;
|
||||
}
|
||||
@ -285,7 +299,7 @@ exec: ;
|
||||
if (lex == NULL) {
|
||||
printf("MemoryError\n");
|
||||
} else {
|
||||
int ret = parse_compile_execute(lex, MP_PARSE_SINGLE_INPUT, EXEC_FLAG_ALLOW_DEBUGGING | EXEC_FLAG_IS_REPL);
|
||||
int ret = parse_compile_execute(lex, MP_PARSE_SINGLE_INPUT, EXEC_FLAG_ALLOW_DEBUGGING | EXEC_FLAG_IS_REPL, NULL);
|
||||
if (ret & PYEXEC_FORCED_EXIT) {
|
||||
return ret;
|
||||
}
|
||||
@ -361,7 +375,7 @@ raw_repl_reset:
|
||||
if (lex == NULL) {
|
||||
printf("\x04MemoryError\n\x04");
|
||||
} else {
|
||||
int ret = parse_compile_execute(lex, MP_PARSE_FILE_INPUT, EXEC_FLAG_PRINT_EOF);
|
||||
int ret = parse_compile_execute(lex, MP_PARSE_FILE_INPUT, EXEC_FLAG_PRINT_EOF, NULL);
|
||||
if (ret & PYEXEC_FORCED_EXIT) {
|
||||
return ret;
|
||||
}
|
||||
@ -380,7 +394,7 @@ int pyexec_friendly_repl(void) {
|
||||
#endif
|
||||
|
||||
friendly_repl_reset:
|
||||
mp_hal_stdout_tx_str("Adafruit MicroPython " MICROPY_GIT_TAG " on " MICROPY_BUILD_DATE "; " MICROPY_HW_BOARD_NAME " with " MICROPY_HW_MCU_NAME "\r\n");
|
||||
mp_hal_stdout_tx_str("\r\nAdafruit MicroPython " MICROPY_GIT_TAG " on " MICROPY_BUILD_DATE "; " MICROPY_HW_BOARD_NAME " with " MICROPY_HW_MCU_NAME "\r\n");
|
||||
// mp_hal_stdout_tx_str("Type \"help()\" for more information.\r\n");
|
||||
|
||||
// to test ctrl-C
|
||||
@ -487,7 +501,7 @@ friendly_repl_reset:
|
||||
if (lex == NULL) {
|
||||
printf("MemoryError\n");
|
||||
} else {
|
||||
ret = parse_compile_execute(lex, parse_input_kind, EXEC_FLAG_ALLOW_DEBUGGING | EXEC_FLAG_IS_REPL);
|
||||
ret = parse_compile_execute(lex, parse_input_kind, EXEC_FLAG_ALLOW_DEBUGGING | EXEC_FLAG_IS_REPL, NULL);
|
||||
if (ret & PYEXEC_FORCED_EXIT) {
|
||||
return ret;
|
||||
}
|
||||
@ -497,7 +511,7 @@ friendly_repl_reset:
|
||||
|
||||
#endif // MICROPY_REPL_EVENT_DRIVEN
|
||||
|
||||
int pyexec_file(const char *filename) {
|
||||
int pyexec_file(const char *filename, pyexec_result_t *exec_result) {
|
||||
mp_lexer_t *lex = mp_lexer_new_from_file(filename);
|
||||
|
||||
if (lex == NULL) {
|
||||
@ -505,7 +519,7 @@ int pyexec_file(const char *filename) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return parse_compile_execute(lex, MP_PARSE_FILE_INPUT, 0);
|
||||
return parse_compile_execute(lex, MP_PARSE_FILE_INPUT, 0, exec_result);
|
||||
}
|
||||
|
||||
#if MICROPY_MODULE_FROZEN
|
||||
@ -516,12 +530,12 @@ int pyexec_frozen_module(const char *name) {
|
||||
switch (frozen_type) {
|
||||
#if MICROPY_MODULE_FROZEN_STR
|
||||
case MP_FROZEN_STR:
|
||||
return parse_compile_execute(frozen_data, MP_PARSE_FILE_INPUT, 0);
|
||||
return parse_compile_execute(frozen_data, MP_PARSE_FILE_INPUT, 0, NULL);
|
||||
#endif
|
||||
|
||||
#if MICROPY_MODULE_FROZEN_MPY
|
||||
case MP_FROZEN_MPY:
|
||||
return parse_compile_execute(frozen_data, MP_PARSE_FILE_INPUT, EXEC_FLAG_SOURCE_IS_RAW_CODE);
|
||||
return parse_compile_execute(frozen_data, MP_PARSE_FILE_INPUT, EXEC_FLAG_SOURCE_IS_RAW_CODE, NULL);
|
||||
#endif
|
||||
|
||||
default:
|
||||
|
@ -31,6 +31,12 @@ typedef enum {
|
||||
PYEXEC_MODE_FRIENDLY_REPL,
|
||||
} pyexec_mode_kind_t;
|
||||
|
||||
typedef struct {
|
||||
int return_code;
|
||||
const mp_obj_type_t * exception_type;
|
||||
int exception_line;
|
||||
} pyexec_result_t;
|
||||
|
||||
extern pyexec_mode_kind_t pyexec_mode_kind;
|
||||
|
||||
// Set this to the value (eg PYEXEC_FORCED_EXIT) that will be propagated through
|
||||
@ -40,10 +46,11 @@ extern int pyexec_system_exit;
|
||||
|
||||
#define PYEXEC_FORCED_EXIT (0x100)
|
||||
#define PYEXEC_SWITCH_MODE (0x200)
|
||||
#define PYEXEC_EXCEPTION (0x400)
|
||||
|
||||
int pyexec_raw_repl(void);
|
||||
int pyexec_friendly_repl(void);
|
||||
int pyexec_file(const char *filename);
|
||||
int pyexec_file(const char *filename, pyexec_result_t *result);
|
||||
int pyexec_frozen_module(const char *name);
|
||||
void pyexec_event_repl_init(void);
|
||||
int pyexec_event_repl_process_char(int c);
|
||||
|
@ -38,7 +38,7 @@
|
||||
|
||||
void shared_module_bitbangio_spi_construct(bitbangio_spi_obj_t *self,
|
||||
const mcu_pin_obj_t * clock, const mcu_pin_obj_t * mosi,
|
||||
const mcu_pin_obj_t * miso, uint32_t baudrate) {
|
||||
const mcu_pin_obj_t * miso) {
|
||||
digitalinout_result_t result = common_hal_nativeio_digitalinout_construct(&self->clock, clock);
|
||||
if (result != DIGITALINOUT_OK) {
|
||||
nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError,
|
||||
@ -81,7 +81,7 @@ void shared_module_bitbangio_spi_deinit(bitbangio_spi_obj_t *self) {
|
||||
}
|
||||
|
||||
void shared_module_bitbangio_spi_configure(bitbangio_spi_obj_t *self,
|
||||
uint32_t baudrate, uint8_t polarity, uint8_t phase) {
|
||||
uint32_t baudrate, uint8_t polarity, uint8_t phase, uint8_t bits) {
|
||||
self->delay_half = 500000 / baudrate;
|
||||
// round delay_half up so that: actual_baudrate <= requested_baudrate
|
||||
if (500000 % baudrate != 0) {
|
||||
@ -148,14 +148,11 @@ bool shared_module_bitbangio_spi_write(bitbangio_spi_obj_t *self, const uint8_t
|
||||
if (self->phase == 0) {
|
||||
common_hal_mcu_delay_us(delay_half);
|
||||
common_hal_nativeio_digitalinout_set_value(&self->clock, 1 - self->polarity);
|
||||
} else {
|
||||
common_hal_nativeio_digitalinout_set_value(&self->clock, 1 - self->polarity);
|
||||
common_hal_mcu_delay_us(delay_half);
|
||||
}
|
||||
if (self->phase == 0) {
|
||||
common_hal_mcu_delay_us(delay_half);
|
||||
common_hal_nativeio_digitalinout_set_value(&self->clock, self->polarity);
|
||||
} else {
|
||||
common_hal_nativeio_digitalinout_set_value(&self->clock, 1 - self->polarity);
|
||||
common_hal_mcu_delay_us(delay_half);
|
||||
common_hal_nativeio_digitalinout_set_value(&self->clock, self->polarity);
|
||||
common_hal_mcu_delay_us(delay_half);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user