Merge pull request #474 from tannewt/mcu_reset

Introduce reset mechanics to microcontroller.
This commit is contained in:
Dan Halbert 2017-12-05 19:20:26 -05:00 committed by GitHub
commit 3c49f53eac
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
25 changed files with 308 additions and 52 deletions

View File

@ -123,6 +123,7 @@ CFLAGS_CORTEX_M0 = \
-DI2S_CALLBACK_MODE=false \ -DI2S_CALLBACK_MODE=false \
-DTC_ASYNC=true \ -DTC_ASYNC=true \
-DUSB_DEVICE_LPM_SUPPORT \ -DUSB_DEVICE_LPM_SUPPORT \
-DCIRCUITPY_SOFTWARE_SAFE_MODE=0x0ADABEEF \
-DCIRCUITPY_CANARY_WORD=0xADAF00 \ -DCIRCUITPY_CANARY_WORD=0xADAF00 \
-DCIRCUITPY_SAFE_RESTART_WORD=0xDEADBEEF \ -DCIRCUITPY_SAFE_RESTART_WORD=0xDEADBEEF \
--param max-inline-insns-single=500 --param max-inline-insns-single=500
@ -315,6 +316,7 @@ SRC_BINDINGS_ENUMS = \
digitalio/Direction.c \ digitalio/Direction.c \
digitalio/DriveMode.c \ digitalio/DriveMode.c \
digitalio/Pull.c \ digitalio/Pull.c \
microcontroller/RunMode.c \
help.c \ help.c \
util.c util.c

View File

@ -11,7 +11,8 @@ MEMORY
} }
/* top end of the stack */ /* top end of the stack */
_estack = ORIGIN(RAM) + LENGTH(RAM); _estack = ORIGIN(RAM) + LENGTH(RAM) - 4;
_bootloader_dbl_tap = _estack;
/* define output sections */ /* define output sections */
SECTIONS SECTIONS

View File

@ -11,7 +11,8 @@ MEMORY
} }
/* top end of the stack */ /* top end of the stack */
_estack = ORIGIN(RAM) + LENGTH(RAM); _estack = ORIGIN(RAM) + LENGTH(RAM) - 4;
_bootloader_dbl_tap = _estack;
/* define output sections */ /* define output sections */
SECTIONS SECTIONS

View File

@ -10,7 +10,8 @@ MEMORY
} }
/* top end of the stack */ /* top end of the stack */
_estack = ORIGIN(RAM) + LENGTH(RAM); _estack = ORIGIN(RAM) + LENGTH(RAM) - 4;
_bootloader_dbl_tap = _estack;
/* define output sections */ /* define output sections */
SECTIONS SECTIONS

View File

@ -11,7 +11,8 @@ MEMORY
} }
/* top end of the stack */ /* top end of the stack */
_estack = ORIGIN(RAM) + LENGTH(RAM); _estack = ORIGIN(RAM) + LENGTH(RAM) - 4;
_bootloader_dbl_tap = _estack;
/* define output sections */ /* define output sections */
SECTIONS SECTIONS

View File

@ -12,6 +12,7 @@ MEMORY
/* top end of the stack */ /* top end of the stack */
_estack = ORIGIN(RAM) + LENGTH(RAM); _estack = ORIGIN(RAM) + LENGTH(RAM);
_bootloader_dbl_tap = 0;
/* define output sections */ /* define output sections */
SECTIONS SECTIONS

View File

@ -12,6 +12,7 @@ MEMORY
/* top end of the stack */ /* top end of the stack */
_estack = ORIGIN(RAM) + LENGTH(RAM); _estack = ORIGIN(RAM) + LENGTH(RAM);
_bootloader_dbl_tap = 0;
/* define output sections */ /* define output sections */
SECTIONS SECTIONS

View File

@ -64,7 +64,7 @@ void common_hal_digitalio_digitalinout_deinit(digitalio_digitalinout_obj_t* self
} }
void common_hal_digitalio_digitalinout_switch_to_input( void common_hal_digitalio_digitalinout_switch_to_input(
digitalio_digitalinout_obj_t* self, enum digitalio_pull_t pull) { digitalio_digitalinout_obj_t* self, digitalio_pull_t pull) {
self->output = false; self->output = false;
common_hal_digitalio_digitalinout_set_pull(self, pull); common_hal_digitalio_digitalinout_set_pull(self, pull);
@ -72,7 +72,7 @@ void common_hal_digitalio_digitalinout_switch_to_input(
void common_hal_digitalio_digitalinout_switch_to_output( void common_hal_digitalio_digitalinout_switch_to_output(
digitalio_digitalinout_obj_t* self, bool value, digitalio_digitalinout_obj_t* self, bool value,
enum digitalio_drive_mode_t drive_mode) { digitalio_drive_mode_t drive_mode) {
struct port_config pin_conf; struct port_config pin_conf;
port_get_config_defaults(&pin_conf); port_get_config_defaults(&pin_conf);
@ -88,7 +88,7 @@ void common_hal_digitalio_digitalinout_switch_to_output(
common_hal_digitalio_digitalinout_set_value(self, value); common_hal_digitalio_digitalinout_set_value(self, value);
} }
enum digitalio_direction_t common_hal_digitalio_digitalinout_get_direction( digitalio_direction_t common_hal_digitalio_digitalinout_get_direction(
digitalio_digitalinout_obj_t* self) { digitalio_digitalinout_obj_t* self) {
return self->output? DIRECTION_OUTPUT : DIRECTION_INPUT; return self->output? DIRECTION_OUTPUT : DIRECTION_INPUT;
} }
@ -131,7 +131,7 @@ bool common_hal_digitalio_digitalinout_get_value(
void common_hal_digitalio_digitalinout_set_drive_mode( void common_hal_digitalio_digitalinout_set_drive_mode(
digitalio_digitalinout_obj_t* self, digitalio_digitalinout_obj_t* self,
enum digitalio_drive_mode_t drive_mode) { digitalio_drive_mode_t drive_mode) {
bool value = common_hal_digitalio_digitalinout_get_value(self); bool value = common_hal_digitalio_digitalinout_get_value(self);
self->open_drain = drive_mode == DRIVE_MODE_OPEN_DRAIN; self->open_drain = drive_mode == DRIVE_MODE_OPEN_DRAIN;
// True is implemented differently between modes so reset the value to make // True is implemented differently between modes so reset the value to make
@ -141,7 +141,7 @@ void common_hal_digitalio_digitalinout_set_drive_mode(
} }
} }
enum digitalio_drive_mode_t common_hal_digitalio_digitalinout_get_drive_mode( digitalio_drive_mode_t common_hal_digitalio_digitalinout_get_drive_mode(
digitalio_digitalinout_obj_t* self) { digitalio_digitalinout_obj_t* self) {
if (self->open_drain) { if (self->open_drain) {
return DRIVE_MODE_OPEN_DRAIN; return DRIVE_MODE_OPEN_DRAIN;
@ -151,7 +151,7 @@ enum digitalio_drive_mode_t common_hal_digitalio_digitalinout_get_drive_mode(
} }
void common_hal_digitalio_digitalinout_set_pull( void common_hal_digitalio_digitalinout_set_pull(
digitalio_digitalinout_obj_t* self, enum digitalio_pull_t pull) { digitalio_digitalinout_obj_t* self, digitalio_pull_t pull) {
enum port_pin_pull asf_pull = PORT_PIN_PULL_NONE; enum port_pin_pull asf_pull = PORT_PIN_PULL_NONE;
switch (pull) { switch (pull) {
case PULL_UP: case PULL_UP:
@ -172,7 +172,7 @@ void common_hal_digitalio_digitalinout_set_pull(
port_pin_set_config(self->pin->pin, &pin_conf); port_pin_set_config(self->pin->pin, &pin_conf);
} }
enum digitalio_pull_t common_hal_digitalio_digitalinout_get_pull( digitalio_pull_t common_hal_digitalio_digitalinout_get_pull(
digitalio_digitalinout_obj_t* self) { digitalio_digitalinout_obj_t* self) {
uint32_t pin = self->pin->pin; uint32_t pin = self->pin->pin;
PortGroup *const port_base = port_get_group_from_gpio_pin(pin); PortGroup *const port_base = port_get_group_from_gpio_pin(pin);

View File

@ -26,10 +26,13 @@
#include "py/mphal.h" #include "py/mphal.h"
#include "py/obj.h" #include "py/obj.h"
#include "py/runtime.h"
#include "reset.h"
#include "samd21_pins.h" #include "samd21_pins.h"
#include "shared-bindings/nvm/ByteArray.h" #include "shared-bindings/nvm/ByteArray.h"
#include "shared-bindings/microcontroller/__init__.h"
#include "shared-bindings/microcontroller/Processor.h" #include "shared-bindings/microcontroller/Processor.h"
void common_hal_mcu_delay_us(uint32_t delay) { void common_hal_mcu_delay_us(uint32_t delay) {
@ -51,9 +54,33 @@ void common_hal_mcu_enable_interrupts(void) {
cpu_irq_restore(irq_flags); cpu_irq_restore(irq_flags);
} }
extern uint32_t _ezero;
extern uint32_t _srelocate;
void common_hal_mcu_on_next_reset(mcu_runmode_t runmode) {
// Set up the defaults.
_bootloader_dbl_tap = DBL_TAP_MAGIC;
_ezero = CIRCUITPY_CANARY_WORD;
if (runmode == RUNMODE_BOOTLOADER) {
if (&_bootloader_dbl_tap < &_srelocate) {
mp_raise_ValueError("Cannot reset into bootloader because no bootloader is present.");
}
// Pretend to be the first of the two reset presses needed to enter the
// bootloader. That way one reset will end in the bootloader.
_bootloader_dbl_tap = DBL_TAP_MAGIC;
} else if (runmode == RUNMODE_SAFE_MODE) {
_ezero = CIRCUITPY_SOFTWARE_SAFE_MODE;
}
}
void common_hal_mcu_reset(void) {
reset();
}
// The singleton microcontroller.Processor object, bound to microcontroller.cpu // The singleton microcontroller.Processor object, bound to microcontroller.cpu
// It currently only has properties, and no state. // It currently only has properties, and no state.
mcu_processor_obj_t common_hal_mcu_processor_obj = { const mcu_processor_obj_t common_hal_mcu_processor_obj = {
.base = { .base = {
.type = &mcu_processor_type, .type = &mcu_processor_type,
}, },
@ -62,7 +89,7 @@ mcu_processor_obj_t common_hal_mcu_processor_obj = {
// NVM is only available on Express boards for now. // NVM is only available on Express boards for now.
#if CIRCUITPY_INTERNAL_NVM_SIZE > 0 #if CIRCUITPY_INTERNAL_NVM_SIZE > 0
// The singleton nvm.ByteArray object. // The singleton nvm.ByteArray object.
nvm_bytearray_obj_t common_hal_mcu_nvm_obj = { const nvm_bytearray_obj_t common_hal_mcu_nvm_obj = {
.base = { .base = {
.type = &nvm_bytearray_type, .type = &nvm_bytearray_type,
}, },

View File

@ -84,6 +84,7 @@ typedef enum {
BROWNOUT, BROWNOUT,
HARD_CRASH, HARD_CRASH,
USER_SAFE_MODE, USER_SAFE_MODE,
SOFTWARE_SAFE_MODE
} safe_mode_t; } safe_mode_t;
void do_str(const char *src, mp_parse_input_kind_t input_kind) { void do_str(const char *src, mp_parse_input_kind_t input_kind) {
@ -375,7 +376,10 @@ bool start_mp(safe_mode_t safe_mode) {
mp_hal_stdout_tx_str(".\r\n"); mp_hal_stdout_tx_str(".\r\n");
} else } else
#endif #endif
if (safe_mode != NO_SAFE_MODE) { if (safe_mode == SOFTWARE_SAFE_MODE) {
mp_hal_stdout_tx_str("\r\nYou requested starting in safe mode from your software.");
mp_hal_stdout_tx_str(".\r\nTo exit, please reset the board.\r\n");
} else if (safe_mode != NO_SAFE_MODE) {
mp_hal_stdout_tx_str("\r\nYou are running in safe mode which means something really bad happened.\r\n"); mp_hal_stdout_tx_str("\r\nYou are running in safe mode which means something really bad happened.\r\n");
if (safe_mode == HARD_CRASH) { if (safe_mode == HARD_CRASH) {
mp_hal_stdout_tx_str("Looks like our core CircuitPython code crashed hard. Whoops!\r\n"); mp_hal_stdout_tx_str("Looks like our core CircuitPython code crashed hard. Whoops!\r\n");
@ -524,10 +528,14 @@ safe_mode_t samd21_init(void) {
REG_MTB_MASTER = 0x00000000 + 6; REG_MTB_MASTER = 0x00000000 + 6;
#endif #endif
// CIRCUITPY_SOFTWARE_SAFE_MODE works just like the canary except if it
// survives we enter safe mode with a friendlier message.
bool software_safe_mode = _ezero == CIRCUITPY_SOFTWARE_SAFE_MODE;
// On power on start or external reset, set _ezero to the canary word. If it // On power on start or external reset, set _ezero to the canary word. If it
// gets killed, we boot in safe mod. _ezero is the boundary between statically // gets killed, we boot in safe mode. _ezero is the boundary between statically
// allocated memory including the fixed MicroPython heap and the stack. If either // allocated memory including the fixed MicroPython heap and the stack. If
// misbehaves, the canary will not be in tact after soft reset. // either misbehaves, the canary will not be intact after soft reset.
#ifdef CIRCUITPY_CANARY_WORD #ifdef CIRCUITPY_CANARY_WORD
if (PM->RCAUSE.bit.POR == 1 || PM->RCAUSE.bit.EXT == 1) { if (PM->RCAUSE.bit.POR == 1 || PM->RCAUSE.bit.EXT == 1) {
_ezero = CIRCUITPY_CANARY_WORD; _ezero = CIRCUITPY_CANARY_WORD;
@ -607,6 +615,10 @@ safe_mode_t samd21_init(void) {
return USER_SAFE_MODE; return USER_SAFE_MODE;
} }
if (software_safe_mode) {
return SOFTWARE_SAFE_MODE;
}
#if CIRCUITPY_INTERNAL_NVM_SIZE > 0 #if CIRCUITPY_INTERNAL_NVM_SIZE > 0
// Upgrade the nvm flash to include one sector for eeprom emulation. // Upgrade the nvm flash to include one sector for eeprom emulation.
struct nvm_fusebits fuses; struct nvm_fusebits fuses;

View File

@ -62,7 +62,7 @@ volatile bool reset_on_disconnect = false;
void usb_dtr_notify(uint8_t port, bool set) { void usb_dtr_notify(uint8_t port, bool set) {
mp_cdc_enabled = set; mp_cdc_enabled = set;
if (!set && reset_on_disconnect) { if (!set && reset_on_disconnect && _bootloader_dbl_tap != 0) {
reset_to_bootloader(); reset_to_bootloader();
} }
} }

View File

@ -29,12 +29,12 @@
#include "asf/sam0/utils/cmsis/samd21/include/samd21.h" #include "asf/sam0/utils/cmsis/samd21/include/samd21.h"
// Copied from inc/uf2.h in https://github.com/Microsoft/uf2-samd21 void reset(void) {
#define DBL_TAP_PTR ((volatile uint32_t *)(HMCRAMC0_ADDR + HMCRAMC0_SIZE - 4))
#define DBL_TAP_MAGIC 0xf01669ef // Randomly selected, adjusted to have first and last bit set
void reset_to_bootloader(void) {
flash_flush(); flash_flush();
*DBL_TAP_PTR = DBL_TAP_MAGIC;
NVIC_SystemReset(); NVIC_SystemReset();
} }
void reset_to_bootloader(void) {
_bootloader_dbl_tap = DBL_TAP_MAGIC;
reset();
}

View File

@ -26,6 +26,12 @@
#ifndef MICROPY_INCLUDED_ATMEL_SAMD_RESET_H #ifndef MICROPY_INCLUDED_ATMEL_SAMD_RESET_H
#define MICROPY_INCLUDED_ATMEL_SAMD_RESET_H #define MICROPY_INCLUDED_ATMEL_SAMD_RESET_H
// Copied from inc/uf2.h in https://github.com/Microsoft/uf2-samd21
#define DBL_TAP_MAGIC 0xf01669ef // Randomly selected, adjusted to have first and last bit set
extern uint32_t _bootloader_dbl_tap;
void reset_to_bootloader(void); void reset_to_bootloader(void);
void reset(void);
#endif // MICROPY_INCLUDED_ATMEL_SAMD_RESET_H #endif // MICROPY_INCLUDED_ATMEL_SAMD_RESET_H

View File

@ -128,6 +128,7 @@ SRC_BINDINGS_ENUMS = \
digitalio/Direction.c \ digitalio/Direction.c \
digitalio/DriveMode.c \ digitalio/DriveMode.c \
digitalio/Pull.c \ digitalio/Pull.c \
microcontroller/RunMode.c \
util.c util.c
SRC_COMMON_HAL_EXPANDED = $(addprefix shared-bindings/, $(SRC_COMMON_HAL)) \ SRC_COMMON_HAL_EXPANDED = $(addprefix shared-bindings/, $(SRC_COMMON_HAL)) \

View File

@ -59,7 +59,7 @@ void common_hal_digitalio_digitalinout_deinit(digitalio_digitalinout_obj_t* self
} }
void common_hal_digitalio_digitalinout_switch_to_input( void common_hal_digitalio_digitalinout_switch_to_input(
digitalio_digitalinout_obj_t* self, enum digitalio_pull_t pull) { digitalio_digitalinout_obj_t* self, digitalio_pull_t pull) {
self->output = false; self->output = false;
if (self->pin->gpio_number == 16) { if (self->pin->gpio_number == 16) {
@ -75,7 +75,7 @@ void common_hal_digitalio_digitalinout_switch_to_input(
void common_hal_digitalio_digitalinout_switch_to_output( void common_hal_digitalio_digitalinout_switch_to_output(
digitalio_digitalinout_obj_t* self, bool value, digitalio_digitalinout_obj_t* self, bool value,
enum digitalio_drive_mode_t drive_mode) { digitalio_drive_mode_t drive_mode) {
self->output = true; self->output = true;
self->open_drain = drive_mode == DRIVE_MODE_OPEN_DRAIN; self->open_drain = drive_mode == DRIVE_MODE_OPEN_DRAIN;
if (self->pin->gpio_number == 16) { if (self->pin->gpio_number == 16) {
@ -89,7 +89,7 @@ void common_hal_digitalio_digitalinout_switch_to_output(
common_hal_digitalio_digitalinout_set_value(self, value); common_hal_digitalio_digitalinout_set_value(self, value);
} }
enum digitalio_direction_t common_hal_digitalio_digitalinout_get_direction( digitalio_direction_t common_hal_digitalio_digitalinout_get_direction(
digitalio_digitalinout_obj_t* self) { digitalio_digitalinout_obj_t* self) {
return self->output? DIRECTION_OUTPUT : DIRECTION_INPUT; return self->output? DIRECTION_OUTPUT : DIRECTION_INPUT;
} }
@ -136,7 +136,7 @@ bool common_hal_digitalio_digitalinout_get_value(
void common_hal_digitalio_digitalinout_set_drive_mode( void common_hal_digitalio_digitalinout_set_drive_mode(
digitalio_digitalinout_obj_t* self, digitalio_digitalinout_obj_t* self,
enum digitalio_drive_mode_t drive_mode) { digitalio_drive_mode_t drive_mode) {
bool value = common_hal_digitalio_digitalinout_get_value(self); bool value = common_hal_digitalio_digitalinout_get_value(self);
self->open_drain = drive_mode == DRIVE_MODE_OPEN_DRAIN; self->open_drain = drive_mode == DRIVE_MODE_OPEN_DRAIN;
// True is implemented differently between modes so reset the value to make // True is implemented differently between modes so reset the value to make
@ -146,7 +146,7 @@ void common_hal_digitalio_digitalinout_set_drive_mode(
} }
} }
enum digitalio_drive_mode_t common_hal_digitalio_digitalinout_get_drive_mode( digitalio_drive_mode_t common_hal_digitalio_digitalinout_get_drive_mode(
digitalio_digitalinout_obj_t* self) { digitalio_digitalinout_obj_t* self) {
if (self->open_drain) { if (self->open_drain) {
return DRIVE_MODE_OPEN_DRAIN; return DRIVE_MODE_OPEN_DRAIN;
@ -156,7 +156,7 @@ enum digitalio_drive_mode_t common_hal_digitalio_digitalinout_get_drive_mode(
} }
void common_hal_digitalio_digitalinout_set_pull( void common_hal_digitalio_digitalinout_set_pull(
digitalio_digitalinout_obj_t* self, enum digitalio_pull_t pull) { digitalio_digitalinout_obj_t* self, digitalio_pull_t pull) {
if (pull == PULL_DOWN) { if (pull == PULL_DOWN) {
nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError,
"ESP8266 does not support pull down.")); "ESP8266 does not support pull down."));
@ -174,7 +174,7 @@ void common_hal_digitalio_digitalinout_set_pull(
} }
} }
enum digitalio_pull_t common_hal_digitalio_digitalinout_get_pull( digitalio_pull_t common_hal_digitalio_digitalinout_get_pull(
digitalio_digitalinout_obj_t* self) { digitalio_digitalinout_obj_t* self) {
if (self->pin->gpio_number < 16 && if (self->pin->gpio_number < 16 &&
(READ_PERI_REG(self->pin->peripheral) & PERIPHS_IO_MUX_PULLUP) != 0) { (READ_PERI_REG(self->pin->peripheral) & PERIPHS_IO_MUX_PULLUP) != 0) {

View File

@ -24,9 +24,12 @@
* THE SOFTWARE. * THE SOFTWARE.
*/ */
#include "py/runtime.h"
#include "common-hal/microcontroller/Pin.h" #include "common-hal/microcontroller/Pin.h"
#include "common-hal/microcontroller/Processor.h" #include "common-hal/microcontroller/Processor.h"
#include "shared-bindings/microcontroller/__init__.h"
#include "shared-bindings/microcontroller/Pin.h" #include "shared-bindings/microcontroller/Pin.h"
#include "shared-bindings/microcontroller/Processor.h" #include "shared-bindings/microcontroller/Processor.h"
@ -34,6 +37,7 @@
#include "ets_alt_task.h" #include "ets_alt_task.h"
#include "etshal.h" #include "etshal.h"
#include "osapi.h" #include "osapi.h"
#include "user_interface.h"
#include "xtirq.h" #include "xtirq.h"
#define ETS_LOOP_ITER_BIT (12) #define ETS_LOOP_ITER_BIT (12)
@ -54,9 +58,21 @@ void common_hal_mcu_enable_interrupts() {
enable_irq(saved_interrupt_state & ~(1 << ETS_LOOP_ITER_BIT)); enable_irq(saved_interrupt_state & ~(1 << ETS_LOOP_ITER_BIT));
} }
void common_hal_mcu_on_next_reset(mcu_runmode_t runmode) {
if (runmode == RUNMODE_BOOTLOADER) {
mp_raise_ValueError("Cannot reset into bootloader because no bootloader is present.");
} else if (runmode == RUNMODE_SAFE_MODE) {
mp_raise_ValueError("ESP8226 does not support safe mode.");
}
}
void common_hal_mcu_reset(void) {
system_restart();
}
// The singleton microcontroller.Processor object, returned by microcontroller.cpu // The singleton microcontroller.Processor object, returned by microcontroller.cpu
// It currently only has properties, and no state. // It currently only has properties, and no state.
mcu_processor_obj_t common_hal_mcu_processor_obj = { const mcu_processor_obj_t common_hal_mcu_processor_obj = {
.base = { .base = {
.type = &mcu_processor_type, .type = &mcu_processor_type,
}, },

View File

@ -124,7 +124,7 @@ STATIC mp_obj_t digitalio_digitalinout_switch_to_output(size_t n_args, const mp_
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
enum digitalio_drive_mode_t drive_mode = DRIVE_MODE_PUSH_PULL; digitalio_drive_mode_t drive_mode = DRIVE_MODE_PUSH_PULL;
if (args[ARG_drive_mode].u_rom_obj == &digitalio_drive_mode_open_drain_obj) { if (args[ARG_drive_mode].u_rom_obj == &digitalio_drive_mode_open_drain_obj) {
drive_mode = DRIVE_MODE_OPEN_DRAIN; drive_mode = DRIVE_MODE_OPEN_DRAIN;
} }
@ -161,7 +161,7 @@ STATIC mp_obj_t digitalio_digitalinout_switch_to_input(size_t n_args, const mp_o
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
enum digitalio_pull_t pull = PULL_NONE; digitalio_pull_t pull = PULL_NONE;
if (args[ARG_pull].u_rom_obj == &digitalio_pull_up_obj) { if (args[ARG_pull].u_rom_obj == &digitalio_pull_up_obj) {
pull = PULL_UP; pull = PULL_UP;
}else if (args[ARG_pull].u_rom_obj == &digitalio_pull_down_obj) { }else if (args[ARG_pull].u_rom_obj == &digitalio_pull_down_obj) {
@ -191,7 +191,7 @@ extern const digitalio_digitalio_direction_obj_t digitalio_digitalio_direction_o
STATIC mp_obj_t digitalio_digitalinout_obj_get_direction(mp_obj_t self_in) { STATIC mp_obj_t digitalio_digitalinout_obj_get_direction(mp_obj_t self_in) {
digitalio_digitalinout_obj_t *self = MP_OBJ_TO_PTR(self_in); digitalio_digitalinout_obj_t *self = MP_OBJ_TO_PTR(self_in);
raise_error_if_deinited(common_hal_digitalio_digitalinout_deinited(self)); raise_error_if_deinited(common_hal_digitalio_digitalinout_deinited(self));
enum digitalio_direction_t direction = common_hal_digitalio_digitalinout_get_direction(self); digitalio_direction_t direction = common_hal_digitalio_digitalinout_get_direction(self);
if (direction == DIRECTION_INPUT) { if (direction == DIRECTION_INPUT) {
return (mp_obj_t)&digitalio_direction_input_obj; return (mp_obj_t)&digitalio_direction_input_obj;
} }
@ -262,7 +262,7 @@ STATIC mp_obj_t digitalio_digitalinout_obj_get_drive_mode(mp_obj_t self_in) {
mp_raise_AttributeError("Drive mode not used when direction is input."); mp_raise_AttributeError("Drive mode not used when direction is input.");
return mp_const_none; return mp_const_none;
} }
enum digitalio_drive_mode_t drive_mode = common_hal_digitalio_digitalinout_get_drive_mode(self); digitalio_drive_mode_t drive_mode = common_hal_digitalio_digitalinout_get_drive_mode(self);
if (drive_mode == DRIVE_MODE_PUSH_PULL) { if (drive_mode == DRIVE_MODE_PUSH_PULL) {
return (mp_obj_t)&digitalio_drive_mode_push_pull_obj; return (mp_obj_t)&digitalio_drive_mode_push_pull_obj;
} }
@ -277,7 +277,7 @@ STATIC mp_obj_t digitalio_digitalinout_obj_set_drive_mode(mp_obj_t self_in, mp_o
mp_raise_AttributeError("Drive mode not used when direction is input."); mp_raise_AttributeError("Drive mode not used when direction is input.");
return mp_const_none; return mp_const_none;
} }
enum digitalio_drive_mode_t c_drive_mode = DRIVE_MODE_PUSH_PULL; digitalio_drive_mode_t c_drive_mode = DRIVE_MODE_PUSH_PULL;
if (drive_mode == &digitalio_drive_mode_open_drain_obj) { if (drive_mode == &digitalio_drive_mode_open_drain_obj) {
c_drive_mode = DRIVE_MODE_OPEN_DRAIN; c_drive_mode = DRIVE_MODE_OPEN_DRAIN;
} }
@ -307,7 +307,7 @@ STATIC mp_obj_t digitalio_digitalinout_obj_get_pull(mp_obj_t self_in) {
mp_raise_AttributeError("Pull not used when direction is output."); mp_raise_AttributeError("Pull not used when direction is output.");
return mp_const_none; return mp_const_none;
} }
enum digitalio_pull_t pull = common_hal_digitalio_digitalinout_get_pull(self); digitalio_pull_t pull = common_hal_digitalio_digitalinout_get_pull(self);
if (pull == PULL_UP) { if (pull == PULL_UP) {
return (mp_obj_t)&digitalio_pull_up_obj; return (mp_obj_t)&digitalio_pull_up_obj;
} else if (pull == PULL_DOWN) { } else if (pull == PULL_DOWN) {
@ -324,7 +324,7 @@ STATIC mp_obj_t digitalio_digitalinout_obj_set_pull(mp_obj_t self_in, mp_obj_t p
mp_raise_AttributeError("Pull not used when direction is output."); mp_raise_AttributeError("Pull not used when direction is output.");
return mp_const_none; return mp_const_none;
} }
enum digitalio_pull_t pull = PULL_NONE; digitalio_pull_t pull = PULL_NONE;
if (pull_obj == &digitalio_pull_up_obj) { if (pull_obj == &digitalio_pull_up_obj) {
pull = PULL_UP; pull = PULL_UP;
} else if (pull_obj == &digitalio_pull_down_obj) { } else if (pull_obj == &digitalio_pull_down_obj) {

View File

@ -43,14 +43,14 @@ typedef enum {
digitalinout_result_t common_hal_digitalio_digitalinout_construct(digitalio_digitalinout_obj_t* self, const mcu_pin_obj_t* pin); digitalinout_result_t common_hal_digitalio_digitalinout_construct(digitalio_digitalinout_obj_t* self, const mcu_pin_obj_t* pin);
void common_hal_digitalio_digitalinout_deinit(digitalio_digitalinout_obj_t* self); void common_hal_digitalio_digitalinout_deinit(digitalio_digitalinout_obj_t* self);
bool common_hal_digitalio_digitalinout_deinited(digitalio_digitalinout_obj_t* self); bool common_hal_digitalio_digitalinout_deinited(digitalio_digitalinout_obj_t* self);
void common_hal_digitalio_digitalinout_switch_to_input(digitalio_digitalinout_obj_t* self, enum digitalio_pull_t pull); void common_hal_digitalio_digitalinout_switch_to_input(digitalio_digitalinout_obj_t* self, digitalio_pull_t pull);
void common_hal_digitalio_digitalinout_switch_to_output(digitalio_digitalinout_obj_t* self, bool value, enum digitalio_drive_mode_t drive_mode); void common_hal_digitalio_digitalinout_switch_to_output(digitalio_digitalinout_obj_t* self, bool value, digitalio_drive_mode_t drive_mode);
enum digitalio_direction_t common_hal_digitalio_digitalinout_get_direction(digitalio_digitalinout_obj_t* self); digitalio_direction_t common_hal_digitalio_digitalinout_get_direction(digitalio_digitalinout_obj_t* self);
void common_hal_digitalio_digitalinout_set_value(digitalio_digitalinout_obj_t* self, bool value); void common_hal_digitalio_digitalinout_set_value(digitalio_digitalinout_obj_t* self, bool value);
bool common_hal_digitalio_digitalinout_get_value(digitalio_digitalinout_obj_t* self); bool common_hal_digitalio_digitalinout_get_value(digitalio_digitalinout_obj_t* self);
void common_hal_digitalio_digitalinout_set_drive_mode(digitalio_digitalinout_obj_t* self, enum digitalio_drive_mode_t drive_mode); void common_hal_digitalio_digitalinout_set_drive_mode(digitalio_digitalinout_obj_t* self, digitalio_drive_mode_t drive_mode);
enum digitalio_drive_mode_t common_hal_digitalio_digitalinout_get_drive_mode(digitalio_digitalinout_obj_t* self); digitalio_drive_mode_t common_hal_digitalio_digitalinout_get_drive_mode(digitalio_digitalinout_obj_t* self);
void common_hal_digitalio_digitalinout_set_pull(digitalio_digitalinout_obj_t* self, enum digitalio_pull_t pull); void common_hal_digitalio_digitalinout_set_pull(digitalio_digitalinout_obj_t* self, digitalio_pull_t pull);
enum digitalio_pull_t common_hal_digitalio_digitalinout_get_pull(digitalio_digitalinout_obj_t* self); digitalio_pull_t common_hal_digitalio_digitalinout_get_pull(digitalio_digitalinout_obj_t* self);
#endif // MICROPY_INCLUDED_SHARED_BINDINGS_DIGITALIO_DIGITALINOUT_H #endif // MICROPY_INCLUDED_SHARED_BINDINGS_DIGITALIO_DIGITALINOUT_H

View File

@ -29,10 +29,10 @@
#include "py/obj.h" #include "py/obj.h"
enum digitalio_direction_t { typedef enum {
DIRECTION_INPUT, DIRECTION_INPUT,
DIRECTION_OUTPUT DIRECTION_OUTPUT
}; } digitalio_direction_t;
typedef struct { typedef struct {
mp_obj_base_t base; mp_obj_base_t base;
} digitalio_direction_obj_t; } digitalio_direction_obj_t;

View File

@ -29,10 +29,10 @@
#include "py/obj.h" #include "py/obj.h"
enum digitalio_drive_mode_t { typedef enum {
DRIVE_MODE_PUSH_PULL, DRIVE_MODE_PUSH_PULL,
DRIVE_MODE_OPEN_DRAIN DRIVE_MODE_OPEN_DRAIN
}; } digitalio_drive_mode_t;
typedef struct { typedef struct {
mp_obj_base_t base; mp_obj_base_t base;

View File

@ -29,11 +29,11 @@
#include "py/obj.h" #include "py/obj.h"
enum digitalio_pull_t { typedef enum _digitalio_pull_t {
PULL_NONE, PULL_NONE,
PULL_UP, PULL_UP,
PULL_DOWN PULL_DOWN
}; } digitalio_pull_t;
const mp_obj_type_t digitalio_pull_type; const mp_obj_type_t digitalio_pull_type;

View File

@ -0,0 +1,90 @@
/*
* This file is part of the Micro Python project, http://micropython.org/
*
* The MIT License (MIT)
*
* Copyright (c) 2017 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 "shared-bindings/microcontroller/RunMode.h"
//| .. currentmodule:: microcontroller
//|
//| :class:`RunMode` -- run state of the microcontroller
//| =============================================================
//|
//| .. class:: microcontroller.RunMode
//|
//| Enum-like class to define the run mode of the microcontroller and
//| CircuitPython.
//|
//| .. data:: NORMAL
//|
//| Run CircuitPython as normal.
//|
//| .. data:: SAFE_MODE
//|
//| Run CircuitPython in safe mode. User code will not be run and the
//| file system will be writeable over USB.
//|
//| .. data:: BOOTLOADER
//|
//| Run the bootloader.
//|
const mp_obj_type_t mcu_runmode_type;
const mcu_runmode_obj_t mcu_runmode_normal_obj = {
{ &mcu_runmode_type },
};
const mcu_runmode_obj_t mcu_runmode_safe_mode_obj = {
{ &mcu_runmode_type },
};
const mcu_runmode_obj_t mcu_runmode_bootloader_obj = {
{ &mcu_runmode_type },
};
STATIC const mp_rom_map_elem_t mcu_runmode_locals_dict_table[] = {
{MP_ROM_QSTR(MP_QSTR_NORMAL), MP_ROM_PTR(&mcu_runmode_normal_obj)},
{MP_ROM_QSTR(MP_QSTR_SAFE_MODE), MP_ROM_PTR(&mcu_runmode_safe_mode_obj)},
{MP_ROM_QSTR(MP_QSTR_BOOTLOADER), MP_ROM_PTR(&mcu_runmode_bootloader_obj)},
};
STATIC MP_DEFINE_CONST_DICT(mcu_runmode_locals_dict, mcu_runmode_locals_dict_table);
STATIC void mcu_runmode_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
qstr runmode = MP_QSTR_NORMAL;
if (MP_OBJ_TO_PTR(self_in) == MP_ROM_PTR(&mcu_runmode_safe_mode_obj)) {
runmode = MP_QSTR_SAFE_MODE;
} else if (MP_OBJ_TO_PTR(self_in) ==
MP_ROM_PTR(&mcu_runmode_bootloader_obj)) {
runmode = MP_QSTR_SAFE_MODE;
}
mp_printf(print, "%q.%q.%q", MP_QSTR_microcontroller, MP_QSTR_RunMode,
runmode);
}
const mp_obj_type_t mcu_runmode_type = {
{ &mp_type_type },
.name = MP_QSTR_RunMode,
.print = mcu_runmode_print,
.locals_dict = (mp_obj_t)&mcu_runmode_locals_dict,
};

View File

@ -0,0 +1,47 @@
/*
* This file is part of the Micro Python project, http://micropython.org/
*
* The MIT License (MIT)
*
* Copyright (c) 2017 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_SHARED_BINDINGS_MICROCONTROLLER_RUNMODE_H
#define MICROPY_INCLUDED_SHARED_BINDINGS_MICROCONTROLLER_RUNMODE_H
#include "py/obj.h"
typedef enum {
RUNMODE_NORMAL,
RUNMODE_SAFE_MODE,
RUNMODE_BOOTLOADER
} mcu_runmode_t;
const mp_obj_type_t mcu_runmode_type;
typedef struct {
mp_obj_base_t base;
} mcu_runmode_obj_t;
extern const mcu_runmode_obj_t mcu_runmode_normal_obj;
extern const mcu_runmode_obj_t mcu_runmode_safe_mode_obj;
extern const mcu_runmode_obj_t mcu_runmode_bootloader_obj;
#endif // MICROPY_INCLUDED_SHARED_BINDINGS_MICROCONTROLLER_RUNMODE_H

View File

@ -102,6 +102,47 @@ STATIC mp_obj_t mcu_enable_interrupts(void) {
} }
STATIC MP_DEFINE_CONST_FUN_OBJ_0(mcu_enable_interrupts_obj, mcu_enable_interrupts); STATIC MP_DEFINE_CONST_FUN_OBJ_0(mcu_enable_interrupts_obj, mcu_enable_interrupts);
//| .. method:: on_next_reset(run_mode)
//|
//| Configure the run mode used the next time the microcontroller is reset but
//| not powered down.
//|
//| :param ~microcontroller.RunMode run_mode: The next run mode
//|
STATIC mp_obj_t mcu_on_next_reset(mp_obj_t run_mode_obj) {
mcu_runmode_t run_mode;
if (run_mode_obj == &mcu_runmode_normal_obj) {
run_mode = RUNMODE_NORMAL;
} else if (run_mode_obj == &mcu_runmode_safe_mode_obj) {
run_mode = RUNMODE_SAFE_MODE;
} else if (run_mode_obj == &mcu_runmode_bootloader_obj) {
run_mode = RUNMODE_BOOTLOADER;
} else {
mp_raise_ValueError("Invalid run mode.");
}
common_hal_mcu_on_next_reset(run_mode);
return mp_const_none;
}
STATIC MP_DEFINE_CONST_FUN_OBJ_1(mcu_on_next_reset_obj, mcu_on_next_reset);
//| .. method:: reset()
//|
//| Reset the microcontroller. After reset, the microcontroller will enter the
//| run mode last set by `one_next_reset`.
//|
//| .. warning:: This may result in file system corruption when connected to a
//| host computer. Be very careful when calling this! Make sure the device
//| "Safely removed" on Windows or "ejected" on Mac OSX and Linux.
//|
STATIC mp_obj_t mcu_reset(void) {
common_hal_mcu_reset();
// We won't actually get here because we're resetting.
return mp_const_none;
}
STATIC MP_DEFINE_CONST_FUN_OBJ_0(mcu_reset_obj, mcu_reset);
//| .. attribute:: nvm //| .. attribute:: nvm
//| //|
//| Available non-volatile memory. //| Available non-volatile memory.
@ -128,11 +169,14 @@ STATIC const mp_rom_map_elem_t mcu_module_globals_table[] = {
{ MP_ROM_QSTR(MP_QSTR_delay_us), MP_ROM_PTR(&mcu_delay_us_obj) }, { MP_ROM_QSTR(MP_QSTR_delay_us), MP_ROM_PTR(&mcu_delay_us_obj) },
{ MP_ROM_QSTR(MP_QSTR_disable_interrupts), MP_ROM_PTR(&mcu_disable_interrupts_obj) }, { MP_ROM_QSTR(MP_QSTR_disable_interrupts), MP_ROM_PTR(&mcu_disable_interrupts_obj) },
{ MP_ROM_QSTR(MP_QSTR_enable_interrupts), MP_ROM_PTR(&mcu_enable_interrupts_obj) }, { MP_ROM_QSTR(MP_QSTR_enable_interrupts), MP_ROM_PTR(&mcu_enable_interrupts_obj) },
{ MP_ROM_QSTR(MP_QSTR_on_next_reset), MP_ROM_PTR(&mcu_on_next_reset_obj) },
{ MP_ROM_QSTR(MP_QSTR_reset), MP_ROM_PTR(&mcu_reset_obj) },
#if CIRCUITPY_INTERNAL_NVM_SIZE > 0 #if CIRCUITPY_INTERNAL_NVM_SIZE > 0
{ MP_ROM_QSTR(MP_QSTR_nvm), MP_ROM_PTR(&common_hal_mcu_nvm_obj) }, { MP_ROM_QSTR(MP_QSTR_nvm), MP_ROM_PTR(&common_hal_mcu_nvm_obj) },
#else #else
{ MP_ROM_QSTR(MP_QSTR_nvm), MP_ROM_PTR(&mp_const_none_obj) }, { MP_ROM_QSTR(MP_QSTR_nvm), MP_ROM_PTR(&mp_const_none_obj) },
#endif #endif
{ MP_ROM_QSTR(MP_QSTR_RunMode), MP_ROM_PTR(&mcu_runmode_type) },
{ MP_ROM_QSTR(MP_QSTR_Pin), MP_ROM_PTR(&mcu_pin_type) }, { MP_ROM_QSTR(MP_QSTR_Pin), MP_ROM_PTR(&mcu_pin_type) },
{ MP_ROM_QSTR(MP_QSTR_pin), MP_ROM_PTR(&mcu_pin_module) }, { MP_ROM_QSTR(MP_QSTR_pin), MP_ROM_PTR(&mcu_pin_module) },
{ MP_ROM_QSTR(MP_QSTR_Processor), MP_ROM_PTR(&mcu_processor_type) }, { MP_ROM_QSTR(MP_QSTR_Processor), MP_ROM_PTR(&mcu_processor_type) },

View File

@ -33,11 +33,16 @@
#include "common-hal/microcontroller/Processor.h" #include "common-hal/microcontroller/Processor.h"
#include "shared-bindings/microcontroller/RunMode.h"
extern void common_hal_mcu_delay_us(uint32_t); extern void common_hal_mcu_delay_us(uint32_t);
extern void common_hal_mcu_disable_interrupts(void); extern void common_hal_mcu_disable_interrupts(void);
extern void common_hal_mcu_enable_interrupts(void); extern void common_hal_mcu_enable_interrupts(void);
extern void common_hal_mcu_on_next_reset(mcu_runmode_t runmode);
extern void common_hal_mcu_reset(void);
extern const mp_obj_dict_t mcu_pin_globals; extern const mp_obj_dict_t mcu_pin_globals;
extern const mcu_processor_obj_t common_hal_mcu_processor_obj; extern const mcu_processor_obj_t common_hal_mcu_processor_obj;