Merge pull request #887 from tannewt/rotaryio

Add rotary encoder support.
This commit is contained in:
Dan Halbert 2018-06-01 18:50:00 -04:00 committed by GitHub
commit de61bd0d05
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
101 changed files with 2012 additions and 1093 deletions

View File

@ -101,6 +101,7 @@ exclude_patterns = ["**/build*",
"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",

View File

@ -242,19 +242,26 @@ 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/external_interrupts.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)/external_interrupts.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 +308,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 +400,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

View File

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

View File

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

View File

@ -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);
MP_DEFINE_CONST_FUN_OBJ_0(board_uart_obj, board_uart);

View File

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

View File

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

View File

@ -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[] = {

View File

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

View File

@ -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[] = {

View File

@ -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[] = {

View File

@ -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[] = {

View File

@ -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[] = {

View File

@ -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[] = {

View File

@ -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[] = {

View File

@ -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[] = {

View File

@ -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[] = {

View File

@ -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[] = {

View File

@ -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[] = {

View File

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

View File

@ -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[] = {

View File

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

View File

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

View File

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

View File

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

View File

@ -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[] = {

View File

@ -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[] = {

View File

@ -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[] = {

View File

@ -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[] = {

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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"
@ -42,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;

View File

@ -36,9 +36,8 @@
#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/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,

View File

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

View File

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

View File

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

View File

@ -63,7 +63,7 @@
#include "common-hal/microcontroller/Processor.h"
#include "peripherals.h"
#include "peripherals/adc.h"
#include "peripheral_clk_config.h"

View File

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

View File

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

View File

@ -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,90 +34,28 @@
#include "mpconfigport.h"
#include "py/gc.h"
#include "py/runtime.h"
#include "samd21_pins.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

View File

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

View File

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

View File

@ -0,0 +1,157 @@
/*
* 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 "atmel_start_pins.h"
#include "peripherals/external_interrupts.h"
#include "py/runtime.h"
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) {
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);
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);
}
bool common_hal_rotaryio_incrementalencoder_deinited(rotaryio_incrementalencoder_obj_t* self) {
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;
}
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 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);
// 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 <oldA><oldB><newA><newB>
#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.
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;
}
self->quarter_count += quarter_incr;
if (self->quarter_count >= 4) {
self->position += 1;
self->quarter_count = 0;
} else if (self->quarter_count <= -4) {
self->position -= 1;
self->quarter_count = 0;
}
}

View File

@ -0,0 +1,48 @@
/*
* 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;
uint8_t eic_channel_a:4;
uint8_t eic_channel_b:4;
uint8_t last_state:4; // <old A><old B><new A><new B>
int8_t quarter_count:4; // count intermediate transitions between detents
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

View File

@ -0,0 +1 @@
// No rotaryio module functions.

View File

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

View File

@ -36,12 +36,9 @@
#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"
//#include "shared_dma.h"
#include "hal_gpio.h"
#include "hal_spi_m_sync.h"

View File

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

View File

@ -29,8 +29,8 @@
#include <string.h>
#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"

View File

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

View File

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

View File

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

View File

@ -56,41 +56,20 @@ uint8_t find_free_gclk(uint16_t divisor) {
return 0xff;
}
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
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) {
for (uint8_t i = last_static_clock + 1; i < GCLK_GEN_NUM; i++) {
disable_gclk(i);
}
}

View File

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

View File

@ -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 <string.h>
@ -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;
}

View File

@ -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 <stdbool.h>
#include <stdint.h>
@ -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

View File

@ -0,0 +1,59 @@
/*
* 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 <stdint.h>
#include "peripherals/events.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;
}

View File

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

View File

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

View File

@ -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 <stdbool.h>
#include <stdint.h>
#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

View File

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

View File

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

View File

@ -0,0 +1,47 @@
/*
* This file is part of the Micro Python project, http://micropython.org/
*
* The MIT License (MIT)
*
* Copyright (c) 2017 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);
}

View File

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

View File

@ -24,7 +24,7 @@
* THE SOFTWARE.
*/
#include "clocks.h"
#include "peripherals/clocks.h"
#include "hpl_gclk_config.h"
@ -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) {

View File

@ -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 <string.h>
#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;
}

View File

@ -24,137 +24,58 @@
* 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 |
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 {
@ -162,14 +83,12 @@ 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);
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.
@ -183,31 +102,17 @@ 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);
if (channel >= 8) {
uint8_t value = 1 << (channel - 8);
overflow = (EVSYS->INTFLAG.reg & EVSYS_INTFLAG_OVRp8(value)) != 0;
} else {
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;
}

View File

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

View File

@ -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"
void turn_on_i2s(void) {
_pm_enable_bus_clock(PM_BUS_APBC, I2S);
}
bool board_requests_safe_mode(void) {
return false;
}
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) {}
}

View File

@ -26,8 +26,6 @@
#include "shared-bindings/microcontroller/Pin.h"
#include "samd21_pins.h"
#define SERCOM(sercom_index, p_pad) \
{ \
.index = sercom_index, \

View File

@ -24,13 +24,14 @@
* 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.
#ifndef MICROPY_INCLUDED_ATMEL_SAMD_PERIPHERALS_SAMD21_PINS_H
#define MICROPY_INCLUDED_ATMEL_SAMD_PERIPHERALS_SAMD21_PINS_H
#include "include/sam.h"
#include "common-hal/microcontroller/Pin.h"
void reset_pin(uint8_t pin);
#define MUX_C 2
@ -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

View File

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

View File

@ -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 <stdbool.h>
#include <stdint.h>
#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) {}
}

View File

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

View File

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

View File

@ -24,7 +24,7 @@
* THE SOFTWARE.
*/
#include "clocks.h"
#include "peripherals/clocks.h"
#include "hpl_gclk_config.h"

View File

@ -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 <string.h>
#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;
}

View File

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

View File

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

View File

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

View File

@ -26,8 +26,6 @@
#include "shared-bindings/microcontroller/Pin.h"
#include "samd51_pins.h"
#define SERCOM(sercom_index, p_pad) \
{ \
.index = sercom_index, \

View File

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

View File

@ -131,47 +131,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;
}

View File

@ -27,36 +27,10 @@
#include <stdbool.h>
#include <stdint.h>
#include "timers.h"
#include "peripherals/timers.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 +59,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 +68,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 +123,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

View File

@ -24,7 +24,7 @@
* THE SOFTWARE.
*/
#include "peripherals.h"
#include "peripherals/sercom.h"
#include "hpl_sercom_config.h"

View File

@ -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 <stdint.h>
#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

View File

@ -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 <stdbool.h>
#include <stdint.h>
#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

View File

@ -55,11 +55,12 @@
#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/external_interrupts.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
@ -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();

View File

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

View File

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

View File

@ -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 <https://www.adafruit.com/product/3364>`_ 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**

View File

@ -0,0 +1,168 @@
/*
* 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 <stdint.h>
#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` -- Track the relative position of an 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_a: First pin to read pulses from.
//| :param ~microcontroller.Pin pin_b: 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()
//|
//| 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);
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);
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)&rotaryio_incrementalencoder_set_position_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,
};

View File

@ -0,0 +1,43 @@
/*
* 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);
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

View File

@ -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 <stdint.h>
#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 reading rotation sensors
//| ========================================================
//|
//| .. 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 <https://en.wikipedia.org/wiki/Rotary_encoder>`_ 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,
};

View File

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

Some files were not shown because too many files have changed in this diff Show More