github.com/aykevl/tinygo@v0.5.0/src/machine/machine_nrf.go (about) 1 // +build nrf 2 3 package machine 4 5 import ( 6 "device/arm" 7 "device/nrf" 8 ) 9 10 type GPIOMode uint8 11 12 const ( 13 GPIO_INPUT = (nrf.GPIO_PIN_CNF_DIR_Input << nrf.GPIO_PIN_CNF_DIR_Pos) | (nrf.GPIO_PIN_CNF_INPUT_Connect << nrf.GPIO_PIN_CNF_INPUT_Pos) 14 GPIO_INPUT_PULLUP = GPIO_INPUT | (nrf.GPIO_PIN_CNF_PULL_Pullup << nrf.GPIO_PIN_CNF_PULL_Pos) 15 GPIO_INPUT_PULLDOWN = GPIO_INPUT | (nrf.GPIO_PIN_CNF_PULL_Pulldown << nrf.GPIO_PIN_CNF_PULL_Pos) 16 GPIO_OUTPUT = (nrf.GPIO_PIN_CNF_DIR_Output << nrf.GPIO_PIN_CNF_DIR_Pos) | (nrf.GPIO_PIN_CNF_INPUT_Disconnect << nrf.GPIO_PIN_CNF_INPUT_Pos) 17 ) 18 19 // Configure this pin with the given configuration. 20 func (p GPIO) Configure(config GPIOConfig) { 21 cfg := config.Mode | nrf.GPIO_PIN_CNF_DRIVE_S0S1 | nrf.GPIO_PIN_CNF_SENSE_Disabled 22 port, pin := p.getPortPin() 23 port.PIN_CNF[pin] = nrf.RegValue(cfg) 24 } 25 26 // Set the pin to high or low. 27 // Warning: only use this on an output pin! 28 func (p GPIO) Set(high bool) { 29 port, pin := p.getPortPin() 30 if high { 31 port.OUTSET = 1 << pin 32 } else { 33 port.OUTCLR = 1 << pin 34 } 35 } 36 37 // Return the register and mask to enable a given GPIO pin. This can be used to 38 // implement bit-banged drivers. 39 func (p GPIO) PortMaskSet() (*uint32, uint32) { 40 port, pin := p.getPortPin() 41 return (*uint32)(&port.OUTSET), 1 << pin 42 } 43 44 // Return the register and mask to disable a given port. This can be used to 45 // implement bit-banged drivers. 46 func (p GPIO) PortMaskClear() (*uint32, uint32) { 47 port, pin := p.getPortPin() 48 return (*uint32)(&port.OUTCLR), 1 << pin 49 } 50 51 // Get returns the current value of a GPIO pin. 52 func (p GPIO) Get() bool { 53 port, pin := p.getPortPin() 54 return (port.IN>>pin)&1 != 0 55 } 56 57 // UART on the NRF. 58 type UART struct { 59 Buffer *RingBuffer 60 } 61 62 // UART 63 var ( 64 // UART0 is the hardware serial port on the NRF. 65 UART0 = UART{Buffer: NewRingBuffer()} 66 ) 67 68 // Configure the UART. 69 func (uart UART) Configure(config UARTConfig) { 70 // Default baud rate to 115200. 71 if config.BaudRate == 0 { 72 config.BaudRate = 115200 73 } 74 75 uart.SetBaudRate(config.BaudRate) 76 77 // Set TX and RX pins from board. 78 uart.setPins(UART_TX_PIN, UART_RX_PIN) 79 80 nrf.UART0.ENABLE = nrf.UART_ENABLE_ENABLE_Enabled 81 nrf.UART0.TASKS_STARTTX = 1 82 nrf.UART0.TASKS_STARTRX = 1 83 nrf.UART0.INTENSET = nrf.UART_INTENSET_RXDRDY_Msk 84 85 // Enable RX IRQ. 86 arm.SetPriority(nrf.IRQ_UART0, 0xc0) // low priority 87 arm.EnableIRQ(nrf.IRQ_UART0) 88 } 89 90 // SetBaudRate sets the communication speed for the UART. 91 func (uart UART) SetBaudRate(br uint32) { 92 // Magic: calculate 'baudrate' register from the input number. 93 // Every value listed in the datasheet will be converted to the 94 // correct register value, except for 192600. I suspect the value 95 // listed in the nrf52 datasheet (0x0EBED000) is incorrectly rounded 96 // and should be 0x0EBEE000, as the nrf51 datasheet lists the 97 // nonrounded value 0x0EBEDFA4. 98 // Some background: 99 // https://devzone.nordicsemi.com/f/nordic-q-a/391/uart-baudrate-register-values/2046#2046 100 rate := uint32((uint64(br/400)*uint64(400*0xffffffff/16000000) + 0x800) & 0xffffff000) 101 102 nrf.UART0.BAUDRATE = nrf.RegValue(rate) 103 } 104 105 // WriteByte writes a byte of data to the UART. 106 func (uart UART) WriteByte(c byte) error { 107 nrf.UART0.EVENTS_TXDRDY = 0 108 nrf.UART0.TXD = nrf.RegValue(c) 109 for nrf.UART0.EVENTS_TXDRDY == 0 { 110 } 111 return nil 112 } 113 114 func (uart UART) handleInterrupt() { 115 if nrf.UART0.EVENTS_RXDRDY != 0 { 116 uart.Receive(byte(nrf.UART0.RXD)) 117 nrf.UART0.EVENTS_RXDRDY = 0x0 118 } 119 } 120 121 // I2C on the NRF. 122 type I2C struct { 123 Bus *nrf.TWI_Type 124 } 125 126 // There are 2 I2C interfaces on the NRF. 127 var ( 128 I2C0 = I2C{Bus: nrf.TWI0} 129 I2C1 = I2C{Bus: nrf.TWI1} 130 ) 131 132 // I2CConfig is used to store config info for I2C. 133 type I2CConfig struct { 134 Frequency uint32 135 SCL uint8 136 SDA uint8 137 } 138 139 // Configure is intended to setup the I2C interface. 140 func (i2c I2C) Configure(config I2CConfig) { 141 // Default I2C bus speed is 100 kHz. 142 if config.Frequency == 0 { 143 config.Frequency = TWI_FREQ_100KHZ 144 } 145 // Default I2C pins if not set. 146 if config.SDA == 0 && config.SCL == 0 { 147 config.SDA = SDA_PIN 148 config.SCL = SCL_PIN 149 } 150 151 // do config 152 sclPort, sclPin := GPIO{config.SCL}.getPortPin() 153 sclPort.PIN_CNF[sclPin] = (nrf.GPIO_PIN_CNF_DIR_Input << nrf.GPIO_PIN_CNF_DIR_Pos) | 154 (nrf.GPIO_PIN_CNF_INPUT_Connect << nrf.GPIO_PIN_CNF_INPUT_Pos) | 155 (nrf.GPIO_PIN_CNF_PULL_Pullup << nrf.GPIO_PIN_CNF_PULL_Pos) | 156 (nrf.GPIO_PIN_CNF_DRIVE_S0D1 << nrf.GPIO_PIN_CNF_DRIVE_Pos) | 157 (nrf.GPIO_PIN_CNF_SENSE_Disabled << nrf.GPIO_PIN_CNF_SENSE_Pos) 158 159 sdaPort, sdaPin := GPIO{config.SDA}.getPortPin() 160 sdaPort.PIN_CNF[sdaPin] = (nrf.GPIO_PIN_CNF_DIR_Input << nrf.GPIO_PIN_CNF_DIR_Pos) | 161 (nrf.GPIO_PIN_CNF_INPUT_Connect << nrf.GPIO_PIN_CNF_INPUT_Pos) | 162 (nrf.GPIO_PIN_CNF_PULL_Pullup << nrf.GPIO_PIN_CNF_PULL_Pos) | 163 (nrf.GPIO_PIN_CNF_DRIVE_S0D1 << nrf.GPIO_PIN_CNF_DRIVE_Pos) | 164 (nrf.GPIO_PIN_CNF_SENSE_Disabled << nrf.GPIO_PIN_CNF_SENSE_Pos) 165 166 if config.Frequency == TWI_FREQ_400KHZ { 167 i2c.Bus.FREQUENCY = nrf.TWI_FREQUENCY_FREQUENCY_K400 168 } else { 169 i2c.Bus.FREQUENCY = nrf.TWI_FREQUENCY_FREQUENCY_K100 170 } 171 172 i2c.Bus.ENABLE = nrf.TWI_ENABLE_ENABLE_Enabled 173 i2c.setPins(config.SCL, config.SDA) 174 } 175 176 // Tx does a single I2C transaction at the specified address. 177 // It clocks out the given address, writes the bytes in w, reads back len(r) 178 // bytes and stores them in r, and generates a stop condition on the bus. 179 func (i2c I2C) Tx(addr uint16, w, r []byte) error { 180 i2c.Bus.ADDRESS = nrf.RegValue(addr) 181 if len(w) != 0 { 182 i2c.Bus.TASKS_STARTTX = 1 // start transmission for writing 183 for _, b := range w { 184 i2c.writeByte(b) 185 } 186 } 187 if len(r) != 0 { 188 i2c.Bus.TASKS_STARTRX = 1 // re-start transmission for reading 189 for i := range r { // read each char 190 if i+1 == len(r) { 191 // The 'stop' signal must be sent before reading back the last 192 // byte, so that it will be sent by the I2C peripheral right 193 // after the last byte has been read. 194 r[i] = i2c.readLastByte() 195 } else { 196 r[i] = i2c.readByte() 197 } 198 } 199 } else { 200 // Nothing to read back. Stop the transmission. 201 i2c.signalStop() 202 } 203 return nil 204 } 205 206 // signalStop sends a stop signal when writing or tells the I2C peripheral that 207 // it must generate a stop condition after the next character is retrieved when 208 // reading. 209 func (i2c I2C) signalStop() { 210 i2c.Bus.TASKS_STOP = 1 211 for i2c.Bus.EVENTS_STOPPED == 0 { 212 } 213 i2c.Bus.EVENTS_STOPPED = 0 214 } 215 216 // writeByte writes a single byte to the I2C bus. 217 func (i2c I2C) writeByte(data byte) { 218 i2c.Bus.TXD = nrf.RegValue(data) 219 for i2c.Bus.EVENTS_TXDSENT == 0 { 220 } 221 i2c.Bus.EVENTS_TXDSENT = 0 222 } 223 224 // readByte reads a single byte from the I2C bus. 225 func (i2c I2C) readByte() byte { 226 for i2c.Bus.EVENTS_RXDREADY == 0 { 227 } 228 i2c.Bus.EVENTS_RXDREADY = 0 229 return byte(i2c.Bus.RXD) 230 } 231 232 // readLastByte reads a single byte from the I2C bus, sending a stop signal 233 // after it has been read. 234 func (i2c I2C) readLastByte() byte { 235 for i2c.Bus.EVENTS_RXDREADY == 0 { 236 } 237 i2c.Bus.EVENTS_RXDREADY = 0 238 i2c.signalStop() // signal 'stop' now, so it is sent when reading RXD 239 return byte(i2c.Bus.RXD) 240 } 241 242 // SPI on the NRF. 243 type SPI struct { 244 Bus *nrf.SPI_Type 245 } 246 247 // There are 2 SPI interfaces on the NRF5x. 248 var ( 249 SPI0 = SPI{Bus: nrf.SPI0} 250 SPI1 = SPI{Bus: nrf.SPI1} 251 ) 252 253 // SPIConfig is used to store config info for SPI. 254 type SPIConfig struct { 255 Frequency uint32 256 SCK uint8 257 MOSI uint8 258 MISO uint8 259 LSBFirst bool 260 Mode uint8 261 } 262 263 // Configure is intended to setup the SPI interface. 264 func (spi SPI) Configure(config SPIConfig) { 265 // Disable bus to configure it 266 spi.Bus.ENABLE = nrf.SPI_ENABLE_ENABLE_Disabled 267 268 // set frequency 269 var freq uint32 270 271 switch config.Frequency { 272 case 125000: 273 freq = nrf.SPI_FREQUENCY_FREQUENCY_K125 274 case 250000: 275 freq = nrf.SPI_FREQUENCY_FREQUENCY_K250 276 case 500000: 277 freq = nrf.SPI_FREQUENCY_FREQUENCY_K500 278 case 1000000: 279 freq = nrf.SPI_FREQUENCY_FREQUENCY_M1 280 case 2000000: 281 freq = nrf.SPI_FREQUENCY_FREQUENCY_M2 282 case 4000000: 283 freq = nrf.SPI_FREQUENCY_FREQUENCY_M4 284 case 8000000: 285 freq = nrf.SPI_FREQUENCY_FREQUENCY_M8 286 default: 287 freq = nrf.SPI_FREQUENCY_FREQUENCY_K500 288 } 289 spi.Bus.FREQUENCY = nrf.RegValue(freq) 290 291 var conf uint32 292 293 // set bit transfer order 294 if config.LSBFirst { 295 conf = (nrf.SPI_CONFIG_ORDER_LsbFirst << nrf.SPI_CONFIG_ORDER_Pos) 296 } 297 298 // set mode 299 switch config.Mode { 300 case 0: 301 conf &^= (nrf.SPI_CONFIG_CPOL_ActiveHigh << nrf.SPI_CONFIG_CPOL_Pos) 302 conf &^= (nrf.SPI_CONFIG_CPHA_Leading << nrf.SPI_CONFIG_CPHA_Pos) 303 case 1: 304 conf &^= (nrf.SPI_CONFIG_CPOL_ActiveHigh << nrf.SPI_CONFIG_CPOL_Pos) 305 conf |= (nrf.SPI_CONFIG_CPHA_Trailing << nrf.SPI_CONFIG_CPHA_Pos) 306 case 2: 307 conf |= (nrf.SPI_CONFIG_CPOL_ActiveLow << nrf.SPI_CONFIG_CPOL_Pos) 308 conf &^= (nrf.SPI_CONFIG_CPHA_Leading << nrf.SPI_CONFIG_CPHA_Pos) 309 case 3: 310 conf |= (nrf.SPI_CONFIG_CPOL_ActiveLow << nrf.SPI_CONFIG_CPOL_Pos) 311 conf |= (nrf.SPI_CONFIG_CPHA_Trailing << nrf.SPI_CONFIG_CPHA_Pos) 312 default: // to mode 313 conf &^= (nrf.SPI_CONFIG_CPOL_ActiveHigh << nrf.SPI_CONFIG_CPOL_Pos) 314 conf &^= (nrf.SPI_CONFIG_CPHA_Leading << nrf.SPI_CONFIG_CPHA_Pos) 315 } 316 spi.Bus.CONFIG = nrf.RegValue(conf) 317 318 // set pins 319 spi.setPins(config.SCK, config.MOSI, config.MISO) 320 321 // Re-enable bus now that it is configured. 322 spi.Bus.ENABLE = nrf.SPI_ENABLE_ENABLE_Enabled 323 } 324 325 // Transfer writes/reads a single byte using the SPI interface. 326 func (spi SPI) Transfer(w byte) (byte, error) { 327 spi.Bus.TXD = nrf.RegValue(w) 328 for spi.Bus.EVENTS_READY == 0 { 329 } 330 r := spi.Bus.RXD 331 spi.Bus.EVENTS_READY = 0 332 333 // TODO: handle SPI errors 334 return byte(r), nil 335 }