Merge pull request #38 from tannewt/autoreset

atmel-samd: Support auto-reset based on USB write activity.
This commit is contained in:
Scott Shawcroft 2016-10-26 11:12:55 -07:00 committed by GitHub
commit 04284a9fe3
14 changed files with 207 additions and 2 deletions

View File

@ -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 \

View File

@ -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;
}

87
atmel-samd/autoreset.c Normal file
View File

@ -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);
}

39
atmel-samd/autoreset.h Normal file
View File

@ -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__

View File

@ -8,3 +8,5 @@
#define MICROPY_HW_LED_TX PIN_PA27
#define MICROPY_HW_LED_RX PIN_PB03
#define AUTORESET_TIMER TC5

View File

@ -5,3 +5,5 @@
#define MICROPY_HW_BOARD_NAME "Adafruit Feather M0 Adalogger"
#define MICROPY_HW_MCU_NAME "samd21g18"
#define AUTORESET_TIMER TC5

View File

@ -5,3 +5,5 @@
#define MICROPY_HW_BOARD_NAME "Adafruit Feather M0 Basic"
#define MICROPY_HW_MCU_NAME "samd21g18"
#define AUTORESET_TIMER TC5

View File

@ -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

View File

@ -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;

View File

@ -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;
}

View File

@ -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];

View File

@ -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)

View File

@ -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;

View File

@ -34,6 +34,8 @@
#include <stdint.h>
#include <stddef.h>
#include "mpconfig.h"
typedef unsigned char byte;
typedef unsigned int uint;