From fd71e56891749837a823a4b555b84150b6fbc1e8 Mon Sep 17 00:00:00 2001 From: Scott Shawcroft Date: Fri, 25 May 2018 18:39:16 -0700 Subject: [PATCH 1/5] atmel-samd: Re-org helper peripheral files into their own subdirectory. Ideally in the future they won't depend on ASF4 or MicroPython. --- conf.py | 1 + ports/atmel-samd/Makefile | 25 ++- ports/atmel-samd/audio_dma.c | 6 +- ports/atmel-samd/bindings/samd/Clock.c | 3 +- ports/atmel-samd/board_busses.c | 6 +- ports/atmel-samd/boards/arduino_zero/pins.c | 2 - .../boards/circuitplayground_express/board.c | 1 - .../boards/circuitplayground_express/pins.c | 3 +- .../circuitplayground_express_crickit/board.c | 1 - .../circuitplayground_express_crickit/pins.c | 3 +- .../boards/feather_m0_adalogger/pins.c | 3 +- .../atmel-samd/boards/feather_m0_basic/pins.c | 3 +- .../boards/feather_m0_express/pins.c | 3 +- .../atmel-samd/boards/feather_m0_rfm69/pins.c | 3 +- .../atmel-samd/boards/feather_m0_rfm9x/pins.c | 3 +- .../boards/feather_m0_supersized/pins.c | 3 +- .../boards/feather_m4_express/pins.c | 3 +- ports/atmel-samd/boards/gemma_m0/pins.c | 3 +- .../boards/itsybitsy_m0_express/pins.c | 3 +- .../boards/itsybitsy_m4_express/pins.c | 3 +- .../atmel-samd/boards/metro_m0_express/pins.c | 3 +- .../atmel-samd/boards/metro_m4_express/pins.c | 3 +- .../metro_m4_express_revb/mpconfigboard.h | 72 -------- .../metro_m4_express_revb/mpconfigboard.mk | 11 -- .../boards/metro_m4_express_revb/pins.c | 48 ----- ports/atmel-samd/boards/pirkey_m0/pins.c | 3 +- ports/atmel-samd/boards/trinket_m0/pins.c | 3 +- .../boards/trinket_m0_haxpress/pins.c | 3 +- ports/atmel-samd/boards/ugame10/pins.c | 3 +- .../atmel-samd/common-hal/analogio/AnalogIn.c | 2 +- .../common-hal/analogio/AnalogOut.c | 6 +- .../atmel-samd/common-hal/audiobusio/I2SOut.c | 13 +- .../atmel-samd/common-hal/audiobusio/PDMIn.c | 11 +- .../atmel-samd/common-hal/audioio/AudioOut.c | 9 +- ports/atmel-samd/common-hal/busio/I2C.c | 3 +- ports/atmel-samd/common-hal/busio/SPI.c | 6 +- ports/atmel-samd/common-hal/busio/UART.c | 3 +- .../common-hal/microcontroller/Pin.c | 7 +- .../common-hal/microcontroller/Pin.h | 2 + .../common-hal/microcontroller/Processor.c | 2 +- .../common-hal/microcontroller/__init__.c | 2 +- ports/atmel-samd/common-hal/pulseio/PWMOut.c | 4 +- ports/atmel-samd/common-hal/pulseio/PulseIn.c | 4 +- .../atmel-samd/common-hal/pulseio/PulseOut.c | 4 +- .../common-hal/rotaryio/IncrementalEncoder.c | 158 +++++++++++++++++ .../common-hal/rotaryio/IncrementalEncoder.h | 40 +++++ .../atmel-samd/common-hal/rotaryio/__init__.c | 1 + ports/atmel-samd/common-hal/touchio/TouchIn.c | 6 +- .../external_flash/external_flash.c | 4 +- ports/atmel-samd/external_flash/qspi_flash.c | 4 +- ports/atmel-samd/external_flash/spi_flash.c | 4 +- ports/atmel-samd/mpconfigport.h | 4 +- .../adc.h} | 9 +- .../cache.h} | 8 - ports/atmel-samd/{ => peripherals}/clocks.c | 0 ports/atmel-samd/{ => peripherals}/clocks.h | 0 .../{shared_dma.c => peripherals/dma.c} | 164 +---------------- .../{shared_dma.h => peripherals/dma.h} | 9 +- ports/atmel-samd/peripherals/events.c | 62 +++++++ ports/atmel-samd/{ => peripherals}/events.h | 2 + ports/atmel-samd/peripherals/i2s.c | 46 +++++ ports/atmel-samd/{ => peripherals}/i2s.h | 0 ports/atmel-samd/peripherals/pins.h | 42 +++++ ports/atmel-samd/peripherals/samd21/adc.c | 47 +++++ .../{pins.h => peripherals/samd21/cache.c} | 19 +- .../samd21/clocks.c} | 2 +- ports/atmel-samd/peripherals/samd21/dma.c | 118 +++++++++++++ .../{ => peripherals/samd21}/events.c | 107 +---------- .../board.c => peripherals/samd21/i2s.c} | 30 ++-- .../samd21/pins.c} | 2 - .../samd21/pins.h} | 11 +- .../samd21/sercom.c} | 20 --- ports/atmel-samd/peripherals/samd21/timers.c | 75 ++++++++ ports/atmel-samd/peripherals/samd51/adc.c | 61 +++++++ ports/atmel-samd/peripherals/samd51/cache.c | 39 ++++ .../samd51/clocks.c} | 2 +- ports/atmel-samd/peripherals/samd51/dma.c | 94 ++++++++++ ports/atmel-samd/peripherals/samd51/events.c | 88 ++++++++++ .../atmel-samd/{ => peripherals/samd51}/i2s.c | 36 +--- .../samd51/pins.c} | 2 - .../samd51/pins.h} | 5 +- .../samd51/sercom.c} | 46 +---- .../{ => peripherals/samd51}/timers.c | 166 +----------------- .../{peripherals.c => peripherals/sercom.c} | 2 +- .../{peripherals.h => peripherals/sercom.h} | 17 +- ports/atmel-samd/peripherals/timers.c | 147 ++++++++++++++++ ports/atmel-samd/{ => peripherals}/timers.h | 0 ports/atmel-samd/supervisor/port.c | 8 +- shared-bindings/board/__init__.h | 2 + shared-bindings/rotaryio/IncrementalEncoder.c | 159 +++++++++++++++++ shared-bindings/rotaryio/IncrementalEncoder.h | 41 +++++ shared-bindings/rotaryio/__init__.c | 75 ++++++++ shared-bindings/rotaryio/__init__.h | 34 ++++ supervisor/shared/rgb_led_status.c | 1 - 94 files changed, 1504 insertions(+), 823 deletions(-) delete mode 100644 ports/atmel-samd/boards/metro_m4_express_revb/mpconfigboard.h delete mode 100644 ports/atmel-samd/boards/metro_m4_express_revb/mpconfigboard.mk delete mode 100644 ports/atmel-samd/boards/metro_m4_express_revb/pins.c create mode 100644 ports/atmel-samd/common-hal/rotaryio/IncrementalEncoder.c create mode 100644 ports/atmel-samd/common-hal/rotaryio/IncrementalEncoder.h create mode 100644 ports/atmel-samd/common-hal/rotaryio/__init__.c rename ports/atmel-samd/{samd21_peripherals.h => peripherals/adc.h} (78%) rename ports/atmel-samd/{samd51_peripherals.h => peripherals/cache.h} (81%) rename ports/atmel-samd/{ => peripherals}/clocks.c (100%) rename ports/atmel-samd/{ => peripherals}/clocks.h (100%) rename ports/atmel-samd/{shared_dma.c => peripherals/dma.c} (62%) rename ports/atmel-samd/{shared_dma.h => peripherals/dma.h} (91%) create mode 100644 ports/atmel-samd/peripherals/events.c rename ports/atmel-samd/{ => peripherals}/events.h (97%) create mode 100644 ports/atmel-samd/peripherals/i2s.c rename ports/atmel-samd/{ => peripherals}/i2s.h (100%) create mode 100644 ports/atmel-samd/peripherals/pins.h create mode 100644 ports/atmel-samd/peripherals/samd21/adc.c rename ports/atmel-samd/{pins.h => peripherals/samd21/cache.c} (79%) rename ports/atmel-samd/{samd21_clocks.c => peripherals/samd21/clocks.c} (99%) create mode 100644 ports/atmel-samd/peripherals/samd21/dma.c rename ports/atmel-samd/{ => peripherals/samd21}/events.c (60%) rename ports/atmel-samd/{boards/metro_m4_express_revb/board.c => peripherals/samd21/i2s.c} (65%) rename ports/atmel-samd/{samd21_pins.c => peripherals/samd21/pins.c} (99%) rename ports/atmel-samd/{samd21_pins.h => peripherals/samd21/pins.h} (93%) rename ports/atmel-samd/{samd21_peripherals.c => peripherals/samd21/sercom.c} (76%) create mode 100644 ports/atmel-samd/peripherals/samd21/timers.c create mode 100644 ports/atmel-samd/peripherals/samd51/adc.c create mode 100644 ports/atmel-samd/peripherals/samd51/cache.c rename ports/atmel-samd/{samd51_clocks.c => peripherals/samd51/clocks.c} (99%) create mode 100644 ports/atmel-samd/peripherals/samd51/dma.c create mode 100644 ports/atmel-samd/peripherals/samd51/events.c rename ports/atmel-samd/{ => peripherals/samd51}/i2s.c (68%) rename ports/atmel-samd/{samd51_pins.c => peripherals/samd51/pins.c} (99%) rename ports/atmel-samd/{samd51_pins.h => peripherals/samd51/pins.h} (98%) rename ports/atmel-samd/{samd51_peripherals.c => peripherals/samd51/sercom.c} (67%) rename ports/atmel-samd/{ => peripherals/samd51}/timers.c (56%) rename ports/atmel-samd/{peripherals.c => peripherals/sercom.c} (98%) rename ports/atmel-samd/{peripherals.h => peripherals/sercom.h} (79%) create mode 100644 ports/atmel-samd/peripherals/timers.c rename ports/atmel-samd/{ => peripherals}/timers.h (100%) create mode 100644 shared-bindings/rotaryio/IncrementalEncoder.c create mode 100644 shared-bindings/rotaryio/IncrementalEncoder.h create mode 100644 shared-bindings/rotaryio/__init__.c create mode 100644 shared-bindings/rotaryio/__init__.h diff --git a/conf.py b/conf.py index eb4b1490f75d5..03d100f121b83 100644 --- a/conf.py +++ b/conf.py @@ -101,6 +101,7 @@ "ports/atmel-samd/asf4_conf", "ports/atmel-samd/external_flash", "ports/atmel-samd/freetouch", + "ports/atmel-samd/peripherals", "ports/atmel-samd/QTouch", "ports/atmel-samd/tools", "ports/bare-arm", diff --git a/ports/atmel-samd/Makefile b/ports/atmel-samd/Makefile index d627e764107c7..162e6b3e6194f 100644 --- a/ports/atmel-samd/Makefile +++ b/ports/atmel-samd/Makefile @@ -242,19 +242,24 @@ SRC_C = \ audio_dma.c \ board_busses.c \ background.c \ - clocks.c \ - $(CHIP_FAMILY)_clocks.c \ - events.c \ fatfs_port.c \ flash_api.c \ mphalport.c \ reset.c \ - $(CHIP_FAMILY)_peripherals.c \ - peripherals.c \ - $(CHIP_FAMILY)_pins.c \ - shared_dma.c \ + peripherals/clocks.c \ + peripherals/dma.c \ + peripherals/events.c \ + peripherals/sercom.c \ + peripherals/timers.c \ + peripherals/$(CHIP_FAMILY)/adc.c \ + peripherals/$(CHIP_FAMILY)/cache.c \ + peripherals/$(CHIP_FAMILY)/clocks.c \ + peripherals/$(CHIP_FAMILY)/dma.c \ + peripherals/$(CHIP_FAMILY)/events.c \ + peripherals/$(CHIP_FAMILY)/pins.c \ + peripherals/$(CHIP_FAMILY)/sercom.c \ + peripherals/$(CHIP_FAMILY)/timers.c \ tick.c \ - timers.c \ usb.c \ usb_mass_storage.c \ bindings/samd/__init__.c \ @@ -301,6 +306,8 @@ SRC_COMMON_HAL = \ microcontroller/Processor.c \ neopixel_write/__init__.c \ os/__init__.c \ + rotaryio/__init__.c \ + rotaryio/IncrementalEncoder.c \ rtc/__init__.c \ rtc/RTC.c \ storage/__init__.c \ @@ -391,7 +398,7 @@ ifneq ($(CHIP_VARIANT),SAMD51G18A) audiobusio/__init__.c \ audiobusio/I2SOut.c \ audiobusio/PDMIn.c - SRC_C += i2s.c + SRC_C += peripherals/i2s.c peripherals/$(CHIP_FAMILY)/i2s.c endif endif diff --git a/ports/atmel-samd/audio_dma.c b/ports/atmel-samd/audio_dma.c index e8dbdc61d6477..5a572e9d1fb59 100644 --- a/ports/atmel-samd/audio_dma.c +++ b/ports/atmel-samd/audio_dma.c @@ -25,9 +25,9 @@ */ #include "audio_dma.h" -#include "clocks.h" -#include "events.h" -#include "shared_dma.h" +#include "peripherals/clocks.h" +#include "peripherals/events.h" +#include "peripherals/dma.h" #include "shared-bindings/audioio/RawSample.h" #include "shared-bindings/audioio/WaveFile.h" diff --git a/ports/atmel-samd/bindings/samd/Clock.c b/ports/atmel-samd/bindings/samd/Clock.c index 81e8fb1cecd2c..3c87177a46426 100644 --- a/ports/atmel-samd/bindings/samd/Clock.c +++ b/ports/atmel-samd/bindings/samd/Clock.c @@ -24,9 +24,8 @@ * THE SOFTWARE. */ -#include "clocks.h" #include "bindings/samd/Clock.h" - +#include "peripherals/clocks.h" #include "py/obj.h" #include "py/objproperty.h" #include "py/runtime.h" diff --git a/ports/atmel-samd/board_busses.c b/ports/atmel-samd/board_busses.c index 02d08133c77d1..008391bf0a4b2 100644 --- a/ports/atmel-samd/board_busses.c +++ b/ports/atmel-samd/board_busses.c @@ -30,11 +30,9 @@ #include "shared-bindings/microcontroller/Pin.h" #include "mpconfigboard.h" -#include "pins.h" +#include "peripherals/pins.h" #include "py/runtime.h" - - #if !defined(DEFAULT_I2C_BUS_SDA) || !defined(DEFAULT_I2C_BUS_SCL) STATIC mp_obj_t board_i2c(void) { mp_raise_NotImplementedError("No default I2C bus"); @@ -112,4 +110,4 @@ MP_DEFINE_CONST_FUN_OBJ_0(board_spi_obj, board_spi); return uart_singleton; } #endif -MP_DEFINE_CONST_FUN_OBJ_0(board_uart_obj, board_uart); \ No newline at end of file +MP_DEFINE_CONST_FUN_OBJ_0(board_uart_obj, board_uart); diff --git a/ports/atmel-samd/boards/arduino_zero/pins.c b/ports/atmel-samd/boards/arduino_zero/pins.c index 4fa417b373c78..8a7ff70e6dbd7 100644 --- a/ports/atmel-samd/boards/arduino_zero/pins.c +++ b/ports/atmel-samd/boards/arduino_zero/pins.c @@ -1,9 +1,7 @@ #include "shared-bindings/board/__init__.h" -#include "samd21_pins.h" #include "board_busses.h" - STATIC const mp_rom_map_elem_t board_global_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_A0), MP_ROM_PTR(&pin_PA02) }, { MP_ROM_QSTR(MP_QSTR_A1), MP_ROM_PTR(&pin_PB08) }, diff --git a/ports/atmel-samd/boards/circuitplayground_express/board.c b/ports/atmel-samd/boards/circuitplayground_express/board.c index eb7ffab4a2fa4..5c5e9f7faf49e 100644 --- a/ports/atmel-samd/boards/circuitplayground_express/board.c +++ b/ports/atmel-samd/boards/circuitplayground_express/board.c @@ -31,7 +31,6 @@ #include "hal/include/hal_gpio.h" #include "shared-bindings/digitalio/DigitalInOut.h" #include "shared-bindings/neopixel_write/__init__.h" -#include "samd21_pins.h" void board_init(void) { diff --git a/ports/atmel-samd/boards/circuitplayground_express/pins.c b/ports/atmel-samd/boards/circuitplayground_express/pins.c index f4540573a8c0c..14ae89c55e838 100644 --- a/ports/atmel-samd/boards/circuitplayground_express/pins.c +++ b/ports/atmel-samd/boards/circuitplayground_express/pins.c @@ -1,4 +1,5 @@ -#include "samd21_pins.h" +#include "shared-bindings/board/__init__.h" + #include "board_busses.h" STATIC const mp_rom_map_elem_t board_global_dict_table[] = { diff --git a/ports/atmel-samd/boards/circuitplayground_express_crickit/board.c b/ports/atmel-samd/boards/circuitplayground_express_crickit/board.c index eb7ffab4a2fa4..5c5e9f7faf49e 100644 --- a/ports/atmel-samd/boards/circuitplayground_express_crickit/board.c +++ b/ports/atmel-samd/boards/circuitplayground_express_crickit/board.c @@ -31,7 +31,6 @@ #include "hal/include/hal_gpio.h" #include "shared-bindings/digitalio/DigitalInOut.h" #include "shared-bindings/neopixel_write/__init__.h" -#include "samd21_pins.h" void board_init(void) { diff --git a/ports/atmel-samd/boards/circuitplayground_express_crickit/pins.c b/ports/atmel-samd/boards/circuitplayground_express_crickit/pins.c index f4540573a8c0c..14ae89c55e838 100644 --- a/ports/atmel-samd/boards/circuitplayground_express_crickit/pins.c +++ b/ports/atmel-samd/boards/circuitplayground_express_crickit/pins.c @@ -1,4 +1,5 @@ -#include "samd21_pins.h" +#include "shared-bindings/board/__init__.h" + #include "board_busses.h" STATIC const mp_rom_map_elem_t board_global_dict_table[] = { diff --git a/ports/atmel-samd/boards/feather_m0_adalogger/pins.c b/ports/atmel-samd/boards/feather_m0_adalogger/pins.c index 7eff106e82994..0754617dddba6 100644 --- a/ports/atmel-samd/boards/feather_m0_adalogger/pins.c +++ b/ports/atmel-samd/boards/feather_m0_adalogger/pins.c @@ -1,4 +1,5 @@ -#include "samd21_pins.h" +#include "shared-bindings/board/__init__.h" + #include "board_busses.h" STATIC const mp_rom_map_elem_t board_global_dict_table[] = { diff --git a/ports/atmel-samd/boards/feather_m0_basic/pins.c b/ports/atmel-samd/boards/feather_m0_basic/pins.c index b3edabe8123b6..4486d27ab4133 100644 --- a/ports/atmel-samd/boards/feather_m0_basic/pins.c +++ b/ports/atmel-samd/boards/feather_m0_basic/pins.c @@ -1,4 +1,5 @@ -#include "samd21_pins.h" +#include "shared-bindings/board/__init__.h" + #include "board_busses.h" STATIC const mp_rom_map_elem_t board_global_dict_table[] = { diff --git a/ports/atmel-samd/boards/feather_m0_express/pins.c b/ports/atmel-samd/boards/feather_m0_express/pins.c index 6bd74f372988d..68666c273ee85 100644 --- a/ports/atmel-samd/boards/feather_m0_express/pins.c +++ b/ports/atmel-samd/boards/feather_m0_express/pins.c @@ -1,4 +1,5 @@ -#include "samd21_pins.h" +#include "shared-bindings/board/__init__.h" + #include "board_busses.h" STATIC const mp_rom_map_elem_t board_global_dict_table[] = { diff --git a/ports/atmel-samd/boards/feather_m0_rfm69/pins.c b/ports/atmel-samd/boards/feather_m0_rfm69/pins.c index e6cede3dd95cb..6055f8a1b2025 100644 --- a/ports/atmel-samd/boards/feather_m0_rfm69/pins.c +++ b/ports/atmel-samd/boards/feather_m0_rfm69/pins.c @@ -1,4 +1,5 @@ -#include "samd21_pins.h" +#include "shared-bindings/board/__init__.h" + #include "board_busses.h" STATIC const mp_rom_map_elem_t board_global_dict_table[] = { diff --git a/ports/atmel-samd/boards/feather_m0_rfm9x/pins.c b/ports/atmel-samd/boards/feather_m0_rfm9x/pins.c index 8f52a5767cdca..7395c6e2f1064 100644 --- a/ports/atmel-samd/boards/feather_m0_rfm9x/pins.c +++ b/ports/atmel-samd/boards/feather_m0_rfm9x/pins.c @@ -1,4 +1,5 @@ -#include "samd21_pins.h" +#include "shared-bindings/board/__init__.h" + #include "board_busses.h" STATIC const mp_rom_map_elem_t board_global_dict_table[] = { diff --git a/ports/atmel-samd/boards/feather_m0_supersized/pins.c b/ports/atmel-samd/boards/feather_m0_supersized/pins.c index 6bd74f372988d..68666c273ee85 100644 --- a/ports/atmel-samd/boards/feather_m0_supersized/pins.c +++ b/ports/atmel-samd/boards/feather_m0_supersized/pins.c @@ -1,4 +1,5 @@ -#include "samd21_pins.h" +#include "shared-bindings/board/__init__.h" + #include "board_busses.h" STATIC const mp_rom_map_elem_t board_global_dict_table[] = { diff --git a/ports/atmel-samd/boards/feather_m4_express/pins.c b/ports/atmel-samd/boards/feather_m4_express/pins.c index bc3cb1f477a15..5767f63fad125 100644 --- a/ports/atmel-samd/boards/feather_m4_express/pins.c +++ b/ports/atmel-samd/boards/feather_m4_express/pins.c @@ -1,4 +1,5 @@ -#include "samd51_pins.h" +#include "shared-bindings/board/__init__.h" + #include "board_busses.h" STATIC const mp_rom_map_elem_t board_global_dict_table[] = { diff --git a/ports/atmel-samd/boards/gemma_m0/pins.c b/ports/atmel-samd/boards/gemma_m0/pins.c index 6d031c6854685..196e438e0b567 100644 --- a/ports/atmel-samd/boards/gemma_m0/pins.c +++ b/ports/atmel-samd/boards/gemma_m0/pins.c @@ -1,4 +1,5 @@ -#include "samd21_pins.h" +#include "shared-bindings/board/__init__.h" + #include "board_busses.h" STATIC const mp_rom_map_elem_t board_global_dict_table[] = { diff --git a/ports/atmel-samd/boards/itsybitsy_m0_express/pins.c b/ports/atmel-samd/boards/itsybitsy_m0_express/pins.c index 2b35c91aad6f8..25407bc147c77 100644 --- a/ports/atmel-samd/boards/itsybitsy_m0_express/pins.c +++ b/ports/atmel-samd/boards/itsybitsy_m0_express/pins.c @@ -1,4 +1,5 @@ -#include "samd21_pins.h" +#include "shared-bindings/board/__init__.h" + #include "board_busses.h" STATIC const mp_rom_map_elem_t board_global_dict_table[] = { diff --git a/ports/atmel-samd/boards/itsybitsy_m4_express/pins.c b/ports/atmel-samd/boards/itsybitsy_m4_express/pins.c index fdcf039e64dbf..3997ecda42b96 100644 --- a/ports/atmel-samd/boards/itsybitsy_m4_express/pins.c +++ b/ports/atmel-samd/boards/itsybitsy_m4_express/pins.c @@ -1,4 +1,5 @@ -#include "samd51_pins.h" +#include "shared-bindings/board/__init__.h" + #include "board_busses.h" // This mapping only includes functional names because pins broken diff --git a/ports/atmel-samd/boards/metro_m0_express/pins.c b/ports/atmel-samd/boards/metro_m0_express/pins.c index 4cd8752bea502..13f0eb0ba2797 100644 --- a/ports/atmel-samd/boards/metro_m0_express/pins.c +++ b/ports/atmel-samd/boards/metro_m0_express/pins.c @@ -1,4 +1,5 @@ -#include "samd21_pins.h" +#include "shared-bindings/board/__init__.h" + #include "board_busses.h" STATIC const mp_rom_map_elem_t board_global_dict_table[] = { diff --git a/ports/atmel-samd/boards/metro_m4_express/pins.c b/ports/atmel-samd/boards/metro_m4_express/pins.c index 8dc0f25d6b3c1..0e66817f7cfcc 100644 --- a/ports/atmel-samd/boards/metro_m4_express/pins.c +++ b/ports/atmel-samd/boards/metro_m4_express/pins.c @@ -1,4 +1,5 @@ -#include "samd51_pins.h" +#include "shared-bindings/board/__init__.h" + #include "board_busses.h" // This mapping only includes functional names because pins broken diff --git a/ports/atmel-samd/boards/metro_m4_express_revb/mpconfigboard.h b/ports/atmel-samd/boards/metro_m4_express_revb/mpconfigboard.h deleted file mode 100644 index db51140d66a83..0000000000000 --- a/ports/atmel-samd/boards/metro_m4_express_revb/mpconfigboard.h +++ /dev/null @@ -1,72 +0,0 @@ -// This is for Rev B which a larger run was done and sent to Adafruit community -// members. - -#define MICROPY_HW_BOARD_NAME "Metro M4 Express Rev B (Black)" -#define MICROPY_HW_MCU_NAME "samd51j19" - -#define CIRCUITPY_MCU_FAMILY samd51 - -#define MICROPY_HW_LED_TX PIN_PA27 -#define MICROPY_HW_LED_RX PIN_PB06 - -#define MICROPY_HW_NEOPIXEL (&pin_PB17) - -#define SPI_FLASH_BAUDRATE (60000000) - -// Rev B: single channel SPI -// Rev C will be QSPI -#define SPI_FLASH_MOSI_PIN PIN_PB08 -#define SPI_FLASH_MISO_PIN PIN_PB11 -#define SPI_FLASH_SCK_PIN PIN_PB09 -#define SPI_FLASH_CS_PIN PIN_PB10 -#define SPI_FLASH_MOSI_PIN_FUNCTION PINMUX_PB08D_SERCOM4_PAD0 -#define SPI_FLASH_MISO_PIN_FUNCTION PINMUX_PB11D_SERCOM4_PAD3 -#define SPI_FLASH_SCK_PIN_FUNCTION PINMUX_PB09D_SERCOM4_PAD1 -#define SPI_FLASH_SERCOM SERCOM4 -#define SPI_FLASH_SERCOM_INDEX 4 -#define SPI_FLASH_MOSI_PAD 0 -#define SPI_FLASH_MISO_PAD 3 -#define SPI_FLASH_SCK_PAD 1 -// Transmit Data Pinout -// <0x0=>PAD[0,1]_DO_SCK -// <0x1=>PAD[2,3]_DO_SCK -// <0x2=>PAD[3,1]_DO_SCK -// <0x3=>PAD[0,3]_DO_SCK -#define SPI_FLASH_DOPO 0 -#define SPI_FLASH_DIPO 3 // same as MISO pad - -// These are pins not to reset. -// Pin for TX LED -#define MICROPY_PORT_A (PORT_PA27) -// Pins for RX LED, SPI flash and neopixel -#define MICROPY_PORT_B (PORT_PB06 | PORT_PB08 | PORT_PB09 | PORT_PB10 | PORT_PB11 | PORT_PB17) -#define MICROPY_PORT_C (0) -#define MICROPY_PORT_D (0) - -#define AUTORESET_DELAY_MS 500 - -#include "external_flash/external_flash.h" - -// If you change this, then make sure to update the linker scripts as well to -// make sure you don't overwrite code -#define CIRCUITPY_INTERNAL_NVM_SIZE 8192 - -#define BOARD_FLASH_SIZE (FLASH_SIZE - 0x4000 - CIRCUITPY_INTERNAL_NVM_SIZE) - -#include "external_flash/devices.h" - -#define EXTERNAL_FLASH_DEVICE_COUNT 2 -#define EXTERNAL_FLASH_DEVICES S25FL216K, \ - GD25Q16C - -#include "external_flash/external_flash.h" - -#define DEFAULT_I2C_BUS_SCL (&pin_PB03) -#define DEFAULT_I2C_BUS_SDA (&pin_PB02) - -#define DEFAULT_SPI_BUS_SCK (&pin_PA13) -#define DEFAULT_SPI_BUS_MOSI (&pin_PA12) -#define DEFAULT_SPI_BUS_MISO (&pin_PA15) - -#define DEFAULT_UART_BUS_RX (&pin_PA23) -#define DEFAULT_UART_BUS_TX (&pin_PA22) diff --git a/ports/atmel-samd/boards/metro_m4_express_revb/mpconfigboard.mk b/ports/atmel-samd/boards/metro_m4_express_revb/mpconfigboard.mk deleted file mode 100644 index 9e6965063c3df..0000000000000 --- a/ports/atmel-samd/boards/metro_m4_express_revb/mpconfigboard.mk +++ /dev/null @@ -1,11 +0,0 @@ -LD_FILE = boards/samd51x19-bootloader-external-flash.ld -USB_VID = 0x239A -USB_PID = 0x8021 -USB_PRODUCT = "Metro M4 Express Rev B (Black)" -USB_MANUFACTURER = "Adafruit Industries LLC" - -SPI_FLASH_FILESYSTEM = 1 -LONGINT_IMPL = MPZ - -CHIP_VARIANT = SAMD51J19A -CHIP_FAMILY = samd51 diff --git a/ports/atmel-samd/boards/metro_m4_express_revb/pins.c b/ports/atmel-samd/boards/metro_m4_express_revb/pins.c deleted file mode 100644 index 23e662f1c3bef..0000000000000 --- a/ports/atmel-samd/boards/metro_m4_express_revb/pins.c +++ /dev/null @@ -1,48 +0,0 @@ -#include "samd51_pins.h" -#include "board_busses.h" - -// This mapping only includes functional names because pins broken -// out on connectors are labeled with their MCU name available from -// microcontroller.pin. -STATIC const mp_map_elem_t board_global_dict_table[] = { - { MP_OBJ_NEW_QSTR(MP_QSTR_A0), (mp_obj_t)&pin_PA02 }, - { MP_OBJ_NEW_QSTR(MP_QSTR_A1), (mp_obj_t)&pin_PA05 }, - { MP_OBJ_NEW_QSTR(MP_QSTR_A2), (mp_obj_t)&pin_PA06 }, - { MP_OBJ_NEW_QSTR(MP_QSTR_A3), (mp_obj_t)&pin_PA04 }, - { MP_OBJ_NEW_QSTR(MP_QSTR_A4), (mp_obj_t)&pin_PA11 }, - { MP_OBJ_NEW_QSTR(MP_QSTR_A5), (mp_obj_t)&pin_PA07 }, - - - { MP_OBJ_NEW_QSTR(MP_QSTR_D0), (mp_obj_t)&pin_PA23 }, - { MP_OBJ_NEW_QSTR(MP_QSTR_RX), (mp_obj_t)&pin_PA23 }, - { MP_OBJ_NEW_QSTR(MP_QSTR_D1), (mp_obj_t)&pin_PA22 }, - { MP_OBJ_NEW_QSTR(MP_QSTR_TX), (mp_obj_t)&pin_PA22 }, - { MP_OBJ_NEW_QSTR(MP_QSTR_D2), (mp_obj_t)&pin_PA08 }, - { MP_OBJ_NEW_QSTR(MP_QSTR_D3), (mp_obj_t)&pin_PA10 }, - { MP_OBJ_NEW_QSTR(MP_QSTR_D4), (mp_obj_t)&pin_PB12 }, - { MP_OBJ_NEW_QSTR(MP_QSTR_D5), (mp_obj_t)&pin_PB14 }, - { MP_OBJ_NEW_QSTR(MP_QSTR_D6), (mp_obj_t)&pin_PB15 }, - { MP_OBJ_NEW_QSTR(MP_QSTR_D7), (mp_obj_t)&pin_PA14 }, - { MP_OBJ_NEW_QSTR(MP_QSTR_D8), (mp_obj_t)&pin_PA16 }, - { MP_OBJ_NEW_QSTR(MP_QSTR_D9), (mp_obj_t)&pin_PA17 }, - { MP_OBJ_NEW_QSTR(MP_QSTR_D10), (mp_obj_t)&pin_PA18 }, - { MP_OBJ_NEW_QSTR(MP_QSTR_D11), (mp_obj_t)&pin_PA19 }, - { MP_OBJ_NEW_QSTR(MP_QSTR_D12), (mp_obj_t)&pin_PA20 }, - { MP_OBJ_NEW_QSTR(MP_QSTR_D13), (mp_obj_t)&pin_PA21 }, - - { MP_OBJ_NEW_QSTR(MP_QSTR_SDA), (mp_obj_t)&pin_PB02 }, - { MP_OBJ_NEW_QSTR(MP_QSTR_SCL), (mp_obj_t)&pin_PB03 }, - - { MP_OBJ_NEW_QSTR(MP_QSTR_NEOPIXEL), (mp_obj_t)&pin_PB17 }, - - { MP_OBJ_NEW_QSTR(MP_QSTR_SCK), (mp_obj_t)&pin_PA13 }, - { MP_OBJ_NEW_QSTR(MP_QSTR_MOSI), (mp_obj_t)&pin_PA12 }, - { MP_OBJ_NEW_QSTR(MP_QSTR_MISO), (mp_obj_t)&pin_PA15 }, - - { MP_OBJ_NEW_QSTR(MP_QSTR_LED_RX), (mp_obj_t)&pin_PB06 }, - { MP_OBJ_NEW_QSTR(MP_QSTR_LED_TX), (mp_obj_t)&pin_PA27 }, - { MP_ROM_QSTR(MP_QSTR_I2C), MP_ROM_PTR(&board_i2c_obj) }, - { MP_ROM_QSTR(MP_QSTR_SPI), MP_ROM_PTR(&board_spi_obj) }, - { MP_ROM_QSTR(MP_QSTR_UART), MP_ROM_PTR(&board_uart_obj) }, -}; -MP_DEFINE_CONST_DICT(board_module_globals, board_global_dict_table); diff --git a/ports/atmel-samd/boards/pirkey_m0/pins.c b/ports/atmel-samd/boards/pirkey_m0/pins.c index 7efc8eb33f42f..e08302f140ba3 100644 --- a/ports/atmel-samd/boards/pirkey_m0/pins.c +++ b/ports/atmel-samd/boards/pirkey_m0/pins.c @@ -1,4 +1,5 @@ -#include "samd21_pins.h" +#include "shared-bindings/board/__init__.h" + #include "board_busses.h" STATIC const mp_rom_map_elem_t board_global_dict_table[] = { diff --git a/ports/atmel-samd/boards/trinket_m0/pins.c b/ports/atmel-samd/boards/trinket_m0/pins.c index 0fdcbc2790378..6330170249073 100644 --- a/ports/atmel-samd/boards/trinket_m0/pins.c +++ b/ports/atmel-samd/boards/trinket_m0/pins.c @@ -1,4 +1,5 @@ -#include "samd21_pins.h" +#include "shared-bindings/board/__init__.h" + #include "board_busses.h" STATIC const mp_rom_map_elem_t board_global_dict_table[] = { diff --git a/ports/atmel-samd/boards/trinket_m0_haxpress/pins.c b/ports/atmel-samd/boards/trinket_m0_haxpress/pins.c index 0fdcbc2790378..6330170249073 100644 --- a/ports/atmel-samd/boards/trinket_m0_haxpress/pins.c +++ b/ports/atmel-samd/boards/trinket_m0_haxpress/pins.c @@ -1,4 +1,5 @@ -#include "samd21_pins.h" +#include "shared-bindings/board/__init__.h" + #include "board_busses.h" STATIC const mp_rom_map_elem_t board_global_dict_table[] = { diff --git a/ports/atmel-samd/boards/ugame10/pins.c b/ports/atmel-samd/boards/ugame10/pins.c index acf73c9ffc9f0..87ace5e96f5bb 100644 --- a/ports/atmel-samd/boards/ugame10/pins.c +++ b/ports/atmel-samd/boards/ugame10/pins.c @@ -1,4 +1,5 @@ -#include "samd21_pins.h" +#include "shared-bindings/board/__init__.h" + #include "board_busses.h" STATIC const mp_rom_map_elem_t board_global_dict_table[] = { diff --git a/ports/atmel-samd/common-hal/analogio/AnalogIn.c b/ports/atmel-samd/common-hal/analogio/AnalogIn.c index 02613ae0785ec..e452eb0305fdc 100644 --- a/ports/atmel-samd/common-hal/analogio/AnalogIn.c +++ b/ports/atmel-samd/common-hal/analogio/AnalogIn.c @@ -34,7 +34,7 @@ #include "py/binary.h" #include "py/mphal.h" -#include "peripherals.h" +#include "peripherals/adc.h" #include "shared-bindings/analogio/AnalogIn.h" #include "atmel_start_pins.h" diff --git a/ports/atmel-samd/common-hal/analogio/AnalogOut.c b/ports/atmel-samd/common-hal/analogio/AnalogOut.c index 97299a8634cde..9ceca386839d9 100644 --- a/ports/atmel-samd/common-hal/analogio/AnalogOut.c +++ b/ports/atmel-samd/common-hal/analogio/AnalogOut.c @@ -42,10 +42,6 @@ #include "hpl/pm/hpl_pm_base.h" #endif -#ifdef SAMD51 -#include "samd51_pins.h" -#endif - void common_hal_analogio_analogout_construct(analogio_analogout_obj_t* self, const mcu_pin_obj_t *pin) { if (pin->pin != PIN_PA02 @@ -73,7 +69,7 @@ void common_hal_analogio_analogout_construct(analogio_analogout_obj_t* self, #endif // SAMD21: This clock should be <= 12 MHz, per datasheet section 47.6.3. - // SAMD51: This clock should be <= 350kHz, per datasheet table 37-6. + // SAMD51: This clock should be <= 350kHz, per datasheet table 37-6. _gclk_enable_channel(DAC_GCLK_ID, CONF_GCLK_DAC_SRC); // Don't double init the DAC on the SAMD51 when both outputs are in use. We use the free state diff --git a/ports/atmel-samd/common-hal/audiobusio/I2SOut.c b/ports/atmel-samd/common-hal/audiobusio/I2SOut.c index f4a8eb52e809c..27a7b9ee0465e 100644 --- a/ports/atmel-samd/common-hal/audiobusio/I2SOut.c +++ b/ports/atmel-samd/common-hal/audiobusio/I2SOut.c @@ -45,13 +45,14 @@ #include "hpl/pm/hpl_pm_base.h" #endif +#include "peripherals/clocks.h" +#include "peripherals/dma.h" +#include "peripherals/events.h" +#include "peripherals/i2s.h" +#include "peripherals/pins.h" +#include "peripherals/timers.h" + #include "audio_dma.h" -#include "clocks.h" -#include "events.h" -#include "i2s.h" -#include "pins.h" -#include "shared_dma.h" -#include "timers.h" #ifdef SAMD21 #define SERCTRL(name) I2S_SERCTRL_ ## name diff --git a/ports/atmel-samd/common-hal/audiobusio/PDMIn.c b/ports/atmel-samd/common-hal/audiobusio/PDMIn.c index 44129eed12399..5502fcd8125b2 100644 --- a/ports/atmel-samd/common-hal/audiobusio/PDMIn.c +++ b/ports/atmel-samd/common-hal/audiobusio/PDMIn.c @@ -41,12 +41,13 @@ #include "hal/include/hal_gpio.h" #include "hal/utils/include/utils.h" +#include "peripherals/clocks.h" +#include "peripherals/events.h" +#include "peripherals/i2s.h" +#include "peripherals/pins.h" +#include "peripherals/dma.h" + #include "audio_dma.h" -#include "clocks.h" -#include "events.h" -#include "i2s.h" -#include "pins.h" -#include "shared_dma.h" #include "tick.h" #define OVERSAMPLING 64 diff --git a/ports/atmel-samd/common-hal/audioio/AudioOut.c b/ports/atmel-samd/common-hal/audioio/AudioOut.c index 331ae9c9b5d49..fc5c7567313c7 100644 --- a/ports/atmel-samd/common-hal/audioio/AudioOut.c +++ b/ports/atmel-samd/common-hal/audioio/AudioOut.c @@ -45,10 +45,11 @@ #endif #include "audio_dma.h" -#include "events.h" -#include "samd21_pins.h" -#include "shared_dma.h" -#include "timers.h" + +#include "peripherals/dma.h" +#include "peripherals/events.h" +#include "peripherals/pins.h" +#include "peripherals/timers.h" void audioout_reset(void) { } diff --git a/ports/atmel-samd/common-hal/busio/I2C.c b/ports/atmel-samd/common-hal/busio/I2C.c index 347a2e3490491..66929beff55b3 100644 --- a/ports/atmel-samd/common-hal/busio/I2C.c +++ b/ports/atmel-samd/common-hal/busio/I2C.c @@ -32,8 +32,7 @@ #include "hal/include/hal_i2c_m_sync.h" #include "hal/include/hpl_i2c_m_sync.h" -#include "peripherals.h" -#include "pins.h" +#include "peripherals/sercom.h" #include "shared-bindings/microcontroller/__init__.h" diff --git a/ports/atmel-samd/common-hal/busio/SPI.c b/ports/atmel-samd/common-hal/busio/SPI.c index a2bf30f054f5a..a2ee93c6db493 100644 --- a/ports/atmel-samd/common-hal/busio/SPI.c +++ b/ports/atmel-samd/common-hal/busio/SPI.c @@ -36,9 +36,9 @@ #include "hal/include/hpl_spi_m_sync.h" #include "supervisor/shared/rgb_led_status.h" -#include "peripherals.h" -#include "pins.h" -#include "shared_dma.h" +#include "peripherals/dma.h" +//#include "peripherals/pins.h" +#include "peripherals/sercom.h" void common_hal_busio_spi_construct(busio_spi_obj_t *self, const mcu_pin_obj_t * clock, const mcu_pin_obj_t * mosi, diff --git a/ports/atmel-samd/common-hal/busio/UART.c b/ports/atmel-samd/common-hal/busio/UART.c index 5376775206c36..a95ccf3accdd4 100644 --- a/ports/atmel-samd/common-hal/busio/UART.c +++ b/ports/atmel-samd/common-hal/busio/UART.c @@ -42,8 +42,7 @@ #include "hal/include/hal_usart_async.h" #include "hal/include/hpl_usart_async.h" -#include "peripherals.h" -#include "pins.h" +#include "peripherals/sercom.h" // Do-nothing callback needed so that usart_async code will enable rx interrupts. // See comment below re usart_async_register_callback() diff --git a/ports/atmel-samd/common-hal/microcontroller/Pin.c b/ports/atmel-samd/common-hal/microcontroller/Pin.c index e1ca5d6223817..ad97581e140d7 100644 --- a/ports/atmel-samd/common-hal/microcontroller/Pin.c +++ b/ports/atmel-samd/common-hal/microcontroller/Pin.c @@ -29,13 +29,8 @@ #include "atmel_start_pins.h" #include "hal/include/hal_gpio.h" +#include "peripherals/pins.h" #include "supervisor/shared/rgb_led_status.h" -#ifdef SAMD21 -#include "samd21_pins.h" -#endif -#ifdef SAMD51 -#include "samd51_pins.h" -#endif #ifdef MICROPY_HW_NEOPIXEL bool neopixel_in_use; diff --git a/ports/atmel-samd/common-hal/microcontroller/Pin.h b/ports/atmel-samd/common-hal/microcontroller/Pin.h index 4e21a14cd860d..4230246a5a52c 100644 --- a/ports/atmel-samd/common-hal/microcontroller/Pin.h +++ b/ports/atmel-samd/common-hal/microcontroller/Pin.h @@ -81,4 +81,6 @@ void reset_all_pins(void); void reset_pin(uint8_t pin); void claim_pin(const mcu_pin_obj_t* pin); +#include "peripherals/pins.h" + #endif // MICROPY_INCLUDED_ATMEL_SAMD_COMMON_HAL_MICROCONTROLLER_PIN_H diff --git a/ports/atmel-samd/common-hal/microcontroller/Processor.c b/ports/atmel-samd/common-hal/microcontroller/Processor.c index e7f758cd105c3..a76ee2e78ce5b 100644 --- a/ports/atmel-samd/common-hal/microcontroller/Processor.c +++ b/ports/atmel-samd/common-hal/microcontroller/Processor.c @@ -63,7 +63,7 @@ #include "common-hal/microcontroller/Processor.h" -#include "peripherals.h" +#include "peripherals/adc.h" #include "peripheral_clk_config.h" diff --git a/ports/atmel-samd/common-hal/microcontroller/__init__.c b/ports/atmel-samd/common-hal/microcontroller/__init__.c index a9c83646fd3c3..fa057facacdde 100644 --- a/ports/atmel-samd/common-hal/microcontroller/__init__.c +++ b/ports/atmel-samd/common-hal/microcontroller/__init__.c @@ -30,10 +30,10 @@ #include "py/runtime.h" #include "reset.h" -#include "samd21_pins.h" #include "shared-bindings/nvm/ByteArray.h" #include "shared-bindings/microcontroller/__init__.h" +#include "shared-bindings/microcontroller/Pin.h" #include "shared-bindings/microcontroller/Processor.h" void common_hal_mcu_delay_us(uint32_t delay) { diff --git a/ports/atmel-samd/common-hal/pulseio/PWMOut.c b/ports/atmel-samd/common-hal/pulseio/PWMOut.c index 24cd154c2a008..18d896686aa42 100644 --- a/ports/atmel-samd/common-hal/pulseio/PWMOut.c +++ b/ports/atmel-samd/common-hal/pulseio/PWMOut.c @@ -34,9 +34,9 @@ #include "atmel_start_pins.h" #include "hal/utils/include/utils_repeat_macro.h" -#include "timers.h" +#include "peripherals/timers.h" -#include "samd21_pins.h" +#include "peripherals/pins.h" #undef ENABLE diff --git a/ports/atmel-samd/common-hal/pulseio/PulseIn.c b/ports/atmel-samd/common-hal/pulseio/PulseIn.c index 6e3aa3abb3c11..266a9251e92b4 100644 --- a/ports/atmel-samd/common-hal/pulseio/PulseIn.c +++ b/ports/atmel-samd/common-hal/pulseio/PulseIn.c @@ -3,7 +3,7 @@ * * The MIT License (MIT) * - * Copyright (c) 2017 Scott Shawcroft for Adafruit Industries + * Copyright (c) 2017-2018 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 @@ -34,7 +34,7 @@ #include "mpconfigport.h" #include "py/gc.h" #include "py/runtime.h" -#include "samd21_pins.h" +#include "peripherals/pins.h" #include "shared-bindings/microcontroller/__init__.h" #include "shared-bindings/pulseio/PulseIn.h" diff --git a/ports/atmel-samd/common-hal/pulseio/PulseOut.c b/ports/atmel-samd/common-hal/pulseio/PulseOut.c index 95b0bbee07267..8e715d41099f6 100644 --- a/ports/atmel-samd/common-hal/pulseio/PulseOut.c +++ b/ports/atmel-samd/common-hal/pulseio/PulseOut.c @@ -31,11 +31,11 @@ #include "hal/include/hal_gpio.h" #include "mpconfigport.h" +#include "peripherals/pins.h" +#include "peripherals/timers.h" #include "py/gc.h" #include "py/runtime.h" -#include "samd21_pins.h" #include "shared-bindings/pulseio/PulseOut.h" -#include "timers.h" // This timer is shared amongst all PulseOut objects under the assumption that // the code is single threaded. diff --git a/ports/atmel-samd/common-hal/rotaryio/IncrementalEncoder.c b/ports/atmel-samd/common-hal/rotaryio/IncrementalEncoder.c new file mode 100644 index 0000000000000..58119fa7e98dc --- /dev/null +++ b/ports/atmel-samd/common-hal/rotaryio/IncrementalEncoder.c @@ -0,0 +1,158 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2018 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 "common-hal/rotaryio/IncrementalEncoder.h" + +#include + +#include "atmel_start_pins.h" +#include "hal/include/hal_gpio.h" + +#include "mpconfigport.h" +#include "peripherals/pins.h" +#include "py/gc.h" +#include "py/runtime.h" +#include "shared-bindings/microcontroller/__init__.h" + +#ifdef SAMD21 +#include "hpl/gclk/hpl_gclk_base.h" +#endif + +void common_hal_rotaryio_incrementalencoder_construct(rotaryio_incrementalencoder_obj_t* self, + const mcu_pin_obj_t* pin, uint16_t maxlen, bool idle_state) { +// if (!pin->has_extint) { +// mp_raise_RuntimeError("No hardware support on pin"); +// } +// uint32_t mask = 1 << pin->extint_channel; +// if (active_incrementalencoders[pin->extint_channel] != NULL || +// (eic_get_enable() == 1 && +// #ifdef SAMD51 +// ((EIC->INTENSET.bit.EXTINT & mask) != 0 || +// (EIC->EVCTRL.bit.EXTINTEO & mask) != 0))) { +// #endif +// #ifdef SAMD21 +// ((EIC->INTENSET.vec.EXTINT & mask) != 0 || +// (EIC->EVCTRL.vec.EXTINTEO & mask) != 0))) { +// #endif +// mp_raise_RuntimeError("EXTINT channel already in use"); +// } +// +// self->buffer = (uint16_t *) m_malloc(maxlen * sizeof(uint16_t), false); +// if (self->buffer == NULL) { +// mp_raise_msg_varg(&mp_type_MemoryError, "Failed to allocate RX buffer of %d bytes", maxlen * sizeof(uint16_t)); +// } +// self->channel = pin->extint_channel; +// self->pin = pin->pin; +// self->maxlen = maxlen; +// self->idle_state = idle_state; +// self->start = 0; +// self->len = 0; +// self->first_edge = true; +// +// active_incrementalencoders[pin->extint_channel] = self; +// +// // Check to see if the EIC is enabled and start it up if its not.' +// // SAMD51 EIC can only be clocked up to 100mhz so we use the 48mhz clock. +// if (eic_get_enable() == 0) { +// #ifdef SAMD51 +// MCLK->APBAMASK.bit.EIC_ = true; +// hri_gclk_write_PCHCTRL_reg(GCLK, EIC_GCLK_ID, +// GCLK_PCHCTRL_GEN_GCLK1_Val | (1 << GCLK_PCHCTRL_CHEN_Pos)); +// #endif +// +// #ifdef SAMD21 +// PM->APBAMASK.bit.EIC_ = true; +// _gclk_enable_channel(EIC_GCLK_ID, GCLK_CLKCTRL_GEN_GCLK0_Val); +// #endif +// +// +// #ifdef SAMD21 +// NVIC_DisableIRQ(EIC_IRQn); +// NVIC_ClearPendingIRQ(EIC_IRQn); +// NVIC_EnableIRQ(EIC_IRQn); +// #endif +// } +// +// gpio_set_pin_function(pin->pin, GPIO_PIN_FUNCTION_A); +// +// #ifdef SAMD51 +// NVIC_DisableIRQ(EIC_0_IRQn + self->channel); +// NVIC_ClearPendingIRQ(EIC_0_IRQn + self->channel); +// NVIC_EnableIRQ(EIC_0_IRQn + self->channel); +// #endif +// +// // Set config will enable the EIC. +// incrementalencoder_set_config(self, true); +// EIC->INTENSET.reg = mask << EIC_INTENSET_EXTINT_Pos; +} + +bool common_hal_rotaryio_incrementalencoder_deinited(rotaryio_incrementalencoder_obj_t* self) { + //return self->pin == NO_PIN; + return true; +} + +void common_hal_rotaryio_incrementalencoder_deinit(rotaryio_incrementalencoder_obj_t* self) { + // if (common_hal_rotaryio_incrementalencoder_deinited(self)) { + // return; + // } + // uint32_t mask = 1 << self->channel; + // EIC->INTENCLR.reg = mask << EIC_INTENSET_EXTINT_Pos; + // #ifdef SAMD51 + // NVIC_DisableIRQ(EIC_0_IRQn + self->channel); + // NVIC_ClearPendingIRQ(EIC_0_IRQn + self->channel); + // #endif + // active_incrementalencoders[self->channel] = NULL; + // reset_pin(self->pin); + // self->pin = NO_PIN; + // + // bool all_null = true; + // for (uint8_t i = 0; all_null && i < 16; i++) { + // all_null = all_null && active_incrementalencoders[i] == NULL; + // } + // #ifdef SAMD21 + // if (all_null && EIC->INTENSET.reg == 0) { + // NVIC_DisableIRQ(EIC_IRQn); + // NVIC_ClearPendingIRQ(EIC_IRQn); + // } + // #endif + // // Test if all channels are null and deinit everything if they are. + // if (all_null && EIC->EVCTRL.reg == 0 && EIC->INTENSET.reg == 0) { + // eic_set_enable(false); + // #ifdef SAMD51 + // MCLK->APBAMASK.bit.EIC_ = false; + // hri_gclk_write_PCHCTRL_reg(GCLK, EIC_GCLK_ID, 0); + // #endif + // + // #ifdef SAMD21 + // PM->APBAMASK.bit.EIC_ = false; + // hri_gclk_write_CLKCTRL_reg(GCLK, GCLK_CLKCTRL_ID(EIC_GCLK_ID)); + // #endif + // } +} + +mp_int_t common_hal_rotaryio_incrementalencoder_get_position(rotaryio_incrementalencoder_obj_t* self) { + return 0; +} diff --git a/ports/atmel-samd/common-hal/rotaryio/IncrementalEncoder.h b/ports/atmel-samd/common-hal/rotaryio/IncrementalEncoder.h new file mode 100644 index 0000000000000..c878239bcf8c1 --- /dev/null +++ b/ports/atmel-samd/common-hal/rotaryio/IncrementalEncoder.h @@ -0,0 +1,40 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2018 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_COMMON_HAL_ROTARYIO_INCREMENTALENCODER_H +#define MICROPY_INCLUDED_ATMEL_SAMD_COMMON_HAL_ROTARYIO_INCREMENTALENCODER_H + +#include "common-hal/microcontroller/Pin.h" + +#include "py/obj.h" + +typedef struct { + mp_obj_base_t base; + uint8_t pin_a; + uint8_t pin_b; +} rotaryio_incrementalencoder_obj_t; + +#endif // MICROPY_INCLUDED_ATMEL_SAMD_COMMON_HAL_ROTARYIO_INCREMENTALENCODER_H diff --git a/ports/atmel-samd/common-hal/rotaryio/__init__.c b/ports/atmel-samd/common-hal/rotaryio/__init__.c new file mode 100644 index 0000000000000..2bee925bc77fb --- /dev/null +++ b/ports/atmel-samd/common-hal/rotaryio/__init__.c @@ -0,0 +1 @@ +// No pulseio module functions. diff --git a/ports/atmel-samd/common-hal/touchio/TouchIn.c b/ports/atmel-samd/common-hal/touchio/TouchIn.c index eda1b72c43719..e39a091d792cf 100644 --- a/ports/atmel-samd/common-hal/touchio/TouchIn.c +++ b/ports/atmel-samd/common-hal/touchio/TouchIn.c @@ -37,10 +37,10 @@ #include "hpl/pm/hpl_pm_base.h" #endif -#include "clocks.h" -#include "samd21_pins.h" -#include "tick.h" +#include "peripherals/clocks.h" +#include "peripherals/pins.h" +#include "tick.h" #include "adafruit_ptc.h" bool touch_enabled = false; diff --git a/ports/atmel-samd/external_flash/external_flash.c b/ports/atmel-samd/external_flash/external_flash.c index ccc47e5b144cd..b0e40fc7050ea 100644 --- a/ports/atmel-samd/external_flash/external_flash.c +++ b/ports/atmel-samd/external_flash/external_flash.c @@ -36,12 +36,10 @@ #include "py/obj.h" #include "py/runtime.h" #include "lib/oofatfs/ff.h" -#include "peripherals.h" +//#include "peripherals.h" #include "shared-bindings/microcontroller/__init__.h" #include "supervisor/shared/rgb_led_status.h" -//#include "shared_dma.h" - #include "hal_gpio.h" #include "hal_spi_m_sync.h" diff --git a/ports/atmel-samd/external_flash/qspi_flash.c b/ports/atmel-samd/external_flash/qspi_flash.c index 3fc9d31be4189..ec91c21e2dd60 100644 --- a/ports/atmel-samd/external_flash/qspi_flash.c +++ b/ports/atmel-samd/external_flash/qspi_flash.c @@ -32,8 +32,8 @@ #include "mpconfigboard.h" // for EXTERNAL_FLASH_QSPI_DUAL #include "external_flash/common_commands.h" -#include "peripherals.h" -#include "shared_dma.h" +#include "peripherals/cache.h" +#include "peripherals/dma.h" #include "atmel_start_pins.h" #include "hal_gpio.h" diff --git a/ports/atmel-samd/external_flash/spi_flash.c b/ports/atmel-samd/external_flash/spi_flash.c index 8a8cbaef816af..faad8d9e0fad1 100644 --- a/ports/atmel-samd/external_flash/spi_flash.c +++ b/ports/atmel-samd/external_flash/spi_flash.c @@ -29,8 +29,8 @@ #include #include "external_flash/common_commands.h" -#include "peripherals.h" -#include "shared_dma.h" +#include "peripherals/sercom.h" +#include "py/mpconfig.h" #include "hal_gpio.h" #include "hal_spi_m_sync.h" diff --git a/ports/atmel-samd/mpconfigport.h b/ports/atmel-samd/mpconfigport.h index cd05927b08043..ee75a26c5b588 100644 --- a/ports/atmel-samd/mpconfigport.h +++ b/ports/atmel-samd/mpconfigport.h @@ -174,6 +174,7 @@ extern const struct _mp_obj_module_t board_module; extern const struct _mp_obj_module_t math_module; extern const struct _mp_obj_module_t os_module; extern const struct _mp_obj_module_t random_module; +extern const struct _mp_obj_module_t rotaryio_module; extern const struct _mp_obj_module_t rtc_module; extern const struct _mp_obj_module_t samd_module; extern const struct _mp_obj_module_t storage_module; @@ -220,6 +221,7 @@ extern const struct _mp_obj_module_t usb_hid_module; { MP_OBJ_NEW_QSTR(MP_QSTR_audioio), (mp_obj_t)&audioio_module }, \ AUDIOBUSIO_MODULE \ { MP_OBJ_NEW_QSTR(MP_QSTR_bitbangio), (mp_obj_t)&bitbangio_module }, \ + { MP_OBJ_NEW_QSTR(MP_QSTR_rotaryio), (mp_obj_t)&rotaryio_module }, \ { MP_OBJ_NEW_QSTR(MP_QSTR_gamepad),(mp_obj_t)&gamepad_module } #endif #define EXPRESS_BOARD @@ -304,7 +306,7 @@ extern const struct _mp_obj_module_t usb_hid_module; #define MP_STATE_PORT MP_STATE_VM -#include "shared_dma.h" +#include "peripherals/dma.h" #define MICROPY_PORT_ROOT_POINTERS \ const char *readline_hist[8]; \ diff --git a/ports/atmel-samd/samd21_peripherals.h b/ports/atmel-samd/peripherals/adc.h similarity index 78% rename from ports/atmel-samd/samd21_peripherals.h rename to ports/atmel-samd/peripherals/adc.h index 805717695aed3..6530b1dcdc033 100644 --- a/ports/atmel-samd/samd21_peripherals.h +++ b/ports/atmel-samd/peripherals/adc.h @@ -24,15 +24,12 @@ * THE SOFTWARE. */ -#ifndef MICROPY_INCLUDED_ATMEL_SAMD_SAMD21_PERIPHERALS_H -#define MICROPY_INCLUDED_ATMEL_SAMD_SAMD21_PERIPHERALS_H +#ifndef MICROPY_INCLUDED_ATMEL_SAMD_PERIPHERALS_ADC_H +#define MICROPY_INCLUDED_ATMEL_SAMD_PERIPHERALS_ADC_H #include "include/sam.h" #include "hal/include/hal_adc_sync.h" -void samd_peripherals_sercom_clock_init(Sercom* sercom, uint8_t sercom_index); -uint8_t samd_peripherals_get_spi_dopo(uint8_t clock_pad, uint8_t mosi_pad); -bool samd_peripherals_valid_spi_clock_pad(uint8_t clock_pad); void samd_peripherals_adc_setup(struct adc_sync_descriptor *adc, Adc *instance); -#endif // MICROPY_INCLUDED_ATMEL_SAMD_SAMD21_PERIPHERALS_H +#endif // MICROPY_INCLUDED_ATMEL_SAMD_PERIPHERALS_ADC_H diff --git a/ports/atmel-samd/samd51_peripherals.h b/ports/atmel-samd/peripherals/cache.h similarity index 81% rename from ports/atmel-samd/samd51_peripherals.h rename to ports/atmel-samd/peripherals/cache.h index 6643379a5ca92..b260568a3b3ca 100644 --- a/ports/atmel-samd/samd51_peripherals.h +++ b/ports/atmel-samd/peripherals/cache.h @@ -27,14 +27,6 @@ #ifndef MICROPY_INCLUDED_ATMEL_SAMD_SAMD51_PERIPHERALS_H #define MICROPY_INCLUDED_ATMEL_SAMD_SAMD51_PERIPHERALS_H -#include "sam.h" -#include "hal/include/hal_adc_sync.h" - -void samd_peripherals_sercom_clock_init(Sercom* sercom, uint8_t sercom_index); -uint8_t samd_peripherals_get_spi_dopo(uint8_t clock_pad, uint8_t mosi_pad); -bool samd_peripherals_valid_spi_clock_pad(uint8_t clock_pad); -void samd_peripherals_adc_setup(struct adc_sync_descriptor *adc, Adc *instance); - void samd_peripherals_disable_and_clear_cache(void); void samd_peripherals_enable_cache(void); diff --git a/ports/atmel-samd/clocks.c b/ports/atmel-samd/peripherals/clocks.c similarity index 100% rename from ports/atmel-samd/clocks.c rename to ports/atmel-samd/peripherals/clocks.c diff --git a/ports/atmel-samd/clocks.h b/ports/atmel-samd/peripherals/clocks.h similarity index 100% rename from ports/atmel-samd/clocks.h rename to ports/atmel-samd/peripherals/clocks.h diff --git a/ports/atmel-samd/shared_dma.c b/ports/atmel-samd/peripherals/dma.c similarity index 62% rename from ports/atmel-samd/shared_dma.c rename to ports/atmel-samd/peripherals/dma.c index edc2d0f1a0d2a..664c6aea8f633 100644 --- a/ports/atmel-samd/shared_dma.c +++ b/ports/atmel-samd/peripherals/dma.c @@ -23,7 +23,7 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#include "shared_dma.h" +#include "peripherals/dma.h" #include @@ -48,164 +48,6 @@ COMPILER_ALIGNED(16) static DmacDescriptor write_back_descriptors[DMA_CHANNEL_CO #define FIRST_SERCOM_TX_TRIGSRC 0x05 #endif -static uint8_t sercom_index(Sercom* sercom) { - #ifdef SAMD21 - return ((uint32_t) sercom - (uint32_t) SERCOM0) / 0x400; - #else - const Sercom* sercoms[SERCOM_INST_NUM] = SERCOM_INSTS; - for (uint8_t i = 0; i < SERCOM_INST_NUM; i++) { - if (sercoms[i] == sercom) { - return i; - } - } - return 0; - #endif -} - -void dma_configure(uint8_t channel_number, uint8_t trigsrc, bool output_event) { - #ifdef SAMD21 - common_hal_mcu_disable_interrupts(); - /** Select the DMA channel and clear software trigger */ - DMAC->CHID.reg = DMAC_CHID_ID(channel_number); - DMAC->CHCTRLA.reg &= ~DMAC_CHCTRLA_ENABLE; - DMAC->CHCTRLA.reg = DMAC_CHCTRLA_SWRST; - DMAC->SWTRIGCTRL.reg &= (uint32_t)(~(1 << channel_number)); - uint32_t event_output_enable = 0; - if (output_event) { - event_output_enable = DMAC_CHCTRLB_EVOE; - } - DMAC->CHCTRLB.reg = DMAC_CHCTRLB_LVL_LVL0 | - DMAC_CHCTRLB_TRIGSRC(trigsrc) | - DMAC_CHCTRLB_TRIGACT_BEAT | - event_output_enable; - common_hal_mcu_enable_interrupts(); - #endif - - #ifdef SAMD51 - DmacChannel* channel = &DMAC->Channel[channel_number]; - channel->CHCTRLA.reg &= ~DMAC_CHCTRLA_ENABLE; - channel->CHCTRLA.reg = DMAC_CHCTRLA_SWRST; - if (output_event) { - channel->CHEVCTRL.reg = DMAC_CHEVCTRL_EVOE; - } - channel->CHCTRLA.reg = DMAC_CHCTRLA_TRIGSRC(trigsrc) | - DMAC_CHCTRLA_TRIGACT_BURST | - DMAC_CHCTRLA_BURSTLEN_SINGLE; - #endif -} - -void dma_enable_channel(uint8_t channel_number) { - #ifdef SAMD21 - common_hal_mcu_disable_interrupts(); - /** Select the DMA channel and clear software trigger */ - DMAC->CHID.reg = DMAC_CHID_ID(channel_number); - // Clear any previous interrupts. - DMAC->CHINTFLAG.reg = DMAC_CHINTFLAG_MASK; - DMAC->CHCTRLA.bit.ENABLE = true; - common_hal_mcu_enable_interrupts(); - #endif - - #ifdef SAMD51 - DmacChannel* channel = &DMAC->Channel[channel_number]; - channel->CHCTRLA.bit.ENABLE = true; - // Clear any previous interrupts. - channel->CHINTFLAG.reg = DMAC_CHINTFLAG_MASK; - #endif -} - -void dma_disable_channel(uint8_t channel_number) { - #ifdef SAMD21 - common_hal_mcu_disable_interrupts(); - /** Select the DMA channel and clear software trigger */ - DMAC->CHID.reg = DMAC_CHID_ID(channel_number); - DMAC->CHCTRLA.bit.ENABLE = false; - common_hal_mcu_enable_interrupts(); - #endif - - #ifdef SAMD51 - DmacChannel* channel = &DMAC->Channel[channel_number]; - channel->CHCTRLA.bit.ENABLE = false; - #endif -} - -void dma_suspend_channel(uint8_t channel_number) { - #ifdef SAMD21 - common_hal_mcu_disable_interrupts(); - /** Select the DMA channel and clear software trigger */ - DMAC->CHID.reg = DMAC_CHID_ID(channel_number); - DMAC->CHCTRLB.bit.CMD = DMAC_CHCTRLB_CMD_SUSPEND_Val; - common_hal_mcu_enable_interrupts(); - #endif - - #ifdef SAMD51 - DmacChannel* channel = &DMAC->Channel[channel_number]; - channel->CHCTRLB.reg = DMAC_CHCTRLB_CMD_SUSPEND; - #endif -} - -void dma_resume_channel(uint8_t channel_number) { - #ifdef SAMD21 - common_hal_mcu_disable_interrupts(); - /** Select the DMA channel and clear software trigger */ - DMAC->CHID.reg = DMAC_CHID_ID(channel_number); - DMAC->CHCTRLB.bit.CMD = DMAC_CHCTRLB_CMD_RESUME_Val; - DMAC->CHINTFLAG.reg = DMAC_CHINTFLAG_SUSP; - common_hal_mcu_enable_interrupts(); - #endif - - #ifdef SAMD51 - DmacChannel* channel = &DMAC->Channel[channel_number]; - channel->CHCTRLB.reg = DMAC_CHCTRLB_CMD_RESUME; - #endif -} - -bool dma_channel_enabled(uint8_t channel_number) { - #ifdef SAMD21 - common_hal_mcu_disable_interrupts(); - /** Select the DMA channel and clear software trigger */ - DMAC->CHID.reg = DMAC_CHID_ID(channel_number); - bool enabled = DMAC->CHCTRLA.bit.ENABLE; - common_hal_mcu_enable_interrupts(); - return enabled; - #endif - - #ifdef SAMD51 - DmacChannel* channel = &DMAC->Channel[channel_number]; - return channel->CHCTRLA.bit.ENABLE; - #endif -} - -uint8_t dma_transfer_status(uint8_t channel_number) { - #ifdef SAMD21 - common_hal_mcu_disable_interrupts(); - /** Select the DMA channel and clear software trigger */ - DMAC->CHID.reg = DMAC_CHID_ID(channel_number); - uint8_t status = DMAC->CHINTFLAG.reg; - common_hal_mcu_enable_interrupts(); - return status; - #endif - - #ifdef SAMD51 - DmacChannel* channel = &DMAC->Channel[channel_number]; - return channel->CHINTFLAG.reg; - #endif -} - -static bool channel_free(uint8_t channel_number) { - #ifdef SAMD21 - common_hal_mcu_disable_interrupts(); - DMAC->CHID.reg = DMAC_CHID_ID(channel_number); - bool channel_free = DMAC->CHSTATUS.reg == 0; - common_hal_mcu_enable_interrupts(); - return channel_free; - #endif - - #ifdef SAMD51 - DmacChannel* channel = &DMAC->Channel[channel_number]; - return channel->CHSTATUS.reg == 0; - #endif -} - void init_shared_dma(void) { // Turn on the clocks #ifdef SAMD51 @@ -237,8 +79,8 @@ static int32_t shared_dma_transfer(void* peripheral, const uint8_t* buffer_out, volatile uint32_t* dest, volatile uint32_t* src, uint8_t* buffer_in, uint32_t length, uint8_t tx) { - if (!channel_free(SHARED_TX_CHANNEL) || - (buffer_in != NULL && !channel_free(SHARED_RX_CHANNEL))) { + if (!dma_channel_free(SHARED_TX_CHANNEL) || + (buffer_in != NULL && !dma_channel_free(SHARED_RX_CHANNEL))) { return -1; } diff --git a/ports/atmel-samd/shared_dma.h b/ports/atmel-samd/peripherals/dma.h similarity index 91% rename from ports/atmel-samd/shared_dma.h rename to ports/atmel-samd/peripherals/dma.h index 03e5b276c895b..cf256b962cb0b 100644 --- a/ports/atmel-samd/shared_dma.h +++ b/ports/atmel-samd/peripherals/dma.h @@ -24,8 +24,8 @@ * THE SOFTWARE. */ -#ifndef MICROPY_INCLUDED_ATMEL_SAMD_SHARED_DMA_H -#define MICROPY_INCLUDED_ATMEL_SAMD_SHARED_DMA_H +#ifndef MICROPY_INCLUDED_ATMEL_SAMD_PERIPHERALS_DMA_H +#define MICROPY_INCLUDED_ATMEL_SAMD_PERIPHERALS_DMA_H #include #include @@ -49,6 +49,8 @@ int32_t qspi_dma_write(uint32_t address, const uint8_t* buffer, uint32_t length) int32_t qspi_dma_read(uint32_t address, uint8_t* buffer, uint32_t length); #endif +uint8_t sercom_index(Sercom* sercom); + int32_t sercom_dma_write(Sercom* sercom, const uint8_t* buffer, uint32_t length); int32_t sercom_dma_read(Sercom* sercom, uint8_t* buffer, uint32_t length, uint8_t tx); int32_t sercom_dma_transfer(Sercom* sercom, const uint8_t* buffer_out, uint8_t* buffer_in, uint32_t length); @@ -58,8 +60,9 @@ void dma_enable_channel(uint8_t channel_number); void dma_disable_channel(uint8_t channel_number); void dma_suspend_channel(uint8_t channel_number); void dma_resume_channel(uint8_t channel_number); +bool dma_channel_free(uint8_t channel_number); bool dma_channel_enabled(uint8_t channel_number); uint8_t dma_transfer_status(uint8_t channel_number); DmacDescriptor* dma_descriptor(uint8_t channel_number); -#endif // MICROPY_INCLUDED_ATMEL_SAMD_SHARED_DMA_H +#endif // MICROPY_INCLUDED_ATMEL_SAMD_PERIPHERALS_DMA_H diff --git a/ports/atmel-samd/peripherals/events.c b/ports/atmel-samd/peripherals/events.c new file mode 100644 index 0000000000000..9a4ab3b0ca5a6 --- /dev/null +++ b/ports/atmel-samd/peripherals/events.c @@ -0,0 +1,62 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2018 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 + +#include "peripherals/events.h" +// +// #include "clocks.h" +// +#include "py/runtime.h" + +uint8_t find_async_event_channel(void) { + int8_t channel; + for (channel = EVSYS_CHANNELS - 1; channel > 0; channel--) { + if (event_channel_free(channel)) { + break; + } + } + if (channel < 0) { + mp_raise_RuntimeError("All event channels in use"); + } + return channel; +} + +#ifdef SAMD21 +#define EVSYS_SYNCH_NUM EVSYS_CHANNELS +#endif +uint8_t find_sync_event_channel(void) { + uint8_t channel; + for (channel = 0; channel < EVSYS_SYNCH_NUM; channel++) { + if (event_channel_free(channel)) { + break; + } + } + if (channel >= EVSYS_SYNCH_NUM) { + mp_raise_RuntimeError("All sync event channels in use"); + } + return channel; +} diff --git a/ports/atmel-samd/events.h b/ports/atmel-samd/peripherals/events.h similarity index 97% rename from ports/atmel-samd/events.h rename to ports/atmel-samd/peripherals/events.h index 64093c0ab3c28..0073142f11e18 100644 --- a/ports/atmel-samd/events.h +++ b/ports/atmel-samd/peripherals/events.h @@ -44,4 +44,6 @@ void init_event_channel_interrupt(uint8_t channel, uint8_t gclk, uint8_t generat bool event_interrupt_active(uint8_t channel); bool event_interrupt_overflow(uint8_t channel); +bool event_channel_free(uint8_t channel); + #endif // MICROPY_INCLUDED_ATMEL_SAMD_EVENTS_H diff --git a/ports/atmel-samd/peripherals/i2s.c b/ports/atmel-samd/peripherals/i2s.c new file mode 100644 index 0000000000000..4d99e7b5b9b82 --- /dev/null +++ b/ports/atmel-samd/peripherals/i2s.c @@ -0,0 +1,46 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2018 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 "i2s.h" + +#include "clocks.h" + +#include "hpl/gclk/hpl_gclk_base.h" +#ifdef SAMD21 +#include "hpl/pm/hpl_pm_base.h" +#endif + +void i2s_set_enable(bool enable) { + while (I2S->SYNCBUSY.bit.ENABLE == 1) {} + I2S->CTRLA.bit.ENABLE = enable; + while (I2S->SYNCBUSY.bit.ENABLE == 1) {} +} + +void i2s_set_clock_unit_enable(uint8_t clock_unit, bool enable) { + while ((I2S->SYNCBUSY.vec.CKEN & (1 << clock_unit)) != 0) {} + I2S->CTRLA.vec.CKEN = 1 << clock_unit; + while ((I2S->SYNCBUSY.vec.CKEN & (1 << clock_unit)) != 0) {} +} diff --git a/ports/atmel-samd/i2s.h b/ports/atmel-samd/peripherals/i2s.h similarity index 100% rename from ports/atmel-samd/i2s.h rename to ports/atmel-samd/peripherals/i2s.h diff --git a/ports/atmel-samd/peripherals/pins.h b/ports/atmel-samd/peripherals/pins.h new file mode 100644 index 0000000000000..1ddbf3329eb13 --- /dev/null +++ b/ports/atmel-samd/peripherals/pins.h @@ -0,0 +1,42 @@ +/* + * 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. + */ + +// DO NOT include this file directly. Use shared-bindings/microcontroller/Pin.h instead to ensure +// that all necessary includes are already included. + +#ifndef MICROPY_INCLUDED_ATMEL_SAMD_PERIPHERALS_PINS_H +#define MICROPY_INCLUDED_ATMEL_SAMD_PERIPHERALS_PINS_H + +#include "mpconfigport.h" + +#ifdef SAMD21 +#include "peripherals/samd21/pins.h" +#endif +#ifdef SAMD51 +#include "peripherals/samd51/pins.h" +#endif + +#endif // MICROPY_INCLUDED_ATMEL_SAMD_PERIPHERALS_PINS_H diff --git a/ports/atmel-samd/peripherals/samd21/adc.c b/ports/atmel-samd/peripherals/samd21/adc.c new file mode 100644 index 0000000000000..3a7f1e8116162 --- /dev/null +++ b/ports/atmel-samd/peripherals/samd21/adc.c @@ -0,0 +1,47 @@ +/* + * This file is part of the Micro Python project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2017 Dan Halbert 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 "hal/include/hal_adc_sync.h" +#include "hpl/gclk/hpl_gclk_base.h" +#include "hpl/pm/hpl_pm_base.h" + +// Do initialization and calibration setup needed for any use of the ADC. +// The reference and resolution should be set by the caller. +void samd_peripherals_adc_setup(struct adc_sync_descriptor *adc, Adc *instance) { + // Turn the clocks on. + _pm_enable_bus_clock(PM_BUS_APBC, ADC); + _gclk_enable_channel(ADC_GCLK_ID, GCLK_CLKCTRL_GEN_GCLK0_Val); + + adc_sync_init(adc, instance, (void *)NULL); + + // Load the factory calibration + hri_adc_write_CALIB_BIAS_CAL_bf(ADC, (*((uint32_t*) ADC_FUSES_BIASCAL_ADDR) & ADC_FUSES_BIASCAL_Msk) >> ADC_FUSES_BIASCAL_Pos); + // Bits 7:5 + uint16_t linearity = ((*((uint32_t*) ADC_FUSES_LINEARITY_1_ADDR) & ADC_FUSES_LINEARITY_1_Msk) >> ADC_FUSES_LINEARITY_1_Pos) << 5; + // Bits 4:0 + linearity |= (*((uint32_t*) ADC_FUSES_LINEARITY_0_ADDR) & ADC_FUSES_LINEARITY_0_Msk) >> ADC_FUSES_LINEARITY_0_Pos; + hri_adc_write_CALIB_LINEARITY_CAL_bf(ADC, linearity); +} diff --git a/ports/atmel-samd/pins.h b/ports/atmel-samd/peripherals/samd21/cache.c similarity index 79% rename from ports/atmel-samd/pins.h rename to ports/atmel-samd/peripherals/samd21/cache.c index 1842efbc06798..641b5e1155463 100644 --- a/ports/atmel-samd/pins.h +++ b/ports/atmel-samd/peripherals/samd21/cache.c @@ -3,7 +3,7 @@ * * The MIT License (MIT) * - * Copyright (c) 2017 Scott Shawcroft for Adafruit Industries + * Copyright (c) 2017 Dan Halbert 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 @@ -24,16 +24,9 @@ * THE SOFTWARE. */ -#ifndef MICROPY_INCLUDED_ATMEL_SAMD_PINS_H -#define MICROPY_INCLUDED_ATMEL_SAMD_PINS_H +// The SAMD21 doesn't have a cache so we have nothing to do. +void samd_peripherals_disable_and_clear_cache(void) { +} -#include "mpconfigport.h" - -#ifdef SAMD21 -#include "samd21_pins.h" -#endif -#ifdef SAMD51 -#include "samd51_pins.h" -#endif - -#endif // MICROPY_INCLUDED_ATMEL_SAMD_PINS_H +void samd_peripherals_enable_cache(void) { +} diff --git a/ports/atmel-samd/samd21_clocks.c b/ports/atmel-samd/peripherals/samd21/clocks.c similarity index 99% rename from ports/atmel-samd/samd21_clocks.c rename to ports/atmel-samd/peripherals/samd21/clocks.c index 0fc4d63e5098b..94b515814691a 100644 --- a/ports/atmel-samd/samd21_clocks.c +++ b/ports/atmel-samd/peripherals/samd21/clocks.c @@ -24,7 +24,7 @@ * THE SOFTWARE. */ -#include "clocks.h" +#include "peripherals/clocks.h" #include "hpl_gclk_config.h" diff --git a/ports/atmel-samd/peripherals/samd21/dma.c b/ports/atmel-samd/peripherals/samd21/dma.c new file mode 100644 index 0000000000000..3a399745ac502 --- /dev/null +++ b/ports/atmel-samd/peripherals/samd21/dma.c @@ -0,0 +1,118 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2017-2018 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 "peripherals/dma.h" + +#include + +#include "py/gc.h" +#include "py/mpstate.h" + +#include "hal/utils/include/utils.h" + +#include "shared-bindings/microcontroller/__init__.h" + +uint8_t sercom_index(Sercom* sercom) { + return ((uint32_t) sercom - (uint32_t) SERCOM0) / 0x400; +} + +void dma_configure(uint8_t channel_number, uint8_t trigsrc, bool output_event) { + common_hal_mcu_disable_interrupts(); + /** Select the DMA channel and clear software trigger */ + DMAC->CHID.reg = DMAC_CHID_ID(channel_number); + DMAC->CHCTRLA.reg &= ~DMAC_CHCTRLA_ENABLE; + DMAC->CHCTRLA.reg = DMAC_CHCTRLA_SWRST; + DMAC->SWTRIGCTRL.reg &= (uint32_t)(~(1 << channel_number)); + uint32_t event_output_enable = 0; + if (output_event) { + event_output_enable = DMAC_CHCTRLB_EVOE; + } + DMAC->CHCTRLB.reg = DMAC_CHCTRLB_LVL_LVL0 | + DMAC_CHCTRLB_TRIGSRC(trigsrc) | + DMAC_CHCTRLB_TRIGACT_BEAT | + event_output_enable; + common_hal_mcu_enable_interrupts(); +} + +void dma_enable_channel(uint8_t channel_number) { + common_hal_mcu_disable_interrupts(); + /** Select the DMA channel and clear software trigger */ + DMAC->CHID.reg = DMAC_CHID_ID(channel_number); + // Clear any previous interrupts. + DMAC->CHINTFLAG.reg = DMAC_CHINTFLAG_MASK; + DMAC->CHCTRLA.bit.ENABLE = true; + common_hal_mcu_enable_interrupts(); +} + +void dma_disable_channel(uint8_t channel_number) { + common_hal_mcu_disable_interrupts(); + /** Select the DMA channel and clear software trigger */ + DMAC->CHID.reg = DMAC_CHID_ID(channel_number); + DMAC->CHCTRLA.bit.ENABLE = false; + common_hal_mcu_enable_interrupts(); +} + +void dma_suspend_channel(uint8_t channel_number) { + common_hal_mcu_disable_interrupts(); + /** Select the DMA channel and clear software trigger */ + DMAC->CHID.reg = DMAC_CHID_ID(channel_number); + DMAC->CHCTRLB.bit.CMD = DMAC_CHCTRLB_CMD_SUSPEND_Val; + common_hal_mcu_enable_interrupts(); +} + +void dma_resume_channel(uint8_t channel_number) { + common_hal_mcu_disable_interrupts(); + /** Select the DMA channel and clear software trigger */ + DMAC->CHID.reg = DMAC_CHID_ID(channel_number); + DMAC->CHCTRLB.bit.CMD = DMAC_CHCTRLB_CMD_RESUME_Val; + DMAC->CHINTFLAG.reg = DMAC_CHINTFLAG_SUSP; + common_hal_mcu_enable_interrupts(); +} + +bool dma_channel_enabled(uint8_t channel_number) { + common_hal_mcu_disable_interrupts(); + /** Select the DMA channel and clear software trigger */ + DMAC->CHID.reg = DMAC_CHID_ID(channel_number); + bool enabled = DMAC->CHCTRLA.bit.ENABLE; + common_hal_mcu_enable_interrupts(); + return enabled; +} + +uint8_t dma_transfer_status(uint8_t channel_number) { + common_hal_mcu_disable_interrupts(); + /** Select the DMA channel and clear software trigger */ + DMAC->CHID.reg = DMAC_CHID_ID(channel_number); + uint8_t status = DMAC->CHINTFLAG.reg; + common_hal_mcu_enable_interrupts(); + return status; +} + +bool dma_channel_free(uint8_t channel_number) { + common_hal_mcu_disable_interrupts(); + DMAC->CHID.reg = DMAC_CHID_ID(channel_number); + bool channel_free = DMAC->CHSTATUS.reg == 0; + common_hal_mcu_enable_interrupts(); + return channel_free; +} diff --git a/ports/atmel-samd/events.c b/ports/atmel-samd/peripherals/samd21/events.c similarity index 60% rename from ports/atmel-samd/events.c rename to ports/atmel-samd/peripherals/samd21/events.c index 05a2ae8a73830..70dfa249dd55c 100644 --- a/ports/atmel-samd/events.c +++ b/ports/atmel-samd/peripherals/samd21/events.c @@ -24,131 +24,52 @@ * THE SOFTWARE. */ -#include "events.h" +#include "peripherals/events.h" -#include "clocks.h" +#include "peripherals/clocks.h" #include "py/runtime.h" -#ifdef SAMD21 #include "hpl/pm/hpl_pm_base.h" -#endif - -#ifdef SAMD51 -#include "hri/hri_mclk_d51.h" -#endif void turn_on_event_system(void) { - #ifdef SAMD51 - hri_mclk_set_APBBMASK_EVSYS_bit(MCLK); - #endif - - #ifdef SAMD21 _pm_enable_bus_clock(PM_BUS_APBC, EVSYS); - #endif } void reset_event_system(void) { - #ifdef SAMD51 - EVSYS->CTRLA.bit.SWRST = true; - hri_mclk_clear_APBBMASK_EVSYS_bit(MCLK); - #endif - - #ifdef SAMD21 EVSYS->CTRL.bit.SWRST = true; _pm_disable_bus_clock(PM_BUS_APBC, EVSYS); - #endif } -static bool channel_free(int8_t channel) { +bool event_channel_free(uint8_t channel) { uint8_t generator; - #ifdef SAMD51 - generator = EVSYS->Channel[channel].CHANNEL.bit.EVGEN; - #endif - #ifdef SAMD21 // Explicitly do a byte write so the peripheral knows we're just wanting to read the channel // rather than write to it. *((uint8_t*) &EVSYS->CHANNEL.reg) = channel; generator = (EVSYS->CHANNEL.reg & EVSYS_CHANNEL_EVGEN_Msk) >> EVSYS_CHANNEL_EVGEN_Pos; - #endif return generator == 0; } -uint8_t find_async_event_channel(void) { - int8_t channel; - for (channel = EVSYS_CHANNELS - 1; channel > 0; channel--) { - if (channel_free(channel)) { - break; - } - } - if (channel < 0) { - mp_raise_RuntimeError("All event channels in use"); - } - return channel; -} - -#ifdef SAMD21 -#define EVSYS_SYNCH_NUM EVSYS_CHANNELS -#endif -uint8_t find_sync_event_channel(void) { - uint8_t channel; - for (channel = 0; channel < EVSYS_SYNCH_NUM; channel++) { - if (channel_free(channel)) { - break; - } - } - if (channel >= EVSYS_SYNCH_NUM) { - mp_raise_RuntimeError("All sync event channels in use"); - } - return channel; -} - void disable_event_channel(uint8_t channel_number) { - #ifdef SAMD51 - EVSYS->Channel[channel_number].CHANNEL.reg = 0; - #endif - #ifdef SAMD21 EVSYS->CHANNEL.reg = EVSYS_CHANNEL_CHANNEL(channel_number); - #endif } void disable_event_user(uint8_t user_number) { - #ifdef SAMD51 - EVSYS->USER[user_number].reg = 0; - #endif - #ifdef SAMD21 EVSYS->USER.reg = EVSYS_USER_USER(user_number); - #endif } void connect_event_user_to_channel(uint8_t user, uint8_t channel) { - #ifdef SAMD51 - EVSYS->USER[user].reg = channel + 1; - #endif - #ifdef SAMD21 EVSYS->USER.reg = EVSYS_USER_USER(user) | EVSYS_USER_CHANNEL(channel + 1); - #endif } void init_async_event_channel(uint8_t channel, uint8_t generator) { - #ifdef SAMD51 - EVSYS->Channel[channel].CHANNEL.reg = EVSYS_CHANNEL_EVGEN(generator) | EVSYS_CHANNEL_PATH_ASYNCHRONOUS; - #endif - #ifdef SAMD21 - EVSYS->CHANNEL.reg = EVSYS_CHANNEL_CHANNEL(channel) | EVSYS_CHANNEL_EVGEN(generator) | EVSYS_CHANNEL_PATH_ASYNCHRONOUS; - #endif + EVSYS->CHANNEL.reg = EVSYS_CHANNEL_CHANNEL(channel) | + EVSYS_CHANNEL_EVGEN(generator) | + EVSYS_CHANNEL_PATH_ASYNCHRONOUS; } void init_event_channel_interrupt(uint8_t channel, uint8_t gclk, uint8_t generator) { connect_gclk_to_peripheral(gclk, EVSYS_GCLK_ID_0 + channel); - #ifdef SAMD51 - EVSYS->Channel[channel].CHANNEL.reg = EVSYS_CHANNEL_EVGEN(generator) | - EVSYS_CHANNEL_PATH_SYNCHRONOUS | - EVSYS_CHANNEL_EDGSEL_RISING_EDGE; - EVSYS->Channel[channel].CHINTFLAG.reg = EVSYS_CHINTFLAG_EVD | EVSYS_CHINTFLAG_OVR; - EVSYS->Channel[channel].CHINTENSET.reg = EVSYS_CHINTENSET_EVD | EVSYS_CHINTENSET_OVR; - #endif - #ifdef SAMD21 EVSYS->CHANNEL.reg = EVSYS_CHANNEL_CHANNEL(channel) | EVSYS_CHANNEL_EVGEN(generator) | EVSYS_CHANNEL_PATH_RESYNCHRONIZED | @@ -162,12 +83,10 @@ void init_event_channel_interrupt(uint8_t channel, uint8_t gclk, uint8_t generat EVSYS->INTFLAG.reg = EVSYS_INTFLAG_EVD(value) | EVSYS_INTFLAG_OVR(value); EVSYS->INTENSET.reg = EVSYS_INTENSET_EVD(value) | EVSYS_INTENSET_OVR(value); } - #endif } bool event_interrupt_active(uint8_t channel) { bool active = false; - #ifdef SAMD21 if (channel > 7) { uint8_t value = 1 << (channel - 7); active = (EVSYS->INTFLAG.reg & EVSYS_INTFLAG_EVDp8(value)) != 0; @@ -183,21 +102,11 @@ bool event_interrupt_active(uint8_t channel) { EVSYS->INTFLAG.reg = EVSYS_INTFLAG_EVD(value) | EVSYS_INTFLAG_OVR(value); } } - #endif - #ifdef SAMD51 - active = EVSYS->Channel[channel].CHINTFLAG.bit.EVD; - // Only clear if we know its active, otherwise there is the possibility it becomes after we - // check but before we clear. - if (active) { - EVSYS->Channel[channel].CHINTFLAG.reg = EVSYS_CHINTFLAG_EVD | EVSYS_CHINTFLAG_OVR; - } - #endif return active; } bool event_interrupt_overflow(uint8_t channel) { bool overflow = false; - #ifdef SAMD21 if (channel > 7) { uint8_t value = 1 << (channel - 7); overflow = (EVSYS->INTFLAG.reg & EVSYS_INTFLAG_OVRp8(value)) != 0; @@ -205,9 +114,5 @@ bool event_interrupt_overflow(uint8_t channel) { uint8_t value = 1 << channel; overflow = (EVSYS->INTFLAG.reg & EVSYS_INTFLAG_OVR(value)) != 0; } - #endif - #ifdef SAMD51 - overflow = EVSYS->Channel[channel].CHINTFLAG.bit.OVR; - #endif return overflow; } diff --git a/ports/atmel-samd/boards/metro_m4_express_revb/board.c b/ports/atmel-samd/peripherals/samd21/i2s.c similarity index 65% rename from ports/atmel-samd/boards/metro_m4_express_revb/board.c rename to ports/atmel-samd/peripherals/samd21/i2s.c index a98385d295b8a..7df401601d358 100644 --- a/ports/atmel-samd/boards/metro_m4_express_revb/board.c +++ b/ports/atmel-samd/peripherals/samd21/i2s.c @@ -3,7 +3,7 @@ * * The MIT License (MIT) * - * Copyright (c) 2017 Scott Shawcroft for Adafruit Industries + * Copyright (c) 2018 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 @@ -24,23 +24,23 @@ * THE SOFTWARE. */ -#include "boards/board.h" -#include "mpconfigboard.h" -#include "hal/include/hal_gpio.h" +#include "peripherals/i2s.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); +#include "peripherals/clocks.h" - 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); -} +#include "hpl/gclk/hpl_gclk_base.h" +#include "hpl/pm/hpl_pm_base.h" -bool board_requests_safe_mode(void) { - return false; +void turn_on_i2s(void) { + _pm_enable_bus_clock(PM_BUS_APBC, I2S); } -void reset_board(void) { +void i2s_set_serializer_enable(uint8_t serializer, bool enable) { + while ((I2S->SYNCBUSY.vec.SEREN & (1 << serializer)) != 0) {} + if (enable) { + I2S->CTRLA.vec.SEREN = 1 << serializer; + } else { + I2S->CTRLA.vec.SEREN &= ~(1 << serializer); + } + while ((I2S->SYNCBUSY.vec.SEREN & (1 << serializer)) != 0) {} } diff --git a/ports/atmel-samd/samd21_pins.c b/ports/atmel-samd/peripherals/samd21/pins.c similarity index 99% rename from ports/atmel-samd/samd21_pins.c rename to ports/atmel-samd/peripherals/samd21/pins.c index 319870b9a3eea..bbb023a54f6b7 100644 --- a/ports/atmel-samd/samd21_pins.c +++ b/ports/atmel-samd/peripherals/samd21/pins.c @@ -26,8 +26,6 @@ #include "shared-bindings/microcontroller/Pin.h" -#include "samd21_pins.h" - #define SERCOM(sercom_index, p_pad) \ { \ .index = sercom_index, \ diff --git a/ports/atmel-samd/samd21_pins.h b/ports/atmel-samd/peripherals/samd21/pins.h similarity index 93% rename from ports/atmel-samd/samd21_pins.h rename to ports/atmel-samd/peripherals/samd21/pins.h index 522563ef11454..0b99ce9b36963 100644 --- a/ports/atmel-samd/samd21_pins.h +++ b/ports/atmel-samd/peripherals/samd21/pins.h @@ -24,12 +24,13 @@ * THE SOFTWARE. */ -#ifndef MICROPY_INCLUDED_ATMEL_SAMD_BOARDS_SAMD21_PINS_H -#define MICROPY_INCLUDED_ATMEL_SAMD_BOARDS_SAMD21_PINS_H +// DO NOT include this file directly. Use shared-bindings/microcontroller/Pin.h instead to ensure +// that all necessary includes are already included. -#include "include/sam.h" +#ifndef MICROPY_INCLUDED_ATMEL_SAMD_PERIPHERALS_SAMD21_PINS_H +#define MICROPY_INCLUDED_ATMEL_SAMD_PERIPHERALS_SAMD21_PINS_H -#include "common-hal/microcontroller/Pin.h" +#include "include/sam.h" void reset_pin(uint8_t pin); @@ -201,4 +202,4 @@ extern const mcu_pin_obj_t pin_PB02; extern const mcu_pin_obj_t pin_PB03; #endif -#endif // MICROPY_INCLUDED_ATMEL_SAMD_BOARDS_SAMD21_PINS_H +#endif // MICROPY_INCLUDED_ATMEL_SAMD_PERIPHERALS_SAMD21_PINS_H diff --git a/ports/atmel-samd/samd21_peripherals.c b/ports/atmel-samd/peripherals/samd21/sercom.c similarity index 76% rename from ports/atmel-samd/samd21_peripherals.c rename to ports/atmel-samd/peripherals/samd21/sercom.c index 5bbac29655fdb..a27e49e0e5e99 100644 --- a/ports/atmel-samd/samd21_peripherals.c +++ b/ports/atmel-samd/peripherals/samd21/sercom.c @@ -24,11 +24,9 @@ * THE SOFTWARE. */ -#include "hal/include/hal_adc_sync.h" #include "hpl/gclk/hpl_gclk_base.h" #include "hpl/pm/hpl_pm_base.h" - // The clock initializer values are rather random, so we need to put them in // tables for lookup. We can't compute them. @@ -93,21 +91,3 @@ uint8_t samd_peripherals_get_spi_dopo(uint8_t clock_pad, uint8_t mosi_pad) { bool samd_peripherals_valid_spi_clock_pad(uint8_t clock_pad) { return clock_pad == 1 || clock_pad == 3; } - -// Do initialization and calibration setup needed for any use of the ADC. -// The reference and resolution should be set by the caller. -void samd_peripherals_adc_setup(struct adc_sync_descriptor *adc, Adc *instance) { - // Turn the clocks on. - _pm_enable_bus_clock(PM_BUS_APBC, ADC); - _gclk_enable_channel(ADC_GCLK_ID, GCLK_CLKCTRL_GEN_GCLK0_Val); - - adc_sync_init(adc, instance, (void *)NULL); - - // Load the factory calibration - hri_adc_write_CALIB_BIAS_CAL_bf(ADC, (*((uint32_t*) ADC_FUSES_BIASCAL_ADDR) & ADC_FUSES_BIASCAL_Msk) >> ADC_FUSES_BIASCAL_Pos); - // Bits 7:5 - uint16_t linearity = ((*((uint32_t*) ADC_FUSES_LINEARITY_1_ADDR) & ADC_FUSES_LINEARITY_1_Msk) >> ADC_FUSES_LINEARITY_1_Pos) << 5; - // Bits 4:0 - linearity |= (*((uint32_t*) ADC_FUSES_LINEARITY_0_ADDR) & ADC_FUSES_LINEARITY_0_Msk) >> ADC_FUSES_LINEARITY_0_Pos; - hri_adc_write_CALIB_LINEARITY_CAL_bf(ADC, linearity); -} diff --git a/ports/atmel-samd/peripherals/samd21/timers.c b/ports/atmel-samd/peripherals/samd21/timers.c new file mode 100644 index 0000000000000..c93a710867600 --- /dev/null +++ b/ports/atmel-samd/peripherals/samd21/timers.c @@ -0,0 +1,75 @@ +/* + * This file is part of the MicroPython 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 +#include + +#include "peripherals/timers.h" + +//#include "common-hal/pulseio/PulseOut.h" + +#include "hpl/gclk/hpl_gclk_base.h" + +const uint8_t tcc_cc_num[3] = {4, 2, 2}; +const uint8_t tc_gclk_ids[TC_INST_NUM] = {TC3_GCLK_ID, + TC4_GCLK_ID, + TC5_GCLK_ID, +#ifdef TC6_GCLK_ID + TC6_GCLK_ID, +#endif +#ifdef TC7_GCLK_ID + TC7_GCLK_ID, +#endif + }; +const uint8_t tcc_gclk_ids[3] = {TCC0_GCLK_ID, TCC1_GCLK_ID, TCC2_GCLK_ID}; + +void turn_on_clocks(bool is_tc, uint8_t index, uint32_t gclk_index) { + uint8_t gclk_id; + if (is_tc) { + gclk_id = tc_gclk_ids[index]; + } else { + gclk_id = tcc_gclk_ids[index]; + } + // Determine the clock slot on the APBC bus. TCC0 is the first and 8 slots in. + uint8_t clock_slot = 8 + index; + // We index TCs starting at zero but in memory they begin at three so we have to add three. + if (is_tc) { + clock_slot += 3; + } + PM->APBCMASK.reg |= 1 << clock_slot; + _gclk_enable_channel(gclk_id, gclk_index); +} + +void tc_set_enable(Tc* tc, bool enable) { + tc->COUNT16.CTRLA.bit.ENABLE = enable; + while (tc->COUNT16.STATUS.bit.SYNCBUSY != 0) { + /* Wait for sync */ + } +} + +void tc_wait_for_sync(Tc* tc) { + while (tc->COUNT16.STATUS.bit.SYNCBUSY != 0) {} +} diff --git a/ports/atmel-samd/peripherals/samd51/adc.c b/ports/atmel-samd/peripherals/samd51/adc.c new file mode 100644 index 0000000000000..af6333a949994 --- /dev/null +++ b/ports/atmel-samd/peripherals/samd51/adc.c @@ -0,0 +1,61 @@ +/* + * This file is part of the Micro Python project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2017 Dan Halbert 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 "hal/include/hal_adc_sync.h" +#include "hpl/gclk/hpl_gclk_base.h" +#include "hri/hri_mclk_d51.h" + +// Do initialization and calibration setup needed for any use of the ADC. +// The reference and resolution should be set by the caller. +void samd_peripherals_adc_setup(struct adc_sync_descriptor *adc, Adc *instance) { + // Turn the clocks on. + if (instance == ADC0) { + hri_mclk_set_APBDMASK_ADC0_bit(MCLK); + hri_gclk_write_PCHCTRL_reg(GCLK, ADC0_GCLK_ID, GCLK_PCHCTRL_GEN_GCLK1_Val | (1 << GCLK_PCHCTRL_CHEN_Pos)); + } else if (instance == ADC1) { + hri_mclk_set_APBDMASK_ADC1_bit(MCLK); + hri_gclk_write_PCHCTRL_reg(GCLK, ADC1_GCLK_ID, GCLK_PCHCTRL_GEN_GCLK1_Val | (1 << GCLK_PCHCTRL_CHEN_Pos)); + } + + adc_sync_init(adc, instance, (void *)NULL); + + // SAMD51 has a CALIB register but doesn't have documented fuses for them. + uint8_t biasrefbuf; + uint8_t biasr2r; + uint8_t biascomp; + if (instance == ADC0) { + biasrefbuf = ((*(uint32_t*) ADC0_FUSES_BIASREFBUF_ADDR) & ADC0_FUSES_BIASREFBUF_Msk) >> ADC0_FUSES_BIASREFBUF_Pos; + biasr2r = ((*(uint32_t*) ADC0_FUSES_BIASR2R_ADDR) & ADC0_FUSES_BIASR2R_Msk) >> ADC0_FUSES_BIASR2R_Pos; + biascomp = ((*(uint32_t*) ADC0_FUSES_BIASCOMP_ADDR) & ADC0_FUSES_BIASCOMP_Msk) >> ADC0_FUSES_BIASCOMP_Pos; + } else { + biasrefbuf = ((*(uint32_t*) ADC1_FUSES_BIASREFBUF_ADDR) & ADC1_FUSES_BIASREFBUF_Msk) >> ADC1_FUSES_BIASREFBUF_Pos; + biasr2r = ((*(uint32_t*) ADC1_FUSES_BIASR2R_ADDR) & ADC1_FUSES_BIASR2R_Msk) >> ADC1_FUSES_BIASR2R_Pos; + biascomp = ((*(uint32_t*) ADC1_FUSES_BIASCOMP_ADDR) & ADC1_FUSES_BIASCOMP_Msk) >> ADC1_FUSES_BIASCOMP_Pos; + } + hri_adc_write_CALIB_BIASREFBUF_bf(instance, biasrefbuf); + hri_adc_write_CALIB_BIASR2R_bf(instance, biasr2r); + hri_adc_write_CALIB_BIASCOMP_bf(instance, biascomp); +} diff --git a/ports/atmel-samd/peripherals/samd51/cache.c b/ports/atmel-samd/peripherals/samd51/cache.c new file mode 100644 index 0000000000000..f94dd830c0aaa --- /dev/null +++ b/ports/atmel-samd/peripherals/samd51/cache.c @@ -0,0 +1,39 @@ +/* + * This file is part of the Micro Python project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2017 Dan Halbert 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 "sam.h" + +// Turn off cache and invalidate all data in it. +void samd_peripherals_disable_and_clear_cache(void) { + CMCC->CTRL.bit.CEN = 0; + while (CMCC->SR.bit.CSTS) {} + CMCC->MAINT0.bit.INVALL = 1; +} + +// Enable cache +void samd_peripherals_enable_cache(void) { + CMCC->CTRL.bit.CEN = 1; +} diff --git a/ports/atmel-samd/samd51_clocks.c b/ports/atmel-samd/peripherals/samd51/clocks.c similarity index 99% rename from ports/atmel-samd/samd51_clocks.c rename to ports/atmel-samd/peripherals/samd51/clocks.c index 6f8b1f0102116..29f9cb99cb280 100644 --- a/ports/atmel-samd/samd51_clocks.c +++ b/ports/atmel-samd/peripherals/samd51/clocks.c @@ -24,7 +24,7 @@ * THE SOFTWARE. */ -#include "clocks.h" +#include "peripherals/clocks.h" #include "hpl_gclk_config.h" diff --git a/ports/atmel-samd/peripherals/samd51/dma.c b/ports/atmel-samd/peripherals/samd51/dma.c new file mode 100644 index 0000000000000..ccb35aaf65736 --- /dev/null +++ b/ports/atmel-samd/peripherals/samd51/dma.c @@ -0,0 +1,94 @@ +/* + * This file is part of the MicroPython 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 "peripherals/dma.h" + +#include + +#include "py/gc.h" +#include "py/mpstate.h" + +#include "hal/utils/include/utils.h" + +#include "shared-bindings/microcontroller/__init__.h" + +uint8_t sercom_index(Sercom* sercom) { + const Sercom* sercoms[SERCOM_INST_NUM] = SERCOM_INSTS; + for (uint8_t i = 0; i < SERCOM_INST_NUM; i++) { + if (sercoms[i] == sercom) { + return i; + } + } + return 0; +} + +void dma_configure(uint8_t channel_number, uint8_t trigsrc, bool output_event) { + DmacChannel* channel = &DMAC->Channel[channel_number]; + channel->CHCTRLA.reg &= ~DMAC_CHCTRLA_ENABLE; + channel->CHCTRLA.reg = DMAC_CHCTRLA_SWRST; + if (output_event) { + channel->CHEVCTRL.reg = DMAC_CHEVCTRL_EVOE; + } + channel->CHCTRLA.reg = DMAC_CHCTRLA_TRIGSRC(trigsrc) | + DMAC_CHCTRLA_TRIGACT_BURST | + DMAC_CHCTRLA_BURSTLEN_SINGLE; +} + +void dma_enable_channel(uint8_t channel_number) { + DmacChannel* channel = &DMAC->Channel[channel_number]; + channel->CHCTRLA.bit.ENABLE = true; + // Clear any previous interrupts. + channel->CHINTFLAG.reg = DMAC_CHINTFLAG_MASK; +} + +void dma_disable_channel(uint8_t channel_number) { + DmacChannel* channel = &DMAC->Channel[channel_number]; + channel->CHCTRLA.bit.ENABLE = false; +} + +void dma_suspend_channel(uint8_t channel_number) { + DmacChannel* channel = &DMAC->Channel[channel_number]; + channel->CHCTRLB.reg = DMAC_CHCTRLB_CMD_SUSPEND; +} + +void dma_resume_channel(uint8_t channel_number) { + DmacChannel* channel = &DMAC->Channel[channel_number]; + channel->CHCTRLB.reg = DMAC_CHCTRLB_CMD_RESUME; +} + +bool dma_channel_enabled(uint8_t channel_number) { + DmacChannel* channel = &DMAC->Channel[channel_number]; + return channel->CHCTRLA.bit.ENABLE; +} + +uint8_t dma_transfer_status(uint8_t channel_number) { + DmacChannel* channel = &DMAC->Channel[channel_number]; + return channel->CHINTFLAG.reg; +} + +bool dma_channel_free(uint8_t channel_number) { + DmacChannel* channel = &DMAC->Channel[channel_number]; + return channel->CHSTATUS.reg == 0; +} diff --git a/ports/atmel-samd/peripherals/samd51/events.c b/ports/atmel-samd/peripherals/samd51/events.c new file mode 100644 index 0000000000000..5ea2c87e696fa --- /dev/null +++ b/ports/atmel-samd/peripherals/samd51/events.c @@ -0,0 +1,88 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2018 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 "peripherals/events.h" + +#include "peripherals/clocks.h" + +#include "py/runtime.h" + +#include "hri/hri_mclk_d51.h" + +void turn_on_event_system(void) { + hri_mclk_set_APBBMASK_EVSYS_bit(MCLK); +} + +void reset_event_system(void) { + EVSYS->CTRLA.bit.SWRST = true; + hri_mclk_clear_APBBMASK_EVSYS_bit(MCLK); +} + +bool event_channel_free(uint8_t channel) { + uint8_t generator; + generator = EVSYS->Channel[channel].CHANNEL.bit.EVGEN; + return generator == 0; +} + +void disable_event_channel(uint8_t channel_number) { + EVSYS->Channel[channel_number].CHANNEL.reg = 0; +} + +void disable_event_user(uint8_t user_number) { + EVSYS->USER[user_number].reg = 0; +} + +void connect_event_user_to_channel(uint8_t user, uint8_t channel) { + EVSYS->USER[user].reg = channel + 1; +} + +void init_async_event_channel(uint8_t channel, uint8_t generator) { + EVSYS->Channel[channel].CHANNEL.reg = EVSYS_CHANNEL_EVGEN(generator) | EVSYS_CHANNEL_PATH_ASYNCHRONOUS; +} + +void init_event_channel_interrupt(uint8_t channel, uint8_t gclk, uint8_t generator) { + connect_gclk_to_peripheral(gclk, EVSYS_GCLK_ID_0 + channel); + EVSYS->Channel[channel].CHANNEL.reg = EVSYS_CHANNEL_EVGEN(generator) | + EVSYS_CHANNEL_PATH_SYNCHRONOUS | + EVSYS_CHANNEL_EDGSEL_RISING_EDGE; + EVSYS->Channel[channel].CHINTFLAG.reg = EVSYS_CHINTFLAG_EVD | EVSYS_CHINTFLAG_OVR; + EVSYS->Channel[channel].CHINTENSET.reg = EVSYS_CHINTENSET_EVD | EVSYS_CHINTENSET_OVR; +} + +bool event_interrupt_active(uint8_t channel) { + bool active = false; + active = EVSYS->Channel[channel].CHINTFLAG.bit.EVD; + // Only clear if we know its active, otherwise there is the possibility it becomes after we + // check but before we clear. + if (active) { + EVSYS->Channel[channel].CHINTFLAG.reg = EVSYS_CHINTFLAG_EVD | EVSYS_CHINTFLAG_OVR; + } + return active; +} + +bool event_interrupt_overflow(uint8_t channel) { + return EVSYS->Channel[channel].CHINTFLAG.bit.OVR; +} diff --git a/ports/atmel-samd/i2s.c b/ports/atmel-samd/peripherals/samd51/i2s.c similarity index 68% rename from ports/atmel-samd/i2s.c rename to ports/atmel-samd/peripherals/samd51/i2s.c index 663ecdd1dc3fc..97ce13f7d9d55 100644 --- a/ports/atmel-samd/i2s.c +++ b/ports/atmel-samd/peripherals/samd51/i2s.c @@ -24,53 +24,22 @@ * THE SOFTWARE. */ -#include "i2s.h" +#include "peripherals/i2s.h" -#include "clocks.h" +#include "peripherals/clocks.h" #include "hpl/gclk/hpl_gclk_base.h" -#ifdef SAMD21 -#include "hpl/pm/hpl_pm_base.h" -#endif void turn_on_i2s(void) { // Make sure the I2S peripheral is running so we can see if the resources we need are free. - #ifdef SAMD51 hri_mclk_set_APBDMASK_I2S_bit(MCLK); // Connect the clock units to the 2mhz clock by default. They can't reset without it. connect_gclk_to_peripheral(5, I2S_GCLK_ID_0); connect_gclk_to_peripheral(5, I2S_GCLK_ID_1); - #endif - - #ifdef SAMD21 - _pm_enable_bus_clock(PM_BUS_APBC, I2S); - #endif -} - -void i2s_set_enable(bool enable) { - while (I2S->SYNCBUSY.bit.ENABLE == 1) {} - I2S->CTRLA.bit.ENABLE = enable; - while (I2S->SYNCBUSY.bit.ENABLE == 1) {} -} - -void i2s_set_clock_unit_enable(uint8_t clock_unit, bool enable) { - while ((I2S->SYNCBUSY.vec.CKEN & (1 << clock_unit)) != 0) {} - I2S->CTRLA.vec.CKEN = 1 << clock_unit; - while ((I2S->SYNCBUSY.vec.CKEN & (1 << clock_unit)) != 0) {} } void i2s_set_serializer_enable(uint8_t serializer, bool enable) { - #ifdef SAMD21 - while ((I2S->SYNCBUSY.vec.SEREN & (1 << serializer)) != 0) {} - if (enable) { - I2S->CTRLA.vec.SEREN = 1 << serializer; - } else { - I2S->CTRLA.vec.SEREN &= ~(1 << serializer); - } - while ((I2S->SYNCBUSY.vec.SEREN & (1 << serializer)) != 0) {} - #endif - #ifdef SAMD51 if (serializer == 0) { while (I2S->SYNCBUSY.bit.TXEN == 1) {} I2S->CTRLA.bit.TXEN = enable; @@ -80,5 +49,4 @@ void i2s_set_serializer_enable(uint8_t serializer, bool enable) { I2S->CTRLA.bit.RXEN = enable; while (I2S->SYNCBUSY.bit.RXEN == 1) {} } - #endif } diff --git a/ports/atmel-samd/samd51_pins.c b/ports/atmel-samd/peripherals/samd51/pins.c similarity index 99% rename from ports/atmel-samd/samd51_pins.c rename to ports/atmel-samd/peripherals/samd51/pins.c index 6d597b6e1a0d6..1c52d35a249d2 100644 --- a/ports/atmel-samd/samd51_pins.c +++ b/ports/atmel-samd/peripherals/samd51/pins.c @@ -26,8 +26,6 @@ #include "shared-bindings/microcontroller/Pin.h" -#include "samd51_pins.h" - #define SERCOM(sercom_index, p_pad) \ { \ .index = sercom_index, \ diff --git a/ports/atmel-samd/samd51_pins.h b/ports/atmel-samd/peripherals/samd51/pins.h similarity index 98% rename from ports/atmel-samd/samd51_pins.h rename to ports/atmel-samd/peripherals/samd51/pins.h index c9ffacc24b427..b9a05a3459967 100644 --- a/ports/atmel-samd/samd51_pins.h +++ b/ports/atmel-samd/peripherals/samd51/pins.h @@ -24,13 +24,14 @@ * THE SOFTWARE. */ +// DO NOT include this file directly. Use shared-bindings/microcontroller/Pin.h instead to ensure +// that all necessary includes are already included. + #ifndef MICROPY_INCLUDED_ATMEL_SAMD_SAMD51_PINS_H #define MICROPY_INCLUDED_ATMEL_SAMD_SAMD51_PINS_H #include "include/sam.h" -#include "common-hal/microcontroller/Pin.h" - void reset_pin(uint8_t pin); #define MUX_C 2 diff --git a/ports/atmel-samd/samd51_peripherals.c b/ports/atmel-samd/peripherals/samd51/sercom.c similarity index 67% rename from ports/atmel-samd/samd51_peripherals.c rename to ports/atmel-samd/peripherals/samd51/sercom.c index 5772b8e0ab4d6..fc44214220a81 100644 --- a/ports/atmel-samd/samd51_peripherals.c +++ b/ports/atmel-samd/peripherals/samd51/sercom.c @@ -28,6 +28,8 @@ #include "hpl/gclk/hpl_gclk_base.h" #include "hri/hri_mclk_d51.h" +// FIXME(tannewt): Should this be called sercom.c? + // The clock initializer values are rather random, so we need to put them in // tables for lookup. We can't compute them. @@ -131,47 +133,3 @@ uint8_t samd_peripherals_get_spi_dopo(uint8_t clock_pad, uint8_t mosi_pad) { bool samd_peripherals_valid_spi_clock_pad(uint8_t clock_pad) { return clock_pad == 1; } - -// Do initialization and calibration setup needed for any use of the ADC. -// The reference and resolution should be set by the caller. -void samd_peripherals_adc_setup(struct adc_sync_descriptor *adc, Adc *instance) { - // Turn the clocks on. - if (instance == ADC0) { - hri_mclk_set_APBDMASK_ADC0_bit(MCLK); - hri_gclk_write_PCHCTRL_reg(GCLK, ADC0_GCLK_ID, GCLK_PCHCTRL_GEN_GCLK1_Val | (1 << GCLK_PCHCTRL_CHEN_Pos)); - } else if (instance == ADC1) { - hri_mclk_set_APBDMASK_ADC1_bit(MCLK); - hri_gclk_write_PCHCTRL_reg(GCLK, ADC1_GCLK_ID, GCLK_PCHCTRL_GEN_GCLK1_Val | (1 << GCLK_PCHCTRL_CHEN_Pos)); - } - - adc_sync_init(adc, instance, (void *)NULL); - - // SAMD51 has a CALIB register but doesn't have documented fuses for them. - uint8_t biasrefbuf; - uint8_t biasr2r; - uint8_t biascomp; - if (instance == ADC0) { - biasrefbuf = ((*(uint32_t*) ADC0_FUSES_BIASREFBUF_ADDR) & ADC0_FUSES_BIASREFBUF_Msk) >> ADC0_FUSES_BIASREFBUF_Pos; - biasr2r = ((*(uint32_t*) ADC0_FUSES_BIASR2R_ADDR) & ADC0_FUSES_BIASR2R_Msk) >> ADC0_FUSES_BIASR2R_Pos; - biascomp = ((*(uint32_t*) ADC0_FUSES_BIASCOMP_ADDR) & ADC0_FUSES_BIASCOMP_Msk) >> ADC0_FUSES_BIASCOMP_Pos; - } else { - biasrefbuf = ((*(uint32_t*) ADC1_FUSES_BIASREFBUF_ADDR) & ADC1_FUSES_BIASREFBUF_Msk) >> ADC1_FUSES_BIASREFBUF_Pos; - biasr2r = ((*(uint32_t*) ADC1_FUSES_BIASR2R_ADDR) & ADC1_FUSES_BIASR2R_Msk) >> ADC1_FUSES_BIASR2R_Pos; - biascomp = ((*(uint32_t*) ADC1_FUSES_BIASCOMP_ADDR) & ADC1_FUSES_BIASCOMP_Msk) >> ADC1_FUSES_BIASCOMP_Pos; - } - hri_adc_write_CALIB_BIASREFBUF_bf(instance, biasrefbuf); - hri_adc_write_CALIB_BIASR2R_bf(instance, biasr2r); - hri_adc_write_CALIB_BIASCOMP_bf(instance, biascomp); -} - -// Turn off cache and invalidate all data in it. -void samd_peripherals_disable_and_clear_cache(void) { - CMCC->CTRL.bit.CEN = 0; - while (CMCC->SR.bit.CSTS) {} - CMCC->MAINT0.bit.INVALL = 1; -} - -// Enable cache -void samd_peripherals_enable_cache(void) { - CMCC->CTRL.bit.CEN = 1; -} diff --git a/ports/atmel-samd/timers.c b/ports/atmel-samd/peripherals/samd51/timers.c similarity index 56% rename from ports/atmel-samd/timers.c rename to ports/atmel-samd/peripherals/samd51/timers.c index 33518b782f838..305acce3817f5 100644 --- a/ports/atmel-samd/timers.c +++ b/ports/atmel-samd/peripherals/samd51/timers.c @@ -27,36 +27,12 @@ #include #include -#include "timers.h" +#include "peripherals/timers.h" -#include "common-hal/pulseio/PulseOut.h" +//#include "common-hal/pulseio/PulseOut.h" -#ifdef SAMD21 -#include "hpl/gclk/hpl_gclk_base.h" -#endif - -#ifdef SAMD51 #include "hri/hri_gclk_d51.h" -#endif - -const uint16_t prescaler[8] = {1, 2, 4, 8, 16, 64, 256, 1024}; -// This bitmask keeps track of which channels of a TCC are currently claimed. -#ifdef SAMD21 -const uint8_t tcc_cc_num[3] = {4, 2, 2}; -const uint8_t tc_gclk_ids[TC_INST_NUM] = {TC3_GCLK_ID, - TC4_GCLK_ID, - TC5_GCLK_ID, -#ifdef TC6_GCLK_ID - TC6_GCLK_ID, -#endif -#ifdef TC7_GCLK_ID - TC7_GCLK_ID, -#endif - }; -const uint8_t tcc_gclk_ids[3] = {TCC0_GCLK_ID, TCC1_GCLK_ID, TCC2_GCLK_ID}; -#endif -#ifdef SAMD51 const uint8_t tcc_cc_num[5] = {6, 4, 3, 2, 2}; const uint8_t tc_gclk_ids[TC_INST_NUM] = {TC0_GCLK_ID, TC1_GCLK_ID, @@ -85,36 +61,6 @@ const uint8_t tcc_gclk_ids[TCC_INST_NUM] = {TCC0_GCLK_ID, TCC4_GCLK_ID #endif }; -#endif -Tc* const tc_insts[TC_INST_NUM] = TC_INSTS; -Tcc* const tcc_insts[TCC_INST_NUM] = TCC_INSTS; - -IRQn_Type const tc_irq[TC_INST_NUM] = { -#ifdef TC0 - TC0_IRQn, -#endif -#ifdef TC1 - TC1_IRQn, -#endif -#ifdef TC2 - TC2_IRQn, -#endif -#ifdef TC3 - TC3_IRQn, -#endif -#ifdef TC4 - TC4_IRQn, -#endif -#ifdef TC5 - TC5_IRQn, -#endif -#ifdef TC6 - TC6_IRQn, -#endif -#ifdef TC7 - TC7_IRQn, -#endif -}; void turn_on_clocks(bool is_tc, uint8_t index, uint32_t gclk_index) { uint8_t gclk_id; @@ -124,7 +70,6 @@ void turn_on_clocks(bool is_tc, uint8_t index, uint32_t gclk_index) { gclk_id = tcc_gclk_ids[index]; } // Turn on the clocks for the peripherals. - #ifdef SAMD51 if (is_tc) { switch (index) { case 0: @@ -180,122 +125,15 @@ void turn_on_clocks(bool is_tc, uint8_t index, uint32_t gclk_index) { hri_gclk_write_PCHCTRL_reg(GCLK, gclk_id, gclk_index | (1 << GCLK_PCHCTRL_CHEN_Pos)); - #endif - - #ifdef SAMD21 - // Determine the clock slot on the APBC bus. TCC0 is the first and 8 slots in. - uint8_t clock_slot = 8 + index; - // We index TCs starting at zero but in memory they begin at three so we have to add three. - if (is_tc) { - clock_slot += 3; - } - PM->APBCMASK.reg |= 1 << clock_slot; - _gclk_enable_channel(gclk_id, gclk_index); - #endif } void tc_set_enable(Tc* tc, bool enable) { tc->COUNT16.CTRLA.bit.ENABLE = enable; - #ifdef SAMD21 - while (tc->COUNT16.STATUS.bit.SYNCBUSY != 0) { - /* Wait for sync */ - } - #endif - #ifdef SAMD51 while (tc->COUNT16.SYNCBUSY.bit.ENABLE != 0) { /* Wait for sync */ } - #endif -} - -void tc_enable_interrupts(uint8_t tc_index) { - NVIC_DisableIRQ(tc_irq[tc_index]); - NVIC_ClearPendingIRQ(tc_irq[tc_index]); - NVIC_EnableIRQ(tc_irq[tc_index]); -} - -void tc_disable_interrupts(uint8_t tc_index) { - NVIC_DisableIRQ(tc_irq[tc_index]); - NVIC_ClearPendingIRQ(tc_irq[tc_index]); -} - -void tcc_set_enable(Tcc* tcc, bool enable) { - tcc->CTRLA.bit.ENABLE = enable; - while (tcc->SYNCBUSY.bit.ENABLE != 0) { - /* Wait for sync */ - } } void tc_wait_for_sync(Tc* tc) { - #ifdef SAMD21 - while (tc->COUNT16.STATUS.bit.SYNCBUSY != 0) {} - #endif - #ifdef SAMD51 while (tc->COUNT16.SYNCBUSY.reg != 0) {} - #endif -} - -void tc_reset(Tc* tc) { - tc->COUNT16.CTRLA.bit.SWRST = 1; - while (tc->COUNT16.CTRLA.bit.SWRST == 1) { - } -} - -void shared_timer_handler(bool is_tc, uint8_t index) { - // Add calls to interrupt handlers for specific functionality here. - if (is_tc) { - pulseout_interrupt_handler(index); - } -} - -#ifdef SAMD51 -#define TC_OFFSET 0 -#endif -#ifdef SAMD21 -#define TC_OFFSET 3 -#endif - -void TCC0_Handler(void) { - shared_timer_handler(false, 0); -} -void TCC1_Handler(void) { - shared_timer_handler(false, 1); } -void TCC2_Handler(void) { - shared_timer_handler(false, 2); -} -// TC0 - TC2 only exist on the SAMD51 -#ifdef TC0 -void TC0_Handler(void) { - shared_timer_handler(true, 0); -} -#endif -#ifdef TC1 -void TC1_Handler(void) { - shared_timer_handler(true, 1); -} -#endif -#ifdef TC2 -void TC2_Handler(void) { - shared_timer_handler(true, 2); -} -#endif -void TC3_Handler(void) { - shared_timer_handler(true, 3 - TC_OFFSET); -} -void TC4_Handler(void) { - shared_timer_handler(true, 4 - TC_OFFSET); -} -void TC5_Handler(void) { - shared_timer_handler(true, 5 - TC_OFFSET); -} -#ifdef TC6 -void TC6_Handler(void) { - shared_timer_handler(true, 6 - TC_OFFSET); -} -#endif -#ifdef TC7 -void TC7_Handler(void) { - shared_timer_handler(true, 7 - TC_OFFSET); -} -#endif diff --git a/ports/atmel-samd/peripherals.c b/ports/atmel-samd/peripherals/sercom.c similarity index 98% rename from ports/atmel-samd/peripherals.c rename to ports/atmel-samd/peripherals/sercom.c index c75a1f43b5b03..04c1fd008d4a3 100644 --- a/ports/atmel-samd/peripherals.c +++ b/ports/atmel-samd/peripherals/sercom.c @@ -24,7 +24,7 @@ * THE SOFTWARE. */ -#include "peripherals.h" +#include "peripherals/sercom.h" #include "hpl_sercom_config.h" diff --git a/ports/atmel-samd/peripherals.h b/ports/atmel-samd/peripherals/sercom.h similarity index 79% rename from ports/atmel-samd/peripherals.h rename to ports/atmel-samd/peripherals/sercom.h index 8a07c00457e89..66ad1a403f120 100644 --- a/ports/atmel-samd/peripherals.h +++ b/ports/atmel-samd/peripherals/sercom.h @@ -24,24 +24,19 @@ * THE SOFTWARE. */ -#ifndef MICROPY_INCLUDED_ATMEL_SAMD_PERIPHERALS_H -#define MICROPY_INCLUDED_ATMEL_SAMD_PERIPHERALS_H +#ifndef MICROPY_INCLUDED_ATMEL_SAMD_PERIPHERALS_SPI_H +#define MICROPY_INCLUDED_ATMEL_SAMD_PERIPHERALS_SPI_H #include #include "mpconfigport.h" -// Routines common across chip families. +void samd_peripherals_sercom_clock_init(Sercom* sercom, uint8_t sercom_index); +uint8_t samd_peripherals_get_spi_dopo(uint8_t clock_pad, uint8_t mosi_pad); uint8_t samd_peripherals_spi_baudrate_to_baud_reg_value(const uint32_t baudrate); uint32_t samd_peripherals_spi_baud_reg_value_to_baudrate(const uint8_t baud_reg_value); +bool samd_peripherals_valid_spi_clock_pad(uint8_t clock_pad); Sercom* sercom_insts[SERCOM_INST_NUM]; -#ifdef SAMD21 -#include "samd21_peripherals.h" -#endif -#ifdef SAMD51 -#include "samd51_peripherals.h" -#endif - -#endif // MICROPY_INCLUDED_ATMEL_SAMD_PERIPHERALS_H +#endif // MICROPY_INCLUDED_ATMEL_SAMD_PERIPHERALS_SPI_H diff --git a/ports/atmel-samd/peripherals/timers.c b/ports/atmel-samd/peripherals/timers.c new file mode 100644 index 0000000000000..cdcb92ac82f13 --- /dev/null +++ b/ports/atmel-samd/peripherals/timers.c @@ -0,0 +1,147 @@ +/* + * This file is part of the MicroPython 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 +#include + +#include "timers.h" + +#include "common-hal/pulseio/PulseOut.h" + +const uint16_t prescaler[8] = {1, 2, 4, 8, 16, 64, 256, 1024}; + +Tc* const tc_insts[TC_INST_NUM] = TC_INSTS; +Tcc* const tcc_insts[TCC_INST_NUM] = TCC_INSTS; + +IRQn_Type const tc_irq[TC_INST_NUM] = { +#ifdef TC0 + TC0_IRQn, +#endif +#ifdef TC1 + TC1_IRQn, +#endif +#ifdef TC2 + TC2_IRQn, +#endif +#ifdef TC3 + TC3_IRQn, +#endif +#ifdef TC4 + TC4_IRQn, +#endif +#ifdef TC5 + TC5_IRQn, +#endif +#ifdef TC6 + TC6_IRQn, +#endif +#ifdef TC7 + TC7_IRQn, +#endif +}; + +void tc_enable_interrupts(uint8_t tc_index) { + NVIC_DisableIRQ(tc_irq[tc_index]); + NVIC_ClearPendingIRQ(tc_irq[tc_index]); + NVIC_EnableIRQ(tc_irq[tc_index]); +} + +void tc_disable_interrupts(uint8_t tc_index) { + NVIC_DisableIRQ(tc_irq[tc_index]); + NVIC_ClearPendingIRQ(tc_irq[tc_index]); +} + +void tcc_set_enable(Tcc* tcc, bool enable) { + tcc->CTRLA.bit.ENABLE = enable; + while (tcc->SYNCBUSY.bit.ENABLE != 0) { + /* Wait for sync */ + } +} + +void tc_reset(Tc* tc) { + tc->COUNT16.CTRLA.bit.SWRST = 1; + while (tc->COUNT16.CTRLA.bit.SWRST == 1) { + } +} + +void shared_timer_handler(bool is_tc, uint8_t index) { + // Add calls to interrupt handlers for specific functionality here. + if (is_tc) { + pulseout_interrupt_handler(index); + } +} + +#ifdef SAMD51 +#define TC_OFFSET 0 +#endif +#ifdef SAMD21 +#define TC_OFFSET 3 +#endif + +void TCC0_Handler(void) { + shared_timer_handler(false, 0); +} +void TCC1_Handler(void) { + shared_timer_handler(false, 1); +} +void TCC2_Handler(void) { + shared_timer_handler(false, 2); +} +// TC0 - TC2 only exist on the SAMD51 +#ifdef TC0 +void TC0_Handler(void) { + shared_timer_handler(true, 0); +} +#endif +#ifdef TC1 +void TC1_Handler(void) { + shared_timer_handler(true, 1); +} +#endif +#ifdef TC2 +void TC2_Handler(void) { + shared_timer_handler(true, 2); +} +#endif +void TC3_Handler(void) { + shared_timer_handler(true, 3 - TC_OFFSET); +} +void TC4_Handler(void) { + shared_timer_handler(true, 4 - TC_OFFSET); +} +void TC5_Handler(void) { + shared_timer_handler(true, 5 - TC_OFFSET); +} +#ifdef TC6 +void TC6_Handler(void) { + shared_timer_handler(true, 6 - TC_OFFSET); +} +#endif +#ifdef TC7 +void TC7_Handler(void) { + shared_timer_handler(true, 7 - TC_OFFSET); +} +#endif diff --git a/ports/atmel-samd/timers.h b/ports/atmel-samd/peripherals/timers.h similarity index 100% rename from ports/atmel-samd/timers.h rename to ports/atmel-samd/peripherals/timers.h diff --git a/ports/atmel-samd/supervisor/port.c b/ports/atmel-samd/supervisor/port.c index 7c682d1206a56..55e0a7ecfce26 100644 --- a/ports/atmel-samd/supervisor/port.c +++ b/ports/atmel-samd/supervisor/port.c @@ -55,11 +55,11 @@ #include "common-hal/rtc/RTC.h" #include "common-hal/touchio/TouchIn.h" #include "common-hal/usb_hid/Device.h" +#include "peripherals/cache.h" +#include "peripherals/clocks.h" +#include "peripherals/events.h" +#include "peripherals/dma.h" #include "shared-bindings/rtc/__init__.h" -#include "clocks.h" -#include "events.h" -#include "peripherals.h" -#include "shared_dma.h" #include "tick.h" #ifdef CIRCUITPY_GAMEPAD_TICKS diff --git a/shared-bindings/board/__init__.h b/shared-bindings/board/__init__.h index 720239f2807dc..2730e5f51b97c 100644 --- a/shared-bindings/board/__init__.h +++ b/shared-bindings/board/__init__.h @@ -29,6 +29,8 @@ #include "py/obj.h" +#include "shared-bindings/microcontroller/Pin.h" // for the pin definitions + extern const mp_obj_dict_t board_module_globals; #endif // MICROPY_INCLUDED_SHARED_BINDINGS_BOARD___INIT___H diff --git a/shared-bindings/rotaryio/IncrementalEncoder.c b/shared-bindings/rotaryio/IncrementalEncoder.c new file mode 100644 index 0000000000000..635826c60e2a6 --- /dev/null +++ b/shared-bindings/rotaryio/IncrementalEncoder.c @@ -0,0 +1,159 @@ +/* + * This file is part of the Micro Python project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2018 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 + +#include "lib/utils/context_manager_helpers.h" +#include "py/objproperty.h" +#include "py/runtime.h" +#include "py/runtime0.h" +#include "shared-bindings/microcontroller/Pin.h" +#include "shared-bindings/rotaryio/IncrementalEncoder.h" +#include "shared-bindings/util.h" + +//| .. currentmodule:: rotaryio +//| +//| :class:`IncrementalEncoder` -- Read the position of the incremental encoder +//| ============================================================================ +//| +//| IncrementalEncoder determines the relative rotational position based on two series of pulses. +//| +//| .. class:: IncrementalEncoder(pin_a, pin_b) +//| +//| Create an IncrementalEncoder object associated with the given pins. It tracks the positional +//| state of an incremental rotary encoder (also known as a quadrature encoder.) Position is +//| relative to the position when the object is contructed. +//| +//| :param ~microcontroller.Pin pin: First pin to read pulses from. +//| :param ~microcontroller.Pin pin: Second pin to read pulses from. +//| +//| For example:: +//| +//| import rotaryio +//| import time +//| from board import * +//| +//| enc = rotaryio.IncrementalEncoder(D1, D2) +//| last_position = None +//| while True; +//| position = enc.position +//| if last_position == None or position != last_position: +//| print(position) +//| last_position = position +//| +STATIC mp_obj_t rotaryio_incrementalencoder_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *pos_args) { + mp_arg_check_num(n_args, n_kw, 2, 2, true); + mp_map_t kw_args; + mp_map_init_fixed_table(&kw_args, n_kw, pos_args + n_args); + enum { ARG_pin_a, ARG_pin_b }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_pin_a, MP_ARG_REQUIRED | MP_ARG_OBJ }, + { MP_QSTR_pin_b, MP_ARG_REQUIRED | MP_ARG_OBJ }, + }; + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args, pos_args, &kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + assert_pin(args[ARG_pin_a].u_obj, false); + const mcu_pin_obj_t* pin_a = MP_OBJ_TO_PTR(args[ARG_pin_a].u_obj); + assert_pin_free(pin_a); + + assert_pin(args[ARG_pin_b].u_obj, false); + const mcu_pin_obj_t* pin_b = MP_OBJ_TO_PTR(args[ARG_pin_b].u_obj); + assert_pin_free(pin_b); + + rotaryio_incrementalencoder_obj_t *self = m_new_obj(rotaryio_incrementalencoder_obj_t); + self->base.type = &rotaryio_incrementalencoder_type; + + common_hal_rotaryio_incrementalencoder_construct(self, pin_a, pin_b); + + return MP_OBJ_FROM_PTR(self); +} + +//| .. method:: deinit() +//| +//| Deinitialises the IncrementalEncoder and releases any hardware resources for reuse. +//| +STATIC mp_obj_t rotaryio_incrementalencoder_deinit(mp_obj_t self_in) { + rotaryio_incrementalencoder_obj_t *self = MP_OBJ_TO_PTR(self_in); + common_hal_rotaryio_incrementalencoder_deinit(self); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(rotaryio_incrementalencoder_deinit_obj, rotaryio_incrementalencoder_deinit); + +//| .. method:: __enter__() +//| +//| No-op used by Context Managers. +//| +// Provided by context manager helper. + +//| .. method:: __exit__() +//| +//| Automatically deinitializes the hardware when exiting a context. See +//| :ref:`lifetime-and-contextmanagers` for more info. +//| +STATIC mp_obj_t rotaryio_incrementalencoder_obj___exit__(size_t n_args, const mp_obj_t *args) { + (void)n_args; + common_hal_rotaryio_incrementalencoder_deinit(args[0]); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(rotaryio_incrementalencoder___exit___obj, 4, 4, rotaryio_incrementalencoder_obj___exit__); + + +//| .. attribute:: position +//| +//| The current position in terms of pulses. The number of pulses per rotation is defined by the +//| specific hardware. +//| +STATIC mp_obj_t rotaryio_incrementalencoder_obj_get_position(mp_obj_t self_in) { + rotaryio_incrementalencoder_obj_t *self = MP_OBJ_TO_PTR(self_in); + raise_error_if_deinited(common_hal_rotaryio_incrementalencoder_deinited(self)); + + return mp_obj_new_int(common_hal_rotaryio_incrementalencoder_get_position(self)); +} +MP_DEFINE_CONST_FUN_OBJ_1(rotaryio_incrementalencoder_get_position_obj, rotaryio_incrementalencoder_obj_get_position); + +const mp_obj_property_t rotaryio_incrementalencoder_position_obj = { + .base.type = &mp_type_property, + .proxy = {(mp_obj_t)&rotaryio_incrementalencoder_get_position_obj, + (mp_obj_t)&mp_const_none_obj, + (mp_obj_t)&mp_const_none_obj}, +}; + +STATIC const mp_rom_map_elem_t rotaryio_incrementalencoder_locals_dict_table[] = { + // Methods + { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&rotaryio_incrementalencoder_deinit_obj) }, + { MP_ROM_QSTR(MP_QSTR___enter__), MP_ROM_PTR(&default___enter___obj) }, + { MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&rotaryio_incrementalencoder___exit___obj) }, + { MP_ROM_QSTR(MP_QSTR_position), MP_ROM_PTR(&rotaryio_incrementalencoder_position_obj) }, +}; +STATIC MP_DEFINE_CONST_DICT(rotaryio_incrementalencoder_locals_dict, rotaryio_incrementalencoder_locals_dict_table); + +const mp_obj_type_t rotaryio_incrementalencoder_type = { + { &mp_type_type }, + .name = MP_QSTR_IncrementalEncoder, + .make_new = rotaryio_incrementalencoder_make_new, + .locals_dict = (mp_obj_dict_t*)&rotaryio_incrementalencoder_locals_dict, +}; diff --git a/shared-bindings/rotaryio/IncrementalEncoder.h b/shared-bindings/rotaryio/IncrementalEncoder.h new file mode 100644 index 0000000000000..29e89e2089433 --- /dev/null +++ b/shared-bindings/rotaryio/IncrementalEncoder.h @@ -0,0 +1,41 @@ +/* + * 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_ROTARYIO_INCREMENTALENCODER_H +#define MICROPY_INCLUDED_SHARED_BINDINGS_ROTARYIO_INCREMENTALENCODER_H + +#include "common-hal/microcontroller/Pin.h" +#include "common-hal/rotaryio/IncrementalEncoder.h" + +extern const mp_obj_type_t rotaryio_incrementalencoder_type; + +extern void common_hal_rotaryio_incrementalencoder_construct(rotaryio_incrementalencoder_obj_t* self, + const mcu_pin_obj_t* pin_a, const mcu_pin_obj_t* pin_b); +extern void common_hal_rotaryio_incrementalencoder_deinit(rotaryio_incrementalencoder_obj_t* self); +extern bool common_hal_rotaryio_incrementalencoder_deinited(rotaryio_incrementalencoder_obj_t* self); +extern mp_int_t common_hal_rotaryio_incrementalencoder_get_position(rotaryio_incrementalencoder_obj_t* self); + +#endif // MICROPY_INCLUDED_SHARED_BINDINGS_ROTARYIO_INCREMENTALENCODER_H diff --git a/shared-bindings/rotaryio/__init__.c b/shared-bindings/rotaryio/__init__.c new file mode 100644 index 0000000000000..db1ff3d4c6f9e --- /dev/null +++ b/shared-bindings/rotaryio/__init__.c @@ -0,0 +1,75 @@ +/* + * This file is part of the MicroPython 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 + +#include "py/obj.h" +#include "py/runtime.h" + +#include "shared-bindings/microcontroller/Pin.h" +#include "shared-bindings/rotaryio/__init__.h" +#include "shared-bindings/rotaryio/IncrementalEncoder.h" + +//| :mod:`rotaryio` --- Support for pulse based protocols +//| ===================================================== +//| +//| .. module:: rotaryio +//| :synopsis: Support for reading rotation sensors +//| :platform: SAMD +//| +//| The `rotaryio` module contains classes to read different rotation encoding schemes. See +//| `Wikipedia's Rotary Encoder page `_ for more +//| background. +//| +//| Libraries +//| +//| .. toctree:: +//| :maxdepth: 3 +//| +//| IncrementalEncoder +//| + +//| .. warning:: This module is not available in some SAMD21 (aka M0) builds. See the +//| :ref:`module-support-matrix` for more info. +//| + +//| All classes change hardware state and should be deinitialized when they +//| are no longer needed if the program continues after use. To do so, either +//| call :py:meth:`!deinit` or use a context manager. See +//| :ref:`lifetime-and-contextmanagers` for more info. +//| + +STATIC const mp_rom_map_elem_t rotaryio_module_globals_table[] = { + { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_rotaryio) }, + { MP_ROM_QSTR(MP_QSTR_IncrementalEncoder), MP_ROM_PTR(&rotaryio_incrementalencoder_type) }, +}; + +STATIC MP_DEFINE_CONST_DICT(rotaryio_module_globals, rotaryio_module_globals_table); + +const mp_obj_module_t rotaryio_module = { + .base = { &mp_type_module }, + .globals = (mp_obj_dict_t*)&rotaryio_module_globals, +}; diff --git a/shared-bindings/rotaryio/__init__.h b/shared-bindings/rotaryio/__init__.h new file mode 100644 index 0000000000000..5d051d5a1aea3 --- /dev/null +++ b/shared-bindings/rotaryio/__init__.h @@ -0,0 +1,34 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2018 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. + */ + +#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_ROTARYIO___INIT___H +#define MICROPY_INCLUDED_SHARED_BINDINGS_ROTARYIO___INIT___H + +#include "py/obj.h" + +// Nothing now. + +#endif // MICROPY_INCLUDED_SHARED_BINDINGS_ROTARYIO___INIT___H diff --git a/supervisor/shared/rgb_led_status.c b/supervisor/shared/rgb_led_status.c index 8f1b506fea31a..584d021b0eebd 100644 --- a/supervisor/shared/rgb_led_status.c +++ b/supervisor/shared/rgb_led_status.c @@ -27,7 +27,6 @@ #include "mphalport.h" #include "common-hal/microcontroller/Pin.h" #include "rgb_led_status.h" -#include "pins.h" #ifdef MICROPY_HW_NEOPIXEL uint8_t rgb_status_brightness = 63; From d0fb6e7a2fd6b60ecc0fc8a332a9de5ed32f88af Mon Sep 17 00:00:00 2001 From: Scott Shawcroft Date: Tue, 29 May 2018 18:21:19 -0700 Subject: [PATCH 2/5] atmel-samd: Add rotary encoder support. Fixes #283 --- ports/atmel-samd/Makefile | 2 + ports/atmel-samd/common-hal/busio/SPI.c | 1 - ports/atmel-samd/common-hal/pulseio/PulseIn.c | 238 ++---------------- ports/atmel-samd/common-hal/pulseio/PulseIn.h | 4 + .../common-hal/rotaryio/IncrementalEncoder.c | 201 +++++++-------- .../common-hal/rotaryio/IncrementalEncoder.h | 7 + .../atmel-samd/common-hal/rotaryio/__init__.c | 2 +- .../external_flash/external_flash.c | 1 - ports/atmel-samd/peripherals/clocks.c | 51 ++-- ports/atmel-samd/peripherals/clocks.h | 1 + ports/atmel-samd/peripherals/events.c | 3 - .../peripherals/external_interrupts.c | 105 ++++++++ .../peripherals/external_interrupts.h | 54 ++++ ports/atmel-samd/peripherals/samd21/clocks.c | 14 +- .../peripherals/samd21/external_interrupts.c | 86 +++++++ .../peripherals/samd51/external_interrupts.c | 132 ++++++++++ ports/atmel-samd/peripherals/samd51/sercom.c | 2 - ports/atmel-samd/peripherals/samd51/timers.c | 2 - ports/atmel-samd/supervisor/port.c | 4 +- shared-bindings/index.rst | 4 + shared-bindings/rotaryio/__init__.c | 4 +- 21 files changed, 537 insertions(+), 381 deletions(-) create mode 100644 ports/atmel-samd/peripherals/external_interrupts.c create mode 100644 ports/atmel-samd/peripherals/external_interrupts.h create mode 100644 ports/atmel-samd/peripherals/samd21/external_interrupts.c create mode 100644 ports/atmel-samd/peripherals/samd51/external_interrupts.c diff --git a/ports/atmel-samd/Makefile b/ports/atmel-samd/Makefile index 162e6b3e6194f..1a406c1d01574 100644 --- a/ports/atmel-samd/Makefile +++ b/ports/atmel-samd/Makefile @@ -249,6 +249,7 @@ SRC_C = \ peripherals/clocks.c \ peripherals/dma.c \ peripherals/events.c \ + peripherals/external_interrupts.c \ peripherals/sercom.c \ peripherals/timers.c \ peripherals/$(CHIP_FAMILY)/adc.c \ @@ -256,6 +257,7 @@ SRC_C = \ peripherals/$(CHIP_FAMILY)/clocks.c \ peripherals/$(CHIP_FAMILY)/dma.c \ peripherals/$(CHIP_FAMILY)/events.c \ + peripherals/$(CHIP_FAMILY)/external_interrupts.c \ peripherals/$(CHIP_FAMILY)/pins.c \ peripherals/$(CHIP_FAMILY)/sercom.c \ peripherals/$(CHIP_FAMILY)/timers.c \ diff --git a/ports/atmel-samd/common-hal/busio/SPI.c b/ports/atmel-samd/common-hal/busio/SPI.c index a2ee93c6db493..a9bd5590394e1 100644 --- a/ports/atmel-samd/common-hal/busio/SPI.c +++ b/ports/atmel-samd/common-hal/busio/SPI.c @@ -37,7 +37,6 @@ #include "supervisor/shared/rgb_led_status.h" #include "peripherals/dma.h" -//#include "peripherals/pins.h" #include "peripherals/sercom.h" void common_hal_busio_spi_construct(busio_spi_obj_t *self, diff --git a/ports/atmel-samd/common-hal/pulseio/PulseIn.c b/ports/atmel-samd/common-hal/pulseio/PulseIn.c index 266a9251e92b4..99a60a82979df 100644 --- a/ports/atmel-samd/common-hal/pulseio/PulseIn.c +++ b/ports/atmel-samd/common-hal/pulseio/PulseIn.c @@ -34,90 +34,28 @@ #include "mpconfigport.h" #include "py/gc.h" #include "py/runtime.h" +#include "peripherals/external_interrupts.h" #include "peripherals/pins.h" #include "shared-bindings/microcontroller/__init__.h" #include "shared-bindings/pulseio/PulseIn.h" -#ifdef SAMD21 -#include "hpl/gclk/hpl_gclk_base.h" -#endif - #include "tick.h" -static pulseio_pulsein_obj_t *active_pulseins[EIC_EXTINT_NUM]; -static uint64_t last_ms[EIC_EXTINT_NUM]; -static uint16_t last_us[EIC_EXTINT_NUM]; - -bool eic_get_enable(void) { - #ifdef SAMD51 - return EIC->CTRLA.bit.ENABLE; - #endif - #ifdef SAMD21 - return EIC->CTRL.bit.ENABLE; - #endif -} - -void eic_set_enable(bool value) { - #ifdef SAMD51 - EIC->CTRLA.bit.ENABLE = value; - while (EIC->SYNCBUSY.bit.ENABLE != 0) {} - // This won't actually block long enough in Rev A of SAMD51 and will miss edges in the first - // three cycles of the peripheral clock. See the errata for details. It shouldn't impact us. - #endif - #ifdef SAMD21 - EIC->CTRL.bit.ENABLE = value; - while (EIC->STATUS.bit.SYNCBUSY != 0) {} - #endif -} - -void eic_reset(void) { - #ifdef SAMD51 - EIC->CTRLA.bit.SWRST = true; - while (EIC->SYNCBUSY.bit.SWRST != 0) {} - // This won't actually block long enough in Rev A of SAMD51 and will miss edges in the first - // three cycles of the peripheral clock. See the errata for details. It shouldn't impact us. - #endif - #ifdef SAMD21 - EIC->CTRL.bit.SWRST = true; - while (EIC->STATUS.bit.SYNCBUSY != 0) {} - #endif -} - -void pulsein_reset(void) { - for (int i = 0; i < EIC_EXTINT_NUM; i++) { - active_pulseins[i] = NULL; - last_ms[i] = 0; - last_us[i] = 0; - #ifdef SAMD51 - NVIC_DisableIRQ(EIC_0_IRQn + i); - NVIC_ClearPendingIRQ(EIC_0_IRQn + i); - #endif - } - eic_reset(); - #ifdef SAMD21 - NVIC_DisableIRQ(EIC_IRQn); - NVIC_ClearPendingIRQ(EIC_IRQn); - #endif -} - static void pulsein_set_config(pulseio_pulsein_obj_t* self, bool first_edge) { - uint8_t sense_setting = EIC_CONFIG_FILTEN0; + uint32_t sense_setting; if (!first_edge) { - sense_setting |= EIC_CONFIG_SENSE0_BOTH_Val; + sense_setting = EIC_CONFIG_SENSE0_BOTH_Val; + configure_eic_channel(self->channel, sense_setting); + return; } else if (self->idle_state) { - sense_setting |= EIC_CONFIG_SENSE0_FALL_Val; + sense_setting = EIC_CONFIG_SENSE0_FALL_Val; } else { - sense_setting |= EIC_CONFIG_SENSE0_RISE_Val; + sense_setting = EIC_CONFIG_SENSE0_RISE_Val; } - eic_set_enable(false); - uint8_t config_index = self->channel / 8; - uint8_t position = (self->channel % 8) * 4; - uint32_t masked_value = EIC->CONFIG[config_index].reg & ~(0xf << position); - EIC->CONFIG[config_index].reg = masked_value | (sense_setting << position); - eic_set_enable(true); + turn_on_eic_channel(self->channel, sense_setting, EIC_HANDLER_PULSEIN); } -static void pulsein_interrupt_handler(uint8_t channel) { +void pulsein_interrupt_handler(uint8_t channel) { // Grab the current time first. uint32_t current_us; uint64_t current_ms; @@ -125,16 +63,16 @@ static void pulsein_interrupt_handler(uint8_t channel) { // current_tick gives us the remaining us until the next tick but we want the number since the // last ms. current_us = 1000 - current_us; - pulseio_pulsein_obj_t* self = active_pulseins[channel]; + pulseio_pulsein_obj_t* self = get_eic_channel_data(channel); if (self->first_edge) { self->first_edge = false; pulsein_set_config(self, false); } else { - uint32_t ms_diff = current_ms - last_ms[self->channel]; - uint16_t us_diff = current_us - last_us[self->channel]; + uint32_t ms_diff = current_ms - self->last_ms; + uint16_t us_diff = current_us - self->last_us; uint32_t total_diff = us_diff; - if (last_us[self->channel] > current_us) { - total_diff = 1000 + current_us - last_us[self->channel]; + if (self->last_us > current_us) { + total_diff = 1000 + current_us - self->last_us; if (ms_diff > 1) { total_diff += (ms_diff - 1) * 1000; } @@ -154,8 +92,8 @@ static void pulsein_interrupt_handler(uint8_t channel) { self->start++; } } - last_ms[self->channel] = current_ms; - last_us[self->channel] = current_us; + self->last_ms = current_ms; + self->last_us = current_us; } void common_hal_pulseio_pulsein_construct(pulseio_pulsein_obj_t* self, @@ -163,17 +101,7 @@ void common_hal_pulseio_pulsein_construct(pulseio_pulsein_obj_t* self, if (!pin->has_extint) { mp_raise_RuntimeError("No hardware support on pin"); } - uint32_t mask = 1 << pin->extint_channel; - if (active_pulseins[pin->extint_channel] != NULL || - (eic_get_enable() == 1 && -#ifdef SAMD51 - ((EIC->INTENSET.bit.EXTINT & mask) != 0 || - (EIC->EVCTRL.bit.EXTINTEO & mask) != 0))) { -#endif -#ifdef SAMD21 - ((EIC->INTENSET.vec.EXTINT & mask) != 0 || - (EIC->EVCTRL.vec.EXTINTEO & mask) != 0))) { -#endif + if (eic_get_enable() && !eic_channel_free(pin->extint_channel)) { mp_raise_RuntimeError("EXTINT channel already in use"); } @@ -188,42 +116,22 @@ void common_hal_pulseio_pulsein_construct(pulseio_pulsein_obj_t* self, self->start = 0; self->len = 0; self->first_edge = true; + self->last_us = 0; + self->last_ms = 0; - active_pulseins[pin->extint_channel] = self; + set_eic_channel_data(pin->extint_channel, (void*) self); // Check to see if the EIC is enabled and start it up if its not.' - // SAMD51 EIC can only be clocked up to 100mhz so we use the 48mhz clock. if (eic_get_enable() == 0) { - #ifdef SAMD51 - MCLK->APBAMASK.bit.EIC_ = true; - hri_gclk_write_PCHCTRL_reg(GCLK, EIC_GCLK_ID, - GCLK_PCHCTRL_GEN_GCLK1_Val | (1 << GCLK_PCHCTRL_CHEN_Pos)); - #endif - - #ifdef SAMD21 - PM->APBAMASK.bit.EIC_ = true; - _gclk_enable_channel(EIC_GCLK_ID, GCLK_CLKCTRL_GEN_GCLK0_Val); - #endif - - - #ifdef SAMD21 - NVIC_DisableIRQ(EIC_IRQn); - NVIC_ClearPendingIRQ(EIC_IRQn); - NVIC_EnableIRQ(EIC_IRQn); - #endif + turn_on_external_interrupt_controller(); } gpio_set_pin_function(pin->pin, GPIO_PIN_FUNCTION_A); - #ifdef SAMD51 - NVIC_DisableIRQ(EIC_0_IRQn + self->channel); - NVIC_ClearPendingIRQ(EIC_0_IRQn + self->channel); - NVIC_EnableIRQ(EIC_0_IRQn + self->channel); - #endif + turn_on_cpu_interrupt(self->channel); // Set config will enable the EIC. pulsein_set_config(self, true); - EIC->INTENSET.reg = mask << EIC_INTENSET_EXTINT_Pos; } bool common_hal_pulseio_pulsein_deinited(pulseio_pulsein_obj_t* self) { @@ -234,39 +142,9 @@ void common_hal_pulseio_pulsein_deinit(pulseio_pulsein_obj_t* self) { if (common_hal_pulseio_pulsein_deinited(self)) { return; } - uint32_t mask = 1 << self->channel; - EIC->INTENCLR.reg = mask << EIC_INTENSET_EXTINT_Pos; - #ifdef SAMD51 - NVIC_DisableIRQ(EIC_0_IRQn + self->channel); - NVIC_ClearPendingIRQ(EIC_0_IRQn + self->channel); - #endif - active_pulseins[self->channel] = NULL; + turn_off_eic_channel(self->channel); reset_pin(self->pin); self->pin = NO_PIN; - - bool all_null = true; - for (uint8_t i = 0; all_null && i < 16; i++) { - all_null = all_null && active_pulseins[i] == NULL; - } - #ifdef SAMD21 - if (all_null && EIC->INTENSET.reg == 0) { - NVIC_DisableIRQ(EIC_IRQn); - NVIC_ClearPendingIRQ(EIC_IRQn); - } - #endif - // Test if all channels are null and deinit everything if they are. - if (all_null && EIC->EVCTRL.reg == 0 && EIC->INTENSET.reg == 0) { - eic_set_enable(false); - #ifdef SAMD51 - MCLK->APBAMASK.bit.EIC_ = false; - hri_gclk_write_PCHCTRL_reg(GCLK, EIC_GCLK_ID, 0); - #endif - - #ifdef SAMD21 - PM->APBAMASK.bit.EIC_ = false; - hri_gclk_write_CLKCTRL_reg(GCLK, GCLK_CLKCTRL_ID(EIC_GCLK_ID)); - #endif - } } void common_hal_pulseio_pulsein_pause(pulseio_pulsein_obj_t* self) { @@ -289,9 +167,9 @@ void common_hal_pulseio_pulsein_resume(pulseio_pulsein_obj_t* self, } // Reconfigure the pin and make sure its set to detect the first edge. - last_ms[self->channel] = 0; - last_us[self->channel] = 0; self->first_edge = true; + self->last_ms = 0; + self->last_us = 0; gpio_set_pin_function(self->pin, GPIO_PIN_FUNCTION_A); uint32_t mask = 1 << self->channel; // Clear previous interrupt state and re-enable it. @@ -343,69 +221,3 @@ uint16_t common_hal_pulseio_pulsein_get_item(pulseio_pulsein_obj_t* self, common_hal_mcu_enable_interrupts(); return value; } - -void external_interrupt_handler(uint8_t channel) { - pulsein_interrupt_handler(channel); - EIC->INTFLAG.reg = (1 << channel) << EIC_INTFLAG_EXTINT_Pos; -} - -#ifdef SAMD21 -void EIC_Handler(void) { - for (uint8_t i = 0; i < 16; i++) { - if ((EIC->INTFLAG.vec.EXTINT & (1 << i)) != 0) { - external_interrupt_handler(i); - } - } -} -#endif - -#ifdef SAMD51 -void EIC_0_Handler(void) { - external_interrupt_handler(0); -} -void EIC_1_Handler(void) { - external_interrupt_handler(1); -} -void EIC_2_Handler(void) { - external_interrupt_handler(2); -} -void EIC_3_Handler(void) { - external_interrupt_handler(3); -} -void EIC_4_Handler(void) { - external_interrupt_handler(4); -} -void EIC_5_Handler(void) { - external_interrupt_handler(5); -} -void EIC_6_Handler(void) { - external_interrupt_handler(6); -} -void EIC_7_Handler(void) { - external_interrupt_handler(7); -} -void EIC_8_Handler(void) { - external_interrupt_handler(8); -} -void EIC_9_Handler(void) { - external_interrupt_handler(9); -} -void EIC_10_Handler(void) { - external_interrupt_handler(10); -} -void EIC_11_Handler(void) { - external_interrupt_handler(11); -} -void EIC_12_Handler(void) { - external_interrupt_handler(12); -} -void EIC_13_Handler(void) { - external_interrupt_handler(13); -} -void EIC_14_Handler(void) { - external_interrupt_handler(14); -} -void EIC_15_Handler(void) { - external_interrupt_handler(15); -} -#endif diff --git a/ports/atmel-samd/common-hal/pulseio/PulseIn.h b/ports/atmel-samd/common-hal/pulseio/PulseIn.h index e3af42e0a3456..3d79b50c3c4a3 100644 --- a/ports/atmel-samd/common-hal/pulseio/PulseIn.h +++ b/ports/atmel-samd/common-hal/pulseio/PulseIn.h @@ -41,8 +41,12 @@ typedef struct { volatile uint16_t start; volatile uint16_t len; volatile bool first_edge; + volatile uint64_t last_ms; + volatile uint16_t last_us; } pulseio_pulsein_obj_t; void pulsein_reset(void); +void pulsein_interrupt_handler(uint8_t channel); + #endif // MICROPY_INCLUDED_ATMEL_SAMD_COMMON_HAL_PULSEIO_PULSEIN_H diff --git a/ports/atmel-samd/common-hal/rotaryio/IncrementalEncoder.c b/ports/atmel-samd/common-hal/rotaryio/IncrementalEncoder.c index 58119fa7e98dc..d86f4763db623 100644 --- a/ports/atmel-samd/common-hal/rotaryio/IncrementalEncoder.c +++ b/ports/atmel-samd/common-hal/rotaryio/IncrementalEncoder.c @@ -26,133 +26,104 @@ #include "common-hal/rotaryio/IncrementalEncoder.h" -#include - #include "atmel_start_pins.h" -#include "hal/include/hal_gpio.h" -#include "mpconfigport.h" -#include "peripherals/pins.h" -#include "py/gc.h" +#include "peripherals/external_interrupts.h" #include "py/runtime.h" -#include "shared-bindings/microcontroller/__init__.h" - -#ifdef SAMD21 -#include "hpl/gclk/hpl_gclk_base.h" -#endif void common_hal_rotaryio_incrementalencoder_construct(rotaryio_incrementalencoder_obj_t* self, - const mcu_pin_obj_t* pin, uint16_t maxlen, bool idle_state) { -// if (!pin->has_extint) { -// mp_raise_RuntimeError("No hardware support on pin"); -// } -// uint32_t mask = 1 << pin->extint_channel; -// if (active_incrementalencoders[pin->extint_channel] != NULL || -// (eic_get_enable() == 1 && -// #ifdef SAMD51 -// ((EIC->INTENSET.bit.EXTINT & mask) != 0 || -// (EIC->EVCTRL.bit.EXTINTEO & mask) != 0))) { -// #endif -// #ifdef SAMD21 -// ((EIC->INTENSET.vec.EXTINT & mask) != 0 || -// (EIC->EVCTRL.vec.EXTINTEO & mask) != 0))) { -// #endif -// mp_raise_RuntimeError("EXTINT channel already in use"); -// } -// -// self->buffer = (uint16_t *) m_malloc(maxlen * sizeof(uint16_t), false); -// if (self->buffer == NULL) { -// mp_raise_msg_varg(&mp_type_MemoryError, "Failed to allocate RX buffer of %d bytes", maxlen * sizeof(uint16_t)); -// } -// self->channel = pin->extint_channel; -// self->pin = pin->pin; -// self->maxlen = maxlen; -// self->idle_state = idle_state; -// self->start = 0; -// self->len = 0; -// self->first_edge = true; -// -// active_incrementalencoders[pin->extint_channel] = self; -// -// // Check to see if the EIC is enabled and start it up if its not.' -// // SAMD51 EIC can only be clocked up to 100mhz so we use the 48mhz clock. -// if (eic_get_enable() == 0) { -// #ifdef SAMD51 -// MCLK->APBAMASK.bit.EIC_ = true; -// hri_gclk_write_PCHCTRL_reg(GCLK, EIC_GCLK_ID, -// GCLK_PCHCTRL_GEN_GCLK1_Val | (1 << GCLK_PCHCTRL_CHEN_Pos)); -// #endif -// -// #ifdef SAMD21 -// PM->APBAMASK.bit.EIC_ = true; -// _gclk_enable_channel(EIC_GCLK_ID, GCLK_CLKCTRL_GEN_GCLK0_Val); -// #endif -// -// -// #ifdef SAMD21 -// NVIC_DisableIRQ(EIC_IRQn); -// NVIC_ClearPendingIRQ(EIC_IRQn); -// NVIC_EnableIRQ(EIC_IRQn); -// #endif -// } -// -// gpio_set_pin_function(pin->pin, GPIO_PIN_FUNCTION_A); -// -// #ifdef SAMD51 -// NVIC_DisableIRQ(EIC_0_IRQn + self->channel); -// NVIC_ClearPendingIRQ(EIC_0_IRQn + self->channel); -// NVIC_EnableIRQ(EIC_0_IRQn + self->channel); -// #endif -// -// // Set config will enable the EIC. -// incrementalencoder_set_config(self, true); -// EIC->INTENSET.reg = mask << EIC_INTENSET_EXTINT_Pos; + const mcu_pin_obj_t* pin_a, const mcu_pin_obj_t* pin_b) { + if (!pin_a->has_extint || !pin_a->has_extint) { + mp_raise_RuntimeError("Both pins must support hardware interrupts"); + } + + // TODO: The SAMD51 has a peripheral dedicated to quadrature encoder debugging. Use it instead + // of the external interrupt. + + if (eic_get_enable()) { + if (!eic_channel_free(pin_a->extint_channel) || !eic_channel_free(pin_b->extint_channel)) { + mp_raise_RuntimeError("A hardware interrupt channel is already in use"); + } + } else { + turn_on_external_interrupt_controller(); + } + + // These default settings apply when the EIC isn't yet enabled. + self->eic_channel_a = pin_a->extint_channel; + self->eic_channel_b = pin_b->extint_channel; + self->pin_a = pin_a->pin; + self->pin_b = pin_b->pin; + + gpio_set_pin_function(self->pin_a, GPIO_PIN_FUNCTION_A); + gpio_set_pin_pull_mode(self->pin_a, GPIO_PULL_UP); + + gpio_set_pin_function(self->pin_b, GPIO_PIN_FUNCTION_A); + gpio_set_pin_pull_mode(self->pin_b, GPIO_PULL_UP); + + set_eic_channel_data(self->eic_channel_a, (void*) self); + set_eic_channel_data(self->eic_channel_b, (void*) self); + + bool pin_a_level = gpio_get_pin_level(self->pin_a); + bool pin_b_level = gpio_get_pin_level(self->pin_b); + if (!pin_a_level && !pin_b_level) { + self->last_state = 1; + } else if (!pin_a_level && pin_b_level) { + self->last_state = 2; + } else if (pin_a_level && pin_b_level) { + self->last_state = 3; + } else { + self->last_state = 4; + } + + turn_on_eic_channel(self->eic_channel_a, EIC_CONFIG_SENSE0_BOTH_Val, EIC_HANDLER_INCREMENTAL_ENCODER); + turn_on_eic_channel(self->eic_channel_b, EIC_CONFIG_SENSE0_BOTH_Val, EIC_HANDLER_INCREMENTAL_ENCODER); } bool common_hal_rotaryio_incrementalencoder_deinited(rotaryio_incrementalencoder_obj_t* self) { - //return self->pin == NO_PIN; - return true; + return self->pin_a == NO_PIN; } void common_hal_rotaryio_incrementalencoder_deinit(rotaryio_incrementalencoder_obj_t* self) { - // if (common_hal_rotaryio_incrementalencoder_deinited(self)) { - // return; - // } - // uint32_t mask = 1 << self->channel; - // EIC->INTENCLR.reg = mask << EIC_INTENSET_EXTINT_Pos; - // #ifdef SAMD51 - // NVIC_DisableIRQ(EIC_0_IRQn + self->channel); - // NVIC_ClearPendingIRQ(EIC_0_IRQn + self->channel); - // #endif - // active_incrementalencoders[self->channel] = NULL; - // reset_pin(self->pin); - // self->pin = NO_PIN; - // - // bool all_null = true; - // for (uint8_t i = 0; all_null && i < 16; i++) { - // all_null = all_null && active_incrementalencoders[i] == NULL; - // } - // #ifdef SAMD21 - // if (all_null && EIC->INTENSET.reg == 0) { - // NVIC_DisableIRQ(EIC_IRQn); - // NVIC_ClearPendingIRQ(EIC_IRQn); - // } - // #endif - // // Test if all channels are null and deinit everything if they are. - // if (all_null && EIC->EVCTRL.reg == 0 && EIC->INTENSET.reg == 0) { - // eic_set_enable(false); - // #ifdef SAMD51 - // MCLK->APBAMASK.bit.EIC_ = false; - // hri_gclk_write_PCHCTRL_reg(GCLK, EIC_GCLK_ID, 0); - // #endif - // - // #ifdef SAMD21 - // PM->APBAMASK.bit.EIC_ = false; - // hri_gclk_write_CLKCTRL_reg(GCLK, GCLK_CLKCTRL_ID(EIC_GCLK_ID)); - // #endif - // } + if (common_hal_rotaryio_incrementalencoder_deinited(self)) { + return; + } + turn_off_eic_channel(self->eic_channel_a); + turn_off_eic_channel(self->eic_channel_b); + reset_pin(self->pin_a); + self->pin_a = NO_PIN; + reset_pin(self->pin_b); + self->pin_b = NO_PIN; } mp_int_t common_hal_rotaryio_incrementalencoder_get_position(rotaryio_incrementalencoder_obj_t* self) { - return 0; + return self->position; +} + +void incrementalencoder_interrupt_handler(uint8_t channel) { + rotaryio_incrementalencoder_obj_t* self = get_eic_channel_data(channel); + // TODO(tannewt): If we need more speed then read the pin directly. gpio_get_pin_level has + // smarts to compensate for pin direction we don't need. + bool pin_a = gpio_get_pin_level(self->pin_a); + bool pin_b = gpio_get_pin_level(self->pin_b); + + uint8_t this_state; + if (!pin_a && !pin_b) { + this_state = 1; + } else if (!pin_a && pin_b) { + this_state = 2; + } else if (pin_a && pin_b) { + this_state = 3; + } else { + this_state = 4; + } + + // Handle wrap around explicitly. + if (this_state == 4 && self->last_state == 1) { + self->position -= 1; + } else if (this_state == 1 && self->last_state == 4) { + self->position += 1; + } else { + self->position += (this_state - self->last_state); + } + self->last_state = this_state; } diff --git a/ports/atmel-samd/common-hal/rotaryio/IncrementalEncoder.h b/ports/atmel-samd/common-hal/rotaryio/IncrementalEncoder.h index c878239bcf8c1..ffdf7da174651 100644 --- a/ports/atmel-samd/common-hal/rotaryio/IncrementalEncoder.h +++ b/ports/atmel-samd/common-hal/rotaryio/IncrementalEncoder.h @@ -35,6 +35,13 @@ typedef struct { mp_obj_base_t base; uint8_t pin_a; uint8_t pin_b; + uint8_t eic_channel_a:4; + uint8_t eic_channel_b:4; + uint8_t last_state; + mp_int_t position; } rotaryio_incrementalencoder_obj_t; + +void incrementalencoder_interrupt_handler(uint8_t channel); + #endif // MICROPY_INCLUDED_ATMEL_SAMD_COMMON_HAL_ROTARYIO_INCREMENTALENCODER_H diff --git a/ports/atmel-samd/common-hal/rotaryio/__init__.c b/ports/atmel-samd/common-hal/rotaryio/__init__.c index 2bee925bc77fb..0aae79c26a1c7 100644 --- a/ports/atmel-samd/common-hal/rotaryio/__init__.c +++ b/ports/atmel-samd/common-hal/rotaryio/__init__.c @@ -1 +1 @@ -// No pulseio module functions. +// No rotaryio module functions. diff --git a/ports/atmel-samd/external_flash/external_flash.c b/ports/atmel-samd/external_flash/external_flash.c index b0e40fc7050ea..e6c407e73ea9b 100644 --- a/ports/atmel-samd/external_flash/external_flash.c +++ b/ports/atmel-samd/external_flash/external_flash.c @@ -36,7 +36,6 @@ #include "py/obj.h" #include "py/runtime.h" #include "lib/oofatfs/ff.h" -//#include "peripherals.h" #include "shared-bindings/microcontroller/__init__.h" #include "supervisor/shared/rgb_led_status.h" diff --git a/ports/atmel-samd/peripherals/clocks.c b/ports/atmel-samd/peripherals/clocks.c index a890210bf40b3..bfcca45475f43 100644 --- a/ports/atmel-samd/peripherals/clocks.c +++ b/ports/atmel-samd/peripherals/clocks.c @@ -56,41 +56,20 @@ uint8_t find_free_gclk(uint16_t divisor) { return 0xff; } +static uint8_t last_static_clock = 0; + +void init_dynamic_clocks(void) { + // Find the last statically initialized clock and save it. Everything after will be reset with + // the VM via reset_gclks. + for (uint8_t i = 0; i < GCLK_GEN_NUM; i++) { + if (gclk_enabled(i)) { + last_static_clock = i; + } + } +} + void reset_gclks(void) { - // Never reset GCLK0 because its used for the core - #if CONF_GCLK_GEN_1_GENEN == 0 - disable_gclk(1); - #endif - #if CONF_GCLK_GEN_2_GENEN == 0 - disable_gclk(2); - #endif - #if CONF_GCLK_GEN_3_GENEN == 0 - disable_gclk(3); - #endif - #if CONF_GCLK_GEN_4_GENEN == 0 - disable_gclk(4); - #endif - #if CONF_GCLK_GEN_5_GENEN == 0 - disable_gclk(5); - #endif - #if CONF_GCLK_GEN_6_GENEN == 0 - disable_gclk(6); - #endif - #if CONF_GCLK_GEN_7_GENEN == 0 - disable_gclk(7); - #endif - #ifdef SAMD51 - #if CONF_GCLK_GEN_8_GENEN == 0 - disable_gclk(8); - #endif - #if CONF_GCLK_GEN_9_GENEN == 0 - disable_gclk(9); - #endif - #if CONF_GCLK_GEN_10_GENEN == 0 - disable_gclk(10); - #endif - #if CONF_GCLK_GEN_11_GENEN == 0 - disable_gclk(11); - #endif - #endif + for (uint8_t i = last_static_clock + 1; i < GCLK_GEN_NUM; i++) { + disable_gclk(i); + } } diff --git a/ports/atmel-samd/peripherals/clocks.h b/ports/atmel-samd/peripherals/clocks.h index 6b7cfedce0292..78b2e2e3d5fcd 100644 --- a/ports/atmel-samd/peripherals/clocks.h +++ b/ports/atmel-samd/peripherals/clocks.h @@ -63,6 +63,7 @@ static inline bool board_has_crystal(void) { } void clock_init(void); +void init_dynamic_clocks(void); bool clock_get_enabled(uint8_t type, uint8_t index); bool clock_get_parent(uint8_t type, uint8_t index, uint8_t *p_type, uint8_t *p_index); diff --git a/ports/atmel-samd/peripherals/events.c b/ports/atmel-samd/peripherals/events.c index 9a4ab3b0ca5a6..2f6aea716600c 100644 --- a/ports/atmel-samd/peripherals/events.c +++ b/ports/atmel-samd/peripherals/events.c @@ -27,9 +27,6 @@ #include #include "peripherals/events.h" -// -// #include "clocks.h" -// #include "py/runtime.h" uint8_t find_async_event_channel(void) { diff --git a/ports/atmel-samd/peripherals/external_interrupts.c b/ports/atmel-samd/peripherals/external_interrupts.c new file mode 100644 index 0000000000000..dfec6c998717c --- /dev/null +++ b/ports/atmel-samd/peripherals/external_interrupts.c @@ -0,0 +1,105 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2018 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 "common-hal/pulseio/PulseIn.h" +#include "common-hal/rotaryio/IncrementalEncoder.h" +#include "shared-bindings/microcontroller/__init__.h" +#include "peripherals/external_interrupts.h" + +#include "sam.h" + +// This structure is used to share per-channel storage amongst all users of external interrupts. +// Without this there would be multiple arrays even though they are disjoint because each channel +// has one user. +static void *channel_data[EIC_EXTINT_NUM]; +static uint8_t channel_handler[EIC_EXTINT_NUM]; + +void external_interrupt_handler(uint8_t channel) { + uint8_t handler = channel_handler[channel]; + if (handler == EIC_HANDLER_PULSEIN) { + pulsein_interrupt_handler(channel); + } else if (handler == EIC_HANDLER_INCREMENTAL_ENCODER) { + incrementalencoder_interrupt_handler(channel); + } + EIC->INTFLAG.reg = (1 << channel) << EIC_INTFLAG_EXTINT_Pos; +} + +void configure_eic_channel(uint8_t eic_channel, uint32_t sense_setting) { + uint8_t config_index = eic_channel / 8; + uint8_t position = (eic_channel % 8) * 4; + #ifdef SAMD51 + eic_set_enable(false); + #endif + common_hal_mcu_disable_interrupts(); + uint32_t masked_value = EIC->CONFIG[config_index].reg & ~(0xf << position); + EIC->CONFIG[config_index].reg = masked_value | (sense_setting << position); + common_hal_mcu_enable_interrupts(); + #ifdef SAMD51 + eic_set_enable(true); + #endif +} + +void turn_on_eic_channel(uint8_t eic_channel, uint32_t sense_setting, + uint8_t channel_interrupt_handler) { + // We do very light filtering using majority voting. + sense_setting |= EIC_CONFIG_FILTEN0; + configure_eic_channel(eic_channel, sense_setting); + uint32_t mask = 1 << eic_channel; + EIC->INTENSET.reg = mask << EIC_INTENSET_EXTINT_Pos; + if (channel_interrupt_handler != EIC_HANDLER_NO_INTERRUPT) { + channel_handler[eic_channel] = channel_interrupt_handler; + turn_on_cpu_interrupt(eic_channel); + } +} + +void turn_off_eic_channel(uint8_t eic_channel) { + uint32_t mask = 1 << eic_channel; + EIC->INTENCLR.reg = mask << EIC_INTENSET_EXTINT_Pos; + #ifdef SAMD51 + NVIC_DisableIRQ(EIC_0_IRQn + eic_channel); + NVIC_ClearPendingIRQ(EIC_0_IRQn + eic_channel); + #endif + channel_data[eic_channel] = NULL; + + #ifdef SAMD21 + if (EIC->INTENSET.reg == 0) { + NVIC_DisableIRQ(EIC_IRQn); + NVIC_ClearPendingIRQ(EIC_IRQn); + } + #endif + // Test if all channels are null and deinit everything if they are. + if (EIC->EVCTRL.reg == 0 && EIC->INTENSET.reg == 0) { + turn_off_external_interrupt_controller(); + } +} + +void* get_eic_channel_data(uint8_t eic_channel) { + return channel_data[eic_channel]; +} + +void set_eic_channel_data(uint8_t eic_channel, void* data) { + channel_data[eic_channel] = data; +} diff --git a/ports/atmel-samd/peripherals/external_interrupts.h b/ports/atmel-samd/peripherals/external_interrupts.h new file mode 100644 index 0000000000000..12d8206770ef2 --- /dev/null +++ b/ports/atmel-samd/peripherals/external_interrupts.h @@ -0,0 +1,54 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2018 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_PERIPHERALS_EXTERNAL_INTERRUPTS_H +#define MICROPY_INCLUDED_ATMEL_SAMD_PERIPHERALS_EXTERNAL_INTERRUPTS_H + +#include +#include + +#define EIC_HANDLER_NO_INTERRUPT 0x0 +#define EIC_HANDLER_PULSEIN 0x1 +#define EIC_HANDLER_INCREMENTAL_ENCODER 0x2 + +void turn_on_external_interrupt_controller(void); +void turn_off_external_interrupt_controller(void); +void turn_on_cpu_interrupt(uint8_t eic_channel); +void turn_on_eic_channel(uint8_t eic_channel, uint32_t sense_setting, + uint8_t channel_interrupt_handler); +void configure_eic_channel(uint8_t eic_channel, uint32_t sense_setting); +void turn_off_eic_channel(uint8_t eic_channel); +bool eic_channel_free(uint8_t eic_channel); +bool eic_get_enable(void); +void eic_set_enable(bool value); +void eic_reset(void); + +void* get_eic_channel_data(uint8_t eic_channel); +void set_eic_channel_data(uint8_t eic_channel, void* data); + +void external_interrupt_handler(uint8_t channel); + +#endif // MICROPY_INCLUDED_ATMEL_SAMD_PERIPHERALS_EXTERNAL_INTERRUPTS_H diff --git a/ports/atmel-samd/peripherals/samd21/clocks.c b/ports/atmel-samd/peripherals/samd21/clocks.c index 94b515814691a..aad251a84cacd 100644 --- a/ports/atmel-samd/peripherals/samd21/clocks.c +++ b/ports/atmel-samd/peripherals/samd21/clocks.c @@ -124,17 +124,23 @@ static void init_clock_source_dfll48m(void) { void clock_init(void) { init_clock_source_osc8m(); - if (board_has_crystal()) + if (board_has_crystal()) { init_clock_source_xosc32k(); - else + } else { init_clock_source_osc32k(); + } + enable_clock_generator(0, GCLK_GENCTRL_SRC_DFLL48M_Val, 1); enable_clock_generator(1, GCLK_GENCTRL_SRC_DFLL48M_Val, 150); init_clock_source_dfll48m(); - if (board_has_crystal()) + if (board_has_crystal()) { enable_clock_generator(2, GCLK_GENCTRL_SRC_XOSC32K_Val, 32); - else + } else { enable_clock_generator(2, GCLK_GENCTRL_SRC_OSC32K_Val, 32); + } + + // Do this after all static clock init so that they aren't used dynamically. + init_dynamic_clocks(); } static bool clk_enabled(uint8_t clk) { diff --git a/ports/atmel-samd/peripherals/samd21/external_interrupts.c b/ports/atmel-samd/peripherals/samd21/external_interrupts.c new file mode 100644 index 0000000000000..209c439c0a999 --- /dev/null +++ b/ports/atmel-samd/peripherals/samd21/external_interrupts.c @@ -0,0 +1,86 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2018 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 "peripherals/external_interrupts.h" + +#include "hpl/gclk/hpl_gclk_base.h" +#include "peripherals/clocks.h" +#include "sam.h" + +void turn_on_external_interrupt_controller(void) { + PM->APBAMASK.bit.EIC_ = true; + _gclk_enable_channel(EIC_GCLK_ID, GCLK_CLKCTRL_GEN_GCLK0_Val); + eic_set_enable(true); +} + +void turn_off_external_interrupt_controller(void) { + eic_set_enable(false); + PM->APBAMASK.bit.EIC_ = false; + hri_gclk_write_CLKCTRL_reg(GCLK, GCLK_CLKCTRL_ID(EIC_GCLK_ID)); +} + +void turn_on_cpu_interrupt(uint8_t eic_channel) { + // Ignore the channel since the CPU interrupt line is shared. + (void) eic_channel; + + NVIC_DisableIRQ(EIC_IRQn); + NVIC_ClearPendingIRQ(EIC_IRQn); + NVIC_EnableIRQ(EIC_IRQn); +} + +bool eic_get_enable(void) { + return EIC->CTRL.bit.ENABLE; +} + +void eic_set_enable(bool value) { + EIC->CTRL.bit.ENABLE = value; + while (EIC->STATUS.bit.SYNCBUSY != 0) {} +} + +void eic_reset(void) { + EIC->CTRL.bit.SWRST = true; + while (EIC->STATUS.bit.SYNCBUSY != 0) {} + for (int i = 0; i < EIC_EXTINT_NUM; i++) { + set_eic_channel_data(i, NULL); + } + NVIC_DisableIRQ(EIC_IRQn); + NVIC_ClearPendingIRQ(EIC_IRQn); +} + +bool eic_channel_free(uint8_t eic_channel) { + uint32_t mask = 1 << eic_channel; + return get_eic_channel_data(eic_channel) == NULL && + (EIC->INTENSET.vec.EXTINT & mask) == 0 && + (EIC->EVCTRL.vec.EXTINTEO & mask) == 0; +} + +void EIC_Handler(void) { + for (uint8_t i = 0; i < 16; i++) { + if ((EIC->INTFLAG.vec.EXTINT & (1 << i)) != 0) { + external_interrupt_handler(i); + } + } +} diff --git a/ports/atmel-samd/peripherals/samd51/external_interrupts.c b/ports/atmel-samd/peripherals/samd51/external_interrupts.c new file mode 100644 index 0000000000000..6006d480e64ae --- /dev/null +++ b/ports/atmel-samd/peripherals/samd51/external_interrupts.c @@ -0,0 +1,132 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2018 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 "peripherals/external_interrupts.h" + +#include "peripherals/clocks.h" +#include "sam.h" + +void turn_on_external_interrupt_controller(void) { + MCLK->APBAMASK.bit.EIC_ = true; + + // We use the 48mhz clock to lightly filter the incoming pulse to reduce spurious interrupts. + connect_gclk_to_peripheral(GCLK_PCHCTRL_GEN_GCLK1_Val, EIC_GCLK_ID); + eic_set_enable(true); +} + +void turn_off_external_interrupt_controller(void) { + eic_set_enable(false); + MCLK->APBAMASK.bit.EIC_ = false; + disconnect_gclk_from_peripheral(GCLK_PCHCTRL_GEN_GCLK1_Val, EIC_GCLK_ID); +} + +void turn_on_cpu_interrupt(uint8_t eic_channel) { + // Ignore the channel since the CPU interrupt line is shared. + (void) eic_channel; + + NVIC_DisableIRQ(EIC_0_IRQn + eic_channel); + NVIC_ClearPendingIRQ(EIC_0_IRQn + eic_channel); + NVIC_EnableIRQ(EIC_0_IRQn + eic_channel); +} + +bool eic_get_enable(void) { + return EIC->CTRLA.bit.ENABLE; +} + +void eic_set_enable(bool value) { + EIC->CTRLA.bit.ENABLE = value; + while (EIC->SYNCBUSY.bit.ENABLE != 0) {} + // This won't actually block long enough in Rev A of SAMD51 and will miss edges in the first + // three cycles of the peripheral clock. See the errata for details. It shouldn't impact us. +} + +void eic_reset(void) { + EIC->CTRLA.bit.SWRST = true; + while (EIC->SYNCBUSY.bit.SWRST != 0) {} + // This won't actually block long enough in Rev A of SAMD51 and will miss edges in the first + // three cycles of the peripheral clock. See the errata for details. It shouldn't impact us. + for (int i = 0; i < EIC_EXTINT_NUM; i++) { + set_eic_channel_data(i, NULL); + NVIC_DisableIRQ(EIC_0_IRQn + i); + NVIC_ClearPendingIRQ(EIC_0_IRQn + i); + } +} + +bool eic_channel_free(uint8_t eic_channel) { + uint32_t mask = 1 << eic_channel; + return get_eic_channel_data(eic_channel) == NULL && + (EIC->INTENSET.bit.EXTINT & mask) == 0 && + (EIC->EVCTRL.bit.EXTINTEO & mask) == 0; +} + +void EIC_0_Handler(void) { + external_interrupt_handler(0); +} +void EIC_1_Handler(void) { + external_interrupt_handler(1); +} +void EIC_2_Handler(void) { + external_interrupt_handler(2); +} +void EIC_3_Handler(void) { + external_interrupt_handler(3); +} +void EIC_4_Handler(void) { + external_interrupt_handler(4); +} +void EIC_5_Handler(void) { + external_interrupt_handler(5); +} +void EIC_6_Handler(void) { + external_interrupt_handler(6); +} +void EIC_7_Handler(void) { + external_interrupt_handler(7); +} +void EIC_8_Handler(void) { + external_interrupt_handler(8); +} +void EIC_9_Handler(void) { + external_interrupt_handler(9); +} +void EIC_10_Handler(void) { + external_interrupt_handler(10); +} +void EIC_11_Handler(void) { + external_interrupt_handler(11); +} +void EIC_12_Handler(void) { + external_interrupt_handler(12); +} +void EIC_13_Handler(void) { + external_interrupt_handler(13); +} +void EIC_14_Handler(void) { + external_interrupt_handler(14); +} +void EIC_15_Handler(void) { + external_interrupt_handler(15); +} diff --git a/ports/atmel-samd/peripherals/samd51/sercom.c b/ports/atmel-samd/peripherals/samd51/sercom.c index fc44214220a81..6d0a02fbd7e1e 100644 --- a/ports/atmel-samd/peripherals/samd51/sercom.c +++ b/ports/atmel-samd/peripherals/samd51/sercom.c @@ -28,8 +28,6 @@ #include "hpl/gclk/hpl_gclk_base.h" #include "hri/hri_mclk_d51.h" -// FIXME(tannewt): Should this be called sercom.c? - // The clock initializer values are rather random, so we need to put them in // tables for lookup. We can't compute them. diff --git a/ports/atmel-samd/peripherals/samd51/timers.c b/ports/atmel-samd/peripherals/samd51/timers.c index 305acce3817f5..f25dbc0e410f7 100644 --- a/ports/atmel-samd/peripherals/samd51/timers.c +++ b/ports/atmel-samd/peripherals/samd51/timers.c @@ -29,8 +29,6 @@ #include "peripherals/timers.h" -//#include "common-hal/pulseio/PulseOut.h" - #include "hri/hri_gclk_d51.h" const uint8_t tcc_cc_num[5] = {6, 4, 3, 2, 2}; diff --git a/ports/atmel-samd/supervisor/port.c b/ports/atmel-samd/supervisor/port.c index 55e0a7ecfce26..e815d0f1ec7b6 100644 --- a/ports/atmel-samd/supervisor/port.c +++ b/ports/atmel-samd/supervisor/port.c @@ -58,6 +58,7 @@ #include "peripherals/cache.h" #include "peripherals/clocks.h" #include "peripherals/events.h" +#include "peripherals/external_interrupts.h" #include "peripherals/dma.h" #include "shared-bindings/rtc/__init__.h" #include "tick.h" @@ -183,6 +184,7 @@ safe_mode_t port_init(void) { _pm_init(); #endif clock_init(); + init_dynamic_clocks(); board_init(); @@ -248,7 +250,7 @@ void reset_port(void) { #ifdef SAMD21 touchin_reset(); #endif - pulsein_reset(); + eic_reset(); pulseout_reset(); pwmout_reset(); diff --git a/shared-bindings/index.rst b/shared-bindings/index.rst index 76b5e340b864f..d985878809237 100644 --- a/shared-bindings/index.rst +++ b/shared-bindings/index.rst @@ -17,6 +17,9 @@ SAMD51, SAMD51 Express, and ESP8266. NOTE 2: **SAMD** and/or **SAMD Express** without additional numbers, means both SAMD21 & SAMD51 versions are supported. +NOTE 3: The `pIRkey SAMD21 board `_ is specialized and may not +have modules as listed below. + ================= ============================== Module Supported Ports ================= ============================== @@ -38,6 +41,7 @@ Module Supported Ports `os` **All Supported** `pulseio` **SAMD/SAMD Express** `random` **All Supported** +`rotaryio` **SAMD51, SAMD Express** `storage` **All Supported** `struct` **All Supported** `supervisor` **SAMD/SAMD Express** diff --git a/shared-bindings/rotaryio/__init__.c b/shared-bindings/rotaryio/__init__.c index db1ff3d4c6f9e..a0166771abe20 100644 --- a/shared-bindings/rotaryio/__init__.c +++ b/shared-bindings/rotaryio/__init__.c @@ -33,8 +33,8 @@ #include "shared-bindings/rotaryio/__init__.h" #include "shared-bindings/rotaryio/IncrementalEncoder.h" -//| :mod:`rotaryio` --- Support for pulse based protocols -//| ===================================================== +//| :mod:`rotaryio` --- Support for reading rotation sensors +//| ======================================================== //| //| .. module:: rotaryio //| :synopsis: Support for reading rotation sensors From 9920f0a5de11b894b6255888475e6272e5e83f94 Mon Sep 17 00:00:00 2001 From: Scott Shawcroft Date: Thu, 31 May 2018 16:47:18 -0700 Subject: [PATCH 3/5] atmel-samd: Make ticks more atomic. Always use current_tick when sub millisecond precision is required. Otherwise getting the ms/us to correspond is tricky. --- .../common-hal/microcontroller/__init__.c | 24 ++++++++++++++-- ports/atmel-samd/tick.c | 28 ++++++++++++++++--- 2 files changed, 45 insertions(+), 7 deletions(-) diff --git a/ports/atmel-samd/common-hal/microcontroller/__init__.c b/ports/atmel-samd/common-hal/microcontroller/__init__.c index fa057facacdde..c57b6939ce5d2 100644 --- a/ports/atmel-samd/common-hal/microcontroller/__init__.c +++ b/ports/atmel-samd/common-hal/microcontroller/__init__.c @@ -42,13 +42,31 @@ void common_hal_mcu_delay_us(uint32_t delay) { // Interrupt flags that will be saved and restored during disable/Enable // interrupt functions below. -volatile hal_atomic_t flags; + +// ASF4's interrupt disable doesn't handle duplicate calls +volatile uint32_t interrupt_flags; +volatile uint32_t nesting_count = 0; void common_hal_mcu_disable_interrupts(void) { - atomic_enter_critical(&flags); + if (nesting_count == 0) { + interrupt_flags = __get_PRIMASK(); + __disable_irq(); + __DMB(); + } + nesting_count++; } void common_hal_mcu_enable_interrupts(void) { - atomic_leave_critical(&flags); + if (nesting_count == 0) { + // This is very very bad because it means there was mismatched disable/enables so we + // "HardFault". + HardFault_Handler(); + } + nesting_count--; + if (nesting_count > 0) { + return; + } + __DMB(); + __set_PRIMASK(interrupt_flags); } extern uint32_t _ezero; diff --git a/ports/atmel-samd/tick.c b/ports/atmel-samd/tick.c index 27b5f05b44296..6cd7c7833fa64 100644 --- a/ports/atmel-samd/tick.c +++ b/ports/atmel-samd/tick.c @@ -30,6 +30,7 @@ #include "supervisor/shared/autoreload.h" #include "shared-module/gamepad/__init__.h" +#include "shared-bindings/microcontroller/__init__.h" #include "shared-bindings/microcontroller/Processor.h" // Global millisecond tick count @@ -38,8 +39,13 @@ volatile uint64_t ticks_ms = 0; void SysTick_Handler(void) { // SysTick interrupt handler called when the SysTick timer reaches zero // (every millisecond). + common_hal_mcu_disable_interrupts(); ticks_ms += 1; + // Read the control register to reset the COUNTFLAG. + (void) SysTick->CTRL; + common_hal_mcu_enable_interrupts(); + #ifdef CIRCUITPY_AUTORELOAD_DELAY_MS autoreload_tick(); #endif @@ -61,7 +67,7 @@ void tick_delay(uint32_t us) { uint32_t us_until_next_tick = SysTick->VAL / ticks_per_us; uint32_t start_tick; while (us >= us_until_next_tick) { - start_tick=SysTick->VAL; // wait for SysTick->VAL to RESET + start_tick = SysTick->VAL; // wait for SysTick->VAL to RESET while (SysTick->VAL < start_tick) {} us -= us_until_next_tick; us_until_next_tick = 1000; @@ -72,11 +78,25 @@ void tick_delay(uint32_t 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; + + // We disable interrupts to prevent ticks_ms from changing while we grab it. + common_hal_mcu_disable_interrupts(); + uint32_t tick_status = SysTick->CTRL; + uint32_t current_us = SysTick->VAL; + uint32_t tick_status2 = SysTick->CTRL; + uint64_t current_ms = ticks_ms; + // The second clause ensures our value actually rolled over. Its possible it hit zero between + // the VAL read and CTRL read. + if ((tick_status & SysTick_CTRL_COUNTFLAG_Msk) != 0 || + ((tick_status2 & SysTick_CTRL_COUNTFLAG_Msk) != 0 && current_us > ticks_per_us)) { + current_ms++; + } + common_hal_mcu_enable_interrupts(); + *ms = current_ms; + *us_until_ms = current_us / 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) {} + while (ticks_ms <= ms && SysTick->VAL / ticks_per_us >= us_until_ms) {} } From f386144428b8ad4fab29e0df6657856141e7f96b Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Fri, 1 Jun 2018 11:00:40 -0400 Subject: [PATCH 4/5] redo state algorithm --- .../common-hal/rotaryio/IncrementalEncoder.c | 83 ++++++++++++------- .../common-hal/rotaryio/IncrementalEncoder.h | 3 +- 2 files changed, 55 insertions(+), 31 deletions(-) diff --git a/ports/atmel-samd/common-hal/rotaryio/IncrementalEncoder.c b/ports/atmel-samd/common-hal/rotaryio/IncrementalEncoder.c index d86f4763db623..9f378f169e7ea 100644 --- a/ports/atmel-samd/common-hal/rotaryio/IncrementalEncoder.c +++ b/ports/atmel-samd/common-hal/rotaryio/IncrementalEncoder.c @@ -63,17 +63,14 @@ void common_hal_rotaryio_incrementalencoder_construct(rotaryio_incrementalencode set_eic_channel_data(self->eic_channel_a, (void*) self); set_eic_channel_data(self->eic_channel_b, (void*) self); - bool pin_a_level = gpio_get_pin_level(self->pin_a); - bool pin_b_level = gpio_get_pin_level(self->pin_b); - if (!pin_a_level && !pin_b_level) { - self->last_state = 1; - } else if (!pin_a_level && pin_b_level) { - self->last_state = 2; - } else if (pin_a_level && pin_b_level) { - self->last_state = 3; - } else { - self->last_state = 4; - } + self->position = 0; + self->quarter_count = 0; + + // Top two bits of self->last_state don't matter, because they'll be gone as soon as + // interrupt handler is called. + self->last_state = + ((uint8_t) gpio_get_pin_level(self->pin_a) << 1) | + (uint8_t) gpio_get_pin_level(self->pin_b); turn_on_eic_channel(self->eic_channel_a, EIC_CONFIG_SENSE0_BOTH_Val, EIC_HANDLER_INCREMENTAL_ENCODER); turn_on_eic_channel(self->eic_channel_b, EIC_CONFIG_SENSE0_BOTH_Val, EIC_HANDLER_INCREMENTAL_ENCODER); @@ -101,29 +98,55 @@ mp_int_t common_hal_rotaryio_incrementalencoder_get_position(rotaryio_incrementa void incrementalencoder_interrupt_handler(uint8_t channel) { rotaryio_incrementalencoder_obj_t* self = get_eic_channel_data(channel); + + // This table also works for detent both at 11 and 00 + // For 11 at detent: + // Turning cw: 11->01->00->10->11 + // Turning ccw: 11->10->00->01->11 + // For 00 at detent: + // Turning cw: 00->10->11->10->00 + // Turning ccw: 00->01->11->10->00 + + // index table by state + #define BAD 7 + static const int8_t transitions[16] = { + 0, // 00 -> 00 no movement + -1, // 00 -> 01 3/4 ccw (11 detent) or 1/4 ccw (00 at detent) + +1, // 00 -> 10 3/4 cw or 1/4 cw + BAD, // 00 -> 11 non-Gray-code transition + +1, // 01 -> 00 2/4 or 4/4 cw + 0, // 01 -> 01 no movement + BAD, // 01 -> 10 non-Gray-code transition + -1, // 01 -> 11 4/4 or 2/4 ccw + -1, // 10 -> 00 2/4 or 4/4 ccw + BAD, // 10 -> 01 non-Gray-code transition + 0, // 10 -> 10 no movement + +1, // 10 -> 11 4/4 or 2/4 cw + BAD, // 11 -> 00 non-Gray-code transition + +1, // 11 -> 01 1/4 or 3/4 cw + -1, // 11 -> 10 1/4 or 3/4 ccw + 0, // 11 -> 11 no movement + }; + + // Shift the old AB bits to the "old" position, and set the new AB bits. // TODO(tannewt): If we need more speed then read the pin directly. gpio_get_pin_level has // smarts to compensate for pin direction we don't need. - bool pin_a = gpio_get_pin_level(self->pin_a); - bool pin_b = gpio_get_pin_level(self->pin_b); - - uint8_t this_state; - if (!pin_a && !pin_b) { - this_state = 1; - } else if (!pin_a && pin_b) { - this_state = 2; - } else if (pin_a && pin_b) { - this_state = 3; - } else { - this_state = 4; + self->last_state = (self->last_state & 0x3) << 2 | + ((uint8_t) gpio_get_pin_level(self->pin_a) << 1) | + (uint8_t) gpio_get_pin_level(self->pin_b); + + int8_t quarter_incr = transitions[self->last_state]; + if (quarter_incr == BAD) { + // Missed a transition. We don't know which way we're going, so do nothing. + return; } - // Handle wrap around explicitly. - if (this_state == 4 && self->last_state == 1) { - self->position -= 1; - } else if (this_state == 1 && self->last_state == 4) { + self->quarter_count += quarter_incr; + if (self->quarter_count >= 4) { self->position += 1; - } else { - self->position += (this_state - self->last_state); + self->quarter_count = 0; + } else if (self->quarter_count <= -4) { + self->position -= 1; + self->quarter_count = 0; } - self->last_state = this_state; } diff --git a/ports/atmel-samd/common-hal/rotaryio/IncrementalEncoder.h b/ports/atmel-samd/common-hal/rotaryio/IncrementalEncoder.h index ffdf7da174651..e07cc84d5daef 100644 --- a/ports/atmel-samd/common-hal/rotaryio/IncrementalEncoder.h +++ b/ports/atmel-samd/common-hal/rotaryio/IncrementalEncoder.h @@ -37,7 +37,8 @@ typedef struct { uint8_t pin_b; uint8_t eic_channel_a:4; uint8_t eic_channel_b:4; - uint8_t last_state; + uint8_t last_state:4; // + int8_t quarter_count:4; // count intermediate transitions between detents mp_int_t position; } rotaryio_incrementalencoder_obj_t; From 717199018bcb43dd50af9011e2259f3caf3290f8 Mon Sep 17 00:00:00 2001 From: Scott Shawcroft Date: Fri, 1 Jun 2018 13:11:40 -0700 Subject: [PATCH 5/5] Adapt for feedback and hack around pIRkey size constraint. --- ports/atmel-samd/common-hal/busio/I2C.c | 4 ++++ .../common-hal/rotaryio/IncrementalEncoder.c | 5 +++++ ports/atmel-samd/peripherals/samd21/events.c | 12 +++++------ shared-bindings/rotaryio/IncrementalEncoder.c | 21 +++++++++++++------ shared-bindings/rotaryio/IncrementalEncoder.h | 2 ++ 5 files changed, 32 insertions(+), 12 deletions(-) diff --git a/ports/atmel-samd/common-hal/busio/I2C.c b/ports/atmel-samd/common-hal/busio/I2C.c index 66929beff55b3..c14b2d68f0887 100644 --- a/ports/atmel-samd/common-hal/busio/I2C.c +++ b/ports/atmel-samd/common-hal/busio/I2C.c @@ -41,6 +41,10 @@ void common_hal_busio_i2c_construct(busio_i2c_obj_t *self, const mcu_pin_obj_t* scl, const mcu_pin_obj_t* sda, uint32_t frequency, uint32_t timeout) { + #ifdef PIRKEY_M0 + mp_raise_NotImplementedError("Not enough pins available"); + return; + #endif Sercom* sercom = NULL; uint8_t sercom_index; uint32_t sda_pinmux = 0; diff --git a/ports/atmel-samd/common-hal/rotaryio/IncrementalEncoder.c b/ports/atmel-samd/common-hal/rotaryio/IncrementalEncoder.c index 9f378f169e7ea..ddc545295078f 100644 --- a/ports/atmel-samd/common-hal/rotaryio/IncrementalEncoder.c +++ b/ports/atmel-samd/common-hal/rotaryio/IncrementalEncoder.c @@ -96,6 +96,11 @@ mp_int_t common_hal_rotaryio_incrementalencoder_get_position(rotaryio_incrementa return self->position; } +void common_hal_rotaryio_incrementalencoder_set_position(rotaryio_incrementalencoder_obj_t* self, + mp_int_t new_position) { + self->position = new_position; +} + void incrementalencoder_interrupt_handler(uint8_t channel) { rotaryio_incrementalencoder_obj_t* self = get_eic_channel_data(channel); diff --git a/ports/atmel-samd/peripherals/samd21/events.c b/ports/atmel-samd/peripherals/samd21/events.c index 70dfa249dd55c..08b82c91fc3fb 100644 --- a/ports/atmel-samd/peripherals/samd21/events.c +++ b/ports/atmel-samd/peripherals/samd21/events.c @@ -74,8 +74,8 @@ void init_event_channel_interrupt(uint8_t channel, uint8_t gclk, uint8_t generat EVSYS_CHANNEL_EVGEN(generator) | EVSYS_CHANNEL_PATH_RESYNCHRONIZED | EVSYS_CHANNEL_EDGSEL_RISING_EDGE; - if (channel > 7) { - uint8_t value = 1 << (channel - 7); + if (channel >= 8) { + uint8_t value = 1 << (channel - 8); EVSYS->INTFLAG.reg = EVSYS_INTFLAG_EVDp8(value) | EVSYS_INTFLAG_OVRp8(value); EVSYS->INTENSET.reg = EVSYS_INTENSET_EVDp8(value) | EVSYS_INTENSET_OVRp8(value); } else { @@ -87,8 +87,8 @@ void init_event_channel_interrupt(uint8_t channel, uint8_t gclk, uint8_t generat bool event_interrupt_active(uint8_t channel) { bool active = false; - if (channel > 7) { - uint8_t value = 1 << (channel - 7); + if (channel >= 8) { + uint8_t value = 1 << (channel - 8); active = (EVSYS->INTFLAG.reg & EVSYS_INTFLAG_EVDp8(value)) != 0; // Only clear if we know its active, otherwise there is the possibility it becomes active // after we check but before we clear. @@ -107,8 +107,8 @@ bool event_interrupt_active(uint8_t channel) { bool event_interrupt_overflow(uint8_t channel) { bool overflow = false; - if (channel > 7) { - uint8_t value = 1 << (channel - 7); + if (channel >= 8) { + uint8_t value = 1 << (channel - 8); overflow = (EVSYS->INTFLAG.reg & EVSYS_INTFLAG_OVRp8(value)) != 0; } else { uint8_t value = 1 << channel; diff --git a/shared-bindings/rotaryio/IncrementalEncoder.c b/shared-bindings/rotaryio/IncrementalEncoder.c index 635826c60e2a6..b2609f4a84daa 100644 --- a/shared-bindings/rotaryio/IncrementalEncoder.c +++ b/shared-bindings/rotaryio/IncrementalEncoder.c @@ -36,8 +36,8 @@ //| .. currentmodule:: rotaryio //| -//| :class:`IncrementalEncoder` -- Read the position of the incremental encoder -//| ============================================================================ +//| :class:`IncrementalEncoder` -- Track the relative position of an incremental encoder +//| ==================================================================================== //| //| IncrementalEncoder determines the relative rotational position based on two series of pulses. //| @@ -47,8 +47,8 @@ //| state of an incremental rotary encoder (also known as a quadrature encoder.) Position is //| relative to the position when the object is contructed. //| -//| :param ~microcontroller.Pin pin: First pin to read pulses from. -//| :param ~microcontroller.Pin pin: Second pin to read pulses from. +//| :param ~microcontroller.Pin pin_a: First pin to read pulses from. +//| :param ~microcontroller.Pin pin_b: Second pin to read pulses from. //| //| For example:: //| @@ -94,7 +94,7 @@ STATIC mp_obj_t rotaryio_incrementalencoder_make_new(const mp_obj_type_t *type, //| .. method:: deinit() //| -//| Deinitialises the IncrementalEncoder and releases any hardware resources for reuse. +//| Deinitializes the IncrementalEncoder and releases any hardware resources for reuse. //| STATIC mp_obj_t rotaryio_incrementalencoder_deinit(mp_obj_t self_in) { rotaryio_incrementalencoder_obj_t *self = MP_OBJ_TO_PTR(self_in); @@ -135,10 +135,19 @@ STATIC mp_obj_t rotaryio_incrementalencoder_obj_get_position(mp_obj_t self_in) { } MP_DEFINE_CONST_FUN_OBJ_1(rotaryio_incrementalencoder_get_position_obj, rotaryio_incrementalencoder_obj_get_position); +STATIC mp_obj_t rotaryio_incrementalencoder_obj_set_position(mp_obj_t self_in, mp_obj_t new_position) { + rotaryio_incrementalencoder_obj_t *self = MP_OBJ_TO_PTR(self_in); + raise_error_if_deinited(common_hal_rotaryio_incrementalencoder_deinited(self)); + + common_hal_rotaryio_incrementalencoder_set_position(self, mp_obj_get_int(new_position)); + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_2(rotaryio_incrementalencoder_set_position_obj, rotaryio_incrementalencoder_obj_set_position); + const mp_obj_property_t rotaryio_incrementalencoder_position_obj = { .base.type = &mp_type_property, .proxy = {(mp_obj_t)&rotaryio_incrementalencoder_get_position_obj, - (mp_obj_t)&mp_const_none_obj, + (mp_obj_t)&rotaryio_incrementalencoder_set_position_obj, (mp_obj_t)&mp_const_none_obj}, }; diff --git a/shared-bindings/rotaryio/IncrementalEncoder.h b/shared-bindings/rotaryio/IncrementalEncoder.h index 29e89e2089433..f70632aefbe62 100644 --- a/shared-bindings/rotaryio/IncrementalEncoder.h +++ b/shared-bindings/rotaryio/IncrementalEncoder.h @@ -37,5 +37,7 @@ extern void common_hal_rotaryio_incrementalencoder_construct(rotaryio_incrementa extern void common_hal_rotaryio_incrementalencoder_deinit(rotaryio_incrementalencoder_obj_t* self); extern bool common_hal_rotaryio_incrementalencoder_deinited(rotaryio_incrementalencoder_obj_t* self); extern mp_int_t common_hal_rotaryio_incrementalencoder_get_position(rotaryio_incrementalencoder_obj_t* self); +extern void common_hal_rotaryio_incrementalencoder_set_position(rotaryio_incrementalencoder_obj_t* self, + mp_int_t new_position); #endif // MICROPY_INCLUDED_SHARED_BINDINGS_ROTARYIO_INCREMENTALENCODER_H