github.com/tinygo-org/tinygo@v0.31.3-0.20240404173401-90b0bf646c27/src/machine/machine_esp32.go (about)

     1  //go:build esp32
     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 peripheralClock = 80000000 // 80MHz
    15  
    16  // CPUFrequency returns the current CPU frequency of the chip.
    17  // Currently it is a fixed frequency but it may allow changing in the future.
    18  func CPUFrequency() uint32 {
    19  	return 160e6 // 160MHz
    20  }
    21  
    22  var (
    23  	ErrInvalidSPIBus = errors.New("machine: invalid SPI bus")
    24  )
    25  
    26  const (
    27  	PinOutput PinMode = iota
    28  	PinInput
    29  	PinInputPullup
    30  	PinInputPulldown
    31  )
    32  
    33  // Hardware pin numbers
    34  const (
    35  	GPIO0  Pin = 0
    36  	GPIO1  Pin = 1
    37  	GPIO2  Pin = 2
    38  	GPIO3  Pin = 3
    39  	GPIO4  Pin = 4
    40  	GPIO5  Pin = 5
    41  	GPIO6  Pin = 6
    42  	GPIO7  Pin = 7
    43  	GPIO8  Pin = 8
    44  	GPIO9  Pin = 9
    45  	GPIO10 Pin = 10
    46  	GPIO11 Pin = 11
    47  	GPIO12 Pin = 12
    48  	GPIO13 Pin = 13
    49  	GPIO14 Pin = 14
    50  	GPIO15 Pin = 15
    51  	GPIO16 Pin = 16
    52  	GPIO17 Pin = 17
    53  	GPIO18 Pin = 18
    54  	GPIO19 Pin = 19
    55  	GPIO21 Pin = 21
    56  	GPIO22 Pin = 22
    57  	GPIO23 Pin = 23
    58  	GPIO25 Pin = 25
    59  	GPIO26 Pin = 26
    60  	GPIO27 Pin = 27
    61  	GPIO32 Pin = 32
    62  	GPIO33 Pin = 33
    63  	GPIO34 Pin = 34
    64  	GPIO35 Pin = 35
    65  	GPIO36 Pin = 36
    66  	GPIO37 Pin = 37
    67  	GPIO38 Pin = 38
    68  	GPIO39 Pin = 39
    69  )
    70  
    71  // Configure this pin with the given configuration.
    72  func (p Pin) Configure(config PinConfig) {
    73  	// Output function 256 is a special value reserved for use as a regular GPIO
    74  	// pin. Peripherals (SPI etc) can set a custom output function by calling
    75  	// lowercase configure() instead with a signal name.
    76  	p.configure(config, 256)
    77  }
    78  
    79  // configure is the same as Configure, but allows for setting a specific input
    80  // or output signal.
    81  // Signals are always routed through the GPIO matrix for simplicity. Output
    82  // signals are configured in FUNCx_OUT_SEL_CFG which selects a particular signal
    83  // to output on a given pin. Input signals are configured in FUNCy_IN_SEL_CFG,
    84  // which sets the pin to use for a particular input signal.
    85  func (p Pin) configure(config PinConfig, signal uint32) {
    86  	if p == NoPin {
    87  		// This simplifies pin configuration in peripherals such as SPI.
    88  		return
    89  	}
    90  
    91  	var muxConfig uint32 // The mux configuration.
    92  
    93  	// Configure this pin as a GPIO pin.
    94  	const function = 3 // function 3 is GPIO for every pin
    95  	muxConfig |= (function - 1) << esp.IO_MUX_GPIO0_MCU_SEL_Pos
    96  
    97  	// Make this pin an input pin (always).
    98  	muxConfig |= esp.IO_MUX_GPIO0_FUN_IE
    99  
   100  	// Set drive strength: 0 is lowest, 3 is highest.
   101  	muxConfig |= 2 << esp.IO_MUX_GPIO0_FUN_DRV_Pos
   102  
   103  	// Select pull mode.
   104  	if config.Mode == PinInputPullup {
   105  		muxConfig |= esp.IO_MUX_GPIO0_FUN_WPU
   106  	} else if config.Mode == PinInputPulldown {
   107  		muxConfig |= esp.IO_MUX_GPIO0_FUN_WPD
   108  	}
   109  
   110  	// Configure the pad with the given IO mux configuration.
   111  	p.mux().Set(muxConfig)
   112  
   113  	switch config.Mode {
   114  	case PinOutput:
   115  		// Set the 'output enable' bit.
   116  		if p < 32 {
   117  			esp.GPIO.ENABLE_W1TS.Set(1 << p)
   118  		} else {
   119  			esp.GPIO.ENABLE1_W1TS.Set(1 << (p - 32))
   120  		}
   121  		// Set the signal to read the output value from. It can be a peripheral
   122  		// output signal, or the special value 256 which indicates regular GPIO
   123  		// usage.
   124  		p.outFunc().Set(signal)
   125  	case PinInput, PinInputPullup, PinInputPulldown:
   126  		// Clear the 'output enable' bit.
   127  		if p < 32 {
   128  			esp.GPIO.ENABLE_W1TC.Set(1 << p)
   129  		} else {
   130  			esp.GPIO.ENABLE1_W1TC.Set(1 << (p - 32))
   131  		}
   132  		if signal != 256 {
   133  			// Signal is a peripheral function (not a simple GPIO). Connect this
   134  			// signal to the pin.
   135  			// Note that outFunc and inFunc work in the opposite direction.
   136  			// outFunc configures a pin to use a given output signal, while
   137  			// inFunc specifies a pin to use to read the signal from.
   138  			inFunc(signal).Set(esp.GPIO_FUNC_IN_SEL_CFG_SEL | uint32(p)<<esp.GPIO_FUNC_IN_SEL_CFG_IN_SEL_Pos)
   139  		}
   140  	}
   141  }
   142  
   143  // outFunc returns the FUNCx_OUT_SEL_CFG register used for configuring the
   144  // output function selection.
   145  func (p Pin) outFunc() *volatile.Register32 {
   146  	return (*volatile.Register32)(unsafe.Add(unsafe.Pointer(&esp.GPIO.FUNC0_OUT_SEL_CFG), uintptr(p)*4))
   147  }
   148  
   149  // inFunc returns the FUNCy_IN_SEL_CFG register used for configuring the input
   150  // function selection.
   151  func inFunc(signal uint32) *volatile.Register32 {
   152  	return (*volatile.Register32)(unsafe.Add(unsafe.Pointer(&esp.GPIO.FUNC0_IN_SEL_CFG), uintptr(signal)*4))
   153  }
   154  
   155  // Set the pin to high or low.
   156  // Warning: only use this on an output pin!
   157  func (p Pin) Set(value bool) {
   158  	if value {
   159  		reg, mask := p.portMaskSet()
   160  		reg.Set(mask)
   161  	} else {
   162  		reg, mask := p.portMaskClear()
   163  		reg.Set(mask)
   164  	}
   165  }
   166  
   167  // Return the register and mask to enable a given GPIO pin. This can be used to
   168  // implement bit-banged drivers.
   169  //
   170  // Warning: only use this on an output pin!
   171  func (p Pin) PortMaskSet() (*uint32, uint32) {
   172  	reg, mask := p.portMaskSet()
   173  	return &reg.Reg, mask
   174  }
   175  
   176  // Return the register and mask to disable a given GPIO pin. This can be used to
   177  // implement bit-banged drivers.
   178  //
   179  // Warning: only use this on an output pin!
   180  func (p Pin) PortMaskClear() (*uint32, uint32) {
   181  	reg, mask := p.portMaskClear()
   182  	return &reg.Reg, mask
   183  }
   184  
   185  func (p Pin) portMaskSet() (*volatile.Register32, uint32) {
   186  	if p < 32 {
   187  		return &esp.GPIO.OUT_W1TS, 1 << p
   188  	} else {
   189  		return &esp.GPIO.OUT1_W1TS, 1 << (p - 32)
   190  	}
   191  }
   192  
   193  func (p Pin) portMaskClear() (*volatile.Register32, uint32) {
   194  	if p < 32 {
   195  		return &esp.GPIO.OUT_W1TC, 1 << p
   196  	} else {
   197  		return &esp.GPIO.OUT1_W1TC, 1 << (p - 32)
   198  	}
   199  }
   200  
   201  // Get returns the current value of a GPIO pin when the pin is configured as an
   202  // input or as an output.
   203  func (p Pin) Get() bool {
   204  	if p < 32 {
   205  		return esp.GPIO.IN.Get()&(1<<p) != 0
   206  	} else {
   207  		return esp.GPIO.IN1.Get()&(1<<(p-32)) != 0
   208  	}
   209  }
   210  
   211  // mux returns the I/O mux configuration register corresponding to the given
   212  // GPIO pin.
   213  func (p Pin) mux() *volatile.Register32 {
   214  	// I have no idea whether there is any pattern in the GPIO <-> pad mapping.
   215  	// I couldn't find it.
   216  	switch p {
   217  	case 36:
   218  		return &esp.IO_MUX.GPIO36
   219  	case 37:
   220  		return &esp.IO_MUX.GPIO37
   221  	case 38:
   222  		return &esp.IO_MUX.GPIO38
   223  	case 39:
   224  		return &esp.IO_MUX.GPIO39
   225  	case 34:
   226  		return &esp.IO_MUX.GPIO34
   227  	case 35:
   228  		return &esp.IO_MUX.GPIO35
   229  	case 32:
   230  		return &esp.IO_MUX.GPIO32
   231  	case 33:
   232  		return &esp.IO_MUX.GPIO33
   233  	case 25:
   234  		return &esp.IO_MUX.GPIO25
   235  	case 26:
   236  		return &esp.IO_MUX.GPIO26
   237  	case 27:
   238  		return &esp.IO_MUX.GPIO27
   239  	case 14:
   240  		return &esp.IO_MUX.GPIO14
   241  	case 12:
   242  		return &esp.IO_MUX.GPIO12
   243  	case 13:
   244  		return &esp.IO_MUX.GPIO13
   245  	case 15:
   246  		return &esp.IO_MUX.GPIO15
   247  	case 2:
   248  		return &esp.IO_MUX.GPIO2
   249  	case 0:
   250  		return &esp.IO_MUX.GPIO0
   251  	case 4:
   252  		return &esp.IO_MUX.GPIO4
   253  	case 16:
   254  		return &esp.IO_MUX.GPIO16
   255  	case 17:
   256  		return &esp.IO_MUX.GPIO17
   257  	case 9:
   258  		return &esp.IO_MUX.GPIO9
   259  	case 10:
   260  		return &esp.IO_MUX.GPIO10
   261  	case 11:
   262  		return &esp.IO_MUX.GPIO11
   263  	case 6:
   264  		return &esp.IO_MUX.GPIO6
   265  	case 7:
   266  		return &esp.IO_MUX.GPIO7
   267  	case 8:
   268  		return &esp.IO_MUX.GPIO8
   269  	case 5:
   270  		return &esp.IO_MUX.GPIO5
   271  	case 18:
   272  		return &esp.IO_MUX.GPIO18
   273  	case 19:
   274  		return &esp.IO_MUX.GPIO19
   275  	case 20:
   276  		return &esp.IO_MUX.GPIO20
   277  	case 21:
   278  		return &esp.IO_MUX.GPIO21
   279  	case 22:
   280  		return &esp.IO_MUX.GPIO22
   281  	case 3:
   282  		return &esp.IO_MUX.GPIO3
   283  	case 1:
   284  		return &esp.IO_MUX.GPIO1
   285  	case 23:
   286  		return &esp.IO_MUX.GPIO23
   287  	case 24:
   288  		return &esp.IO_MUX.GPIO24
   289  	default:
   290  		return nil
   291  	}
   292  }
   293  
   294  var DefaultUART = UART0
   295  
   296  var (
   297  	UART0  = &_UART0
   298  	_UART0 = UART{Bus: esp.UART0, Buffer: NewRingBuffer()}
   299  	UART1  = &_UART1
   300  	_UART1 = UART{Bus: esp.UART1, Buffer: NewRingBuffer()}
   301  	UART2  = &_UART2
   302  	_UART2 = UART{Bus: esp.UART2, Buffer: NewRingBuffer()}
   303  )
   304  
   305  type UART struct {
   306  	Bus    *esp.UART_Type
   307  	Buffer *RingBuffer
   308  }
   309  
   310  func (uart *UART) Configure(config UARTConfig) {
   311  	if config.BaudRate == 0 {
   312  		config.BaudRate = 115200
   313  	}
   314  	uart.Bus.CLKDIV.Set(peripheralClock / config.BaudRate)
   315  }
   316  
   317  func (uart *UART) writeByte(b byte) error {
   318  	for (uart.Bus.STATUS.Get()>>16)&0xff >= 128 {
   319  		// Read UART_TXFIFO_CNT from the status register, which indicates how
   320  		// many bytes there are in the transmit buffer. Wait until there are
   321  		// less than 128 bytes in this buffer (the default buffer size).
   322  	}
   323  	// Write to the TX_FIFO register.
   324  	(*volatile.Register8)(unsafe.Add(unsafe.Pointer(uart.Bus), 0x200C0000)).Set(b)
   325  	return nil
   326  }
   327  
   328  func (uart *UART) flush() {}
   329  
   330  // Serial Peripheral Interface on the ESP32.
   331  type SPI struct {
   332  	Bus *esp.SPI_Type
   333  }
   334  
   335  var (
   336  	// SPI0 and SPI1 are reserved for use by the caching system etc.
   337  	SPI2 = SPI{esp.SPI2}
   338  	SPI3 = SPI{esp.SPI3}
   339  )
   340  
   341  // SPIConfig configures a SPI peripheral on the ESP32. Make sure to set at least
   342  // SCK, SDO and SDI (possibly to NoPin if not in use). The default for LSBFirst
   343  // (false) and Mode (0) are good for most applications. The frequency defaults
   344  // to 1MHz if not set but can be configured up to 40MHz. Possible values are
   345  // 40MHz and integer divisions from 40MHz such as 20MHz, 13.3MHz, 10MHz, 8MHz,
   346  // etc.
   347  type SPIConfig struct {
   348  	Frequency uint32
   349  	SCK       Pin
   350  	SDO       Pin
   351  	SDI       Pin
   352  	LSBFirst  bool
   353  	Mode      uint8
   354  }
   355  
   356  // Configure and make the SPI peripheral ready to use.
   357  func (spi SPI) Configure(config SPIConfig) error {
   358  	if config.Frequency == 0 {
   359  		config.Frequency = 4e6 // default to 4MHz
   360  	}
   361  
   362  	// Configure the SPI clock. This assumes a peripheral clock of 80MHz.
   363  	var clockReg uint32
   364  	if config.Frequency > 40e6 {
   365  		// Don't use a prescaler, but directly connect to the APB clock. This
   366  		// results in a SPI clock frequency of 40MHz.
   367  		clockReg |= esp.SPI_CLOCK_CLK_EQU_SYSCLK
   368  	} else {
   369  		// Use a prescaler for frequencies below 40MHz. They will get rounded
   370  		// down to the next possible frequency (20MHz, 13.3MHz, 10MHz, 8MHz,
   371  		// 6.7MHz, 5.7MHz, 5MHz, etc).
   372  		// This code is much simpler than how ESP-IDF configures the frequency,
   373  		// but should be just as accurate. The only exception is for frequencies
   374  		// below 4883Hz, which will need special support.
   375  		if config.Frequency < 4883 {
   376  			// The current lower limit is 4883Hz.
   377  			// The hardware supports lower frequencies by setting the h and n
   378  			// variables, but that's not yet implemented.
   379  			config.Frequency = 4883
   380  		}
   381  		// The prescaler value is 40e6 / config.Frequency, but rounded up so
   382  		// that the actual frequency is never higher than the frequency
   383  		// requested in config.Frequency.
   384  		var (
   385  			pre uint32 = (40e6 + config.Frequency - 1) / config.Frequency
   386  			n   uint32 = 2 // this value seems to equal the number of ticks per SPI clock tick
   387  			h   uint32 = 1 // must be half of n according to the formula in the reference manual
   388  			l   uint32 = n // must equal n according to the reference manual
   389  		)
   390  		clockReg |= (pre - 1) << esp.SPI_CLOCK_CLKDIV_PRE_Pos
   391  		clockReg |= (n - 1) << esp.SPI_CLOCK_CLKCNT_N_Pos
   392  		clockReg |= (h - 1) << esp.SPI_CLOCK_CLKCNT_H_Pos
   393  		clockReg |= (l - 1) << esp.SPI_CLOCK_CLKCNT_L_Pos
   394  	}
   395  	spi.Bus.CLOCK.Set(clockReg)
   396  
   397  	// SPI_CTRL_REG controls bit order.
   398  	var ctrlReg uint32
   399  	if config.LSBFirst {
   400  		ctrlReg |= esp.SPI_CTRL_WR_BIT_ORDER
   401  		ctrlReg |= esp.SPI_CTRL_RD_BIT_ORDER
   402  	}
   403  	spi.Bus.CTRL.Set(ctrlReg)
   404  
   405  	// SPI_CTRL2_REG, SPI_USER_REG and SPI_PIN_REG control SPI clock polarity
   406  	// (mode), among others.
   407  	var ctrl2Reg, userReg, pinReg uint32
   408  	// For mode configuration, see table 29 in the reference manual (page 128).
   409  	switch config.Mode {
   410  	case 0:
   411  	case 1:
   412  		userReg |= esp.SPI_USER_CK_OUT_EDGE
   413  	case 2:
   414  		userReg |= esp.SPI_USER_CK_OUT_EDGE
   415  		pinReg |= esp.SPI_PIN_CK_IDLE_EDGE
   416  	case 3:
   417  		pinReg |= esp.SPI_PIN_CK_IDLE_EDGE
   418  	}
   419  	// Enable full-duplex communication.
   420  	userReg |= esp.SPI_USER_DOUTDIN
   421  	userReg |= esp.SPI_USER_USR_MOSI
   422  	// Write values to registers.
   423  	spi.Bus.CTRL2.Set(ctrl2Reg)
   424  	spi.Bus.USER.Set(userReg)
   425  	spi.Bus.PIN.Set(pinReg)
   426  
   427  	// Configure pins.
   428  	// TODO: use direct output if possible, if the configured pins match the
   429  	// possible direct configurations (e.g. for SPI2, when SCK is pin 14 etc).
   430  	if spi.Bus == esp.SPI2 {
   431  		config.SCK.configure(PinConfig{Mode: PinOutput}, 8)  // HSPICLK
   432  		config.SDI.configure(PinConfig{Mode: PinInput}, 9)   // HSPIQ
   433  		config.SDO.configure(PinConfig{Mode: PinOutput}, 10) // HSPID
   434  	} else if spi.Bus == esp.SPI3 {
   435  		config.SCK.configure(PinConfig{Mode: PinOutput}, 63) // VSPICLK
   436  		config.SDI.configure(PinConfig{Mode: PinInput}, 64)  // VSPIQ
   437  		config.SDO.configure(PinConfig{Mode: PinOutput}, 65) // VSPID
   438  	} else {
   439  		// Don't know how to configure this bus.
   440  		return ErrInvalidSPIBus
   441  	}
   442  
   443  	return nil
   444  }
   445  
   446  // Transfer writes/reads a single byte using the SPI interface. If you need to
   447  // transfer larger amounts of data, Tx will be faster.
   448  func (spi SPI) Transfer(w byte) (byte, error) {
   449  	spi.Bus.MISO_DLEN.Set(7 << esp.SPI_MISO_DLEN_USR_MISO_DBITLEN_Pos)
   450  	spi.Bus.MOSI_DLEN.Set(7 << esp.SPI_MOSI_DLEN_USR_MOSI_DBITLEN_Pos)
   451  
   452  	spi.Bus.W0.Set(uint32(w))
   453  
   454  	// Send/receive byte.
   455  	spi.Bus.CMD.Set(esp.SPI_CMD_USR)
   456  	for spi.Bus.CMD.Get() != 0 {
   457  	}
   458  
   459  	// The received byte is stored in W0.
   460  	return byte(spi.Bus.W0.Get()), nil
   461  }
   462  
   463  // Tx handles read/write operation for SPI interface. Since SPI is a syncronous write/read
   464  // interface, there must always be the same number of bytes written as bytes read.
   465  // This is accomplished by sending zero bits if r is bigger than w or discarding
   466  // the incoming data if w is bigger than r.
   467  func (spi SPI) Tx(w, r []byte) error {
   468  	toTransfer := len(w)
   469  	if len(r) > toTransfer {
   470  		toTransfer = len(r)
   471  	}
   472  
   473  	for toTransfer != 0 {
   474  		// Do only 64 bytes at a time.
   475  		chunkSize := toTransfer
   476  		if chunkSize > 64 {
   477  			chunkSize = 64
   478  		}
   479  
   480  		// Fill tx buffer.
   481  		transferWords := (*[16]volatile.Register32)(unsafe.Pointer(uintptr(unsafe.Pointer(&spi.Bus.W0))))
   482  		if len(w) >= 64 {
   483  			// We can fill the entire 64-byte transfer buffer with data.
   484  			// This loop is slightly faster than the loop below.
   485  			for i := 0; i < 16; i++ {
   486  				word := uint32(w[i*4])<<0 | uint32(w[i*4+1])<<8 | uint32(w[i*4+2])<<16 | uint32(w[i*4+3])<<24
   487  				transferWords[i].Set(word)
   488  			}
   489  		} else {
   490  			// We can't fill the entire transfer buffer, so we need to be a bit
   491  			// more careful.
   492  			// Note that parts of the transfer buffer that aren't used still
   493  			// need to be set to zero, otherwise we might be transferring
   494  			// garbage from a previous transmission if w is smaller than r.
   495  			for i := 0; i < 16; i++ {
   496  				var word uint32
   497  				if i*4+3 < len(w) {
   498  					word |= uint32(w[i*4+3]) << 24
   499  				}
   500  				if i*4+2 < len(w) {
   501  					word |= uint32(w[i*4+2]) << 16
   502  				}
   503  				if i*4+1 < len(w) {
   504  					word |= uint32(w[i*4+1]) << 8
   505  				}
   506  				if i*4+0 < len(w) {
   507  					word |= uint32(w[i*4+0]) << 0
   508  				}
   509  				transferWords[i].Set(word)
   510  			}
   511  		}
   512  
   513  		// Do the transfer.
   514  		spi.Bus.MISO_DLEN.Set((uint32(chunkSize)*8 - 1) << esp.SPI_MISO_DLEN_USR_MISO_DBITLEN_Pos)
   515  		spi.Bus.MOSI_DLEN.Set((uint32(chunkSize)*8 - 1) << esp.SPI_MOSI_DLEN_USR_MOSI_DBITLEN_Pos)
   516  		spi.Bus.CMD.Set(esp.SPI_CMD_USR)
   517  		for spi.Bus.CMD.Get() != 0 {
   518  		}
   519  
   520  		// Read rx buffer.
   521  		rxSize := 64
   522  		if rxSize > len(r) {
   523  			rxSize = len(r)
   524  		}
   525  		for i := 0; i < rxSize; i++ {
   526  			r[i] = byte(transferWords[i/4].Get() >> ((i % 4) * 8))
   527  		}
   528  
   529  		// Cut off some part of the output buffer so the next iteration we will
   530  		// only send the remaining bytes.
   531  		if len(w) < chunkSize {
   532  			w = nil
   533  		} else {
   534  			w = w[chunkSize:]
   535  		}
   536  		if len(r) < chunkSize {
   537  			r = nil
   538  		} else {
   539  			r = r[chunkSize:]
   540  		}
   541  		toTransfer -= chunkSize
   542  	}
   543  
   544  	return nil
   545  }