diff options
| author | Scott Shawcroft <scott@chickadee.tech> | 2016-10-25 14:27:59 -0700 |
|---|---|---|
| committer | Scott Shawcroft <scott@chickadee.tech> | 2016-10-25 18:36:37 -0700 |
| commit | d189a3f3cf1b9aaaccf0996e8846aabe6e70cb4a (patch) | |
| tree | 079bfb21ec2d46e60d22ba5bcca0e6e5f6f94574 | |
| parent | 614c1fdba2aca393e6769221cf8d8b55ee3464fe (diff) | |
atmel-samd: Support auto-reset based on USB write activity.
It will soft-reboot micropython after a burst of writes to the
file system. This means that after you save files on your computer
they will be automatically rerun.
This can be disabled in the build by unsetting AUTORESET_TIMER in
mpconfigboard.h.
Using the REPL will also prevent the soft resets until you reset
with CTRL-D manually.
| -rw-r--r-- | atmel-samd/Makefile | 3 | ||||
| -rw-r--r-- | atmel-samd/access_vfs.c | 4 | ||||
| -rw-r--r-- | atmel-samd/autoreset.c | 87 | ||||
| -rw-r--r-- | atmel-samd/autoreset.h | 39 | ||||
| -rw-r--r-- | atmel-samd/boards/arduino_zero/mpconfigboard.h | 2 | ||||
| -rw-r--r-- | atmel-samd/boards/feather_m0_adalogger/mpconfigboard.h | 2 | ||||
| -rw-r--r-- | atmel-samd/boards/feather_m0_basic/mpconfigboard.h | 2 | ||||
| -rw-r--r-- | atmel-samd/boards/metro_m0_flash/mpconfigboard.h | 2 | ||||
| -rw-r--r-- | atmel-samd/internal_flash.c | 3 | ||||
| -rw-r--r-- | atmel-samd/main.c | 22 | ||||
| -rw-r--r-- | atmel-samd/mphalport.c | 38 | ||||
| -rw-r--r-- | lib/mp-readline/readline.h | 2 | ||||
| -rw-r--r-- | lib/utils/pyexec.c | 1 | ||||
| -rw-r--r-- | py/misc.h | 2 |
14 files changed, 207 insertions, 2 deletions
diff --git a/atmel-samd/Makefile b/atmel-samd/Makefile index fbdfa3f93..2cd917beb 100644 --- a/atmel-samd/Makefile +++ b/atmel-samd/Makefile @@ -101,6 +101,7 @@ CFLAGS_CORTEX_M0 = \ -DEXTINT_CALLBACK_MODE=true \ -DUDD_ENABLE \ -DUSART_CALLBACK_MODE=true \ + -DTC_ASYNC=true \ -DUSB_DEVICE_LPM_SUPPORT CFLAGS = $(INC) -Wall -Werror -ansi -std=gnu99 -nostdlib $(CFLAGS_CORTEX_M0) $(COPT) @@ -135,6 +136,7 @@ SRC_ASF = $(addprefix asf/sam0/,\ drivers/system/interrupt/system_interrupt.c \ drivers/system/pinmux/pinmux.c \ drivers/system/system.c \ + drivers/tc/tc_interrupt.c \ drivers/tc/tc_sam_d_r/tc.c \ drivers/tcc/tcc.c \ drivers/usb/stack_interface/usb_device_udd.c \ @@ -144,6 +146,7 @@ SRC_ASF = $(addprefix asf/sam0/,\ SRC_C = \ access_vfs.c \ + autoreset.c \ builtin_open.c \ fatfs_port.c \ main.c \ diff --git a/atmel-samd/access_vfs.c b/atmel-samd/access_vfs.c index cfd5dfe54..a8cb33e9c 100644 --- a/atmel-samd/access_vfs.c +++ b/atmel-samd/access_vfs.c @@ -27,11 +27,13 @@ #include <string.h> #include "access_vfs.h" +#include "autoreset.h" #include "asf/common/services/usb/class/msc/device/udi_msc.h" #include "extmod/fsusermount.h" #include "lib/fatfs/diskio.h" #include "py/mpconfig.h" +#include "py/mphal.h" #include "py/mpstate.h" #include "py/misc.h" @@ -140,7 +142,6 @@ Ctrl_status vfs_usb_read_10(uint32_t addr, volatile uint16_t nb_sector) return CTRL_GOOD; } - //! This function transfers the USB MSC data to the memory //! //! @param addr Sector address to start write @@ -183,5 +184,6 @@ Ctrl_status vfs_usb_write_10(uint32_t addr, volatile uint16_t nb_sector) } } } + autoreset_start(); return CTRL_GOOD; } diff --git a/atmel-samd/autoreset.c b/atmel-samd/autoreset.c new file mode 100644 index 000000000..ef7ca62a5 --- /dev/null +++ b/atmel-samd/autoreset.c @@ -0,0 +1,87 @@ +/* + * This file is part of the Micro Python project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2016 Scott Shawcroft for Adafruit Industries + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "autoreset.h" + +#include "asf/sam0/drivers/tc/tc_interrupt.h" +#include "lib/mp-readline/readline.h" +#include "py/mphal.h" + +struct tc_module autoreset_timer; + +static bool autoreset_initialized = false; + +static bool autoreset_enabled = false; + +extern void inject_character(char); +void mp_keyboard_interrupt(void); + +void autoreset_callback(struct tc_module *const module_inst) { + if (autoreset_enabled) { + mp_keyboard_interrupt(); + inject_character(CHAR_CTRL_D); + } + + tc_stop_counter(&autoreset_timer); +} + +void autoreset_init() { + #ifdef AUTORESET_TIMER + struct tc_config config_tc; + tc_get_config_defaults(&config_tc); + config_tc.counter_size = TC_COUNTER_SIZE_16BIT; + config_tc.clock_prescaler = TC_CLOCK_PRESCALER_DIV256; + config_tc.counter_16_bit.compare_capture_channel[0] = 0xFFFF; + tc_init(&autoreset_timer, AUTORESET_TIMER, &config_tc); + tc_enable(&autoreset_timer); + tc_register_callback(&autoreset_timer, autoreset_callback, TC_CALLBACK_CC_CHANNEL0); + tc_enable_callback(&autoreset_timer, TC_CALLBACK_CC_CHANNEL0); + tc_stop_counter(&autoreset_timer); + + autoreset_initialized = true; + #endif +} + +void autoreset_enable() { + autoreset_enabled = true; +} + +void autoreset_disable() { + autoreset_enabled = false; +} + +void autoreset_start() { + if (!autoreset_initialized) return; + + tc_stop_counter(&autoreset_timer); + tc_start_counter(&autoreset_timer); +} + +void autoreset_stop() { + if (!autoreset_initialized) return; + + tc_stop_counter(&autoreset_timer); +} diff --git a/atmel-samd/autoreset.h b/atmel-samd/autoreset.h new file mode 100644 index 000000000..da9803fde --- /dev/null +++ b/atmel-samd/autoreset.h @@ -0,0 +1,39 @@ +/* + * This file is part of the Micro Python project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2016 Scott Shawcroft for Adafruit Industries + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#ifndef __MICROPY_INCLUDED_ATMEL_SAMD_AUTORESET_H__ +#define __MICROPY_INCLUDED_ATMEL_SAMD_AUTORESET_H__ + +#include "asf/sam0/drivers/tc/tc.h" + +void autoreset_callback(struct tc_module *const module_inst); +void autoreset_init(); +void autoreset_start(); +void autoreset_stop(); +void autoreset_enable(); +void autoreset_disable(); + +#endif // __MICROPY_INCLUDED_ATMEL_SAMD_AUTORESET_H__ diff --git a/atmel-samd/boards/arduino_zero/mpconfigboard.h b/atmel-samd/boards/arduino_zero/mpconfigboard.h index fbebaed2d..42b4e7635 100644 --- a/atmel-samd/boards/arduino_zero/mpconfigboard.h +++ b/atmel-samd/boards/arduino_zero/mpconfigboard.h @@ -8,3 +8,5 @@ #define MICROPY_HW_LED_TX PIN_PA27 #define MICROPY_HW_LED_RX PIN_PB03 + +#define AUTORESET_TIMER TC5 diff --git a/atmel-samd/boards/feather_m0_adalogger/mpconfigboard.h b/atmel-samd/boards/feather_m0_adalogger/mpconfigboard.h index f820ce4a5..8af47af1e 100644 --- a/atmel-samd/boards/feather_m0_adalogger/mpconfigboard.h +++ b/atmel-samd/boards/feather_m0_adalogger/mpconfigboard.h @@ -5,3 +5,5 @@ #define MICROPY_HW_BOARD_NAME "Adafruit Feather M0 Adalogger" #define MICROPY_HW_MCU_NAME "samd21g18" + +#define AUTORESET_TIMER TC5 diff --git a/atmel-samd/boards/feather_m0_basic/mpconfigboard.h b/atmel-samd/boards/feather_m0_basic/mpconfigboard.h index a5b3ef063..29027c0b8 100644 --- a/atmel-samd/boards/feather_m0_basic/mpconfigboard.h +++ b/atmel-samd/boards/feather_m0_basic/mpconfigboard.h @@ -5,3 +5,5 @@ #define MICROPY_HW_BOARD_NAME "Adafruit Feather M0 Basic" #define MICROPY_HW_MCU_NAME "samd21g18" + +#define AUTORESET_TIMER TC5 diff --git a/atmel-samd/boards/metro_m0_flash/mpconfigboard.h b/atmel-samd/boards/metro_m0_flash/mpconfigboard.h index a4e1e3fc5..3cbd0a641 100644 --- a/atmel-samd/boards/metro_m0_flash/mpconfigboard.h +++ b/atmel-samd/boards/metro_m0_flash/mpconfigboard.h @@ -29,3 +29,5 @@ #define SPI_FLASH_PAD3_PINMUX PINMUX_PB11D_SERCOM4_PAD3 // SCK #define SPI_FLASH_CS PIN_PA13 #define SPI_FLASH_SERCOM SERCOM4 + +#define AUTORESET_TIMER TC5 diff --git a/atmel-samd/internal_flash.c b/atmel-samd/internal_flash.c index 68a3100c5..1bbbd23e8 100644 --- a/atmel-samd/internal_flash.c +++ b/atmel-samd/internal_flash.c @@ -27,6 +27,7 @@ #include <stdint.h> #include <string.h> +#include "py/mphal.h" #include "py/obj.h" #include "py/runtime.h" #include "lib/fatfs/ff.h" @@ -40,7 +41,7 @@ #define TOTAL_INTERNAL_FLASH_SIZE 0x010000 #define INTERNAL_FLASH_MEM_SEG1_START_ADDR (0x00040000 - TOTAL_INTERNAL_FLASH_SIZE) -#define INTERNAL_FLASH_PART1_START_BLOCK (0x100) +#define INTERNAL_FLASH_PART1_START_BLOCK (0x1) #define INTERNAL_FLASH_PART1_NUM_BLOCKS (TOTAL_INTERNAL_FLASH_SIZE / INTERNAL_FLASH_BLOCK_SIZE) static bool internal_flash_is_initialised = false; diff --git a/atmel-samd/main.c b/atmel-samd/main.c index df259d9c4..2a0dff851 100644 --- a/atmel-samd/main.c +++ b/atmel-samd/main.c @@ -22,6 +22,7 @@ #include "asf/sam0/drivers/system/system.h" #include <board.h> +#include "autoreset.h" #include "mpconfigboard.h" #include "modmachine_pin.h" @@ -172,6 +173,9 @@ static char *stack_top; static char heap[16384]; void reset_mp() { + autoreset_stop(); + autoreset_enable(); + // Sync the file systems in case any used RAM from the GC to cache. As soon // as we re-init the GC all bets are off on the cache. disk_ioctl(0, CTRL_SYNC, NULL); @@ -191,8 +195,18 @@ void reset_mp() { MP_STATE_PORT(mp_kbd_exception) = mp_obj_new_exception(&mp_type_KeyboardInterrupt); pin_init0(); +} + +void start_mp() { + #ifdef AUTORESET_TIMER + 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 + mp_hal_stdout_tx_str("boot.py output:\r\n"); pyexec_file("boot.py"); + mp_hal_stdout_tx_str("\r\nmain.py output:\r\n"); pyexec_file("main.py"); } @@ -216,11 +230,18 @@ int main(int argc, char **argv) { // as current dir. init_flash_fs(); + // Initialize the autoreset timer. It will automatically reset the repl + // after a burst of writes to the FS. + autoreset_init(); + // Start USB after getting everything going. #ifdef USB_REPL 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; @@ -233,6 +254,7 @@ int main(int argc, char **argv) { if (exit_code == PYEXEC_FORCED_EXIT) { mp_hal_stdout_tx_str("soft reboot\r\n"); reset_mp(); + start_mp(); } else if (exit_code != 0) { break; } diff --git a/atmel-samd/mphalport.c b/atmel-samd/mphalport.c index 7102bf220..c84640fd5 100644 --- a/atmel-samd/mphalport.c +++ b/atmel-samd/mphalport.c @@ -1,5 +1,6 @@ #include <string.h> +#include "autoreset.h" #include "compiler.h" #include "asf/common/services/sleepmgr/sleepmgr.h" #include "asf/common/services/usb/class/cdc/device/udi_cdc.h" @@ -67,6 +68,40 @@ void usb_rts_notify(uint8_t port, bool set) { return; } +void inject_character(char c) { + // Introduce a critical section to avoid buffer corruption. We use + // cpu_irq_save instead of cpu_irq_disable because we don't know the + // current state of IRQs. They may have been turned off already and + // we don't want to accidentally turn them back on. + irqflags_t flags = cpu_irq_save(); + // If our buffer is full, then don't get another character otherwise + // we'll lose a previous character. + if (usb_rx_count >= USB_RX_BUF_SIZE) { + cpu_irq_restore(flags); + return; + } + + uint8_t current_tail = usb_rx_buf_tail; + // Pretend we've received a character so that any nested calls to + // this function have to consider the spot we've reserved. + if ((USB_RX_BUF_SIZE - 1) == usb_rx_buf_tail) { + // Reached the end of buffer, revert back to beginning of + // buffer. + usb_rx_buf_tail = 0x00; + } else { + usb_rx_buf_tail++; + } + // The count of characters present in receive buffer is + // incremented. + usb_rx_count++; + + // We put the next character where we expected regardless of whether + // the next character was already loaded in the buffer. + usb_rx_buf[current_tail] = c; + + cpu_irq_restore(flags); +} + void usb_rx_notify(void) { irqflags_t flags; @@ -129,6 +164,9 @@ int receive_usb() { return 0; } + // Disable autoreset if someone is using the repl. + autoreset_disable(); + // Copy from head. cpu_irq_disable(); int data = usb_rx_buf[usb_rx_buf_head]; diff --git a/lib/mp-readline/readline.h b/lib/mp-readline/readline.h index f73934d23..ffb0d0e1c 100644 --- a/lib/mp-readline/readline.h +++ b/lib/mp-readline/readline.h @@ -24,6 +24,8 @@ * THE SOFTWARE. */ +#include "py/misc.h" + #define CHAR_CTRL_A (1) #define CHAR_CTRL_B (2) #define CHAR_CTRL_C (3) diff --git a/lib/utils/pyexec.c b/lib/utils/pyexec.c index f9bbf68a1..ce68e40b3 100644 --- a/lib/utils/pyexec.c +++ b/lib/utils/pyexec.c @@ -226,6 +226,7 @@ STATIC int pyexec_friendly_repl_process_char(int c) { } else if (ret == CHAR_CTRL_B) { // reset friendly REPL mp_hal_stdout_tx_str("\r\n"); + mp_hal_stdout_tx_str("\r\n"); 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("Type \"help()\" for more information.\r\n"); goto input_restart; @@ -34,6 +34,8 @@ #include <stdint.h> #include <stddef.h> +#include "mpconfig.h" + typedef unsigned char byte; typedef unsigned int uint; |
