github.com/tinygo-org/tinygo@v0.31.3-0.20240404173401-90b0bf646c27/src/machine/machine_nrf51.go (about) 1 //go:build nrf51 2 3 package machine 4 5 import ( 6 "device/nrf" 7 ) 8 9 const eraseBlockSizeValue = 1024 10 11 func eraseBlockSize() int64 { 12 return eraseBlockSizeValue 13 } 14 15 // Get peripheral and pin number for this GPIO pin. 16 func (p Pin) getPortPin() (*nrf.GPIO_Type, uint32) { 17 return nrf.GPIO, uint32(p) 18 } 19 20 func (uart *UART) setPins(tx, rx Pin) { 21 nrf.UART0.PSELTXD.Set(uint32(tx)) 22 nrf.UART0.PSELRXD.Set(uint32(rx)) 23 } 24 25 func (i2c *I2C) setPins(scl, sda Pin) { 26 i2c.Bus.PSELSCL.Set(uint32(scl)) 27 i2c.Bus.PSELSDA.Set(uint32(sda)) 28 } 29 30 // SPI on the NRF. 31 type SPI struct { 32 Bus *nrf.SPI_Type 33 } 34 35 // There are 2 SPI interfaces on the NRF51. 36 var ( 37 SPI0 = SPI{Bus: nrf.SPI0} 38 SPI1 = SPI{Bus: nrf.SPI1} 39 ) 40 41 // SPIConfig is used to store config info for SPI. 42 type SPIConfig struct { 43 Frequency uint32 44 SCK Pin 45 SDO Pin 46 SDI Pin 47 LSBFirst bool 48 Mode uint8 49 } 50 51 // Configure is intended to setup the SPI interface. 52 func (spi SPI) Configure(config SPIConfig) error { 53 // Disable bus to configure it 54 spi.Bus.ENABLE.Set(nrf.SPI_ENABLE_ENABLE_Disabled) 55 56 // set frequency 57 var freq uint32 58 59 if config.Frequency == 0 { 60 config.Frequency = 4000000 // 4MHz 61 } 62 63 switch { 64 case config.Frequency >= 8000000: 65 freq = nrf.SPI_FREQUENCY_FREQUENCY_M8 66 case config.Frequency >= 4000000: 67 freq = nrf.SPI_FREQUENCY_FREQUENCY_M4 68 case config.Frequency >= 2000000: 69 freq = nrf.SPI_FREQUENCY_FREQUENCY_M2 70 case config.Frequency >= 1000000: 71 freq = nrf.SPI_FREQUENCY_FREQUENCY_M1 72 case config.Frequency >= 500000: 73 freq = nrf.SPI_FREQUENCY_FREQUENCY_K500 74 case config.Frequency >= 250000: 75 freq = nrf.SPI_FREQUENCY_FREQUENCY_K250 76 default: // below 250kHz, default to the lowest speed available 77 freq = nrf.SPI_FREQUENCY_FREQUENCY_K125 78 } 79 spi.Bus.FREQUENCY.Set(freq) 80 81 var conf uint32 82 83 // set bit transfer order 84 if config.LSBFirst { 85 conf = (nrf.SPI_CONFIG_ORDER_LsbFirst << nrf.SPI_CONFIG_ORDER_Pos) 86 } 87 88 // set mode 89 switch config.Mode { 90 case 0: 91 conf &^= (nrf.SPI_CONFIG_CPOL_ActiveHigh << nrf.SPI_CONFIG_CPOL_Pos) 92 conf &^= (nrf.SPI_CONFIG_CPHA_Leading << nrf.SPI_CONFIG_CPHA_Pos) 93 case 1: 94 conf &^= (nrf.SPI_CONFIG_CPOL_ActiveHigh << nrf.SPI_CONFIG_CPOL_Pos) 95 conf |= (nrf.SPI_CONFIG_CPHA_Trailing << nrf.SPI_CONFIG_CPHA_Pos) 96 case 2: 97 conf |= (nrf.SPI_CONFIG_CPOL_ActiveLow << nrf.SPI_CONFIG_CPOL_Pos) 98 conf &^= (nrf.SPI_CONFIG_CPHA_Leading << nrf.SPI_CONFIG_CPHA_Pos) 99 case 3: 100 conf |= (nrf.SPI_CONFIG_CPOL_ActiveLow << nrf.SPI_CONFIG_CPOL_Pos) 101 conf |= (nrf.SPI_CONFIG_CPHA_Trailing << nrf.SPI_CONFIG_CPHA_Pos) 102 default: // to mode 103 conf &^= (nrf.SPI_CONFIG_CPOL_ActiveHigh << nrf.SPI_CONFIG_CPOL_Pos) 104 conf &^= (nrf.SPI_CONFIG_CPHA_Leading << nrf.SPI_CONFIG_CPHA_Pos) 105 } 106 spi.Bus.CONFIG.Set(conf) 107 108 // set pins 109 if config.SCK == 0 && config.SDO == 0 && config.SDI == 0 { 110 config.SCK = SPI0_SCK_PIN 111 config.SDO = SPI0_SDO_PIN 112 config.SDI = SPI0_SDI_PIN 113 } 114 spi.Bus.PSELSCK.Set(uint32(config.SCK)) 115 spi.Bus.PSELMOSI.Set(uint32(config.SDO)) 116 spi.Bus.PSELMISO.Set(uint32(config.SDI)) 117 118 // Re-enable bus now that it is configured. 119 spi.Bus.ENABLE.Set(nrf.SPI_ENABLE_ENABLE_Enabled) 120 121 return nil 122 } 123 124 // Transfer writes/reads a single byte using the SPI interface. 125 func (spi SPI) Transfer(w byte) (byte, error) { 126 spi.Bus.TXD.Set(uint32(w)) 127 for spi.Bus.EVENTS_READY.Get() == 0 { 128 } 129 r := spi.Bus.RXD.Get() 130 spi.Bus.EVENTS_READY.Set(0) 131 132 // TODO: handle SPI errors 133 return byte(r), nil 134 } 135 136 // Tx handles read/write operation for SPI interface. Since SPI is a syncronous write/read 137 // interface, there must always be the same number of bytes written as bytes read. 138 // The Tx method knows about this, and offers a few different ways of calling it. 139 // 140 // This form sends the bytes in tx buffer, putting the resulting bytes read into the rx buffer. 141 // Note that the tx and rx buffers must be the same size: 142 // 143 // spi.Tx(tx, rx) 144 // 145 // This form sends the tx buffer, ignoring the result. Useful for sending "commands" that return zeros 146 // until all the bytes in the command packet have been received: 147 // 148 // spi.Tx(tx, nil) 149 // 150 // This form sends zeros, putting the result into the rx buffer. Good for reading a "result packet": 151 // 152 // spi.Tx(nil, rx) 153 func (spi SPI) Tx(w, r []byte) error { 154 var err error 155 156 switch { 157 case len(w) == 0: 158 // read only, so write zero and read a result. 159 for i := range r { 160 r[i], err = spi.Transfer(0) 161 if err != nil { 162 return err 163 } 164 } 165 case len(r) == 0: 166 // write only 167 spi.Bus.TXD.Set(uint32(w[0])) 168 w = w[1:] 169 for _, b := range w { 170 spi.Bus.TXD.Set(uint32(b)) 171 for spi.Bus.EVENTS_READY.Get() == 0 { 172 } 173 spi.Bus.EVENTS_READY.Set(0) 174 _ = spi.Bus.RXD.Get() 175 } 176 for spi.Bus.EVENTS_READY.Get() == 0 { 177 } 178 spi.Bus.EVENTS_READY.Set(0) 179 _ = spi.Bus.RXD.Get() 180 181 default: 182 // write/read 183 if len(w) != len(r) { 184 return ErrTxInvalidSliceSize 185 } 186 187 for i, b := range w { 188 r[i], err = spi.Transfer(b) 189 if err != nil { 190 return err 191 } 192 } 193 } 194 195 return nil 196 } 197 198 // InitADC initializes the registers needed for ADC. 199 func InitADC() { 200 return // no specific setup on nrf51 machine. 201 } 202 203 // Configure configures an ADC pin to be able to read analog data. 204 func (a ADC) Configure(ADCConfig) { 205 return // no pin specific setup on nrf51 machine. 206 } 207 208 // Get returns the current value of a ADC pin in the range 0..0xffff. 209 func (a ADC) Get() uint16 { 210 var value uint32 211 212 adcPin := a.getADCPin() 213 214 // Enable ADC. 215 nrf.ADC.SetENABLE(nrf.ADC_ENABLE_ENABLE_Enabled) 216 217 // Set pin to read. 218 nrf.ADC.SetCONFIG_PSEL(adcPin) 219 220 // config ADC 221 nrf.ADC.SetCONFIG_RES(nrf.ADC_CONFIG_RES_10bit) 222 nrf.ADC.SetCONFIG_INPSEL(nrf.ADC_CONFIG_INPSEL_AnalogInputOneThirdPrescaling) 223 nrf.ADC.SetCONFIG_REFSEL(nrf.ADC_CONFIG_REFSEL_SupplyOneThirdPrescaling) 224 225 // Start tasks. 226 nrf.ADC.TASKS_START.Set(1) 227 228 // Wait until the sample task is done. 229 for nrf.ADC.EVENTS_END.Get() == 0 { 230 } 231 nrf.ADC.EVENTS_END.Set(0x00) 232 233 value = nrf.ADC.GetRESULT() 234 235 // Stop the ADC 236 nrf.ADC.TASKS_STOP.Set(1) 237 238 // Disable ADC. 239 nrf.ADC.SetENABLE(nrf.ADC_ENABLE_ENABLE_Disabled) 240 241 if value < 0 { 242 value = 0 243 } 244 245 // Return 16-bit result from 10-bit value. 246 return uint16(value << 6) 247 } 248 249 func (a ADC) getADCPin() uint32 { 250 switch a.Pin { 251 case 1: 252 return nrf.ADC_CONFIG_PSEL_AnalogInput2 253 254 case 2: 255 return nrf.ADC_CONFIG_PSEL_AnalogInput3 256 257 case 3: 258 return nrf.ADC_CONFIG_PSEL_AnalogInput4 259 260 case 4: 261 return nrf.ADC_CONFIG_PSEL_AnalogInput5 262 263 case 5: 264 return nrf.ADC_CONFIG_PSEL_AnalogInput6 265 266 case 6: 267 return nrf.ADC_CONFIG_PSEL_AnalogInput7 268 269 case 26: 270 return nrf.ADC_CONFIG_PSEL_AnalogInput0 271 272 case 27: 273 return nrf.ADC_CONFIG_PSEL_AnalogInput1 274 275 default: 276 return 0 277 } 278 }