diff --git a/.gitmodules b/.gitmodules index 7c477d9758..37cee7e810 100644 --- a/.gitmodules +++ b/.gitmodules @@ -70,6 +70,9 @@ [submodule "ports/atmel-samd/peripherals"] path = ports/atmel-samd/peripherals url = https://github.com/adafruit/samd-peripherals.git +[submodule "frozen/Adafruit_CircuitPython_Crickit"] + path = frozen/Adafruit_CircuitPython_Crickit + url = https://github.com/adafruit/Adafruit_CircuitPython_Crickit [submodule "ports/nrf/nrfx"] path = ports/nrf/nrfx url = https://github.com/NordicSemiconductor/nrfx.git diff --git a/docs/drivers.rst b/docs/drivers.rst index 951967e09e..37bebb46ac 100644 --- a/docs/drivers.rst +++ b/docs/drivers.rst @@ -191,6 +191,7 @@ These provide functionality similar to `analogio`, `digitalio`, `pulseio`, and ` Adafruit SeeSaw ADS1x15 Analog-to-Digital Converter + Crickit Robotics Boards < DS2413 OneWire GPIO Expander FocalTech Capacitive Touch MCP230xx GPIO Expander @@ -200,7 +201,6 @@ These provide functionality similar to `analogio`, `digitalio`, `pulseio`, and ` TLC59711 12 x 16-bit PWM Driver MPR121 Capacitive Touch Sensor - Miscellaneous ---------------- diff --git a/frozen/Adafruit_CircuitPython_BusDevice b/frozen/Adafruit_CircuitPython_BusDevice index 376a80e62a..0791964147 160000 --- a/frozen/Adafruit_CircuitPython_BusDevice +++ b/frozen/Adafruit_CircuitPython_BusDevice @@ -1 +1 @@ -Subproject commit 376a80e62acb3ba8b9a1e5c11bb75d36352f2190 +Subproject commit 07919641470edb602585c6a91f7b8eacf17e664b diff --git a/frozen/Adafruit_CircuitPython_CircuitPlayground b/frozen/Adafruit_CircuitPython_CircuitPlayground index d0022de9d5..d0aa6dc56d 160000 --- a/frozen/Adafruit_CircuitPython_CircuitPlayground +++ b/frozen/Adafruit_CircuitPython_CircuitPlayground @@ -1 +1 @@ -Subproject commit d0022de9d5e9b4c3d4998a5d708e59ee147f0a21 +Subproject commit d0aa6dc56d66decfae92daced7384c1e3518a666 diff --git a/frozen/Adafruit_CircuitPython_Crickit b/frozen/Adafruit_CircuitPython_Crickit new file mode 160000 index 0000000000..44f52c5dac --- /dev/null +++ b/frozen/Adafruit_CircuitPython_Crickit @@ -0,0 +1 @@ +Subproject commit 44f52c5dacd9fc605565e5794e95c9a785aaf693 diff --git a/frozen/Adafruit_CircuitPython_HID b/frozen/Adafruit_CircuitPython_HID index 1da880cee3..5c2f6ef1ed 160000 --- a/frozen/Adafruit_CircuitPython_HID +++ b/frozen/Adafruit_CircuitPython_HID @@ -1 +1 @@ -Subproject commit 1da880cee3c2d64e2e7e4ca5082f3a74c4a37a5a +Subproject commit 5c2f6ef1ed80f24b6a3878067d40350d3725e198 diff --git a/frozen/Adafruit_CircuitPython_Motor b/frozen/Adafruit_CircuitPython_Motor index 6da5d14b98..e0b709f171 160000 --- a/frozen/Adafruit_CircuitPython_Motor +++ b/frozen/Adafruit_CircuitPython_Motor @@ -1 +1 @@ -Subproject commit 6da5d14b98ac3d929662731f73ce03c0c958b520 +Subproject commit e0b709f1710555da67705360870ba0d14ced7e06 diff --git a/frozen/Adafruit_CircuitPython_seesaw b/frozen/Adafruit_CircuitPython_seesaw index 498f59bf92..340cd17fad 160000 --- a/frozen/Adafruit_CircuitPython_seesaw +++ b/frozen/Adafruit_CircuitPython_seesaw @@ -1 +1 @@ -Subproject commit 498f59bf926477b3a8fb8eb157ca05eb12c3e298 +Subproject commit 340cd17fad0c29d3a70d6e298a30ecc753df054e diff --git a/ports/atmel-samd/Makefile b/ports/atmel-samd/Makefile index 9c14ac29c3..249f003f9b 100755 --- a/ports/atmel-samd/Makefile +++ b/ports/atmel-samd/Makefile @@ -119,6 +119,9 @@ else ifdef INTERNAL_FLASH_FILESYSTEM CFLAGS += -finline-limit=55 endif + ifdef CFLAGS_INLINE_LIMIT + CFLAGS += -finline-limit=$(CFLAGS_INLINE_LIMIT) + endif CFLAGS += -flto endif diff --git a/ports/atmel-samd/boards/circuitplayground_express_crickit/mpconfigboard.mk b/ports/atmel-samd/boards/circuitplayground_express_crickit/mpconfigboard.mk index 0145bf7850..972c4b10dc 100644 --- a/ports/atmel-samd/boards/circuitplayground_express_crickit/mpconfigboard.mk +++ b/ports/atmel-samd/boards/circuitplayground_express_crickit/mpconfigboard.mk @@ -11,9 +11,12 @@ LONGINT_IMPL = NONE CHIP_VARIANT = SAMD21G18A CHIP_FAMILY = samd21 +CFLAGS_INLINE_LIMIT = 55 + # Include these Python libraries in firmware. FROZEN_MPY_DIRS += $(TOP)/frozen/Adafruit_CircuitPython_BusDevice FROZEN_MPY_DIRS += $(TOP)/frozen/Adafruit_CircuitPython_CircuitPlayground +FROZEN_MPY_DIRS += $(TOP)/frozen/Adafruit_CircuitPython_Crickit FROZEN_MPY_DIRS += $(TOP)/frozen/Adafruit_CircuitPython_LIS3DH FROZEN_MPY_DIRS += $(TOP)/frozen/Adafruit_CircuitPython_Motor FROZEN_MPY_DIRS += $(TOP)/frozen/Adafruit_CircuitPython_NeoPixel diff --git a/ports/atmel-samd/boards/feather_m0_express_crickit/mpconfigboard.mk b/ports/atmel-samd/boards/feather_m0_express_crickit/mpconfigboard.mk index 4096560c22..7ff5337a34 100644 --- a/ports/atmel-samd/boards/feather_m0_express_crickit/mpconfigboard.mk +++ b/ports/atmel-samd/boards/feather_m0_express_crickit/mpconfigboard.mk @@ -10,8 +10,11 @@ LONGINT_IMPL = MPZ CHIP_VARIANT = SAMD21G18A CHIP_FAMILY = samd21 +CFLAGS_INLINE_LIMIT = 55 + # Include these Python libraries in firmware. FROZEN_MPY_DIRS += $(TOP)/frozen/Adafruit_CircuitPython_BusDevice +FROZEN_MPY_DIRS += $(TOP)/frozen/Adafruit_CircuitPython_Crickit FROZEN_MPY_DIRS += $(TOP)/frozen/Adafruit_CircuitPython_Motor FROZEN_MPY_DIRS += $(TOP)/frozen/Adafruit_CircuitPython_NeoPixel FROZEN_MPY_DIRS += $(TOP)/frozen/Adafruit_CircuitPython_seesaw diff --git a/ports/atmel-samd/common-hal/digitalio/DigitalInOut.c b/ports/atmel-samd/common-hal/digitalio/DigitalInOut.c index cd0e3f91e5..c5c8f48e9f 100644 --- a/ports/atmel-samd/common-hal/digitalio/DigitalInOut.c +++ b/ports/atmel-samd/common-hal/digitalio/DigitalInOut.c @@ -40,8 +40,9 @@ digitalinout_result_t common_hal_digitalio_digitalinout_construct( claim_pin(pin); self->pin = pin; - gpio_set_pin_pull_mode(pin->pin, GPIO_PULL_OFF); + // Must set pull after setting direction. gpio_set_pin_direction(pin->pin, GPIO_DIRECTION_IN); + gpio_set_pin_pull_mode(pin->pin, GPIO_PULL_OFF); return DIGITALINOUT_OK; } @@ -60,7 +61,7 @@ void common_hal_digitalio_digitalinout_deinit(digitalio_digitalinout_obj_t* self void common_hal_digitalio_digitalinout_switch_to_input( digitalio_digitalinout_obj_t* self, digitalio_pull_t pull) { self->output = false; - + // This also sets direction to input. common_hal_digitalio_digitalinout_set_pull(self, pull); } @@ -69,13 +70,13 @@ void common_hal_digitalio_digitalinout_switch_to_output( digitalio_drive_mode_t drive_mode) { const uint8_t pin = self->pin->pin; gpio_set_pin_pull_mode(pin, GPIO_PULL_OFF); - gpio_set_pin_direction(pin, GPIO_DIRECTION_OUT); - // Turn on "strong" pin driving (more current available). See DRVSTR doc in datasheet. hri_port_set_PINCFG_DRVSTR_bit(PORT, (enum gpio_port)GPIO_PORT(pin), GPIO_PIN(pin)); self->output = true; self->open_drain = drive_mode == DRIVE_MODE_OPEN_DRAIN; + + // Direction is set in set_value. We don't need to do it here. common_hal_digitalio_digitalinout_set_value(self, value); } @@ -86,16 +87,22 @@ digitalio_direction_t common_hal_digitalio_digitalinout_get_direction( void common_hal_digitalio_digitalinout_set_value( digitalio_digitalinout_obj_t* self, bool value) { + const uint8_t pin = self->pin->pin; + const uint8_t port = GPIO_PORT(pin); + const uint32_t pin_mask = 1U << GPIO_PIN(pin); if (value) { if (self->open_drain) { - gpio_set_pin_direction(self->pin->pin, GPIO_DIRECTION_IN); + // Assertion: pull is off, so the pin is floating in this case. + // We do open-drain high output (no sinking of current) + // by changing the direction to input with no pulls. + hri_port_clear_DIR_DIR_bf(PORT, port, pin_mask); } else { - gpio_set_pin_level(self->pin->pin, true); - gpio_set_pin_direction(self->pin->pin, GPIO_DIRECTION_OUT); + hri_port_set_DIR_DIR_bf(PORT, port, pin_mask); + hri_port_set_OUT_OUT_bf(PORT, port, pin_mask); } } else { - gpio_set_pin_level(self->pin->pin, false); - gpio_set_pin_direction(self->pin->pin, GPIO_DIRECTION_OUT); + hri_port_set_DIR_DIR_bf(PORT, port, pin_mask); + hri_port_clear_OUT_OUT_bf(PORT,port, pin_mask); } } @@ -105,10 +112,10 @@ bool common_hal_digitalio_digitalinout_get_value( if (!self->output) { return gpio_get_pin_level(pin); } else { - if (self->open_drain && hri_port_get_DIR_reg(PORT, (enum gpio_port)GPIO_PORT(pin), 1U << GPIO_PIN(pin)) == 0) { + if (self->open_drain && hri_port_get_DIR_reg(PORT, GPIO_PORT(pin), 1U << GPIO_PIN(pin)) == 0) { return true; } else { - return hri_port_get_OUT_reg(PORT, (enum gpio_port)GPIO_PORT(pin), 1U << GPIO_PIN(pin)); + return hri_port_get_OUT_reg(PORT, GPIO_PORT(pin), 1U << GPIO_PIN(pin)); } } } @@ -119,7 +126,7 @@ void common_hal_digitalio_digitalinout_set_drive_mode( bool value = common_hal_digitalio_digitalinout_get_value(self); self->open_drain = drive_mode == DRIVE_MODE_OPEN_DRAIN; // True is implemented differently between modes so reset the value to make - // sure its correct for the new mode. + // sure it's correct for the new mode. if (value) { common_hal_digitalio_digitalinout_set_value(self, value); } @@ -148,6 +155,8 @@ void common_hal_digitalio_digitalinout_set_pull( default: break; } + // Must set pull after setting direction. + gpio_set_pin_direction(self->pin->pin, GPIO_DIRECTION_IN); gpio_set_pin_pull_mode(self->pin->pin, asf_pull); } @@ -158,9 +167,9 @@ digitalio_pull_t common_hal_digitalio_digitalinout_get_pull( mp_raise_AttributeError("Cannot get pull while in output mode"); return PULL_NONE; } else { - if (hri_port_get_PINCFG_PULLEN_bit(PORT, (enum gpio_port)GPIO_PORT(pin), GPIO_PIN(pin)) == 0) { + if (hri_port_get_PINCFG_PULLEN_bit(PORT, GPIO_PORT(pin), GPIO_PIN(pin)) == 0) { return PULL_NONE; - } if (hri_port_get_OUT_reg(PORT, (enum gpio_port)GPIO_PORT(pin), 1U << GPIO_PIN(pin)) > 0) { + } if (hri_port_get_OUT_reg(PORT, GPIO_PORT(pin), 1U << GPIO_PIN(pin)) > 0) { return PULL_UP; } else { return PULL_DOWN; diff --git a/ports/atmel-samd/mphalport.c b/ports/atmel-samd/mphalport.c index c1b8ce5504..a4eca1c748 100644 --- a/ports/atmel-samd/mphalport.c +++ b/ports/atmel-samd/mphalport.c @@ -1,3 +1,29 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2016 Scott Shawcroft + * + * 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 #include "lib/mp-readline/readline.h" @@ -14,6 +40,7 @@ #include "hal/include/hal_delay.h" #include "hal/include/hal_gpio.h" #include "hal/include/hal_sleep.h" +#include "sam.h" #include "mpconfigboard.h" #include "mphalport.h" @@ -22,6 +49,7 @@ #include "usb.h" extern struct usart_module usart_instance; +extern uint32_t common_hal_mcu_processor_get_frequency(void); int mp_hal_stdin_rx_chr(void) { for (;;) { @@ -71,8 +99,23 @@ void mp_hal_delay_ms(mp_uint_t delay) { } } +// Use mp_hal_delay_us() for timing of less than 1ms. +// Do a simple timing loop to wait for a certain number of microseconds. +// Can be used when interrupts are disabled, which makes tick_delay() unreliable. +// +// Testing done at 48 MHz on SAMD21 and 120 MHz on SAMD51, multiplication and division cancel out. +// But get the frequency just in case. +#ifdef SAMD21 +#define DELAY_LOOP_ITERATIONS_PER_US ( (10U*48000000U) / common_hal_mcu_processor_get_frequency()) +#endif +#ifdef SAMD51 +#define DELAY_LOOP_ITERATIONS_PER_US ( (30U*120000000U) / common_hal_mcu_processor_get_frequency()) +#endif + void mp_hal_delay_us(mp_uint_t delay) { - tick_delay(delay); + for (uint32_t i = delay*DELAY_LOOP_ITERATIONS_PER_US; i > 0; i--) { + asm volatile("nop"); + } } void mp_hal_disable_all_interrupts(void) { diff --git a/ports/atmel-samd/mphalport.h b/ports/atmel-samd/mphalport.h index 3b5955a4ff..3bc824d4e9 100644 --- a/ports/atmel-samd/mphalport.h +++ b/ports/atmel-samd/mphalport.h @@ -48,7 +48,6 @@ int receive_usb(void); void mp_hal_set_interrupt_char(int c); void mp_hal_disable_all_interrupts(void); - void mp_hal_enable_all_interrupts(void); #endif // MICROPY_INCLUDED_ATMEL_SAMD_MPHALPORT_H diff --git a/ports/atmel-samd/tick.c b/ports/atmel-samd/tick.c index 9753a1a0c7..1493477933 100644 --- a/ports/atmel-samd/tick.c +++ b/ports/atmel-samd/tick.c @@ -64,8 +64,8 @@ void tick_init() { for (uint16_t i = 0; i < PERIPH_COUNT_IRQn; i++) { NVIC_SetPriority(i, (1UL << __NVIC_PRIO_BITS) - 1UL); } - // Bump up the systick interrupt. - NVIC_SetPriority(SysTick_IRQn, 1); + // Bump up the systick interrupt so nothing else interferes with timekeeping. + NVIC_SetPriority(SysTick_IRQn, 0); #ifdef SAMD21 NVIC_SetPriority(USB_IRQn, 1); #endif diff --git a/ports/nrf/common-hal/microcontroller/__init__.c b/ports/nrf/common-hal/microcontroller/__init__.c index b63ee5a880..e88c741365 100644 --- a/ports/nrf/common-hal/microcontroller/__init__.c +++ b/ports/nrf/common-hal/microcontroller/__init__.c @@ -34,6 +34,8 @@ #include "supervisor/filesystem.h" #include "nrfx_glue.h" +// This routine should work even when interrupts are disabled. Used by OneWire +// for precise timing. void common_hal_mcu_delay_us(uint32_t delay) { NRFX_DELAY_US(delay); } @@ -60,4 +62,3 @@ const mcu_processor_obj_t common_hal_mcu_processor_obj = { .type = &mcu_processor_type, }, }; - diff --git a/ports/nrf/mphalport.h b/ports/nrf/mphalport.h index 2aa2a4f309..f283cf38da 100644 --- a/ports/nrf/mphalport.h +++ b/ports/nrf/mphalport.h @@ -49,4 +49,3 @@ void mp_hal_delay_ms(mp_uint_t ms); #define mp_hal_delay_us(us) NRFX_DELAY_US((uint32_t) (us)) #endif - diff --git a/py/runtime.c b/py/runtime.c index a7ff57a47f..33671e7f25 100644 --- a/py/runtime.c +++ b/py/runtime.c @@ -1060,7 +1060,8 @@ void mp_convert_member_lookup(mp_obj_t self, const mp_obj_type_t *type, mp_obj_t dest[1] = self; } #if MICROPY_PY_BUILTINS_PROPERTY - } else if (MP_OBJ_IS_TYPE(member, &mp_type_property) && mp_obj_is_native_type(type)) { + // If self is MP_OBJ_NULL, we looking at the class itself, not an instance. + } else if (MP_OBJ_IS_TYPE(member, &mp_type_property) && mp_obj_is_native_type(type) && self != MP_OBJ_NULL) { // object member is a property; delegate the load to the property // Note: This is an optimisation for code size and execution time. // The proper way to do it is have the functionality just below @@ -1161,7 +1162,8 @@ void mp_store_attr(mp_obj_t base, qstr attr, mp_obj_t value) { assert(type->locals_dict->base.type == &mp_type_dict); // Micro Python restriction, for now mp_map_t *locals_map = &type->locals_dict->map; mp_map_elem_t *elem = mp_map_lookup(locals_map, MP_OBJ_NEW_QSTR(attr), MP_MAP_LOOKUP); - if (elem != NULL && MP_OBJ_IS_TYPE(elem->value, &mp_type_property)) { + // If base is MP_OBJ_NULL, we looking at the class itself, not an instance. + if (elem != NULL && MP_OBJ_IS_TYPE(elem->value, &mp_type_property) && base != MP_OBJ_NULL) { // attribute exists and is a property; delegate the store/delete // Note: This is an optimisation for code size and execution time. // The proper way to do it is have the functionality just below in diff --git a/shared-module/bitbangio/OneWire.c b/shared-module/bitbangio/OneWire.c index e77bdb3b29..f5f4790876 100644 --- a/shared-module/bitbangio/OneWire.c +++ b/shared-module/bitbangio/OneWire.c @@ -49,6 +49,9 @@ void shared_module_bitbangio_onewire_deinit(bitbangio_onewire_obj_t* self) { common_hal_digitalio_digitalinout_deinit(&self->pin); } +// We use common_hal_mcu_delay_us(). It should not be dependent on interrupts +// to do accurate timekeeping, since we disable interrupts during the delays below. + bool shared_module_bitbangio_onewire_reset(bitbangio_onewire_obj_t* self) { common_hal_mcu_disable_interrupts(); common_hal_digitalio_digitalinout_switch_to_output(&self->pin, false, DRIVE_MODE_OPEN_DRAIN);