From fc9188a29894493d9fbbd24da3d793eacf7bf977 Mon Sep 17 00:00:00 2001 From: Ron Evans Date: Sat, 15 Jun 2019 07:14:05 +0200 Subject: [PATCH] machine/samd21/arduino-nano33: adds support for Arduino Nano33 IoT along with mapping to NINA-W102 WiFi chip. Also adds DTR and RTS functions along with timeouts to USBCDC functions to prevent lockups. Signed-off-by: Ron Evans --- src/machine/board_arduino_nano33.go | 138 +++++++++++++++++++++++ src/machine/board_circuitplay_express.go | 14 +++ src/machine/board_feather-m0.go | 14 +++ src/machine/board_itsybitsy-m0.go | 14 +++ src/machine/board_trinket.go | 14 +++ src/machine/machine_atsamd21.go | 102 +++++++++++------ src/machine/usb.go | 3 + targets/arduino-nano33.json | 5 + 8 files changed, 272 insertions(+), 32 deletions(-) create mode 100644 src/machine/board_arduino_nano33.go create mode 100644 targets/arduino-nano33.json diff --git a/src/machine/board_arduino_nano33.go b/src/machine/board_arduino_nano33.go new file mode 100644 index 00000000..0a64e7ca --- /dev/null +++ b/src/machine/board_arduino_nano33.go @@ -0,0 +1,138 @@ +// +build sam,atsamd21,arduino_nano33 + +// This contains the pin mappings for the Arduino Nano33 IoT board. +// +// For more information, see: https://store.arduino.cc/nano-33-iot +// +package machine + +import "device/sam" + +// GPIO Pins +const ( + RX0 Pin = PB23 // UART2 RX + TX1 Pin = PB22 // UART2 TX + + D2 Pin = PB10 // PWM available + D3 Pin = PB11 // PWM available + D4 Pin = PA07 + D5 Pin = PA05 // PWM available + D6 Pin = PA04 // PWM available + D7 Pin = PA06 + + D8 Pin = PA18 + D9 Pin = PA20 // PWM available + D10 Pin = PA21 // PWM available + D11 Pin = PA16 // PWM available + D12 Pin = PA19 // PWM available + + D13 Pin = PA17 +) + +// Analog pins +const ( + A0 Pin = PA02 // ADC/AIN[0] + A1 Pin = PB02 // ADC/AIN[10] + A2 Pin = PA11 // ADC/AIN[19] + A3 Pin = PA10 // ADC/AIN[18] + A4 Pin = PB08 // ADC/AIN[2], SCL: SERCOM2/PAD[1] + A5 Pin = PB09 // ADC/AIN[3], SDA: SERCOM2/PAD[1] + A6 Pin = PA09 // ADC/AIN[17] + A7 Pin = PB03 // ADC/AIN[11] +) + +const ( + LED = D13 +) + +// NINA-W102 Pins + +const ( + NINA_MOSI Pin = PA12 + NINA_MISO Pin = PA13 + NINA_CS Pin = PA14 + NINA_SCK Pin = PA15 + NINA_GPIO0 Pin = PA27 + NINA_RESETN Pin = PA08 + NINA_ACK Pin = PA28 +) + +// UART0 aka USBCDC pins +const ( + USBCDC_DM_PIN Pin = PA24 + USBCDC_DP_PIN Pin = PA25 +) + +// UART1 on the Arduino Nano 33 connects to the onboard NINA-W102 WiFi chip. +var ( + UART1 = UART{Bus: sam.SERCOM5_USART, + Buffer: NewRingBuffer(), + Mode: PinSERCOMAlt, + IRQVal: sam.IRQ_SERCOM5, + } +) + +// UART1 pins +const ( + UART_TX_PIN Pin = PA22 + UART_RX_PIN Pin = PA23 +) + +//go:export SERCOM5_IRQHandler +func handleUART1() { + defaultUART1Handler() +} + +// UART2 on the Arduino Nano 33 connects to the normal TX/RX pins. +var ( + UART2 = UART{Bus: sam.SERCOM3_USART, + Buffer: NewRingBuffer(), + Mode: PinSERCOMAlt, + IRQVal: sam.IRQ_SERCOM3, + } +) + +//go:export SERCOM3_IRQHandler +func handleUART2() { + // should reset IRQ + UART2.Receive(byte((UART2.Bus.DATA.Get() & 0xFF))) + UART2.Bus.INTFLAG.SetBits(sam.SERCOM_USART_INTFLAG_RXC) +} + +// I2C pins +const ( + SDA_PIN Pin = A4 // SDA: SERCOM4/PAD[1] + SCL_PIN Pin = A5 // SCL: SERCOM4/PAD[1] +) + +// I2C on the Arduino Nano 33. +var ( + I2C0 = I2C{Bus: sam.SERCOM4_I2CM, + SDA: SDA_PIN, + SCL: SCL_PIN, + PinMode: PinSERCOMAlt} +) + +// SPI pins +const ( + SPI0_SCK_PIN Pin = PB11 // SCK: SERCOM4/PAD[3] + SPI0_MOSI_PIN Pin = PB10 // MOSI: SERCOM4/PAD[2] + SPI0_MISO_PIN Pin = PA12 // MISO: SERCOM4/PAD[0] +) + +// SPI on the Arduino Nano 33. +var ( + SPI0 = SPI{Bus: sam.SERCOM1_SPI} +) + +// I2S pins +const ( + I2S_SCK_PIN Pin = PA10 + I2S_SD_PIN Pin = PA08 + I2S_WS_PIN = NoPin // TODO: figure out what this is on Arduino Nano 33. +) + +// I2S on the Arduino Nano 33. +var ( + I2S0 = I2S{Bus: sam.I2S} +) diff --git a/src/machine/board_circuitplay_express.go b/src/machine/board_circuitplay_express.go index 120f74af..66ffd201 100644 --- a/src/machine/board_circuitplay_express.go +++ b/src/machine/board_circuitplay_express.go @@ -65,6 +65,20 @@ const ( UART_RX_PIN = PB09 // PORTB ) +// UART1 on the Circuit Playground Express. +var ( + UART1 = UART{Bus: sam.SERCOM1_USART, + Buffer: NewRingBuffer(), + Mode: PinSERCOM, + IRQVal: sam.IRQ_SERCOM1, + } +) + +//go:export SERCOM1_IRQHandler +func handleUART1() { + defaultUART1Handler() +} + // I2C pins const ( SDA_PIN = PB02 // I2C0 external diff --git a/src/machine/board_feather-m0.go b/src/machine/board_feather-m0.go index 753e630c..8457e94f 100644 --- a/src/machine/board_feather-m0.go +++ b/src/machine/board_feather-m0.go @@ -48,6 +48,20 @@ const ( UART_RX_PIN = D11 ) +// UART1 on the Feather M0. +var ( + UART1 = UART{Bus: sam.SERCOM1_USART, + Buffer: NewRingBuffer(), + Mode: PinSERCOM, + IRQVal: sam.IRQ_SERCOM1, + } +) + +//go:export SERCOM1_IRQHandler +func handleUART1() { + defaultUART1Handler() +} + // I2C pins const ( SDA_PIN = PA22 // SDA: SERCOM3/PAD[0] diff --git a/src/machine/board_itsybitsy-m0.go b/src/machine/board_itsybitsy-m0.go index 772fefc2..fa2134e8 100644 --- a/src/machine/board_itsybitsy-m0.go +++ b/src/machine/board_itsybitsy-m0.go @@ -48,6 +48,20 @@ const ( UART_RX_PIN = D11 ) +// UART1 on the ItsyBitsy M0. +var ( + UART1 = UART{Bus: sam.SERCOM1_USART, + Buffer: NewRingBuffer(), + Mode: PinSERCOM, + IRQVal: sam.IRQ_SERCOM1, + } +) + +//go:export SERCOM1_IRQHandler +func handleUART1() { + defaultUART1Handler() +} + // I2C pins const ( SDA_PIN = PA22 // SDA: SERCOM3/PAD[0] diff --git a/src/machine/board_trinket.go b/src/machine/board_trinket.go index 552b1571..3d2eaa0a 100644 --- a/src/machine/board_trinket.go +++ b/src/machine/board_trinket.go @@ -39,6 +39,20 @@ const ( UART_RX_PIN = D3 ) +// UART1 on the Trinket M0. +var ( + UART1 = UART{Bus: sam.SERCOM1_USART, + Buffer: NewRingBuffer(), + Mode: PinSERCOM, + IRQVal: sam.IRQ_SERCOM1, + } +) + +//go:export SERCOM1_IRQHandler +func handleUART1() { + defaultUART1Handler() +} + // SPI pins const ( SPI0_SCK_PIN = D3 diff --git a/src/machine/machine_atsamd21.go b/src/machine/machine_atsamd21.go index 5c08b2ee..cd1743ec 100644 --- a/src/machine/machine_atsamd21.go +++ b/src/machine/machine_atsamd21.go @@ -250,14 +250,13 @@ func waitADCSync() { type UART struct { Buffer *RingBuffer Bus *sam.SERCOM_USART_Type + Mode PinMode + IRQVal uint32 } var ( // UART0 is actually a USB CDC interface. UART0 = USBCDC{Buffer: NewRingBuffer()} - - // The first hardware serial port on the SAMD21. Uses the SERCOM0 interface. - UART1 = UART{Bus: sam.SERCOM1_USART, Buffer: NewRingBuffer()} ) const ( @@ -300,6 +299,8 @@ func (uart UART) Configure(config UARTConfig) { txpad = sercomTXPad2 case PA16: txpad = sercomTXPad0 + case PA22: + txpad = sercomTXPad0 default: panic("Invalid TX pin for UART") } @@ -315,13 +316,15 @@ func (uart UART) Configure(config UARTConfig) { rxpad = sercomRXPad3 case PA17: rxpad = sercomRXPad1 + case PA23: + rxpad = sercomRXPad1 default: panic("Invalid RX pin for UART") } // configure pins - config.TX.Configure(PinConfig{Mode: PinSERCOM}) - config.RX.Configure(PinConfig{Mode: PinSERCOM}) + config.TX.Configure(PinConfig{Mode: uart.Mode}) + config.RX.Configure(PinConfig{Mode: uart.Mode}) // reset SERCOM0 uart.Bus.CTRLA.SetBits(sam.SERCOM_USART_CTRLA_SWRST) @@ -372,13 +375,7 @@ func (uart UART) Configure(config UARTConfig) { uart.Bus.INTENSET.Set(sam.SERCOM_USART_INTENSET_RXC) // Enable RX IRQ. - if config.TX == PA10 { - // UART0 - arm.EnableIRQ(sam.IRQ_SERCOM0) - } else { - // UART1 which is the normal default, since UART0 is used for USBCDC. - arm.EnableIRQ(sam.IRQ_SERCOM1) - } + arm.EnableIRQ(uart.IRQVal) } // SetBaudRate sets the communication speed for the UART. @@ -404,8 +401,8 @@ func (uart UART) WriteByte(c byte) error { return nil } -//go:export SERCOM1_IRQHandler -func handleUART1() { +// defaultUART1Handler handles the UART1 IRQ. +func defaultUART1Handler() { // should reset IRQ UART1.Receive(byte((UART1.Bus.DATA.Get() & 0xFF))) UART1.Bus.INTFLAG.SetBits(sam.SERCOM_USART_INTFLAG_RXC) @@ -1182,23 +1179,35 @@ func (usbcdc USBCDC) WriteByte(c byte) error { usbEndpointDescriptors[usb_CDC_ENDPOINT_IN].DeviceDescBank[1].PCKSIZE.ClearBits(usb_DEVICE_PCKSIZE_MULTI_PACKET_SIZE_Mask << usb_DEVICE_PCKSIZE_MULTI_PACKET_SIZE_Pos) // set count of bytes to be sent - usbEndpointDescriptors[usb_CDC_ENDPOINT_IN].DeviceDescBank[1].PCKSIZE.SetBits((1&usb_DEVICE_PCKSIZE_BYTE_COUNT_Mask)< 0 +} + +func (usbcdc USBCDC) RTS() bool { + return (usbLineInfo.lineState & usb_CDC_LINESTATE_RTS) > 0 +} + const ( // these are SAMD21 specific. usb_DEVICE_PCKSIZE_BYTE_COUNT_Pos = 0 @@ -1346,6 +1355,7 @@ func handleUSB() { // Clear the Bank 0 ready flag on Control OUT setEPSTATUSCLR(0, sam.USB_DEVICE_EPSTATUSCLR_BK0RDY) + usbEndpointDescriptors[0].DeviceDescBank[0].PCKSIZE.ClearBits(usb_DEVICE_PCKSIZE_BYTE_COUNT_Mask << usb_DEVICE_PCKSIZE_BYTE_COUNT_Pos) ok := false if (setup.bmRequestType & usb_REQUEST_TYPE) == usb_REQUEST_STANDARD { @@ -1375,19 +1385,24 @@ func handleUSB() { } } - // Now the actual transfer handlers - eptInts := sam.USB_DEVICE.EPINTSMRY.Get() & 0xFE // Remove endpoint number 0 (setup) + // Now the actual transfer handlers, ignore endpoint number 0 (setup) var i uint32 for i = 1; i < uint32(len(endPoints)); i++ { // Check if endpoint has a pending interrupt - if eptInts&(1< 0 { - // yes, so handle flags - epFlags := getEPINTFLAG(i) - setEPINTFLAG(i, epFlags) - - // Endpoint Transfer Complete Interrupt - if (epFlags & sam.USB_DEVICE_EPINTFLAG_TRCPT0) > 0 { - handleEndpoint(i) + epFlags := getEPINTFLAG(i) + if epFlags > 0 { + switch i { + case usb_CDC_ENDPOINT_OUT: + if (epFlags & sam.USB_DEVICE_EPINTFLAG_TRCPT0) > 0 { + handleEndpoint(i) + } + setEPINTFLAG(i, epFlags) + case usb_CDC_ENDPOINT_IN, usb_CDC_ENDPOINT_ACM: + // set bank ready + setEPSTATUSCLR(i, sam.USB_DEVICE_EPSTATUSCLR_BK1RDY) + + // ack transfer complete + setEPINTFLAG(i, sam.USB_DEVICE_EPINTFLAG_TRCPT1) } } } @@ -1403,7 +1418,7 @@ func initEndpoint(ep, config uint32) { usbEndpointDescriptors[ep].DeviceDescBank[1].ADDR.Set(uint32(uintptr(unsafe.Pointer(&udd_ep_in_cache_buffer[ep])))) // set endpoint type - setEPCFG(ep, getEPCFG(ep)|((usb_ENDPOINT_TYPE_INTERRUPT+1)<