summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDan Halbert <halbert@halwitz.org>2018-02-21 16:30:26 -0500
committerDan Halbert <halbert@halwitz.org>2018-02-21 17:18:49 -0500
commit9b4477e1dc088d18127838310b828514cb33edea (patch)
treec15d3c890b0186e5e7a68748d7d245b86d8796dc
parentfd9d3de208e8d5994916e3365cc3f5dea57e19de (diff)
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.
-rw-r--r--ports/atmel-samd/Makefile6
m---------ports/atmel-samd/asf40
-rw-r--r--ports/atmel-samd/asf4_conf/samd21/hpl_gclk_config.h11
-rw-r--r--ports/atmel-samd/asf4_conf/samd21/hpl_sercom_config.h188
-rw-r--r--ports/atmel-samd/asf4_conf/samd21/peripheral_clk_config.h166
-rw-r--r--ports/atmel-samd/asf4_conf/samd51/hpl_gclk_config.h18
-rw-r--r--ports/atmel-samd/asf4_conf/samd51/hpl_sercom_config.h195
-rw-r--r--ports/atmel-samd/asf4_conf/samd51/peripheral_clk_config.h140
-rw-r--r--ports/atmel-samd/boards/metro_m4_express/pins.c2
-rw-r--r--ports/atmel-samd/common-hal/busio/SPI.c2
-rw-r--r--ports/atmel-samd/common-hal/busio/UART.c455
-rw-r--r--ports/atmel-samd/common-hal/busio/UART.h29
-rw-r--r--ports/atmel-samd/common-hal/neopixel_write/__init__.c32
-rw-r--r--ports/atmel-samd/supervisor/port.c38
-rw-r--r--shared-bindings/busio/UART.c39
-rw-r--r--shared-bindings/busio/UART.h4
-rw-r--r--shared-bindings/busio/__init__.c8
17 files changed, 870 insertions, 463 deletions
diff --git a/ports/atmel-samd/Makefile b/ports/atmel-samd/Makefile
index a5d1fd7c0..4660d575e 100644
--- a/ports/atmel-samd/Makefile
+++ b/ports/atmel-samd/Makefile
@@ -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 \
diff --git a/ports/atmel-samd/asf4 b/ports/atmel-samd/asf4
-Subproject 0efc3407dd97ef617a5655674a3516693897a96
+Subproject aaa0f428111fbea7d56ab548053b11c9f12068f
diff --git a/ports/atmel-samd/asf4_conf/samd21/hpl_gclk_config.h b/ports/atmel-samd/asf4_conf/samd21/hpl_gclk_config.h
index fa9bb661c..90df195cd 100644
--- a/ports/atmel-samd/asf4_conf/samd21/hpl_gclk_config.h
+++ b/ports/atmel-samd/asf4_conf/samd21/hpl_gclk_config.h
@@ -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
diff --git a/ports/atmel-samd/asf4_conf/samd21/hpl_sercom_config.h b/ports/atmel-samd/asf4_conf/samd21/hpl_sercom_config.h
index 91141bcfc..85d05fc50 100644
--- a/ports/atmel-samd/asf4_conf/samd21/hpl_sercom_config.h
+++ b/ports/atmel-samd/asf4_conf/samd21/hpl_sercom_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
diff --git a/ports/atmel-samd/asf4_conf/samd21/peripheral_clk_config.h b/ports/atmel-samd/asf4_conf/samd21/peripheral_clk_config.h
index b8080d059..84fc6b9e4 100644
--- a/ports/atmel-samd/asf4_conf/samd21/peripheral_clk_config.h
+++ b/ports/atmel-samd/asf4_conf/samd21/peripheral_clk_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
diff --git a/ports/atmel-samd/asf4_conf/samd51/hpl_gclk_config.h b/ports/atmel-samd/asf4_conf/samd51/hpl_gclk_config.h
index 9a0081c79..300db2716 100644
--- a/ports/atmel-samd/asf4_conf/samd51/hpl_gclk_config.h
+++ b/ports/atmel-samd/asf4_conf/samd51/hpl_gclk_config.h
@@ -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
diff --git a/ports/atmel-samd/asf4_conf/samd51/hpl_sercom_config.h b/ports/atmel-samd/asf4_conf/samd51/hpl_sercom_config.h
index 1830c5490..cd411154c 100644
--- a/ports/atmel-samd/asf4_conf/samd51/hpl_sercom_config.h
+++ b/ports/atmel-samd/asf4_conf/samd51/hpl_sercom_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
diff --git a/ports/atmel-samd/asf4_conf/samd51/peripheral_clk_config.h b/ports/atmel-samd/asf4_conf/samd51/peripheral_clk_config.h
index 830f0e83b..c1df63211 100644
--- a/ports/atmel-samd/asf4_conf/samd51/peripheral_clk_config.h
+++ b/ports/atmel-samd/asf4_conf/samd51/peripheral_clk_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
diff --git a/ports/atmel-samd/boards/metro_m4_express/pins.c b/ports/atmel-samd/boards/metro_m4_express/pins.c
index 5889c6c68..33b69b32b 100644
--- a/ports/atmel-samd/boards/metro_m4_express/pins.c
+++ b/ports/atmel-samd/boards/metro_m4_express/pins.c
@@ -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 },
diff --git a/ports/atmel-samd/common-hal/busio/SPI.c b/ports/atmel-samd/common-hal/busio/SPI.c
index ca98d1d2f..c4cd6e66f 100644
--- a/ports/atmel-samd/common-hal/busio/SPI.c
+++ b/ports/atmel-samd/common-hal/busio/SPI.c
@@ -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);
diff --git a/ports/atmel-samd/common-hal/busio/UART.c b/ports/atmel-samd/common-hal/busio/UART.c
index 79f7cf4a9..292e01e60 100644
--- a/ports/atmel-samd/common-hal/busio/UART.c
+++ b/ports/atmel-samd/common-hal/busio/UART.c
@@ -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) {
// Read characters.
size_t common_hal_busio_uart_read(busio_uart_obj_t *self, uint8_t *data, size_t len, int *errcode) {
+ if (self->rx_pin == NO_PIN) {
+ mp_raise_ValueError("No RX pin");
+ }
+
+ // 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;
+
+ if (len == 0) {
+ // Nothing to read.
+ return 0;
+ }
+
+ struct io_descriptor *io;
+ usart_async_get_io_descriptor(usart_desc_p, &io);
+
size_t total_read = 0;
uint64_t start_ticks = ticks_ms;
- while (total_read < len && ticks_ms - start_ticks < self->timeout_ms) {
- if (self->buffer_size > 0) {
- common_hal_mcu_disable_interrupts();
- data[total_read] = self->buffer[self->buffer_start];
- if (self->uart_instance.character_size == USART_CHARACTER_SIZE_9BIT) {
- data[total_read + 1] = self->buffer[self->buffer_start + 1];
- self->buffer_start += 2;
- self->buffer_size -= 2;
- } else {
- self->buffer_start++;
- self->buffer_size--;
- }
- self->buffer_start = self->buffer_start % self->buffer_length;
- common_hal_mcu_enable_interrupts();
- // Reset the timeout every character read.
- total_read++;
+
+ // Busy-wait until timeout or until we've read enough chars.
+ while (ticks_ms - start_ticks < self->timeout_ms) {
+ // Read as many chars as we can right now, up to len.
+ size_t num_read = io_read(io, data, len);
+
+ // Advance pointer in data buffer, and decrease how many chars left to read.
+ data += num_read;
+ len -= num_read;
+ total_read += num_read;
+ if (len == 0) {
+ // Don't need to read any more: data buf is full.
+ break;
+ }
+ if (num_read > 0) {
+ // Reset the timeout on every character read.
start_ticks = ticks_ms;
}
- #ifdef MICROPY_VM_HOOK_LOOP
- MICROPY_VM_HOOK_LOOP
- #endif
- }
- if (total_read == 0) {
- *errcode = MP_EAGAIN;
- return MP_STREAM_ERROR;
+#ifdef MICROPY_VM_HOOK_LOOP
+ MICROPY_VM_HOOK_LOOP
+#endif
}
+
return total_read;
}
// Write characters.
size_t common_hal_busio_uart_write(busio_uart_obj_t *self, const uint8_t *data, size_t len, int *errcode) {
- /* Check that the transmitter is enabled */
- if (!(self->uart_instance.transmitter_enabled)) {
- *errcode = MP_EIO;
- return MP_STREAM_ERROR;
+ if (self->tx_pin == NO_PIN) {
+ mp_raise_ValueError("No TX pin");
}
- /* Get a pointer to the hardware module instance */
- SercomUsart *const usart_hw = &(self->uart_instance.hw->USART);
-
- /* Wait until synchronization is complete */
- _usart_wait_for_sync(&self->uart_instance);
-
- uint16_t tx_pos = 0;
-
- bool ok = true;
- uint64_t start_ticks = 0;
- /* Blocks while buffer is being transferred */
- while (len--) {
- /* Wait for the USART to be ready for new data and abort
- * operation if it doesn't get ready within the timeout*/
- ok = false;
- start_ticks = ticks_ms;
- while (ticks_ms - start_ticks < self->timeout_ms) {
- if (usart_hw->INTFLAG.reg & SERCOM_USART_INTFLAG_DRE) {
- ok = true;
- break;
- }
- #ifdef MICROPY_VM_HOOK_LOOP
- MICROPY_VM_HOOK_LOOP
- #endif
- }
-
- if (!ok) {
- break;
- }
-
- /* Data to send is at least 8 bits long */
- uint16_t data_to_send = data[tx_pos++];
-
- /* Check if the character size exceeds 8 bit */
- if (self->uart_instance.character_size == USART_CHARACTER_SIZE_9BIT) {
- data_to_send |= (data[tx_pos++] << 8);
- }
+ // 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;
- /* Send the data through the USART module */
+ struct io_descriptor *io;
+ usart_async_get_io_descriptor(usart_desc_p, &io);
- enum status_code status = usart_write_wait(&self->uart_instance, data_to_send);
- if (status != STATUS_OK) {
- ok = false;
- }
+ if (io_write(io, data, len) < 0) {
+ *errcode = MP_EAGAIN;
+ return MP_STREAM_ERROR;
}
- /* Wait until Transmit is complete or timeout */
- if (ok) {
- ok = false;
- start_ticks = ticks_ms;
- while (ticks_ms - start_ticks < self->timeout_ms) {
- if (usart_hw->INTFLAG.reg & SERCOM_USART_INTFLAG_TXC) {
- ok = true;
- break;
- }
- #ifdef MICROPY_VM_HOOK_LOOP
- MICROPY_VM_HOOK_LOOP
- #endif
+ // Wait until write is complete or timeout.
+ bool done = false;
+ uint64_t start_ticks = ticks_ms;
+ // Busy-wait for timeout.
+ while (ticks_ms - start_ticks < self->timeout_ms) {
+ if (usart_async_is_tx_empty(usart_desc_p)) {
+ done = true;
+ break;
}
+ #ifdef MICROPY_VM_HOOK_LOOP
+ MICROPY_VM_HOOK_LOOP
+ #endif
}
- if (!ok && tx_pos == 0) {
+ if (!done) {
*errcode = MP_EAGAIN;
return MP_STREAM_ERROR;
}
- return tx_pos;
+
+ struct usart_async_status async_status;
+ // Could return ERR_BUSY, but if that's true there's already a problem.
+ usart_async_get_status(usart_desc_p, &async_status);
+ return async_status.txcnt;
+}
+
+uint32_t common_hal_busio_uart_get_baudrate(busio_uart_obj_t *self) {
+ return self->baudrate;
+}
+
+void common_hal_busio_uart_set_baudrate(busio_uart_obj_t *self, uint32_t baudrate) {
+ // 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_set_baud_rate(usart_desc_p,
+ // Samples and ARITHMETIC vs FRACTIONAL must correspond to USART_SAMPR in
+ // hpl_sercom_config.h.
+ _usart_async_calculate_baud_rate(baudrate, // e.g. 9600 baud
+ PROTOTYPE_SERCOM_USART_ASYNC_CLOCK_FREQUENCY,
+ 16, // samples
+ USART_BAUDRATE_ASYNCH_ARITHMETIC,
+ 0 // fraction - not used for ARITHMETIC
+ ));
+ self->baudrate = baudrate;
}
uint32_t common_hal_busio_uart_rx_characters_available(busio_uart_obj_t *self) {
- if (self->uart_instance.character_size == USART_CHARACTER_SIZE_9BIT) {
- return self->buffer_size / 2;
- }
return self->buffer_size;
}
bool common_hal_busio_uart_ready_to_tx(busio_uart_obj_t *self) {
- if (!(self->uart_instance.transmitter_enabled)) {
+ if (self->tx_pin == NO_PIN) {
return false;
}
- return self->uart_instance.hw->USART.INTFLAG.bit.DRE;
+ // This assignment is only here because the usart_async routines take a *const argument.
+ const struct _usart_async_device * const usart_device_p =
+ (struct _usart_async_device * const) &self->usart_desc.device;
+ return _usart_async_is_byte_sent(usart_device_p);
}
diff --git a/ports/atmel-samd/common-hal/busio/UART.h b/ports/atmel-samd/common-hal/busio/UART.h
index 5adc11514..685755a5d 100644
--- a/ports/atmel-samd/common-hal/busio/UART.h
+++ b/ports/atmel-samd/common-hal/busio/UART.h
@@ -29,22 +29,25 @@
#include "common-hal/microcontroller/Pin.h"
-#include "asf/sam0/drivers/sercom/usart/usart.h"
+#include "hal/include/hal_usart_async.h"
+
#include "py/obj.h"
typedef struct {
- mp_obj_base_t base;
- struct usart_module uart_instance;
- uint8_t rx_pin;
- uint8_t tx_pin;
- uint32_t timeout_ms;
- bool rx_error;
- // Index of the oldest received character.
- uint32_t buffer_start;
- // Index of the next available spot to store a character.
- uint32_t buffer_size;
- uint32_t buffer_length;
- uint8_t* buffer;
+ mp_obj_base_t base;
+ struct usart_async_descriptor usart_desc;
+ uint8_t rx_pin;
+ uint8_t tx_pin;
+ uint8_t character_bits;
+ bool rx_error;
+ uint32_t baudrate;
+ uint32_t timeout_ms;
+ // Index of the oldest received character.
+ uint32_t buffer_start;
+ // Index of the next available spot to store a character.
+ uint32_t buffer_size;
+ uint32_t buffer_length;
+ uint8_t* buffer;
} busio_uart_obj_t;
#endif // MICROPY_INCLUDED_ATMEL_SAMD_COMMON_HAL_BUSIO_UART_H
diff --git a/ports/atmel-samd/common-hal/neopixel_write/__init__.c b/ports/atmel-samd/common-hal/neopixel_write/__init__.c
index 6133415f4..5530d0408 100644
--- a/ports/atmel-samd/common-hal/neopixel_write/__init__.c
+++ b/ports/atmel-samd/common-hal/neopixel_write/__init__.c
@@ -32,6 +32,9 @@
#include "tick.h"
#ifdef SAMD51
+#include "hri/hri_cmcc_d51.h"
+#include "hri/hri_nvmctrl_d51.h"
+
// This magical macro makes sure the delay isn't optimized out and is the
// minimal three instructions.
#define delay_cycles(cycles) \
@@ -62,11 +65,30 @@ void common_hal_neopixel_write(const digitalio_digitalinout_obj_t* digitalinout,
// Turn off interrupts of any kind during timing-sensitive code.
mp_hal_disable_all_interrupts();
+
#ifdef SAMD21
// Make sure the NVM cache is consistently timed.
NVMCTRL->CTRLB.bit.READMODE = NVMCTRL_CTRLB_READMODE_DETERMINISTIC_Val;
#endif
+ #ifdef SAMD51
+ // When this routine is positioned at certain addresses, the timing logic
+ // below can be too fast by about 2.5x. This is some kind of (un)fortunate code
+ // positiong with respect to a cache line.
+ // Theoretically we should turn on off the CMCC caches and the
+ // NVM caches to ensure consistent timing. Testing shows the the NVMCTRL
+ // cache disabling seems to make the difference. But turn both off to make sure.
+ // It's difficult to test because additions to the code before the timing loop
+ // below change instruction placement. Testing was done by adding cache changes
+ // below the loop (so only the first time through is wrong).
+ //
+ // Turn off instruction, data, and NVM caches to force consistent timing.
+ // Invalidate existing cache entries.
+ hri_cmcc_set_CFG_reg(CMCC, CMCC_CFG_DCDIS | CMCC_CFG_ICDIS);
+ hri_cmcc_write_MAINT0_reg(CMCC, CMCC_MAINT0_INVALL);
+ hri_nvmctrl_set_CTRLA_CACHEDIS0_bit(NVMCTRL);
+ hri_nvmctrl_set_CTRLA_CACHEDIS1_bit(NVMCTRL);
+ #endif
uint32_t pin = digitalinout->pin->pin;
port = &PORT->Group[GPIO_PORT(pin)]; // Convert GPIO # to port register
@@ -124,7 +146,7 @@ void common_hal_neopixel_write(const digitalio_digitalinout_obj_t* digitalinout,
if(ptr >= end) break;
p = *ptr++;
bitMask = 0x80;
- // This is the delay between bytes. Its similar to the other branch
+ // This is the delay between bytes. It's similar to the other branch
// in the if statement except its tuned to account for the time the
// above operations take.
// For the SK6812 its 0.6us +- 0.15us
@@ -139,6 +161,14 @@ void common_hal_neopixel_write(const digitalio_digitalinout_obj_t* digitalinout,
NVMCTRL->CTRLB.bit.READMODE = NVMCTRL_CTRLB_READMODE_NO_MISS_PENALTY_Val;
#endif
+ #ifdef SAMD51
+ // Turn instruction, data, and NVM caches back on.
+ hri_cmcc_clear_CFG_reg(CMCC, CMCC_CFG_DCDIS | CMCC_CFG_ICDIS);
+ hri_nvmctrl_clear_CTRLA_CACHEDIS0_bit(NVMCTRL);
+ hri_nvmctrl_clear_CTRLA_CACHEDIS1_bit(NVMCTRL);
+
+ #endif
+
// ticks_ms may be out of date at this point because we stopped the
// interrupt. We'll risk it anyway.
current_tick(&next_start_tick_ms, &next_start_tick_us);
diff --git a/ports/atmel-samd/supervisor/port.c b/ports/atmel-samd/supervisor/port.c
index 726a48d06..fe6591510 100644
--- a/ports/atmel-samd/supervisor/port.c
+++ b/ports/atmel-samd/supervisor/port.c
@@ -114,23 +114,6 @@ safe_mode_t port_init(void) {
// Configure millisecond timer initialization.
tick_init();
- // Uncomment to init PIN_PA17 for debugging.
- // struct port_config pin_conf;
- // port_get_config_defaults(&pin_conf);
- //
- // pin_conf.direction = PORT_PIN_DIR_OUTPUT;
- // port_pin_set_config(MICROPY_HW_LED1, &pin_conf);
- // port_pin_set_output_level(MICROPY_HW_LED1, false);
-
- // Output clocks for debugging.
- // not supported by SAMD51G; uncomment for SAMD51J or update for 51G
- // #ifdef SAMD51
- // gpio_set_pin_function(PIN_PA10, GPIO_PIN_FUNCTION_M); // GCLK4, D3
- // gpio_set_pin_function(PIN_PA11, GPIO_PIN_FUNCTION_M); // GCLK5, A4
- // gpio_set_pin_function(PIN_PB14, GPIO_PIN_FUNCTION_M); // GCLK0, D5
- // gpio_set_pin_function(PIN_PB15, GPIO_PIN_FUNCTION_M); // GCLK1, D6
- // #endif
-
// Init the nvm controller.
// struct nvm_config config_nvm;
// nvm_get_config_defaults(&config_nvm);
@@ -221,7 +204,26 @@ void reset_port(void) {
analogout_reset();
reset_all_pins();
-//
+
+ // Set up debugging pins after reset_all_pins().
+
+ // Uncomment to init PIN_PA17 for debugging.
+ // struct port_config pin_conf;
+ // port_get_config_defaults(&pin_conf);
+ //
+ // pin_conf.direction = PORT_PIN_DIR_OUTPUT;
+ // port_pin_set_config(MICROPY_HW_LED1, &pin_conf);
+ // port_pin_set_output_level(MICROPY_HW_LED1, false);
+
+ // Output clocks for debugging.
+ // not supported by SAMD51G; uncomment for SAMD51J or update for 51G
+ // #ifdef SAMD51
+ // gpio_set_pin_function(PIN_PA10, GPIO_PIN_FUNCTION_M); // GCLK4, D3
+ // gpio_set_pin_function(PIN_PA11, GPIO_PIN_FUNCTION_M); // GCLK5, A4
+ // gpio_set_pin_function(PIN_PB14, GPIO_PIN_FUNCTION_M); // GCLK0, D5
+ // gpio_set_pin_function(PIN_PB15, GPIO_PIN_FUNCTION_M); // GCLK1, D6
+ // #endif
+
//
// usb_hid_reset();
//
diff --git a/shared-bindings/busio/UART.c b/shared-bindings/busio/UART.c
index 3a3cb4246..1b63d8d0e 100644
--- a/shared-bindings/busio/UART.c
+++ b/shared-bindings/busio/UART.c
@@ -33,6 +33,7 @@
#include "lib/utils/context_manager_helpers.h"
#include "py/ioctl.h"
+#include "py/objproperty.h"
#include "py/runtime.h"
#include "py/stream.h"
@@ -48,11 +49,11 @@
//| A common bidirectional serial protocol that uses an an agreed upon speed
//| rather than a shared clock line.
//|
-//| :param ~microcontroller.Pin tx: the pin to transmit with
-//| :param ~microcontroller.Pin rx: the pin to receive on
-//| :param int baudrate: the transmit and receive speed
+//| :param ~microcontroller.Pin tx: the pin to transmit with, or ``None`` if this ``UART`` is receive-only.
+//| :param ~microcontroller.Pin rx: the pin to receive on, or ``None`` if this ``UART`` is transmit-only.
+//| :param int baudrate: the transmit and receive speed.
/// :param int bits: the number of bits per byte, 7, 8 or 9.
-/// :param Parity parity: the parity used for error checking
+/// :param Parity parity: the parity used for error checking.
/// :param int stop: the number of stop bits, 1 or 2.
/// :param int timeout: the timeout in milliseconds to wait for the first character and between subsequent characters.
/// :param int receiver_buffer_size: the character length of the read buffer (0 to disable). (When a character is 9 bits the buffer will be 2 * receiver_buffer_size bytes.)
@@ -220,6 +221,33 @@ STATIC mp_uint_t busio_uart_ioctl(mp_obj_t self_in, mp_uint_t request, mp_uint_t
return ret;
}
+//| .. attribute:: baudrate
+//|
+//| The current baudrate.
+//|
+STATIC mp_obj_t busio_uart_obj_get_baudrate(mp_obj_t self_in) {
+ busio_uart_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ raise_error_if_deinited(common_hal_busio_uart_deinited(self));
+ return MP_OBJ_NEW_SMALL_INT(common_hal_busio_uart_get_baudrate(self));
+}
+MP_DEFINE_CONST_FUN_OBJ_1(busio_uart_get_baudrate_obj, busio_uart_obj_get_baudrate);
+
+STATIC mp_obj_t busio_uart_obj_set_baudrate(mp_obj_t self_in, mp_obj_t baudrate) {
+ busio_uart_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ raise_error_if_deinited(common_hal_busio_uart_deinited(self));
+ common_hal_busio_uart_set_baudrate(self, mp_obj_get_int(baudrate));
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_2(busio_uart_set_baudrate_obj, busio_uart_obj_set_baudrate);
+
+
+const mp_obj_property_t busio_uart_baudrate_obj = {
+ .base.type = &mp_type_property,
+ .proxy = {(mp_obj_t)&busio_uart_get_baudrate_obj,
+ (mp_obj_t)&busio_uart_set_baudrate_obj,
+ (mp_obj_t)&mp_const_none_obj},
+};
+
//| .. class:: busio.UART.Parity
//|
//| Enum-like class to define the parity used to verify correct data transfer.
@@ -274,6 +302,9 @@ STATIC const mp_rom_map_elem_t busio_uart_locals_dict_table[] = {
{ MP_OBJ_NEW_QSTR(MP_QSTR_readinto), MP_ROM_PTR(&mp_stream_readinto_obj) },
{ MP_OBJ_NEW_QSTR(MP_QSTR_write), MP_ROM_PTR(&mp_stream_write_obj) },
+ // Properties
+ { MP_ROM_QSTR(MP_QSTR_baudrate), MP_ROM_PTR(&busio_uart_baudrate_obj) },
+
// Nested Enum-like Classes.
{ MP_ROM_QSTR(MP_QSTR_Parity), MP_ROM_PTR(&busio_uart_parity_type) },
};
diff --git a/shared-bindings/busio/UART.h b/shared-bindings/busio/UART.h
index 28196931a..fa39d8ad5 100644
--- a/shared-bindings/busio/UART.h
+++ b/shared-bindings/busio/UART.h
@@ -55,6 +55,10 @@ extern size_t common_hal_busio_uart_read(busio_uart_obj_t *self,
extern size_t common_hal_busio_uart_write(busio_uart_obj_t *self,
const uint8_t *data, size_t len, int *errcode);
+extern uint32_t common_hal_busio_uart_get_baudrate(busio_uart_obj_t *self);
+extern void common_hal_busio_uart_set_baudrate(busio_uart_obj_t *self, uint32_t baudrate);
+
+
extern uint32_t common_hal_busio_uart_rx_characters_available(busio_uart_obj_t *self);
extern bool common_hal_busio_uart_ready_to_tx(busio_uart_obj_t *self);
diff --git a/shared-bindings/busio/__init__.c b/shared-bindings/busio/__init__.c
index 6956e3c3d..958ee062a 100644
--- a/shared-bindings/busio/__init__.c
+++ b/shared-bindings/busio/__init__.c
@@ -32,9 +32,9 @@
#include "shared-bindings/microcontroller/Pin.h"
#include "shared-bindings/busio/__init__.h"
#include "shared-bindings/busio/I2C.h"
-//xxxx #include "shared-bindings/busio/OneWire.h"
+#include "shared-bindings/busio/OneWire.h"
#include "shared-bindings/busio/SPI.h"
-//xxxx #include "shared-bindings/busio/UART.h"
+#include "shared-bindings/busio/UART.h"
#include "shared-bindings/busio/__init__.h"
#include "py/runtime.h"
@@ -89,8 +89,8 @@ STATIC const mp_rom_map_elem_t busio_module_globals_table[] = {
{ MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_busio) },
{ MP_ROM_QSTR(MP_QSTR_I2C), MP_ROM_PTR(&busio_i2c_type) },
{ MP_ROM_QSTR(MP_QSTR_SPI), MP_ROM_PTR(&busio_spi_type) },
- //xxxx { MP_ROM_QSTR(MP_QSTR_OneWire), MP_ROM_PTR(&busio_onewire_type) },
- //xxxx { MP_ROM_QSTR(MP_QSTR_UART), MP_ROM_PTR(&busio_uart_type) },
+ { MP_ROM_QSTR(MP_QSTR_OneWire), MP_ROM_PTR(&busio_onewire_type) },
+ { MP_ROM_QSTR(MP_QSTR_UART), MP_ROM_PTR(&busio_uart_type) },
};
STATIC MP_DEFINE_CONST_DICT(busio_module_globals, busio_module_globals_table);