From 8cbbbb0e767c977f38977af0da8766e5fe2a1c84 Mon Sep 17 00:00:00 2001 From: Ron Evans Date: Sun, 20 Jan 2019 12:30:13 +0100 Subject: [PATCH] machine/atsamd21: improve GPIO config to support all 32 pins on PORTA as well as correct handling for OUTPUT and SERCOM pin modes Signed-off-by: Ron Evans --- src/machine/machine_atsamd21g18.go | 261 ++++++++++++++++++++++++++++- 1 file changed, 256 insertions(+), 5 deletions(-) diff --git a/src/machine/machine_atsamd21g18.go b/src/machine/machine_atsamd21g18.go index 1c1ed83e..e9dc8766 100644 --- a/src/machine/machine_atsamd21g18.go +++ b/src/machine/machine_atsamd21g18.go @@ -1,6 +1,6 @@ // +build sam,atsamd21g18a -// Peripheral abstraction layer for the atsamd21g18. +// Peripheral abstraction layer for the atsamd21. // // Datasheet: // http://ww1.microchip.com/downloads/en/DeviceDoc/SAMD21-Family-DataSheet-DS40001882D.pdf @@ -16,16 +16,45 @@ const CPU_FREQUENCY = 48000000 type GPIOMode uint8 const ( - GPIO_INPUT = 0 - GPIO_OUTPUT = 1 + GPIO_ANALOG = 1 + GPIO_SERCOM = 2 + GPIO_SERCOM_ALT = 3 + GPIO_TIMER = 4 + GPIO_TIMER_ALT = 5 + GPIO_COM = 6 + GPIO_AC_CLK = 7 + GPIO_DIGITAL = 8 + GPIO_INPUT = 9 + GPIO_INPUT_PULLUP = 10 + GPIO_OUTPUT = 11 + GPIO_PWM = GPIO_TIMER + GPIO_PWM_ALT = GPIO_TIMER_ALT ) // Configure this pin with the given configuration. func (p GPIO) Configure(config GPIOConfig) { - if config.Mode == GPIO_OUTPUT { // set output bit + switch config.Mode { + case GPIO_OUTPUT: sam.PORT.DIRSET0 = (1 << p.Pin) - } else { + // output is also set to input enable so pin can read back its own value + p.setPinCfg(sam.PORT_PINCFG0_INEN) + + case GPIO_INPUT: sam.PORT.DIRCLR0 = (1 << p.Pin) + p.setPinCfg(sam.PORT_PINCFG0_INEN) + + case GPIO_SERCOM: + if p.Pin&1 > 0 { + // odd pin, so save the even pins + val := p.getPMux() & sam.PORT_PMUX0_PMUXE_Msk + p.setPMux(val | (GPIO_SERCOM << sam.PORT_PMUX0_PMUXO_Pos)) + } else { + // even pin, so save the odd pins + val := p.getPMux() & sam.PORT_PMUX0_PMUXO_Msk + p.setPMux(val | (GPIO_SERCOM << sam.PORT_PMUX0_PMUXE_Pos)) + } + // enable port config + p.setPinCfg(sam.PORT_PINCFG0_PMUXEN | sam.PORT_PINCFG0_DRVSTR) } } @@ -43,3 +72,225 @@ func (p GPIO) Set(high bool) { sam.PORT.OUTCLR0 = (1 << p.Pin) } } + +// getPMux returns the value for the correct PMUX register for this pin. +func (p GPIO) getPMux() sam.RegValue8 { + pin := p.Pin >> 1 + switch pin { + case 0: + return sam.PORT.PMUX0_0 + case 1: + return sam.PORT.PMUX0_1 + case 2: + return sam.PORT.PMUX0_2 + case 3: + return sam.PORT.PMUX0_3 + case 4: + return sam.PORT.PMUX0_4 + case 5: + return sam.PORT.PMUX0_5 + case 6: + return sam.PORT.PMUX0_6 + case 7: + return sam.PORT.PMUX0_7 + case 8: + return sam.PORT.PMUX0_8 + case 9: + return sam.PORT.PMUX0_9 + case 10: + return sam.PORT.PMUX0_10 + case 11: + return sam.PORT.PMUX0_11 + case 12: + return sam.PORT.PMUX0_12 + case 13: + return sam.PORT.PMUX0_13 + case 14: + return sam.PORT.PMUX0_14 + case 15: + return sam.PORT.PMUX0_15 + default: + return 0 + } +} + +// setPMux sets the value for the correct PMUX register for this pin. +func (p GPIO) setPMux(val sam.RegValue8) { + pin := p.Pin >> 1 + switch pin { + case 0: + sam.PORT.PMUX0_0 = val + case 1: + sam.PORT.PMUX0_1 = val + case 2: + sam.PORT.PMUX0_2 = val + case 3: + sam.PORT.PMUX0_3 = val + case 4: + sam.PORT.PMUX0_4 = val + case 5: + sam.PORT.PMUX0_5 = val + case 6: + sam.PORT.PMUX0_6 = val + case 7: + sam.PORT.PMUX0_7 = val + case 8: + sam.PORT.PMUX0_8 = val + case 9: + sam.PORT.PMUX0_9 = val + case 10: + sam.PORT.PMUX0_10 = val + case 11: + sam.PORT.PMUX0_11 = val + case 12: + sam.PORT.PMUX0_12 = val + case 13: + sam.PORT.PMUX0_13 = val + case 14: + sam.PORT.PMUX0_14 = val + case 15: + sam.PORT.PMUX0_15 = val + } +} + +// getPinCfg returns the value for the correct PINCFG register for this pin. +func (p GPIO) getPinCfg() sam.RegValue8 { + switch p.Pin { + case 0: + return sam.PORT.PINCFG0_0 + case 1: + return sam.PORT.PINCFG0_1 + case 2: + return sam.PORT.PINCFG0_2 + case 3: + return sam.PORT.PINCFG0_3 + case 4: + return sam.PORT.PINCFG0_4 + case 5: + return sam.PORT.PINCFG0_5 + case 6: + return sam.PORT.PINCFG0_6 + case 7: + return sam.PORT.PINCFG0_7 + case 8: + return sam.PORT.PINCFG0_8 + case 9: + return sam.PORT.PINCFG0_9 + case 10: + return sam.PORT.PINCFG0_10 + case 11: + return sam.PORT.PINCFG0_11 + case 12: + return sam.PORT.PINCFG0_12 + case 13: + return sam.PORT.PINCFG0_13 + case 14: + return sam.PORT.PINCFG0_14 + case 15: + return sam.PORT.PINCFG0_15 + case 16: + return sam.PORT.PINCFG0_16 + case 17: + return sam.PORT.PINCFG0_17 + case 18: + return sam.PORT.PINCFG0_18 + case 19: + return sam.PORT.PINCFG0_19 + case 20: + return sam.PORT.PINCFG0_20 + case 21: + return sam.PORT.PINCFG0_21 + case 22: + return sam.PORT.PINCFG0_22 + case 23: + return sam.PORT.PINCFG0_23 + case 24: + return sam.PORT.PINCFG0_24 + case 25: + return sam.PORT.PINCFG0_25 + case 26: + return sam.PORT.PINCFG0_26 + case 27: + return sam.PORT.PINCFG0_27 + case 28: + return sam.PORT.PINCFG0_28 + case 29: + return sam.PORT.PINCFG0_29 + case 30: + return sam.PORT.PINCFG0_30 + case 31: + return sam.PORT.PINCFG0_31 + default: + return 0 + } +} + +// setPinCfg sets the value for the correct PINCFG register for this pin. +func (p GPIO) setPinCfg(val sam.RegValue8) { + switch p.Pin { + case 0: + sam.PORT.PINCFG0_0 = val + case 1: + sam.PORT.PINCFG0_1 = val + case 2: + sam.PORT.PINCFG0_2 = val + case 3: + sam.PORT.PINCFG0_3 = val + case 4: + sam.PORT.PINCFG0_4 = val + case 5: + sam.PORT.PINCFG0_5 = val + case 6: + sam.PORT.PINCFG0_6 = val + case 7: + sam.PORT.PINCFG0_7 = val + case 8: + sam.PORT.PINCFG0_8 = val + case 9: + sam.PORT.PINCFG0_9 = val + case 10: + sam.PORT.PINCFG0_10 = val + case 11: + sam.PORT.PINCFG0_11 = val + case 12: + sam.PORT.PINCFG0_12 = val + case 13: + sam.PORT.PINCFG0_13 = val + case 14: + sam.PORT.PINCFG0_14 = val + case 15: + sam.PORT.PINCFG0_15 = val + case 16: + sam.PORT.PINCFG0_16 = val + case 17: + sam.PORT.PINCFG0_17 = val + case 18: + sam.PORT.PINCFG0_18 = val + case 19: + sam.PORT.PINCFG0_19 = val + case 20: + sam.PORT.PINCFG0_20 = val + case 21: + sam.PORT.PINCFG0_21 = val + case 22: + sam.PORT.PINCFG0_22 = val + case 23: + sam.PORT.PINCFG0_23 = val + case 24: + sam.PORT.PINCFG0_24 = val + case 25: + sam.PORT.PINCFG0_25 = val + case 26: + sam.PORT.PINCFG0_26 = val + case 27: + sam.PORT.PINCFG0_27 = val + case 28: + sam.PORT.PINCFG0_28 = val + case 29: + sam.PORT.PINCFG0_29 = val + case 30: + sam.PORT.PINCFG0_30 = val + case 31: + sam.PORT.PINCFG0_31 = val + } +}