machine_esp32s3.go
1 //go:build esp32s3 2 3 package machine 4 5 import ( 6 "device/esp" 7 "errors" 8 "runtime/volatile" 9 "unsafe" 10 ) 11 12 const deviceName = esp.Device 13 14 const xtalClock = 40_000000 // 40MHz 15 const apbClock = 80_000000 // 80MHz 16 const cryptoPWMClock = 160_000000 // 160MHz 17 18 // GetCPUFrequency returns the current CPU frequency of the chip. 19 func GetCPUFrequency() (uint32, error) { 20 switch esp.SYSTEM.GetSYSCLK_CONF_SOC_CLK_SEL() { 21 case 0: 22 return xtalClock / (esp.SYSTEM.GetSYSCLK_CONF_PRE_DIV_CNT() + 1), nil 23 case 1: 24 switch esp.SYSTEM.GetCPU_PER_CONF_CPUPERIOD_SEL() { 25 case 0: 26 return 80e6, nil 27 case 1: 28 return 160e6, nil 29 case 2: 30 // If esp.SYSTEM.GetCPU_PER_CONF_PLL_FREQ_SEL() == 1, this is undefined 31 return 240e6, nil 32 } 33 case 2: 34 //RC Fast Clock 35 return (175e5) / (esp.SYSTEM.GetSYSCLK_CONF_PRE_DIV_CNT() + 1), nil 36 } 37 return 0, errors.New("machine: Unable to determine current cpu frequency") 38 } 39 40 // SetCPUFrequency sets the frequency of the CPU to one of several targets 41 func SetCPUFrequency(frequency uint32) error { 42 // Always assume we are on PLL. Lower frequencies can be set with a different 43 // clock source, but this will change the behavior of APB clock and Crypto PWM 44 // clock 45 //esp.SYSTEM.SetSYSCLK_CONF_SOC_CLK_SEL(1) 46 47 switch frequency { 48 case 80_000000: 49 esp.SYSTEM.SetCPU_PER_CONF_CPUPERIOD_SEL(0) 50 esp.SYSTEM.SetCPU_PER_CONF_PLL_FREQ_SEL(0) // Reduce PLL freq when possible 51 return nil 52 case 160_000000: 53 esp.SYSTEM.SetCPU_PER_CONF_CPUPERIOD_SEL(1) 54 esp.SYSTEM.SetCPU_PER_CONF_PLL_FREQ_SEL(0) 55 return nil 56 case 240_000000: 57 esp.SYSTEM.SetCPU_PER_CONF_PLL_FREQ_SEL(1) // Increase PLL freq when needed 58 esp.SYSTEM.SetCPU_PER_CONF_CPUPERIOD_SEL(2) 59 return nil 60 } 61 return errors.New("machine: Unsupported CPU frequency selected. Supported: 80, 160, 240 MHz") 62 } 63 64 var ( 65 ErrInvalidSPIBus = errors.New("machine: invalid SPI bus") 66 ) 67 68 const ( 69 PinOutput PinMode = iota 70 PinInput 71 PinInputPullup 72 PinInputPulldown 73 ) 74 75 // Hardware pin numbers 76 const ( 77 GPIO0 Pin = 0 78 GPIO1 Pin = 1 79 GPIO2 Pin = 2 80 GPIO3 Pin = 3 81 GPIO4 Pin = 4 82 GPIO5 Pin = 5 83 GPIO6 Pin = 6 84 GPIO7 Pin = 7 85 GPIO8 Pin = 8 86 GPIO9 Pin = 9 87 GPIO10 Pin = 10 88 GPIO11 Pin = 11 89 GPIO12 Pin = 12 90 GPIO13 Pin = 13 91 GPIO14 Pin = 14 92 GPIO15 Pin = 15 93 GPIO16 Pin = 16 94 GPIO17 Pin = 17 95 GPIO18 Pin = 18 96 GPIO19 Pin = 19 97 GPIO20 Pin = 20 98 GPIO21 Pin = 21 99 GPIO26 Pin = 26 100 GPIO27 Pin = 27 101 GPIO28 Pin = 28 102 GPIO29 Pin = 29 103 GPIO30 Pin = 30 104 GPIO31 Pin = 31 105 GPIO32 Pin = 32 106 GPIO33 Pin = 33 107 GPIO34 Pin = 34 108 GPIO35 Pin = 35 109 GPIO36 Pin = 36 110 GPIO37 Pin = 37 111 GPIO38 Pin = 38 112 GPIO39 Pin = 39 113 GPIO40 Pin = 40 114 GPIO41 Pin = 41 115 GPIO42 Pin = 42 116 GPIO43 Pin = 43 117 GPIO44 Pin = 44 118 GPIO45 Pin = 45 119 GPIO46 Pin = 46 120 GPIO47 Pin = 47 121 GPIO48 Pin = 48 122 ) 123 124 // Configure this pin with the given configuration. 125 func (p Pin) Configure(config PinConfig) { 126 // Output function 256 is a special value reserved for use as a regular GPIO 127 // pin. Peripherals (SPI etc) can set a custom output function by calling 128 // lowercase configure() instead with a signal name. 129 p.configure(config, 256) 130 } 131 132 // configure is the same as Configure, but allows for setting a specific input 133 // or output signal. 134 // Signals are always routed through the GPIO matrix for simplicity. Output 135 // signals are configured in FUNCx_OUT_SEL_CFG which selects a particular signal 136 // to output on a given pin. Input signals are configured in FUNCy_IN_SEL_CFG, 137 // which sets the pin to use for a particular input signal. 138 func (p Pin) configure(config PinConfig, signal uint32) { 139 if p == NoPin { 140 // This simplifies pin configuration in peripherals such as SPI. 141 return 142 } 143 144 ioConfig := uint32(0) 145 146 // MCU_SEL: Function 1 is always GPIO 147 ioConfig |= (1 << esp.IO_MUX_GPIO_MCU_SEL_Pos) 148 149 // FUN_IE: Make this pin an input pin (always set for GPIO operation) 150 ioConfig |= esp.IO_MUX_GPIO_FUN_IE 151 152 // DRV: Set drive strength to 20 mA as a default. Pins 17 and 18 are special 153 var drive uint32 154 if p == GPIO17 || p == GPIO18 { 155 drive = 1 // 20 mA 156 } else { 157 drive = 2 // 20 mA 158 } 159 ioConfig |= (drive << esp.IO_MUX_GPIO_FUN_DRV_Pos) 160 161 // WPU/WPD: Select pull mode. 162 if config.Mode == PinInputPullup { 163 ioConfig |= esp.IO_MUX_GPIO_FUN_WPU 164 } else if config.Mode == PinInputPulldown { 165 ioConfig |= esp.IO_MUX_GPIO_FUN_WPD 166 } 167 168 // Set configuration 169 ioRegister := p.ioMuxReg() 170 ioRegister.Set(ioConfig) 171 172 switch config.Mode { 173 case PinOutput: 174 // Set the 'output enable' bit. 175 if p < 32 { 176 esp.GPIO.ENABLE_W1TS.Set(1 << p) 177 } else { 178 esp.GPIO.ENABLE1_W1TS.Set(1 << (p - 32)) 179 } 180 // Set the signal to read the output value from. It can be a peripheral 181 // output signal, or the special value 256 which indicates regular GPIO 182 // usage. 183 p.outFunc().Set(signal) 184 case PinInput, PinInputPullup, PinInputPulldown: 185 // Clear the 'output enable' bit. 186 if p < 32 { 187 esp.GPIO.ENABLE_W1TC.Set(1 << p) 188 } else { 189 esp.GPIO.ENABLE1_W1TC.Set(1 << (p - 32)) 190 } 191 if signal != 256 { 192 // Signal is a peripheral function (not a simple GPIO). Connect this 193 // signal to the pin. 194 // Note that outFunc and inFunc work in the opposite direction. 195 // outFunc configures a pin to use a given output signal, while 196 // inFunc specifies a pin to use to read the signal from. 197 inFunc(signal).Set(esp.GPIO_FUNC_IN_SEL_CFG_SEL | uint32(p)<<esp.GPIO_FUNC_IN_SEL_CFG_IN_SEL_Pos) 198 } 199 } 200 } 201 202 // ioMuxReg returns the IO_MUX_n_REG register used for configuring the io mux for 203 // this pin 204 func (p Pin) ioMuxReg() *volatile.Register32 { 205 return (*volatile.Register32)(unsafe.Add(unsafe.Pointer(&esp.IO_MUX.GPIO0), uintptr(p)*4)) 206 } 207 208 // outFunc returns the FUNCx_OUT_SEL_CFG register used for configuring the 209 // output function selection. 210 func (p Pin) outFunc() *volatile.Register32 { 211 return (*volatile.Register32)(unsafe.Add(unsafe.Pointer(&esp.GPIO.FUNC0_OUT_SEL_CFG), uintptr(p)*4)) 212 } 213 214 // inFunc returns the FUNCy_IN_SEL_CFG register used for configuring the input 215 // function selection. 216 func inFunc(signal uint32) *volatile.Register32 { 217 return (*volatile.Register32)(unsafe.Add(unsafe.Pointer(&esp.GPIO.FUNC0_IN_SEL_CFG), uintptr(signal)*4)) 218 } 219 220 // Set the pin to high or low. 221 // Warning: only use this on an output pin! 222 func (p Pin) Set(value bool) { 223 if value { 224 reg, mask := p.portMaskSet() 225 reg.Set(mask) 226 } else { 227 reg, mask := p.portMaskClear() 228 reg.Set(mask) 229 } 230 } 231 232 // Return the register and mask to enable a given GPIO pin. This can be used to 233 // implement bit-banged drivers. 234 // 235 // Warning: only use this on an output pin! 236 func (p Pin) PortMaskSet() (*uint32, uint32) { 237 reg, mask := p.portMaskSet() 238 return ®.Reg, mask 239 } 240 241 // Return the register and mask to disable a given GPIO pin. This can be used to 242 // implement bit-banged drivers. 243 // 244 // Warning: only use this on an output pin! 245 func (p Pin) PortMaskClear() (*uint32, uint32) { 246 reg, mask := p.portMaskClear() 247 return ®.Reg, mask 248 } 249 250 func (p Pin) portMaskSet() (*volatile.Register32, uint32) { 251 if p < 32 { 252 return &esp.GPIO.OUT_W1TS, 1 << p 253 } else { 254 return &esp.GPIO.OUT1_W1TS, 1 << (p - 32) 255 } 256 } 257 258 func (p Pin) portMaskClear() (*volatile.Register32, uint32) { 259 if p < 32 { 260 return &esp.GPIO.OUT_W1TC, 1 << p 261 } else { 262 return &esp.GPIO.OUT1_W1TC, 1 << (p - 32) 263 } 264 } 265 266 // Get returns the current value of a GPIO pin when the pin is configured as an 267 // input or as an output. 268 func (p Pin) Get() bool { 269 if p < 32 { 270 return esp.GPIO.IN.Get()&(1<<p) != 0 271 } else { 272 return esp.GPIO.IN1.Get()&(1<<(p-32)) != 0 273 } 274 } 275 276 var DefaultUART = UART0 277 278 var ( 279 UART0 = &_UART0 280 _UART0 = UART{Bus: esp.UART0, Buffer: NewRingBuffer()} 281 UART1 = &_UART1 282 _UART1 = UART{Bus: esp.UART1, Buffer: NewRingBuffer()} 283 UART2 = &_UART2 284 _UART2 = UART{Bus: esp.UART2, Buffer: NewRingBuffer()} 285 ) 286 287 type UART struct { 288 Bus *esp.UART_Type 289 Buffer *RingBuffer 290 } 291 292 func (uart *UART) Configure(config UARTConfig) { 293 if config.BaudRate == 0 { 294 config.BaudRate = 115200 295 } 296 // Crystal clock source is selected by default 297 uart.Bus.CLKDIV.Set(xtalClock / config.BaudRate) 298 } 299 300 func (uart *UART) writeByte(b byte) error { 301 for (uart.Bus.STATUS.Get()>>16)&0xff >= 128 { 302 // Read UART_TXFIFO_CNT from the status register, which indicates how 303 // many bytes there are in the transmit buffer. Wait until there are 304 // less than 128 bytes in this buffer (the default buffer size). 305 } 306 uart.Bus.FIFO.Set(uint32(b)) 307 return nil 308 } 309 310 func (uart *UART) flush() {} 311 312 // TODO: SPI