/ firmware / machine / machine_esp32s3.go
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.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.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