Implement UART for 3.0 + related fixes.

1. UART: ported to ASF4. Allow rx-only and tx-only. Add .baudrate r/w property.

2. Make NeoPixel timing deterministic by turning off caches during NeoPixel writes.
3. Incorporate asf4 updates:
  a. async USART driver
  b. bringing Atmel START configuration closer to what we use
  c. Clock initialization order now specified by CIRCUITPY_GCLK_INIT_1ST and _LAST.
4. supervisor/port.c: Move commented-out clock-test pin setting to correct location.
crypto-aes
Dan Halbert 5 years ago
parent fd9d3de208
commit 9b4477e1dc

@ -36,6 +36,7 @@ INC += -I. \
-Iasf4/$(CHIP_FAMILY)/hal/utils/include \
-Iasf4/$(CHIP_FAMILY)/hri \
-Iasf4/$(CHIP_FAMILY)/hpl/core \
-Iasf4/$(CHIP_FAMILY)/hpl/gclk \
-Iasf4/$(CHIP_FAMILY)/hpl/pm \
-Iasf4/$(CHIP_FAMILY)/hpl/port \
-Iasf4/$(CHIP_FAMILY)/hpl/tc \
@ -96,6 +97,7 @@ ifeq ($(DEBUG), 1)
# Turn on Python modules useful for debugging (e.g. uheap, ustack).
CFLAGS += -ggdb
CFLAGS += -flto
## CFLAGS += -fno-inline
ifeq ($(CHIP_FAMILY), samd21)
CFLAGS += -DENABLE_MICRO_TRACE_BUFFER
endif
@ -178,6 +180,7 @@ SRC_ASF := \
hal/src/hal_sleep.c \
hal/src/hal_spi_m_sync.c \
hal/src/hal_timer.c \
hal/src/hal_usart_async.c \
hal/src/hal_usb_device.c \
hpl/adc/hpl_adc.c \
hpl/core/hpl_init.c \
@ -194,6 +197,7 @@ SRC_ASF := \
usb/device/usbdc.c \
usb/usb_protocol.c \
hal/utils/src/utils_list.c \
hal/utils/src/utils_ringbuffer.c \
ifeq ($(CHIP_FAMILY), samd21)
SRC_ASF += \
@ -263,6 +267,7 @@ SRC_COMMON_HAL = \
busio/__init__.c \
busio/I2C.c \
busio/SPI.c \
busio/UART.c \
digitalio/__init__.c \
digitalio/DigitalInOut.c \
microcontroller/__init__.c \
@ -283,7 +288,6 @@ SRC_COMMON_HAL = \
audiobusio/PDMIn.c \
audioio/__init__.c \
audioio/AudioOut.c \
busio/UART.c \
nvm/__init__.c \
nvm/ByteArray.c \
touchio/__init__.c \

@ -1 +1 @@
Subproject commit 0efc3407dd97ef617a5655674a3516693897a961
Subproject commit aaa0f428111fbea7d56ab548053b11c9f12068f1

@ -1,3 +1,14 @@
// Circuit Python SAMD21 clock tree:
// DFLL48M (with USBCRM on to sync with external USB ref) -> GCLK0
// GCLK0 (48MHz) -> peripherals
// We'd like to use XOSC32K as a ref for DFLL48M on boards with a 32kHz crystal,
// but haven't figured that out yet.
// Used in hpl/core/hpl_init.c to define which clocks should be initialized first.
#define CIRCUITPY_GCLK_INIT_1ST (1 << 0)
/* Auto-generated config file hpl_gclk_config.h */
#ifndef HPL_GCLK_CONFIG_H
#define HPL_GCLK_CONFIG_H

@ -3,14 +3,16 @@
//
// SERCOM0: SPI with hal_spi_m_sync.c driver: spi master synchronous
// SERCOM1: I2C with hal_i2c_m_sync.c driver: i2c master synchronous
// SERCOM2: USART with hal_usart_sync.c driver: usart synchronous
// SERCOM2: USART with hal_usart_async.c driver: usart asynchronous
// SERCOM3: SPI with hal_spi_m_dma.c: spi master DMA
#define PROTOTYPE_SERCOM_SPI_M_SYNC SERCOM0
#define PROTOTYPE_SERCOM_SPI_M_SYNC_CLOCK_FREQUENCY CONF_GCLK_SERCOM0_CORE_FREQUENCY
#define PROTOTYPE_SERCOM_I2CM_SYNC SERCOM1
#define PROTOTYPE_SERCOM_USART_SYNC SERCOM2
#define PROTOTYPE_SERCOM_USART_ASYNC SERCOM2
#define PROTOTYPE_SERCOM_USART_ASYNC_CLOCK_FREQUENCY CONF_GCLK_SERCOM2_CORE_FREQUENCY
/* Auto-generated config file hpl_sercom_config.h */
#ifndef HPL_SERCOM_CONFIG_H
@ -543,6 +545,188 @@
#endif
#endif
#include <peripheral_clk_config.h>
// Enable configuration of module
#ifndef CONF_SERCOM_3_SPI_ENABLE
#define CONF_SERCOM_3_SPI_ENABLE 1
#endif
//<o> SPI DMA TX Channel <0-32>
//<i> This defines DMA channel to be used
//<id> spi_master_dma_tx_channel
#ifndef CONF_SERCOM_3_SPI_M_DMA_TX_CHANNEL
#define CONF_SERCOM_3_SPI_M_DMA_TX_CHANNEL 0
#endif
// <e> SPI RX Channel Enable
// <id> spi_master_rx_channel
#ifndef CONF_SERCOM_3_SPI_RX_CHANNEL
#define CONF_SERCOM_3_SPI_RX_CHANNEL 1
#endif
//<o> DMA Channel <0-32>
//<i> This defines DMA channel to be used
//<id> spi_master_dma_rx_channel
#ifndef CONF_SERCOM_3_SPI_M_DMA_RX_CHANNEL
#define CONF_SERCOM_3_SPI_M_DMA_RX_CHANNEL 1
#endif
// </e>
// Set module in SPI Master mode
#ifndef CONF_SERCOM_3_SPI_MODE
#define CONF_SERCOM_3_SPI_MODE 0x03
#endif
// <h> Basic Configuration
// <q> Receive buffer enable
// <i> Enable receive buffer to receive data from slave (RXEN)
// <id> spi_master_rx_enable
#ifndef CONF_SERCOM_3_SPI_RXEN
#define CONF_SERCOM_3_SPI_RXEN 0x1
#endif
// <o> Character Size
// <i> Bit size for all characters sent over the SPI bus (CHSIZE)
// <0x0=>8 bits
// <0x1=>9 bits
// <id> spi_master_character_size
#ifndef CONF_SERCOM_3_SPI_CHSIZE
#define CONF_SERCOM_3_SPI_CHSIZE 0x0
#endif
// <o> Baud rate <1-12000000>
// <i> The SPI data transfer rate
// <id> spi_master_baud_rate
#ifndef CONF_SERCOM_3_SPI_BAUD
#define CONF_SERCOM_3_SPI_BAUD 50000
#endif
// </h>
// <e> Advanced Configuration
// <id> spi_master_advanced
#ifndef CONF_SERCOM_3_SPI_ADVANCED
#define CONF_SERCOM_3_SPI_ADVANCED 0
#endif
// <o> Dummy byte <0x00-0x1ff>
// <id> spi_master_dummybyte
// <i> Dummy byte used when reading data from the slave without sending any data
#ifndef CONF_SERCOM_3_SPI_DUMMYBYTE
#define CONF_SERCOM_3_SPI_DUMMYBYTE 0x1ff
#endif
// <o> Data Order
// <0=>MSB first
// <1=>LSB first
// <i> I least significant or most significant bit is shifted out first (DORD)
// <id> spi_master_arch_dord
#ifndef CONF_SERCOM_3_SPI_DORD
#define CONF_SERCOM_3_SPI_DORD 0x0
#endif
// <o> Clock Polarity
// <0=>SCK is low when idle
// <1=>SCK is high when idle
// <i> Determines if the leading edge is rising or falling with a corresponding opposite edge at the trailing edge. (CPOL)
// <id> spi_master_arch_cpol
#ifndef CONF_SERCOM_3_SPI_CPOL
#define CONF_SERCOM_3_SPI_CPOL 0x0
#endif
// <o> Clock Phase
// <0x0=>Sample input on leading edge
// <0x1=>Sample input on trailing edge
// <i> Determines if input data is sampled on leading or trailing SCK edge. (CPHA)
// <id> spi_master_arch_cpha
#ifndef CONF_SERCOM_3_SPI_CPHA
#define CONF_SERCOM_3_SPI_CPHA 0x0
#endif
// <o> Immediate Buffer Overflow Notification
// <i> Controls when OVF is asserted (IBON)
// <0x0=>In data stream
// <0x1=>On buffer overflow
// <id> spi_master_arch_ibon
#ifndef CONF_SERCOM_3_SPI_IBON
#define CONF_SERCOM_3_SPI_IBON 0x0
#endif
// <q> Run in stand-by
// <i> Module stays active in stand-by sleep mode. (RUNSTDBY)
// <id> spi_master_arch_runstdby
#ifndef CONF_SERCOM_3_SPI_RUNSTDBY
#define CONF_SERCOM_3_SPI_RUNSTDBY 0x0
#endif
// <o> Debug Stop Mode
// <i> Behavior of the baud-rate generator when CPU is halted by external debugger. (DBGSTOP)
// <0=>Keep running
// <1=>Halt
// <id> spi_master_arch_dbgstop
#ifndef CONF_SERCOM_3_SPI_DBGSTOP
#define CONF_SERCOM_3_SPI_DBGSTOP 0
#endif
// </e>
// Address mode disabled in master mode
#ifndef CONF_SERCOM_3_SPI_AMODE_EN
#define CONF_SERCOM_3_SPI_AMODE_EN 0
#endif
#ifndef CONF_SERCOM_3_SPI_AMODE
#define CONF_SERCOM_3_SPI_AMODE 0
#endif
#ifndef CONF_SERCOM_3_SPI_ADDR
#define CONF_SERCOM_3_SPI_ADDR 0
#endif
#ifndef CONF_SERCOM_3_SPI_ADDRMASK
#define CONF_SERCOM_3_SPI_ADDRMASK 0
#endif
#ifndef CONF_SERCOM_3_SPI_SSDE
#define CONF_SERCOM_3_SPI_SSDE 0
#endif
#ifndef CONF_SERCOM_3_SPI_MSSEN
#define CONF_SERCOM_3_SPI_MSSEN 0x0
#endif
#ifndef CONF_SERCOM_3_SPI_PLOADEN
#define CONF_SERCOM_3_SPI_PLOADEN 0
#endif
// <o> Receive Data Pinout
// <0x0=>PAD[0]
// <0x1=>PAD[1]
// <0x2=>PAD[2]
// <0x3=>PAD[3]
// <id> spi_master_rxpo
#ifndef CONF_SERCOM_3_SPI_RXPO
#define CONF_SERCOM_3_SPI_RXPO 0
#endif
// <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
// <id> spi_master_txpo
#ifndef CONF_SERCOM_3_SPI_TXPO
#define CONF_SERCOM_3_SPI_TXPO 1
#endif
// Calculate baud register value from requested baudrate value
#ifndef CONF_SERCOM_3_SPI_BAUD_RATE
#define CONF_SERCOM_3_SPI_BAUD_RATE ((float)CONF_GCLK_SERCOM3_CORE_FREQUENCY / (float)(2 * CONF_SERCOM_3_SPI_BAUD)) - 1
#endif
// <<< end of configuration section >>>
#endif // HPL_SERCOM_CONFIG_H

@ -4,6 +4,38 @@
// <<< Use Configuration Wizard in Context Menu >>>
// <y> ADC Clock Source
// <id> adc_gclk_selection
// <GCLK_CLKCTRL_GEN_GCLK0_Val"> Generic clock generator 0
// <GCLK_CLKCTRL_GEN_GCLK1_Val"> Generic clock generator 1
// <GCLK_CLKCTRL_GEN_GCLK2_Val"> Generic clock generator 2
// <GCLK_CLKCTRL_GEN_GCLK3_Val"> Generic clock generator 3
// <GCLK_CLKCTRL_GEN_GCLK4_Val"> Generic clock generator 4
// <GCLK_CLKCTRL_GEN_GCLK5_Val"> Generic clock generator 5
// <GCLK_CLKCTRL_GEN_GCLK6_Val"> Generic clock generator 6
// <GCLK_CLKCTRL_GEN_GCLK7_Val"> Generic clock generator 7
// <i> Select the clock source for ADC.
#ifndef CONF_GCLK_ADC_SRC
#define CONF_GCLK_ADC_SRC GCLK_CLKCTRL_GEN_GCLK0_Val
#endif
/**
* \def CONF_GCLK_ADC_FREQUENCY
* \brief ADC's Clock frequency
*/
#ifndef CONF_GCLK_ADC_FREQUENCY
#define CONF_GCLK_ADC_FREQUENCY 48000000
#endif
/**
* \def CONF_CPU_FREQUENCY
* \brief CPU's Clock frequency
@ -268,134 +300,6 @@
#define CONF_GCLK_SERCOM3_SLOW_FREQUENCY 400000
#endif
// <y> Core Clock Source
// <id> core_gclk_selection
// <GCLK_CLKCTRL_GEN_GCLK0_Val"> Generic clock generator 0
// <GCLK_CLKCTRL_GEN_GCLK1_Val"> Generic clock generator 1
// <GCLK_CLKCTRL_GEN_GCLK2_Val"> Generic clock generator 2
// <GCLK_CLKCTRL_GEN_GCLK3_Val"> Generic clock generator 3
// <GCLK_CLKCTRL_GEN_GCLK4_Val"> Generic clock generator 4
// <GCLK_CLKCTRL_GEN_GCLK5_Val"> Generic clock generator 5
// <GCLK_CLKCTRL_GEN_GCLK6_Val"> Generic clock generator 6
// <GCLK_CLKCTRL_GEN_GCLK7_Val"> Generic clock generator 7
// <i> Select the clock source for CORE.
#ifndef CONF_GCLK_SERCOM4_CORE_SRC
#define CONF_GCLK_SERCOM4_CORE_SRC GCLK_CLKCTRL_GEN_GCLK0_Val
#endif
// <y> Slow Clock Source
// <id> slow_gclk_selection
// <GCLK_CLKCTRL_GEN_GCLK0_Val"> Generic clock generator 0
// <GCLK_CLKCTRL_GEN_GCLK1_Val"> Generic clock generator 1
// <GCLK_CLKCTRL_GEN_GCLK2_Val"> Generic clock generator 2
// <GCLK_CLKCTRL_GEN_GCLK3_Val"> Generic clock generator 3
// <GCLK_CLKCTRL_GEN_GCLK4_Val"> Generic clock generator 4
// <GCLK_CLKCTRL_GEN_GCLK5_Val"> Generic clock generator 5
// <GCLK_CLKCTRL_GEN_GCLK6_Val"> Generic clock generator 6
// <GCLK_CLKCTRL_GEN_GCLK7_Val"> Generic clock generator 7
// <i> Select the slow clock source.
#ifndef CONF_GCLK_SERCOM4_SLOW_SRC
#define CONF_GCLK_SERCOM4_SLOW_SRC GCLK_CLKCTRL_GEN_GCLK3_Val
#endif
/**
* \def CONF_GCLK_SERCOM4_CORE_FREQUENCY
* \brief SERCOM4's Core Clock frequency
*/
#ifndef CONF_GCLK_SERCOM4_CORE_FREQUENCY
#define CONF_GCLK_SERCOM4_CORE_FREQUENCY 48000000
#endif
/**
* \def CONF_GCLK_SERCOM4_SLOW_FREQUENCY
* \brief SERCOM4's Slow Clock frequency
*/
#ifndef CONF_GCLK_SERCOM4_SLOW_FREQUENCY
#define CONF_GCLK_SERCOM4_SLOW_FREQUENCY 400000
#endif
// <y> Core Clock Source
// <id> core_gclk_selection
// <GCLK_CLKCTRL_GEN_GCLK0_Val"> Generic clock generator 0
// <GCLK_CLKCTRL_GEN_GCLK1_Val"> Generic clock generator 1
// <GCLK_CLKCTRL_GEN_GCLK2_Val"> Generic clock generator 2
// <GCLK_CLKCTRL_GEN_GCLK3_Val"> Generic clock generator 3
// <GCLK_CLKCTRL_GEN_GCLK4_Val"> Generic clock generator 4
// <GCLK_CLKCTRL_GEN_GCLK5_Val"> Generic clock generator 5
// <GCLK_CLKCTRL_GEN_GCLK6_Val"> Generic clock generator 6
// <GCLK_CLKCTRL_GEN_GCLK7_Val"> Generic clock generator 7
// <i> Select the clock source for CORE.
#ifndef CONF_GCLK_SERCOM5_CORE_SRC
#define CONF_GCLK_SERCOM5_CORE_SRC GCLK_CLKCTRL_GEN_GCLK0_Val
#endif
// <y> Slow Clock Source
// <id> slow_gclk_selection
// <GCLK_CLKCTRL_GEN_GCLK0_Val"> Generic clock generator 0
// <GCLK_CLKCTRL_GEN_GCLK1_Val"> Generic clock generator 1
// <GCLK_CLKCTRL_GEN_GCLK2_Val"> Generic clock generator 2
// <GCLK_CLKCTRL_GEN_GCLK3_Val"> Generic clock generator 3
// <GCLK_CLKCTRL_GEN_GCLK4_Val"> Generic clock generator 4
// <GCLK_CLKCTRL_GEN_GCLK5_Val"> Generic clock generator 5
// <GCLK_CLKCTRL_GEN_GCLK6_Val"> Generic clock generator 6
// <GCLK_CLKCTRL_GEN_GCLK7_Val"> Generic clock generator 7
// <i> Select the slow clock source.
#ifndef CONF_GCLK_SERCOM5_SLOW_SRC
#define CONF_GCLK_SERCOM5_SLOW_SRC GCLK_CLKCTRL_GEN_GCLK3_Val
#endif
/**
* \def CONF_GCLK_SERCOM5_CORE_FREQUENCY
* \brief SERCOM5's Core Clock frequency
*/
#ifndef CONF_GCLK_SERCOM5_CORE_FREQUENCY
#define CONF_GCLK_SERCOM5_CORE_FREQUENCY 48000000
#endif
/**
* \def CONF_GCLK_SERCOM5_SLOW_FREQUENCY
* \brief SERCOM5's Slow Clock frequency
*/
#ifndef CONF_GCLK_SERCOM5_SLOW_FREQUENCY
#define CONF_GCLK_SERCOM5_SLOW_FREQUENCY 400000
#endif
// <y> RTC Clock Source
// <id> rtc_clk_selection
@ -425,7 +329,7 @@
* \brief RTC's Clock frequency
*/
#ifndef CONF_GCLK_RTC_FREQUENCY
#define CONF_GCLK_RTC_FREQUENCY 1000000
#define CONF_GCLK_RTC_FREQUENCY 48000000
#endif
// <y> TC Clock Source
@ -457,7 +361,7 @@
* \brief TC3's Clock frequency
*/
#ifndef CONF_GCLK_TC3_FREQUENCY
#define CONF_GCLK_TC3_FREQUENCY 1000000
#define CONF_GCLK_TC3_FREQUENCY 48000000
#endif
// <y> DAC Clock Source
@ -489,7 +393,7 @@
* \brief DAC's Clock frequency
*/
#ifndef CONF_GCLK_DAC_FREQUENCY
#define CONF_GCLK_DAC_FREQUENCY 1000000
#define CONF_GCLK_DAC_FREQUENCY 48000000
#endif
// <y> USB Clock Source

@ -1,7 +1,17 @@
// The clock tree starts with 48mhz DFLL48M based on USB. GCLK5 divides it down
// to 2mhz which DPLL0 boosts to 120mhz. This is then used by GCLK0 to clock the
// core and main bus. GCLK1 is 48mhz based on DFLL48M which is used for USB.
// GCLK4 also outputs the 120mhz clock for monitoring.
// Circuit Python SAMD51 clock tree:
// DFLL48M (with USBCRM on to sync with external USB ref) -> GCLK1, GCLK5
// GCLK1 (48MHz) -> peripherals
// GCLK5 (divided down to 2 MHz) -> DPLL0
// DPLL0 (multiplied up to 120 MHz) -> GCLK0, GCLK4 (output for monitoring)
// We'd like to use XOSC32K as a ref for DFLL48M on boards with a 32kHz crystal,
// but haven't figured that out yet.
// Used in hpl/core/hpl_init.c to define which clocks should be initialized first.
// Not clear why all these need to be specified, but it doesn't work properly otherwise.
//#define CIRCUITPY_GCLK_INIT_1ST (1 << 0 | 1 << 1 | 1 << 3 | 1 <<5)
#define CIRCUITPY_GCLK_INIT_1ST 0xffff
/* Auto-generated config file hpl_gclk_config.h */
#ifndef HPL_GCLK_CONFIG_H

@ -3,13 +3,16 @@
//
// SERCOM0: SPI with hal_spi_m_sync.c driver: spi master synchronous
// SERCOM1: I2C with hal_i2c_m_sync.c driver: i2c master synchronous
// SERCOM2: USART with hal_usart_sync.c driver: usart synchronous
// SERCOM2: USART with hal_usart_async.c driver: usart asynchronous
// SERCOM3: SPI with hal_spi_m_dma.c: spi master DMA
#define PROTOTYPE_SERCOM_SPI_M_SYNC SERCOM0
#define PROTOTYPE_SERCOM_SPI_M_SYNC_CLOCK_FREQUENCY CONF_GCLK_SERCOM0_CORE_FREQUENCY
#define PROTOTYPE_SERCOM_I2CM_SYNC SERCOM1
#define PROTOTYPE_SERCOM_USART_SYNC SERCOM2
#define PROTOTYPE_SERCOM_USART_ASYNC SERCOM2
#define PROTOTYPE_SERCOM_USART_ASYNC_CLOCK_FREQUENCY CONF_GCLK_SERCOM2_CORE_FREQUENCY
/* Auto-generated config file hpl_sercom_config.h */
#ifndef HPL_SERCOM_CONFIG_H
@ -59,7 +62,7 @@
// <e> Advanced Configuration
// <id> spi_master_advanced
#ifndef CONF_SERCOM_0_SPI_ADVANCED
#define CONF_SERCOM_0_SPI_ADVANCED 0
#define CONF_SERCOM_0_SPI_ADVANCED 1
#endif
// <o> Dummy byte <0x00-0x1ff>
@ -201,7 +204,7 @@
// <e> Advanced
// <id> i2c_master_advanced
#ifndef CONF_SERCOM_1_I2CM_ADVANCED_CONFIG
#define CONF_SERCOM_1_I2CM_ADVANCED_CONFIG 0
#define CONF_SERCOM_1_I2CM_ADVANCED_CONFIG 1
#endif
// <o> TRise (ns) <0-300>
@ -377,7 +380,7 @@
// <e> Advanced configuration
// <id> usart_advanced
#ifndef CONF_SERCOM_2_USART_ADVANCED_CONFIG
#define CONF_SERCOM_2_USART_ADVANCED_CONFIG 0
#define CONF_SERCOM_2_USART_ADVANCED_CONFIG 1
#endif
// <q> Run in stand-by
@ -561,6 +564,188 @@
#endif
#endif
#include <peripheral_clk_config.h>
// Enable configuration of module
#ifndef CONF_SERCOM_3_SPI_ENABLE
#define CONF_SERCOM_3_SPI_ENABLE 1
#endif
//<o> SPI DMA TX Channel <0-32>
//<i> This defines DMA channel to be used
//<id> spi_master_dma_tx_channel
#ifndef CONF_SERCOM_3_SPI_M_DMA_TX_CHANNEL
#define CONF_SERCOM_3_SPI_M_DMA_TX_CHANNEL 0
#endif
// <e> SPI RX Channel Enable
// <id> spi_master_rx_channel
#ifndef CONF_SERCOM_3_SPI_RX_CHANNEL
#define CONF_SERCOM_3_SPI_RX_CHANNEL 1
#endif
//<o> DMA Channel <0-32>
//<i> This defines DMA channel to be used
//<id> spi_master_dma_rx_channel
#ifndef CONF_SERCOM_3_SPI_M_DMA_RX_CHANNEL
#define CONF_SERCOM_3_SPI_M_DMA_RX_CHANNEL 1
#endif
// </e>
// Set module in SPI Master mode
#ifndef CONF_SERCOM_3_SPI_MODE
#define CONF_SERCOM_3_SPI_MODE 0x03
#endif
// <h> Basic Configuration
// <q> Receive buffer enable
// <i> Enable receive buffer to receive data from slave (RXEN)
// <id> spi_master_rx_enable
#ifndef CONF_SERCOM_3_SPI_RXEN
#define CONF_SERCOM_3_SPI_RXEN 0x1
#endif
// <o> Character Size
// <i> Bit size for all characters sent over the SPI bus (CHSIZE)
// <0x0=>8 bits
// <0x1=>9 bits
// <id> spi_master_character_size
#ifndef CONF_SERCOM_3_SPI_CHSIZE
#define CONF_SERCOM_3_SPI_CHSIZE 0x0
#endif
// <o> Baud rate <1-12000000>
// <i> The SPI data transfer rate
// <id> spi_master_baud_rate
#ifndef CONF_SERCOM_3_SPI_BAUD
#define CONF_SERCOM_3_SPI_BAUD 50000
#endif
// </h>
// <e> Advanced Configuration
// <id> spi_master_advanced
#ifndef CONF_SERCOM_3_SPI_ADVANCED
#define CONF_SERCOM_3_SPI_ADVANCED 0
#endif
// <o> Dummy byte <0x00-0x1ff>
// <id> spi_master_dummybyte
// <i> Dummy byte used when reading data from the slave without sending any data
#ifndef CONF_SERCOM_3_SPI_DUMMYBYTE
#define CONF_SERCOM_3_SPI_DUMMYBYTE 0x1ff
#endif
// <o> Data Order
// <0=>MSB first
// <1=>LSB first
// <i> I least significant or most significant bit is shifted out first (DORD)
// <id> spi_master_arch_dord
#ifndef CONF_SERCOM_3_SPI_DORD
#define CONF_SERCOM_3_SPI_DORD 0x0
#endif
// <o> Clock Polarity
// <0=>SCK is low when idle
// <1=>SCK is high when idle
// <i> Determines if the leading edge is rising or falling with a corresponding opposite edge at the trailing edge. (CPOL)
// <id> spi_master_arch_cpol
#ifndef CONF_SERCOM_3_SPI_CPOL
#define CONF_SERCOM_3_SPI_CPOL 0x0
#endif
// <o> Clock Phase
// <0x0=>Sample input on leading edge
// <0x1=>Sample input on trailing edge
// <i> Determines if input data is sampled on leading or trailing SCK edge. (CPHA)
// <id> spi_master_arch_cpha
#ifndef CONF_SERCOM_3_SPI_CPHA
#define CONF_SERCOM_3_SPI_CPHA 0x0
#endif
// <o> Immediate Buffer Overflow Notification
// <i> Controls when OVF is asserted (IBON)
// <0x0=>In data stream
// <0x1=>On buffer overflow
// <id> spi_master_arch_ibon
#ifndef CONF_SERCOM_3_SPI_IBON
#define CONF_SERCOM_3_SPI_IBON 0x0
#endif
// <q> Run in stand-by
// <i> Module stays active in stand-by sleep mode. (RUNSTDBY)
// <id> spi_master_arch_runstdby
#ifndef CONF_SERCOM_3_SPI_RUNSTDBY
#define CONF_SERCOM_3_SPI_RUNSTDBY 0x0
#endif
// <o> Debug Stop Mode
// <i> Behavior of the baud-rate generator when CPU is halted by external debugger. (DBGSTOP)
// <0=>Keep running
// <1=>Halt
// <id> spi_master_arch_dbgstop
#ifndef CONF_SERCOM_3_SPI_DBGSTOP
#define CONF_SERCOM_3_SPI_DBGSTOP 0
#endif
// </e>
// Address mode disabled in master mode
#ifndef CONF_SERCOM_3_SPI_AMODE_EN
#define CONF_SERCOM_3_SPI_AMODE_EN 0
#endif
#ifndef CONF_SERCOM_3_SPI_AMODE
#define CONF_SERCOM_3_SPI_AMODE 0
#endif
#ifndef CONF_SERCOM_3_SPI_ADDR
#define CONF_SERCOM_3_SPI_ADDR 0
#endif
#ifndef CONF_SERCOM_3_SPI_ADDRMASK
#define CONF_SERCOM_3_SPI_ADDRMASK 0
#endif
#ifndef CONF_SERCOM_3_SPI_SSDE
#define CONF_SERCOM_3_SPI_SSDE 0
#endif
#ifndef CONF_SERCOM_3_SPI_MSSEN
#define CONF_SERCOM_3_SPI_MSSEN 0x0
#endif
#ifndef CONF_SERCOM_3_SPI_PLOADEN
#define CONF_SERCOM_3_SPI_PLOADEN 0
#endif
// <o> Receive Data Pinout
// <0x0=>PAD[0]
// <0x1=>PAD[1]
// <0x2=>PAD[2]
// <0x3=>PAD[3]
// <id> spi_master_rxpo
#ifndef CONF_SERCOM_3_SPI_RXPO
#define CONF_SERCOM_3_SPI_RXPO 2
#endif
// <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
// <id> spi_master_txpo
#ifndef CONF_SERCOM_3_SPI_TXPO
#define CONF_SERCOM_3_SPI_TXPO 0
#endif
// Calculate baud register value from requested baudrate value
#ifndef CONF_SERCOM_3_SPI_BAUD_RATE
#define CONF_SERCOM_3_SPI_BAUD_RATE ((float)CONF_GCLK_SERCOM3_CORE_FREQUENCY / (float)(2 * CONF_SERCOM_3_SPI_BAUD)) - 1
#endif
// <<< end of configuration section >>>
#endif // HPL_SERCOM_CONFIG_H

@ -33,7 +33,7 @@
// <i> Select the clock source for ADC.
#ifndef CONF_GCLK_ADC0_SRC
#define CONF_GCLK_ADC0_SRC GCLK_PCHCTRL_GEN_GCLK0_Val
#define CONF_GCLK_ADC0_SRC GCLK_PCHCTRL_GEN_GCLK1_Val
#endif
/**
@ -41,7 +41,7 @@
* \brief ADC0's Clock frequency
*/
#ifndef CONF_GCLK_ADC0_FREQUENCY
#define CONF_GCLK_ADC0_FREQUENCY 120000000
#define CONF_GCLK_ADC0_FREQUENCY 48000000
#endif
// <y> DAC Clock Source
@ -73,7 +73,7 @@
// <id> dac_gclk_selection
// <i> Select the clock source for DAC.
#ifndef CONF_GCLK_DAC_SRC
#define CONF_GCLK_DAC_SRC GCLK_PCHCTRL_GEN_GCLK0_Val
#define CONF_GCLK_DAC_SRC GCLK_PCHCTRL_GEN_GCLK1_Val
#endif
/**
@ -81,7 +81,7 @@
* \brief DAC's Clock frequency
*/
#ifndef CONF_GCLK_DAC_FREQUENCY
#define CONF_GCLK_DAC_FREQUENCY 120000000
#define CONF_GCLK_DAC_FREQUENCY 48000000
#endif
// <y> EVSYS Channel 0 Clock Source
@ -113,7 +113,7 @@
// <i> Select the clock source for channel 0.
#ifndef CONF_GCLK_EVSYS_CHANNEL_0_SRC
#define CONF_GCLK_EVSYS_CHANNEL_0_SRC GCLK_PCHCTRL_GEN_GCLK0_Val
#define CONF_GCLK_EVSYS_CHANNEL_0_SRC GCLK_PCHCTRL_GEN_GCLK1_Val
#endif
/**
@ -122,7 +122,7 @@
*/
#ifndef CONF_GCLK_EVSYS_CHANNEL_0_FREQUENCY
#define CONF_GCLK_EVSYS_CHANNEL_0_FREQUENCY 120000000.0
#define CONF_GCLK_EVSYS_CHANNEL_0_FREQUENCY 48000000.0
#endif
// <y> EVSYS Channel 1 Clock Source
@ -154,7 +154,7 @@
// <i> Select the clock source for channel 1.
#ifndef CONF_GCLK_EVSYS_CHANNEL_1_SRC
#define CONF_GCLK_EVSYS_CHANNEL_1_SRC GCLK_PCHCTRL_GEN_GCLK0_Val
#define CONF_GCLK_EVSYS_CHANNEL_1_SRC GCLK_PCHCTRL_GEN_GCLK1_Val
#endif
/**
@ -163,7 +163,7 @@
*/
#ifndef CONF_GCLK_EVSYS_CHANNEL_1_FREQUENCY
#define CONF_GCLK_EVSYS_CHANNEL_1_FREQUENCY 120000000.0
#define CONF_GCLK_EVSYS_CHANNEL_1_FREQUENCY 48000000.0
#endif
// <y> EVSYS Channel 2 Clock Source
@ -195,7 +195,7 @@
// <i> Select the clock source for channel 2.
#ifndef CONF_GCLK_EVSYS_CHANNEL_2_SRC
#define CONF_GCLK_EVSYS_CHANNEL_2_SRC GCLK_PCHCTRL_GEN_GCLK0_Val
#define CONF_GCLK_EVSYS_CHANNEL_2_SRC GCLK_PCHCTRL_GEN_GCLK1_Val
#endif
/**
@ -204,7 +204,7 @@
*/
#ifndef CONF_GCLK_EVSYS_CHANNEL_2_FREQUENCY
#define CONF_GCLK_EVSYS_CHANNEL_2_FREQUENCY 120000000.0
#define CONF_GCLK_EVSYS_CHANNEL_2_FREQUENCY 48000000.0
#endif
// <y> EVSYS Channel 3 Clock Source
@ -236,7 +236,7 @@
// <i> Select the clock source for channel 3.
#ifndef CONF_GCLK_EVSYS_CHANNEL_3_SRC
#define CONF_GCLK_EVSYS_CHANNEL_3_SRC GCLK_PCHCTRL_GEN_GCLK0_Val
#define CONF_GCLK_EVSYS_CHANNEL_3_SRC GCLK_PCHCTRL_GEN_GCLK1_Val
#endif
/**
@ -245,7 +245,7 @@
*/
#ifndef CONF_GCLK_EVSYS_CHANNEL_3_FREQUENCY
#define CONF_GCLK_EVSYS_CHANNEL_3_FREQUENCY 120000000.0
#define CONF_GCLK_EVSYS_CHANNEL_3_FREQUENCY 48000000.0
#endif
// <y> EVSYS Channel 4 Clock Source
@ -277,7 +277,7 @@
// <i> Select the clock source for channel 4.
#ifndef CONF_GCLK_EVSYS_CHANNEL_4_SRC
#define CONF_GCLK_EVSYS_CHANNEL_4_SRC GCLK_PCHCTRL_GEN_GCLK0_Val
#define CONF_GCLK_EVSYS_CHANNEL_4_SRC GCLK_PCHCTRL_GEN_GCLK1_Val
#endif
/**
@ -286,7 +286,7 @@
*/
#ifndef CONF_GCLK_EVSYS_CHANNEL_4_FREQUENCY
#define CONF_GCLK_EVSYS_CHANNEL_4_FREQUENCY 120000000.0
#define CONF_GCLK_EVSYS_CHANNEL_4_FREQUENCY 48000000.0
#endif
// <y> EVSYS Channel 5 Clock Source
@ -318,7 +318,7 @@
// <i> Select the clock source for channel 5.
#ifndef CONF_GCLK_EVSYS_CHANNEL_5_SRC
#define CONF_GCLK_EVSYS_CHANNEL_5_SRC GCLK_PCHCTRL_GEN_GCLK0_Val
#define CONF_GCLK_EVSYS_CHANNEL_5_SRC GCLK_PCHCTRL_GEN_GCLK1_Val
#endif
/**
@ -327,7 +327,7 @@
*/
#ifndef CONF_GCLK_EVSYS_CHANNEL_5_FREQUENCY
#define CONF_GCLK_EVSYS_CHANNEL_5_FREQUENCY 120000000.0
#define CONF_GCLK_EVSYS_CHANNEL_5_FREQUENCY 48000000.0
#endif
// <y> EVSYS Channel 6 Clock Source
@ -359,7 +359,7 @@
// <i> Select the clock source for channel 6.
#ifndef CONF_GCLK_EVSYS_CHANNEL_6_SRC
#define CONF_GCLK_EVSYS_CHANNEL_6_SRC GCLK_PCHCTRL_GEN_GCLK0_Val
#define CONF_GCLK_EVSYS_CHANNEL_6_SRC GCLK_PCHCTRL_GEN_GCLK1_Val
#endif
/**
@ -368,7 +368,7 @@
*/
#ifndef CONF_GCLK_EVSYS_CHANNEL_6_FREQUENCY
#define CONF_GCLK_EVSYS_CHANNEL_6_FREQUENCY 120000000.0
#define CONF_GCLK_EVSYS_CHANNEL_6_FREQUENCY 48000000.0
#endif
// <y> EVSYS Channel 7 Clock Source
@ -400,7 +400,7 @@
// <i> Select the clock source for channel 7.
#ifndef CONF_GCLK_EVSYS_CHANNEL_7_SRC
#define CONF_GCLK_EVSYS_CHANNEL_7_SRC GCLK_PCHCTRL_GEN_GCLK0_Val
#define CONF_GCLK_EVSYS_CHANNEL_7_SRC GCLK_PCHCTRL_GEN_GCLK1_Val
#endif
/**
@ -409,7 +409,7 @@
*/
#ifndef CONF_GCLK_EVSYS_CHANNEL_7_FREQUENCY
#define CONF_GCLK_EVSYS_CHANNEL_7_FREQUENCY 120000000.0
#define CONF_GCLK_EVSYS_CHANNEL_7_FREQUENCY 48000000.0
#endif
// <y> EVSYS Channel 8 Clock Source
@ -441,7 +441,7 @@
// <i> Select the clock source for channel 8.
#ifndef CONF_GCLK_EVSYS_CHANNEL_8_SRC
#define CONF_GCLK_EVSYS_CHANNEL_8_SRC GCLK_PCHCTRL_GEN_GCLK0_Val
#define CONF_GCLK_EVSYS_CHANNEL_8_SRC GCLK_PCHCTRL_GEN_GCLK1_Val
#endif
/**
@ -450,7 +450,7 @@
*/
#ifndef CONF_GCLK_EVSYS_CHANNEL_8_FREQUENCY
#define CONF_GCLK_EVSYS_CHANNEL_8_FREQUENCY 120000000.0
#define CONF_GCLK_EVSYS_CHANNEL_8_FREQUENCY 48000000.0
#endif
// <y> EVSYS Channel 9 Clock Source
@ -482,7 +482,7 @@
// <i> Select the clock source for channel 9.
#ifndef CONF_GCLK_EVSYS_CHANNEL_9_SRC
#define CONF_GCLK_EVSYS_CHANNEL_9_SRC GCLK_PCHCTRL_GEN_GCLK0_Val
#define CONF_GCLK_EVSYS_CHANNEL_9_SRC GCLK_PCHCTRL_GEN_GCLK1_Val
#endif
/**
@ -491,7 +491,7 @@
*/
#ifndef CONF_GCLK_EVSYS_CHANNEL_9_FREQUENCY
#define CONF_GCLK_EVSYS_CHANNEL_9_FREQUENCY 120000000.0
#define CONF_GCLK_EVSYS_CHANNEL_9_FREQUENCY 48000000.0
#endif
// <y> EVSYS Channel 10 Clock Source
@ -523,7 +523,7 @@
// <i> Select the clock source for channel 10.
#ifndef CONF_GCLK_EVSYS_CHANNEL_10_SRC
#define CONF_GCLK_EVSYS_CHANNEL_10_SRC GCLK_PCHCTRL_GEN_GCLK0_Val
#define CONF_GCLK_EVSYS_CHANNEL_10_SRC GCLK_PCHCTRL_GEN_GCLK1_Val
#endif
/**
@ -532,7 +532,7 @@
*/
#ifndef CONF_GCLK_EVSYS_CHANNEL_10_FREQUENCY
#define CONF_GCLK_EVSYS_CHANNEL_10_FREQUENCY 120000000.0
#define CONF_GCLK_EVSYS_CHANNEL_10_FREQUENCY 48000000.0
#endif
// <y> EVSYS Channel 11 Clock Source
@ -564,7 +564,7 @@
// <i> Select the clock source for channel 11.
#ifndef CONF_GCLK_EVSYS_CHANNEL_11_SRC
#define CONF_GCLK_EVSYS_CHANNEL_11_SRC GCLK_PCHCTRL_GEN_GCLK0_Val
#define CONF_GCLK_EVSYS_CHANNEL_11_SRC GCLK_PCHCTRL_GEN_GCLK1_Val
#endif
/**
@ -573,7 +573,7 @@
*/
#ifndef CONF_GCLK_EVSYS_CHANNEL_11_FREQUENCY
#define CONF_GCLK_EVSYS_CHANNEL_11_FREQUENCY 120000000.0
#define CONF_GCLK_EVSYS_CHANNEL_11_FREQUENCY 48000000.0
#endif
/**
@ -840,6 +840,86 @@
#define CONF_GCLK_SERCOM2_SLOW_FREQUENCY 32768
#endif
// <y> Core Clock Source
// <id> core_gclk_selection
// <GCLK_PCHCTRL_GEN_GCLK0_Val"> Generic clock generator 0
// <GCLK_PCHCTRL_GEN_GCLK1_Val"> Generic clock generator 1
// <GCLK_PCHCTRL_GEN_GCLK2_Val"> Generic clock generator 2
// <GCLK_PCHCTRL_GEN_GCLK3_Val"> Generic clock generator 3
// <GCLK_PCHCTRL_GEN_GCLK4_Val"> Generic clock generator 4
// <GCLK_PCHCTRL_GEN_GCLK5_Val"> Generic clock generator 5
// <GCLK_PCHCTRL_GEN_GCLK6_Val"> Generic clock generator 6
// <GCLK_PCHCTRL_GEN_GCLK7_Val"> Generic clock generator 7
// <GCLK_PCHCTRL_GEN_GCLK8_Val"> Generic clock generator 8
// <GCLK_PCHCTRL_GEN_GCLK9_Val"> Generic clock generator 9
// <GCLK_PCHCTRL_GEN_GCLK10_Val"> Generic clock generator 10
// <GCLK_PCHCTRL_GEN_GCLK11_Val"> Generic clock generator 11
// <i> Select the clock source for CORE.
#ifndef CONF_GCLK_SERCOM3_CORE_SRC
#define CONF_GCLK_SERCOM3_CORE_SRC GCLK_PCHCTRL_GEN_GCLK1_Val
#endif
// <y> Slow Clock Source
// <id> slow_gclk_selection
// <GCLK_PCHCTRL_GEN_GCLK0_Val"> Generic clock generator 0
// <GCLK_PCHCTRL_GEN_GCLK1_Val"> Generic clock generator 1
// <GCLK_PCHCTRL_GEN_GCLK2_Val"> Generic clock generator 2
// <GCLK_PCHCTRL_GEN_GCLK3_Val"> Generic clock generator 3
// <GCLK_PCHCTRL_GEN_GCLK4_Val"> Generic clock generator 4
// <GCLK_PCHCTRL_GEN_GCLK5_Val"> Generic clock generator 5
// <GCLK_PCHCTRL_GEN_GCLK6_Val"> Generic clock generator 6
// <GCLK_PCHCTRL_GEN_GCLK7_Val"> Generic clock generator 7
// <GCLK_PCHCTRL_GEN_GCLK8_Val"> Generic clock generator 8
// <GCLK_PCHCTRL_GEN_GCLK9_Val"> Generic clock generator 9
// <GCLK_PCHCTRL_GEN_GCLK10_Val"> Generic clock generator 10
// <GCLK_PCHCTRL_GEN_GCLK11_Val"> Generic clock generator 11
// <i> Select the slow clock source.
#ifndef CONF_GCLK_SERCOM3_SLOW_SRC
#define CONF_GCLK_SERCOM3_SLOW_SRC GCLK_PCHCTRL_GEN_GCLK3_Val
#endif
/**
* \def CONF_GCLK_SERCOM3_CORE_FREQUENCY
* \brief SERCOM3's Core Clock frequency
*/
#ifndef CONF_GCLK_SERCOM3_CORE_FREQUENCY
#define CONF_GCLK_SERCOM3_CORE_FREQUENCY 48000000
#endif
/**
* \def CONF_GCLK_SERCOM3_SLOW_FREQUENCY
* \brief SERCOM3's Slow Clock frequency
*/
#ifndef CONF_GCLK_SERCOM3_SLOW_FREQUENCY
#define CONF_GCLK_SERCOM3_SLOW_FREQUENCY 32768
#endif
// <y> TC Clock Source
// <id> tc_gclk_selection
@ -869,7 +949,7 @@
// <i> Select the clock source for TC.
#ifndef CONF_GCLK_TC0_SRC
#define CONF_GCLK_TC0_SRC GCLK_PCHCTRL_GEN_GCLK0_Val
#define CONF_GCLK_TC0_SRC GCLK_PCHCTRL_GEN_GCLK1_Val
#endif
/**
@ -877,7 +957,7 @@
* \brief TC0's Clock frequency
*/
#ifndef CONF_GCLK_TC0_FREQUENCY
#define CONF_GCLK_TC0_FREQUENCY 120000000
#define CONF_GCLK_TC0_FREQUENCY 48000000
#endif
// <y> USB Clock Source

@ -13,7 +13,9 @@ STATIC const mp_map_elem_t board_global_dict_table[] = {
{ 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_PA04 },
{ MP_OBJ_NEW_QSTR(MP_QSTR_D3), (mp_obj_t)&pin_PB16 },
{ MP_OBJ_NEW_QSTR(MP_QSTR_D4), (mp_obj_t)&pin_PB13 },

@ -117,6 +117,8 @@ void common_hal_busio_spi_construct(busio_spi_obj_t *self,
mp_raise_OSError(MP_EIO);
}
// Pads must be set after spi_m_sync_init(), which uses default values from
// the prototypical SERCOM.
hri_sercomspi_write_CTRLA_DOPO_bf(sercom, dopo);
hri_sercomspi_write_CTRLA_DIPO_bf(sercom, miso_pad);

@ -30,97 +30,25 @@
#include "mpconfigport.h"
#include "py/gc.h"
#include "py/mperrno.h"
#include "py/nlr.h"
#include "py/runtime.h"
#include "py/stream.h"
#include "samd21_pins.h"
#include "tick.h"
#include "asf/sam0/drivers/sercom/sercom_interrupt.h"
#undef ENABLE
busio_uart_obj_t *_uart_instances[SERCOM_INST_NUM];
static void _sercom_default_handler(
const uint8_t instance)
{
Assert(false);
}
static void _busio_uart_interrupt_handler(uint8_t instance)
{
/* Temporary variables */
uint16_t interrupt_status;
uint8_t error_code;
/* Get device instance from the look-up table */
struct usart_module *module
= (struct usart_module *)_sercom_instances[instance];
busio_uart_obj_t *self = _uart_instances[instance];
/* Pointer to the hardware module instance */
SercomUsart *const usart_hw = &(module->hw->USART);
#include "tick.h"
/* Wait for the synchronization to complete */
_usart_wait_for_sync(module);
#include "hpl_sercom_config.h"
#include "peripheral_clk_config.h"
/* Read and mask interrupt flag register */
interrupt_status = usart_hw->INTFLAG.reg;
interrupt_status &= usart_hw->INTENSET.reg;
#include "hal/include/hal_gpio.h"
#include "hal/include/hal_usart_async.h"
#include "hal/include/hpl_usart_async.h"
/* Check if the Receive Complete interrupt has occurred, and that
* there's more data to receive */
if (interrupt_status & SERCOM_USART_INTFLAG_RXC) {
/* Read out the status code and mask away all but the 4 LSBs*/
error_code = (uint8_t)(usart_hw->STATUS.reg & SERCOM_USART_STATUS_MASK);
/* CTS status should not be considered as an error */
if(error_code & SERCOM_USART_STATUS_CTS) {
error_code &= ~SERCOM_USART_STATUS_CTS;
}
/* Check if an error has occurred during the receiving */
if (error_code) {
/* Check which error occurred */
if (error_code & SERCOM_USART_STATUS_FERR) {
/* Store the error code and clear flag by writing 1 to it */
usart_hw->STATUS.reg = SERCOM_USART_STATUS_FERR;
} else if (error_code & SERCOM_USART_STATUS_BUFOVF) {
/* Store the error code and clear flag by writing 1 to it */
usart_hw->STATUS.reg = SERCOM_USART_STATUS_BUFOVF;
} else if (error_code & SERCOM_USART_STATUS_PERR) {
/* Store the error code and clear flag by writing 1 to it */
usart_hw->STATUS.reg = SERCOM_USART_STATUS_PERR;
}
self->rx_error = true;
} else {
/* Read current packet from DATA register,
* increment buffer pointer and decrement buffer length */
uint16_t received_data = (usart_hw->DATA.reg & SERCOM_USART_DATA_MASK);
common_hal_mcu_disable_interrupts();
/* Read value will be at least 8-bits long */
uint32_t buffer_end = (self->buffer_start + self->buffer_size) % self->buffer_length;
self->buffer[buffer_end] = received_data;
self->buffer_size++;
if (module->character_size == USART_CHARACTER_SIZE_9BIT) {
buffer_end = (self->buffer_start + self->buffer_size) % self->buffer_length;
/* 9-bit data, write next received byte to the buffer */
self->buffer[buffer_end] = (received_data >> 8);
self->buffer_size++;
}
#include "peripherals.h"
#include "pins.h"
if (self->buffer_size > self->buffer_length) {
self->buffer_start++;
if (module->character_size == USART_CHARACTER_SIZE_9BIT) {
self->buffer_start++;
}
self->buffer_size = self->buffer_length;
}
common_hal_mcu_enable_interrupts();
}
}
// Do-nothing callback needed so that usart_async code will enable rx interrupts.
// See comment below re usart_async_register_callback()
static void usart_async_rxc_callback(const struct usart_async_descriptor *const descr) {
// Nothing needs to be done by us.
}
void common_hal_busio_uart_construct(busio_uart_obj_t *self,
@ -128,34 +56,55 @@ void common_hal_busio_uart_construct(busio_uart_obj_t *self,
uint8_t bits, uart_parity_t parity, uint8_t stop, uint32_t timeout,
uint8_t receiver_buffer_size) {
Sercom* sercom = NULL;
uint32_t rx_pinmux = PINMUX_UNUSED;
uint8_t rx_pad = 5; // Unset pad
uint32_t tx_pinmux = PINMUX_UNUSED;
uint8_t tx_pad = 5; // Unset pad
uint8_t sercom_index;
uint32_t rx_pinmux = 0;
uint8_t rx_pad = 255; // Unset pad
uint32_t tx_pinmux = 0;
uint8_t tx_pad = 255; // Unset pad
if (bits > 8) {
mp_raise_NotImplementedError("bytes > 8 bits not supported");
}
bool have_tx = tx != mp_const_none;
bool have_rx = rx != mp_const_none;
if (!have_tx && !have_rx) {
mp_raise_ValueError("tx and rx cannot both be None");
}
self->baudrate = baudrate;
self->character_bits = bits;
self->timeout_ms = timeout;
// This assignment is only here because the usart_async routines take a *const argument.
struct usart_async_descriptor * const usart_desc_p = (struct usart_async_descriptor * const) &self->usart_desc;
for (int i = 0; i < NUM_SERCOMS_PER_PIN; i++) {
Sercom* potential_sercom = NULL;
if (tx != NULL) {
if (have_tx) {
potential_sercom = tx->sercom[i].sercom;
sercom_index = tx->sercom[i].index;
if (potential_sercom == NULL ||
potential_sercom->I2CM.CTRLA.bit.ENABLE != 0 ||
potential_sercom->USART.CTRLA.bit.ENABLE != 0 ||
!(tx->sercom[i].pad == 0 ||
tx->sercom[i].pad == 2)) {
continue;
}
tx_pinmux = PINMUX(tx->pin, (i == 0) ? MUX_C : MUX_D);
tx_pad = tx->sercom[i].pad;
if (rx == NULL) {
if (rx == mp_const_none) {
sercom = potential_sercom;
break;
}
}
for (int j = 0; j < NUM_SERCOMS_PER_PIN; j++) {
if (((tx == NULL && rx->sercom[j].sercom->I2CM.CTRLA.bit.ENABLE == 0) ||
if (((!have_tx && rx->sercom[j].sercom->USART.CTRLA.bit.ENABLE == 0) ||
potential_sercom == rx->sercom[j].sercom) &&
rx->sercom[j].pad != tx_pad) {
rx_pinmux = PINMUX(rx->pin, (j == 0) ? MUX_C : MUX_D);
rx_pad = rx->sercom[j].pad;
sercom = rx->sercom[j].sercom;
sercom_index = rx->sercom[j].index;
break;
}
}
@ -166,81 +115,96 @@ void common_hal_busio_uart_construct(busio_uart_obj_t *self,
if (sercom == NULL) {
mp_raise_ValueError("Invalid pins");
}
if (tx == NULL) {
if (!have_tx) {
tx_pad = 0;
if (rx_pad == 0) {
tx_pad = 2;
}
}
if (rx == NULL) {
if (!have_rx) {
rx_pad = (tx_pad + 1) % 4;
}
struct usart_config config_usart;
usart_get_config_defaults(&config_usart);
config_usart.mux_setting = (SERCOM_USART_CTRLA_RXPO(rx_pad) | SERCOM_USART_CTRLA_TXPO(tx_pad / 2));
if (parity == PARITY_ODD) {
config_usart.parity = USART_PARITY_ODD;
} else if (parity == PARITY_EVEN) {
config_usart.parity = USART_PARITY_EVEN;
}
config_usart.stopbits = stop - 1;
config_usart.character_size = bits % 8;
config_usart.baudrate = baudrate;
// Map pad to pinmux through a short array.
uint32_t *pinmuxes[4] = {&config_usart.pinmux_pad0,
&config_usart.pinmux_pad1,
&config_usart.pinmux_pad2,
&config_usart.pinmux_pad3};
// Pin muxes have a default pin, set them to unused so that no other pins are changed.
for (int i = 0; i < 4; i++) {
*pinmuxes[i] = PINMUX_UNUSED;
}
self->rx_pin = NO_PIN;
config_usart.receiver_enable = rx != NULL;
if (rx != NULL) {
*pinmuxes[rx_pad] = rx_pinmux;
self->rx_pin = rx->pin;
claim_pin(rx);
}
// Set up clocks on SERCOM.
samd_peripherals_sercom_clock_init(sercom, sercom_index);
self->tx_pin = NO_PIN;
config_usart.transmitter_enable = tx != NULL;
if (tx != NULL) {
*pinmuxes[tx_pad] = tx_pinmux;
self->tx_pin = tx->pin;
claim_pin(tx);
if (rx && receiver_buffer_size > 0) {
self->buffer_length = receiver_buffer_size;
self->buffer = (uint8_t *) gc_alloc(self->buffer_length * sizeof(uint8_t), false, false);
if (self->buffer == NULL) {
common_hal_busio_uart_deinit(self);
mp_raise_msg(&mp_type_MemoryError, "Failed to allocate RX buffer");
}
} else {
self->buffer_length = 0;
self->buffer = NULL;
}
self->timeout_ms = timeout;
self->buffer_length = receiver_buffer_size;
self->buffer_length *= (bits + 7) / 8;
self->buffer = (uint8_t *) gc_alloc(self->buffer_length * sizeof(uint8_t), false);
if (self->buffer == NULL) {
common_hal_busio_uart_deinit(self);
mp_raise_msg(&mp_type_MemoryError, "Failed to allocate RX buffer");
if (usart_async_init(usart_desc_p, sercom, self->buffer, self->buffer_length, NULL) != ERR_NONE) {
mp_raise_ValueError("Could not initialize UART");
}
if (usart_init(&self->uart_instance, sercom, &config_usart) != STATUS_OK) {
common_hal_busio_uart_deinit(self);
mp_raise_OSError(MP_EIO);
// usart_async_init() sets a number of defaults based on a prototypical SERCOM
// which don't necessarily match what we need. After calling it, set the values
// specific to this instantiation of UART.
// Set pads computed for this SERCOM.
// TXPO:
// 0x0: TX pad 0; no RTS/CTS
// 0x1: TX pad 2; no RTS/CTS
// 0x2: TX pad 0; RTS: pad 2, CTS: pad 3 (not used by us right now)
// So divide by 2 to map pad to value.
hri_sercomusart_write_CTRLA_TXPO_bf(sercom, tx_pad / 2);
// RXPO:
// 0x0: RX pad 0
// 0x1: RX pad 1
// 0x2: RX pad 2
// 0x3: RX pad 3
hri_sercomusart_write_CTRLA_RXPO_bf(sercom, rx_pad);
// Enable tx and/or rx based on whether the pins were specified.
hri_sercomusart_write_CTRLB_TXEN_bit(sercom, have_tx);
hri_sercomusart_write_CTRLB_RXEN_bit(sercom, have_rx);
// Set parity, baud rate, stop bits, etc. 9-bit bytes not supported.
usart_async_set_parity(usart_desc_p, parity == PARITY_NONE ? USART_PARITY_NONE :
(parity == PARITY_ODD ? USART_PARITY_ODD : USART_PARITY_EVEN));
usart_async_set_stopbits(usart_desc_p, stop == 1 ? USART_STOP_BITS_ONE : USART_STOP_BITS_TWO);
// This field is 0 for 8 bits, 5, 6, 7 for 5, 6, 7 bits. 1 for 9 bits, but we don't support that.
usart_async_set_character_size(usart_desc_p, bits % 8);
common_hal_busio_uart_set_baudrate(self, baudrate);
// Turn on rx interrupt handling. The UART async driver has its own set of internal callbacks,
// which are set up by uart_async_init(). These in turn can call user-specified callbacks.
// In fact, the actual interrupts are not enabled unless we set up a user-specified callback.
// This is confusing. It's explained in the Atmel START User Guide -> Implementation Description ->
// Different read function behavior in some asynchronous drivers. As of this writing:
// http://start.atmel.com/static/help/index.html?GUID-79201A5A-226F-4FBB-B0B8-AB0BE0554836
// Look at the ASFv4 code example for async USART.
usart_async_register_callback(usart_desc_p, USART_ASYNC_RXC_CB, usart_async_rxc_callback);
if (have_tx) {
gpio_set_pin_direction(tx->pin, GPIO_DIRECTION_OUT);
gpio_set_pin_pull_mode(tx->pin, GPIO_PULL_OFF);
gpio_set_pin_function(tx->pin, tx_pinmux);
self->tx_pin = tx->pin;
claim_pin(tx);
} else {
self->tx_pin = NO_PIN;
}
if (have_rx) {
gpio_set_pin_direction(rx->pin, GPIO_DIRECTION_IN);
gpio_set_pin_pull_mode(rx->pin, GPIO_PULL_OFF);
gpio_set_pin_function(rx->pin, rx_pinmux);
self->rx_pin = rx->pin;
claim_pin(rx);
} else {
self->rx_pin = NO_PIN;
}
// We use our own interrupt handler because we want a circular buffer
// instead of the jobs that ASF provides.
uint8_t instance_index = _sercom_get_sercom_inst_index(self->uart_instance.hw);
_sercom_set_handler(instance_index, _busio_uart_interrupt_handler);
_sercom_instances[instance_index] = &self->uart_instance;
_uart_instances[instance_index] = self;
/* Enable Global interrupt for module */
system_interrupt_enable(_sercom_get_interrupt_vector(self->uart_instance.hw));
usart_enable(&self->uart_instance);
self->uart_instance.hw->USART.INTENSET.bit.RXC = true;
usart_async_enable(usart_desc_p);
}
bool common_hal_busio_uart_deinited(busio_uart_obj_t *self) {
@ -251,16 +215,10 @@ void common_hal_busio_uart_deinit(busio_uart_obj_t *self) {
if (common_hal_busio_uart_deinited(self)) {
return;
}
self->uart_instance.hw->USART.INTENCLR.bit.RXC = true;
uint8_t instance_index = _sercom_get_sercom_inst_index(self->uart_instance.hw);
_sercom_set_handler(instance_index, &_sercom_default_handler);
_sercom_instances[instance_index] = NULL;
_uart_instances[instance_index] = NULL;
system_interrupt_disable(_sercom_get_interrupt_vector(self->uart_instance.hw));
usart_disable(&self->uart_instance);
// This assignment is only here because the usart_async routines take a *const argument.
struct usart_async_descriptor * const usart_desc_p = (struct usart_async_descriptor * const) &self->usart_desc;
usart_async_disable(usart_desc_p);
usart_async_deinit(usart_desc_p);
reset_pin(self->rx_pin);
reset_pin(self->tx_pin);
self->rx_pin = NO_PIN;
@ -269,123 +227,120 @@ void common_hal_busio_uart_deinit(busio_uart_obj_t *self) {