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

     1  //go:build nrf
     2  
     3  package machine
     4  
     5  import (
     6  	"bytes"
     7  	"device/nrf"
     8  	"encoding/binary"
     9  	"runtime/interrupt"
    10  	"unsafe"
    11  )
    12  
    13  const deviceName = nrf.Device
    14  
    15  var deviceID [8]byte
    16  
    17  // DeviceID returns an identifier that is unique within
    18  // a particular chipset.
    19  //
    20  // The identity is one burnt into the MCU itself, or the
    21  // flash chip at time of manufacture.
    22  //
    23  // It's possible that two different vendors may allocate
    24  // the same DeviceID, so callers should take this into
    25  // account if needing to generate a globally unique id.
    26  //
    27  // The length of the hardware ID is vendor-specific, but
    28  // 8 bytes (64 bits) is common.
    29  func DeviceID() []byte {
    30  	words := make([]uint32, 2)
    31  	words[0] = nrf.FICR.DEVICEID[0].Get()
    32  	words[1] = nrf.FICR.DEVICEID[1].Get()
    33  
    34  	for i := 0; i < 8; i++ {
    35  		shift := (i % 4) * 8
    36  		w := i / 4
    37  		deviceID[i] = byte(words[w] >> shift)
    38  	}
    39  
    40  	return deviceID[:]
    41  }
    42  
    43  const (
    44  	PinInput         PinMode = (nrf.GPIO_PIN_CNF_DIR_Input << nrf.GPIO_PIN_CNF_DIR_Pos) | (nrf.GPIO_PIN_CNF_INPUT_Connect << nrf.GPIO_PIN_CNF_INPUT_Pos)
    45  	PinInputPullup   PinMode = PinInput | (nrf.GPIO_PIN_CNF_PULL_Pullup << nrf.GPIO_PIN_CNF_PULL_Pos)
    46  	PinInputPulldown PinMode = PinInput | (nrf.GPIO_PIN_CNF_PULL_Pulldown << nrf.GPIO_PIN_CNF_PULL_Pos)
    47  	PinOutput        PinMode = (nrf.GPIO_PIN_CNF_DIR_Output << nrf.GPIO_PIN_CNF_DIR_Pos) | (nrf.GPIO_PIN_CNF_INPUT_Connect << nrf.GPIO_PIN_CNF_INPUT_Pos)
    48  )
    49  
    50  type PinChange uint8
    51  
    52  // Pin change interrupt constants for SetInterrupt.
    53  const (
    54  	PinRising  PinChange = nrf.GPIOTE_CONFIG_POLARITY_LoToHi
    55  	PinFalling PinChange = nrf.GPIOTE_CONFIG_POLARITY_HiToLo
    56  	PinToggle  PinChange = nrf.GPIOTE_CONFIG_POLARITY_Toggle
    57  )
    58  
    59  // Callbacks to be called for pins configured with SetInterrupt.
    60  var pinCallbacks [len(nrf.GPIOTE.CONFIG)]func(Pin)
    61  
    62  // Configure this pin with the given configuration.
    63  func (p Pin) Configure(config PinConfig) {
    64  	cfg := config.Mode | nrf.GPIO_PIN_CNF_DRIVE_S0S1 | nrf.GPIO_PIN_CNF_SENSE_Disabled
    65  	port, pin := p.getPortPin()
    66  	port.PIN_CNF[pin].Set(uint32(cfg))
    67  }
    68  
    69  // Set the pin to high or low.
    70  // Warning: only use this on an output pin!
    71  func (p Pin) Set(high bool) {
    72  	port, pin := p.getPortPin()
    73  	if high {
    74  		port.OUTSET.Set(1 << pin)
    75  	} else {
    76  		port.OUTCLR.Set(1 << pin)
    77  	}
    78  }
    79  
    80  // Return the register and mask to enable a given GPIO pin. This can be used to
    81  // implement bit-banged drivers.
    82  func (p Pin) PortMaskSet() (*uint32, uint32) {
    83  	port, pin := p.getPortPin()
    84  	return &port.OUTSET.Reg, 1 << pin
    85  }
    86  
    87  // Return the register and mask to disable a given port. This can be used to
    88  // implement bit-banged drivers.
    89  func (p Pin) PortMaskClear() (*uint32, uint32) {
    90  	port, pin := p.getPortPin()
    91  	return &port.OUTCLR.Reg, 1 << pin
    92  }
    93  
    94  // Get returns the current value of a GPIO pin when the pin is configured as an
    95  // input or as an output.
    96  func (p Pin) Get() bool {
    97  	port, pin := p.getPortPin()
    98  	return (port.IN.Get()>>pin)&1 != 0
    99  }
   100  
   101  // SetInterrupt sets an interrupt to be executed when a particular pin changes
   102  // state. The pin should already be configured as an input, including a pull up
   103  // or down if no external pull is provided.
   104  //
   105  // This call will replace a previously set callback on this pin. You can pass a
   106  // nil func to unset the pin change interrupt. If you do so, the change
   107  // parameter is ignored and can be set to any value (such as 0).
   108  func (p Pin) SetInterrupt(change PinChange, callback func(Pin)) error {
   109  	// Some variables to easily check whether a channel was already configured
   110  	// as an event channel for the given pin.
   111  	// This is not just an optimization, this is requred: the datasheet says
   112  	// that configuring more than one channel for a given pin results in
   113  	// unpredictable behavior.
   114  	expectedConfigMask := uint32(nrf.GPIOTE_CONFIG_MODE_Msk | nrf.GPIOTE_CONFIG_PSEL_Msk)
   115  	expectedConfig := nrf.GPIOTE_CONFIG_MODE_Event<<nrf.GPIOTE_CONFIG_MODE_Pos | uint32(p)<<nrf.GPIOTE_CONFIG_PSEL_Pos
   116  
   117  	foundChannel := false
   118  	for i := range nrf.GPIOTE.CONFIG {
   119  		config := nrf.GPIOTE.CONFIG[i].Get()
   120  		if config == 0 || config&expectedConfigMask == expectedConfig {
   121  			// Found an empty GPIOTE channel or one that was already configured
   122  			// for this pin.
   123  			if callback == nil {
   124  				// Disable this channel.
   125  				nrf.GPIOTE.INTENCLR.Set(uint32(1 << uint(i)))
   126  				pinCallbacks[i] = nil
   127  				return nil
   128  			}
   129  			// Enable this channel with the given callback.
   130  			nrf.GPIOTE.INTENCLR.Set(uint32(1 << uint(i)))
   131  			nrf.GPIOTE.CONFIG[i].Set(nrf.GPIOTE_CONFIG_MODE_Event<<nrf.GPIOTE_CONFIG_MODE_Pos |
   132  				uint32(p)<<nrf.GPIOTE_CONFIG_PSEL_Pos |
   133  				uint32(change)<<nrf.GPIOTE_CONFIG_POLARITY_Pos)
   134  			pinCallbacks[i] = callback
   135  			nrf.GPIOTE.INTENSET.Set(uint32(1 << uint(i)))
   136  			foundChannel = true
   137  			break
   138  		}
   139  	}
   140  
   141  	if !foundChannel {
   142  		return ErrNoPinChangeChannel
   143  	}
   144  
   145  	// Set and enable the GPIOTE interrupt. It's not a problem if this happens
   146  	// more than once.
   147  	interrupt.New(nrf.IRQ_GPIOTE, func(interrupt.Interrupt) {
   148  		for i := range nrf.GPIOTE.EVENTS_IN {
   149  			if nrf.GPIOTE.EVENTS_IN[i].Get() != 0 {
   150  				nrf.GPIOTE.EVENTS_IN[i].Set(0)
   151  				pin := Pin((nrf.GPIOTE.CONFIG[i].Get() & nrf.GPIOTE_CONFIG_PSEL_Msk) >> nrf.GPIOTE_CONFIG_PSEL_Pos)
   152  				pinCallbacks[i](pin)
   153  			}
   154  		}
   155  	}).Enable()
   156  
   157  	// Everything was configured correctly.
   158  	return nil
   159  }
   160  
   161  // UART on the NRF.
   162  type UART struct {
   163  	Buffer *RingBuffer
   164  }
   165  
   166  // UART
   167  var (
   168  	// UART0 is the hardware UART on the NRF SoC.
   169  	_UART0 = UART{Buffer: NewRingBuffer()}
   170  	UART0  = &_UART0
   171  )
   172  
   173  // Configure the UART.
   174  func (uart *UART) Configure(config UARTConfig) {
   175  	// Default baud rate to 115200.
   176  	if config.BaudRate == 0 {
   177  		config.BaudRate = 115200
   178  	}
   179  
   180  	uart.SetBaudRate(config.BaudRate)
   181  
   182  	// Set TX and RX pins
   183  	if config.TX == 0 && config.RX == 0 {
   184  		// Use default pins
   185  		uart.setPins(UART_TX_PIN, UART_RX_PIN)
   186  	} else {
   187  		uart.setPins(config.TX, config.RX)
   188  	}
   189  
   190  	nrf.UART0.ENABLE.Set(nrf.UART_ENABLE_ENABLE_Enabled)
   191  	nrf.UART0.TASKS_STARTTX.Set(1)
   192  	nrf.UART0.TASKS_STARTRX.Set(1)
   193  	nrf.UART0.INTENSET.Set(nrf.UART_INTENSET_RXDRDY_Msk)
   194  
   195  	// Enable RX IRQ.
   196  	intr := interrupt.New(nrf.IRQ_UART0, _UART0.handleInterrupt)
   197  	intr.SetPriority(0xc0) // low priority
   198  	intr.Enable()
   199  }
   200  
   201  // SetBaudRate sets the communication speed for the UART.
   202  func (uart *UART) SetBaudRate(br uint32) {
   203  	// Magic: calculate 'baudrate' register from the input number.
   204  	// Every value listed in the datasheet will be converted to the
   205  	// correct register value, except for 192600. I suspect the value
   206  	// listed in the nrf52 datasheet (0x0EBED000) is incorrectly rounded
   207  	// and should be 0x0EBEE000, as the nrf51 datasheet lists the
   208  	// nonrounded value 0x0EBEDFA4.
   209  	// Some background:
   210  	// https://devzone.nordicsemi.com/f/nordic-q-a/391/uart-baudrate-register-values/2046#2046
   211  	rate := uint32((uint64(br/400)*uint64(400*0xffffffff/16000000) + 0x800) & 0xffffff000)
   212  
   213  	nrf.UART0.BAUDRATE.Set(rate)
   214  }
   215  
   216  // WriteByte writes a byte of data to the UART.
   217  func (uart *UART) writeByte(c byte) error {
   218  	nrf.UART0.EVENTS_TXDRDY.Set(0)
   219  	nrf.UART0.TXD.Set(uint32(c))
   220  	for nrf.UART0.EVENTS_TXDRDY.Get() == 0 {
   221  	}
   222  	return nil
   223  }
   224  
   225  func (uart *UART) flush() {}
   226  
   227  func (uart *UART) handleInterrupt(interrupt.Interrupt) {
   228  	if nrf.UART0.EVENTS_RXDRDY.Get() != 0 {
   229  		uart.Receive(byte(nrf.UART0.RXD.Get()))
   230  		nrf.UART0.EVENTS_RXDRDY.Set(0x0)
   231  	}
   232  }
   233  
   234  const i2cTimeout = 0xffff // this is around 29ms on a nrf52
   235  
   236  // I2CConfig is used to store config info for I2C.
   237  type I2CConfig struct {
   238  	Frequency uint32
   239  	SCL       Pin
   240  	SDA       Pin
   241  	Mode      I2CMode
   242  }
   243  
   244  // Configure is intended to setup the I2C interface.
   245  func (i2c *I2C) Configure(config I2CConfig) error {
   246  
   247  	i2c.disable()
   248  
   249  	// Default I2C bus speed is 100 kHz.
   250  	if config.Frequency == 0 {
   251  		config.Frequency = 100 * KHz
   252  	}
   253  	// Default I2C pins if not set.
   254  	if config.SDA == 0 && config.SCL == 0 {
   255  		config.SDA = SDA_PIN
   256  		config.SCL = SCL_PIN
   257  	}
   258  
   259  	// do config
   260  	sclPort, sclPin := config.SCL.getPortPin()
   261  	sclPort.PIN_CNF[sclPin].Set((nrf.GPIO_PIN_CNF_DIR_Input << nrf.GPIO_PIN_CNF_DIR_Pos) |
   262  		(nrf.GPIO_PIN_CNF_INPUT_Connect << nrf.GPIO_PIN_CNF_INPUT_Pos) |
   263  		(nrf.GPIO_PIN_CNF_PULL_Pullup << nrf.GPIO_PIN_CNF_PULL_Pos) |
   264  		(nrf.GPIO_PIN_CNF_DRIVE_S0D1 << nrf.GPIO_PIN_CNF_DRIVE_Pos) |
   265  		(nrf.GPIO_PIN_CNF_SENSE_Disabled << nrf.GPIO_PIN_CNF_SENSE_Pos))
   266  
   267  	sdaPort, sdaPin := config.SDA.getPortPin()
   268  	sdaPort.PIN_CNF[sdaPin].Set((nrf.GPIO_PIN_CNF_DIR_Input << nrf.GPIO_PIN_CNF_DIR_Pos) |
   269  		(nrf.GPIO_PIN_CNF_INPUT_Connect << nrf.GPIO_PIN_CNF_INPUT_Pos) |
   270  		(nrf.GPIO_PIN_CNF_PULL_Pullup << nrf.GPIO_PIN_CNF_PULL_Pos) |
   271  		(nrf.GPIO_PIN_CNF_DRIVE_S0D1 << nrf.GPIO_PIN_CNF_DRIVE_Pos) |
   272  		(nrf.GPIO_PIN_CNF_SENSE_Disabled << nrf.GPIO_PIN_CNF_SENSE_Pos))
   273  
   274  	i2c.setPins(config.SCL, config.SDA)
   275  
   276  	i2c.mode = config.Mode
   277  	if i2c.mode == I2CModeController {
   278  		i2c.SetBaudRate(config.Frequency)
   279  
   280  		i2c.enableAsController()
   281  	} else {
   282  		i2c.enableAsTarget()
   283  	}
   284  
   285  	return nil
   286  }
   287  
   288  // SetBaudRate sets the I2C frequency. It has the side effect of also
   289  // enabling the I2C hardware if disabled beforehand.
   290  //
   291  //go:inline
   292  func (i2c *I2C) SetBaudRate(br uint32) error {
   293  	switch {
   294  	case br >= 400*KHz:
   295  		i2c.Bus.SetFREQUENCY(nrf.TWI_FREQUENCY_FREQUENCY_K400)
   296  	case br >= 250*KHz:
   297  		i2c.Bus.SetFREQUENCY(nrf.TWI_FREQUENCY_FREQUENCY_K250)
   298  	default:
   299  		i2c.Bus.SetFREQUENCY(nrf.TWI_FREQUENCY_FREQUENCY_K100)
   300  	}
   301  
   302  	return nil
   303  }
   304  
   305  // signalStop sends a stop signal to the I2C peripheral and waits for confirmation.
   306  func (i2c *I2C) signalStop() error {
   307  	tries := 0
   308  	i2c.Bus.TASKS_STOP.Set(1)
   309  	for i2c.Bus.EVENTS_STOPPED.Get() == 0 {
   310  		tries++
   311  		if tries >= i2cTimeout {
   312  			return errI2CSignalStopTimeout
   313  		}
   314  	}
   315  	i2c.Bus.EVENTS_STOPPED.Set(0)
   316  	return nil
   317  }
   318  
   319  var rngStarted = false
   320  
   321  // GetRNG returns 32 bits of non-deterministic random data based on internal thermal noise.
   322  // According to Nordic's documentation, the random output is suitable for cryptographic purposes.
   323  func GetRNG() (ret uint32, err error) {
   324  	// There's no apparent way to check the status of the RNG peripheral's task, so simply start it
   325  	// to avoid deadlocking while waiting for output.
   326  	if !rngStarted {
   327  		nrf.RNG.TASKS_START.Set(1)
   328  		nrf.RNG.SetCONFIG_DERCEN(nrf.RNG_CONFIG_DERCEN_Enabled)
   329  		rngStarted = true
   330  	}
   331  
   332  	// The RNG returns one byte at a time, so stack up four bytes into a single uint32 for return.
   333  	for i := 0; i < 4; i++ {
   334  		// Wait for data to be ready.
   335  		for nrf.RNG.EVENTS_VALRDY.Get() == 0 {
   336  		}
   337  		// Append random byte to output.
   338  		ret = (ret << 8) ^ nrf.RNG.GetVALUE()
   339  		// Unset the EVENTS_VALRDY register to avoid reading the same random output twice.
   340  		nrf.RNG.EVENTS_VALRDY.Set(0)
   341  	}
   342  
   343  	return ret, nil
   344  }
   345  
   346  // ReadTemperature reads the silicon die temperature of the chip. The return
   347  // value is in milli-celsius.
   348  func ReadTemperature() int32 {
   349  	nrf.TEMP.TASKS_START.Set(1)
   350  	for nrf.TEMP.EVENTS_DATARDY.Get() == 0 {
   351  	}
   352  	temp := int32(nrf.TEMP.TEMP.Get()) * 250 // the returned value is in units of 0.25°C
   353  	nrf.TEMP.EVENTS_DATARDY.Set(0)
   354  	return temp
   355  }
   356  
   357  const memoryStart = 0x0
   358  
   359  // compile-time check for ensuring we fulfill BlockDevice interface
   360  var _ BlockDevice = flashBlockDevice{}
   361  
   362  var Flash flashBlockDevice
   363  
   364  type flashBlockDevice struct {
   365  }
   366  
   367  // ReadAt reads the given number of bytes from the block device.
   368  func (f flashBlockDevice) ReadAt(p []byte, off int64) (n int, err error) {
   369  	if FlashDataStart()+uintptr(off)+uintptr(len(p)) > FlashDataEnd() {
   370  		return 0, errFlashCannotReadPastEOF
   371  	}
   372  
   373  	data := unsafe.Slice((*byte)(unsafe.Pointer(FlashDataStart()+uintptr(off))), len(p))
   374  	copy(p, data)
   375  
   376  	return len(p), nil
   377  }
   378  
   379  // WriteAt writes the given number of bytes to the block device.
   380  // Only double-word (64 bits) length data can be programmed. See rm0461 page 78.
   381  // If the length of p is not long enough it will be padded with 0xFF bytes.
   382  // This method assumes that the destination is already erased.
   383  func (f flashBlockDevice) WriteAt(p []byte, off int64) (n int, err error) {
   384  	if FlashDataStart()+uintptr(off)+uintptr(len(p)) > FlashDataEnd() {
   385  		return 0, errFlashCannotWritePastEOF
   386  	}
   387  
   388  	address := FlashDataStart() + uintptr(off)
   389  	padded := f.pad(p)
   390  
   391  	waitWhileFlashBusy()
   392  
   393  	nrf.NVMC.SetCONFIG_WEN(nrf.NVMC_CONFIG_WEN_Wen)
   394  	defer nrf.NVMC.SetCONFIG_WEN(nrf.NVMC_CONFIG_WEN_Ren)
   395  
   396  	for j := 0; j < len(padded); j += int(f.WriteBlockSize()) {
   397  		// write word
   398  		*(*uint32)(unsafe.Pointer(address)) = binary.LittleEndian.Uint32(padded[j : j+int(f.WriteBlockSize())])
   399  		address += uintptr(f.WriteBlockSize())
   400  		waitWhileFlashBusy()
   401  	}
   402  
   403  	return len(padded), nil
   404  }
   405  
   406  // Size returns the number of bytes in this block device.
   407  func (f flashBlockDevice) Size() int64 {
   408  	return int64(FlashDataEnd() - FlashDataStart())
   409  }
   410  
   411  const writeBlockSize = 4
   412  
   413  // WriteBlockSize returns the block size in which data can be written to
   414  // memory. It can be used by a client to optimize writes, non-aligned writes
   415  // should always work correctly.
   416  func (f flashBlockDevice) WriteBlockSize() int64 {
   417  	return writeBlockSize
   418  }
   419  
   420  // EraseBlockSize returns the smallest erasable area on this particular chip
   421  // in bytes. This is used for the block size in EraseBlocks.
   422  // It must be a power of two, and may be as small as 1. A typical size is 4096.
   423  func (f flashBlockDevice) EraseBlockSize() int64 {
   424  	return eraseBlockSize()
   425  }
   426  
   427  // EraseBlocks erases the given number of blocks. An implementation may
   428  // transparently coalesce ranges of blocks into larger bundles if the chip
   429  // supports this. The start and len parameters are in block numbers, use
   430  // EraseBlockSize to map addresses to blocks.
   431  func (f flashBlockDevice) EraseBlocks(start, len int64) error {
   432  	address := FlashDataStart() + uintptr(start*f.EraseBlockSize())
   433  	waitWhileFlashBusy()
   434  
   435  	nrf.NVMC.SetCONFIG_WEN(nrf.NVMC_CONFIG_WEN_Een)
   436  	defer nrf.NVMC.SetCONFIG_WEN(nrf.NVMC_CONFIG_WEN_Ren)
   437  
   438  	for i := start; i < start+len; i++ {
   439  		nrf.NVMC.ERASEPAGE.Set(uint32(address))
   440  		waitWhileFlashBusy()
   441  		address += uintptr(f.EraseBlockSize())
   442  	}
   443  
   444  	return nil
   445  }
   446  
   447  // pad data if needed so it is long enough for correct byte alignment on writes.
   448  func (f flashBlockDevice) pad(p []byte) []byte {
   449  	overflow := int64(len(p)) % f.WriteBlockSize()
   450  	if overflow == 0 {
   451  		return p
   452  	}
   453  
   454  	padding := bytes.Repeat([]byte{0xff}, int(f.WriteBlockSize()-overflow))
   455  	return append(p, padding...)
   456  }
   457  
   458  func waitWhileFlashBusy() {
   459  	for nrf.NVMC.GetREADY() != nrf.NVMC_READY_READY_Ready {
   460  	}
   461  }