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 }