diff options
| author | Dan Halbert <halbert@halwitz.org> | 2017-11-01 08:17:41 -0400 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2017-11-01 08:17:41 -0400 |
| commit | 0076a3c868b489cf837bfcde72890aefdcb93bed (patch) | |
| tree | 5572e3f865c8d9b70c21955224666733f2681b05 | |
| parent | dc3f13d13f0f07124bd4cca51dededa46246c05b (diff) | |
| parent | f4c82563451fe51d679d159c156926e47181d5db (diff) | |
Merge pull request #393 from tannewt/m4_neopixel
Now with more blinky!!!
| -rw-r--r-- | main.c | 2 | ||||
| -rw-r--r-- | ports/atmel-samd/Makefile | 1 | ||||
| -rw-r--r-- | ports/atmel-samd/boards/circuitplayground_express/board.c | 2 | ||||
| -rw-r--r-- | ports/atmel-samd/boards/metro_m4_express/board.c | 8 | ||||
| -rw-r--r-- | ports/atmel-samd/boards/metro_m4_express/mpconfigboard.h | 2 | ||||
| -rw-r--r-- | ports/atmel-samd/common-hal/neopixel_write/__init__.c | 81 | ||||
| -rw-r--r-- | ports/atmel-samd/mpconfigport.h | 2 | ||||
| -rw-r--r-- | ports/atmel-samd/tick.c | 14 | ||||
| -rw-r--r-- | ports/atmel-samd/tick.h | 5 | ||||
| -rw-r--r-- | ports/atmel-samd/usb_mass_storage.c | 3 | ||||
| -rw-r--r-- | supervisor/shared/rgb_led_status.c | 37 | ||||
| -rw-r--r-- | supervisor/shared/rgb_led_status.h | 8 |
12 files changed, 132 insertions, 33 deletions
@@ -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 diff --git a/ports/atmel-samd/Makefile b/ports/atmel-samd/Makefile index 2dd4802ba..bb5c39e99 100644 --- a/ports/atmel-samd/Makefile +++ b/ports/atmel-samd/Makefile @@ -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 \ diff --git a/ports/atmel-samd/boards/circuitplayground_express/board.c b/ports/atmel-samd/boards/circuitplayground_express/board.c index 4467180c7..eb7ffab4a 100644 --- a/ports/atmel-samd/boards/circuitplayground_express/board.c +++ b/ports/atmel-samd/boards/circuitplayground_express/board.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); } diff --git a/ports/atmel-samd/boards/metro_m4_express/board.c b/ports/atmel-samd/boards/metro_m4_express/board.c index 8096b9b8e..a98385d29 100644 --- a/ports/atmel-samd/boards/metro_m4_express/board.c +++ b/ports/atmel-samd/boards/metro_m4_express/board.c @@ -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) { diff --git a/ports/atmel-samd/boards/metro_m4_express/mpconfigboard.h b/ports/atmel-samd/boards/metro_m4_express/mpconfigboard.h index 27426940d..34a681607 100644 --- a/ports/atmel-samd/boards/metro_m4_express/mpconfigboard.h +++ b/ports/atmel-samd/boards/metro_m4_express/mpconfigboard.h @@ -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) diff --git a/ports/atmel-samd/common-hal/neopixel_write/__init__.c b/ports/atmel-samd/common-hal/neopixel_write/__init__.c index 27dc7d6ad..fbe7a2ff6 100644 --- a/ports/atmel-samd/common-hal/neopixel_write/__init__.c +++ b/ports/atmel-samd/common-hal/neopixel_write/__init__.c @@ -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); } diff --git a/ports/atmel-samd/mpconfigport.h b/ports/atmel-samd/mpconfigport.h index 37840e0ad..88a467c20 100644 --- a/ports/atmel-samd/mpconfigport.h +++ b/ports/atmel-samd/mpconfigport.h @@ -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 }, \ diff --git a/ports/atmel-samd/tick.c b/ports/atmel-samd/tick.c index ecef96992..f5fd57f5d 100644 --- a/ports/atmel-samd/tick.c +++ b/ports/atmel-samd/tick.c @@ -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) {} } diff --git a/ports/atmel-samd/tick.h b/ports/atmel-samd/tick.h index a987ff7ad..80e7bc9af 100644 --- a/ports/atmel-samd/tick.h +++ b/ports/atmel-samd/tick.h @@ -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 diff --git a/ports/atmel-samd/usb_mass_storage.c b/ports/atmel-samd/usb_mass_storage.c index 3e96c3787..c8301228c 100644 --- a/ports/atmel-samd/usb_mass_storage.c +++ b/ports/atmel-samd/usb_mass_storage.c @@ -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; diff --git a/supervisor/shared/rgb_led_status.c b/supervisor/shared/rgb_led_status.c index 15150f18b..0f29b254a 100644 --- a/supervisor/shared/rgb_led_status.c +++ b/supervisor/shared/rgb_led_status.c @@ -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); diff --git a/supervisor/shared/rgb_led_status.h b/supervisor/shared/rgb_led_status.h index 2ea00f4fe..24e071aac 100644 --- a/supervisor/shared/rgb_led_status.h +++ b/supervisor/shared/rgb_led_status.h @@ -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 |
