github.com/tinygo-org/tinygo@v0.31.3-0.20240404173401-90b0bf646c27/src/machine/machine_nrf528xx.go (about) 1 //go:build nrf52840 || nrf52833 2 3 package machine 4 5 import ( 6 "device/nrf" 7 "unsafe" 8 ) 9 10 // I2C on the NRF528xx. 11 type I2C struct { 12 Bus *nrf.TWIM_Type // Called Bus to align with Bus field in nrf51 13 BusT *nrf.TWIS_Type 14 mode I2CMode 15 } 16 17 // There are 2 I2C interfaces on the NRF. 18 var ( 19 I2C0 = &I2C{Bus: nrf.TWIM0, BusT: nrf.TWIS0} 20 I2C1 = &I2C{Bus: nrf.TWIM1, BusT: nrf.TWIS1} 21 ) 22 23 func (i2c *I2C) enableAsController() { 24 i2c.Bus.ENABLE.Set(nrf.TWIM_ENABLE_ENABLE_Enabled) 25 } 26 27 func (i2c *I2C) enableAsTarget() { 28 i2c.BusT.ENABLE.Set(nrf.TWIS_ENABLE_ENABLE_Enabled) 29 } 30 31 func (i2c *I2C) disable() { 32 i2c.Bus.ENABLE.Set(0) 33 } 34 35 // Tx does a single I2C transaction at the specified address (when in controller mode). 36 // 37 // It clocks out the given address, writes the bytes in w, reads back len(r) 38 // bytes and stores them in r, and generates a stop condition on the bus. 39 func (i2c *I2C) Tx(addr uint16, w, r []byte) (err error) { 40 i2c.Bus.ADDRESS.Set(uint32(addr)) 41 42 i2c.Bus.EVENTS_STOPPED.Set(0) 43 i2c.Bus.EVENTS_ERROR.Set(0) 44 i2c.Bus.EVENTS_RXSTARTED.Set(0) 45 i2c.Bus.EVENTS_TXSTARTED.Set(0) 46 i2c.Bus.EVENTS_LASTRX.Set(0) 47 i2c.Bus.EVENTS_LASTTX.Set(0) 48 i2c.Bus.EVENTS_SUSPENDED.Set(0) 49 50 // Configure for a single shot to perform both write and read (as applicable) 51 if len(w) != 0 { 52 i2c.Bus.TXD.PTR.Set(uint32(uintptr(unsafe.Pointer(&w[0])))) 53 i2c.Bus.TXD.MAXCNT.Set(uint32(len(w))) 54 55 // If no read, immediately signal stop after TX 56 if len(r) == 0 { 57 i2c.Bus.SHORTS.Set(nrf.TWIM_SHORTS_LASTTX_STOP) 58 } 59 } 60 if len(r) != 0 { 61 i2c.Bus.RXD.PTR.Set(uint32(uintptr(unsafe.Pointer(&r[0])))) 62 i2c.Bus.RXD.MAXCNT.Set(uint32(len(r))) 63 64 // Auto-start Rx after Tx and Stop after Rx 65 i2c.Bus.SHORTS.Set(nrf.TWIM_SHORTS_LASTTX_STARTRX | nrf.TWIM_SHORTS_LASTRX_STOP) 66 } 67 68 // Fire the transaction 69 i2c.Bus.TASKS_RESUME.Set(1) 70 if len(w) != 0 { 71 i2c.Bus.TASKS_STARTTX.Set(1) 72 } else if len(r) != 0 { 73 i2c.Bus.TASKS_STARTRX.Set(1) 74 } 75 76 // Wait until transaction stopped to ensure buffers fully processed 77 for i2c.Bus.EVENTS_STOPPED.Get() == 0 { 78 // Allow scheduler to run 79 gosched() 80 81 // Handle errors by ensuring STOP sent on bus 82 if i2c.Bus.EVENTS_ERROR.Get() != 0 { 83 if i2c.Bus.EVENTS_STOPPED.Get() == 0 { 84 // STOP cannot be sent during SUSPEND 85 i2c.Bus.TASKS_RESUME.Set(1) 86 i2c.Bus.TASKS_STOP.Set(1) 87 } 88 err = twiCError(i2c.Bus.ERRORSRC.Get()) 89 } 90 } 91 92 return 93 } 94 95 // Listen starts listening for I2C requests sent to specified address 96 // 97 // addr is the address to listen to 98 func (i2c *I2C) Listen(addr uint8) error { 99 i2c.BusT.ADDRESS[0].Set(uint32(addr)) 100 i2c.BusT.CONFIG.Set(nrf.TWIS_CONFIG_ADDRESS0_Enabled) 101 102 i2c.BusT.EVENTS_STOPPED.Set(0) 103 i2c.BusT.EVENTS_ERROR.Set(0) 104 i2c.BusT.EVENTS_RXSTARTED.Set(0) 105 i2c.BusT.EVENTS_TXSTARTED.Set(0) 106 i2c.BusT.EVENTS_WRITE.Set(0) 107 i2c.BusT.EVENTS_READ.Set(0) 108 109 return nil 110 } 111 112 // WaitForEvent blocks the current go-routine until an I2C event is received (when in Target mode). 113 // 114 // The passed buffer will be populated for receive events, with the number of bytes 115 // received returned in count. For other event types, buf is not modified and a count 116 // of zero is returned. 117 // 118 // For request events, the caller MUST call `Reply` to avoid hanging the i2c bus indefinitely. 119 func (i2c *I2C) WaitForEvent(buf []byte) (evt I2CTargetEvent, count int, err error) { 120 i2c.BusT.RXD.PTR.Set(uint32(uintptr(unsafe.Pointer(&buf[0])))) 121 i2c.BusT.RXD.MAXCNT.Set(uint32(len(buf))) 122 123 i2c.BusT.TASKS_PREPARERX.Set(nrf.TWIS_TASKS_PREPARERX_TASKS_PREPARERX_Trigger) 124 125 i2c.Bus.TASKS_RESUME.Set(1) 126 127 for i2c.BusT.EVENTS_STOPPED.Get() == 0 && 128 i2c.BusT.EVENTS_READ.Get() == 0 { 129 gosched() 130 131 if i2c.BusT.EVENTS_ERROR.Get() != 0 { 132 i2c.BusT.EVENTS_ERROR.Set(0) 133 return I2CReceive, 0, twisError(i2c.BusT.ERRORSRC.Get()) 134 } 135 } 136 137 count = 0 138 evt = I2CFinish 139 err = nil 140 141 if i2c.BusT.EVENTS_WRITE.Get() != 0 { 142 i2c.BusT.EVENTS_WRITE.Set(0) 143 144 // Data was sent to this target. We've waited for 145 // READ or STOPPED event, so transmission should be 146 // complete. 147 count = int(i2c.BusT.RXD.AMOUNT.Get()) 148 evt = I2CReceive 149 } else if i2c.BusT.EVENTS_READ.Get() != 0 { 150 i2c.BusT.EVENTS_READ.Set(0) 151 152 // Data is requested from this target, hw will stretch 153 // the controller's clock until there is a reply to 154 // send 155 evt = I2CRequest 156 } else if i2c.BusT.EVENTS_STOPPED.Get() != 0 { 157 i2c.BusT.EVENTS_STOPPED.Set(0) 158 evt = I2CFinish 159 } 160 161 return 162 } 163 164 // Reply supplies the response data the controller. 165 func (i2c *I2C) Reply(buf []byte) error { 166 i2c.BusT.TXD.PTR.Set(uint32(uintptr(unsafe.Pointer(&buf[0])))) 167 i2c.BusT.TXD.MAXCNT.Set(uint32(len(buf))) 168 169 i2c.BusT.EVENTS_STOPPED.Set(0) 170 171 // Trigger Tx 172 i2c.BusT.TASKS_PREPARETX.Set(nrf.TWIS_TASKS_PREPARETX_TASKS_PREPARETX_Trigger) 173 174 // Block, waiting for Tx to complete 175 for i2c.BusT.EVENTS_STOPPED.Get() == 0 { 176 gosched() 177 178 if i2c.BusT.EVENTS_ERROR.Get() != 0 { 179 return twisError(i2c.BusT.ERRORSRC.Get()) 180 } 181 } 182 183 i2c.BusT.EVENTS_STOPPED.Set(0) 184 185 return nil 186 } 187 188 // twiCError converts an I2C controller error to Go 189 func twiCError(val uint32) error { 190 if val == 0 { 191 return nil 192 } else if val&nrf.TWIM_ERRORSRC_OVERRUN_Msk == nrf.TWIM_ERRORSRC_OVERRUN { 193 return errI2CBusError 194 } else if val&nrf.TWIM_ERRORSRC_ANACK_Msk == nrf.TWIM_ERRORSRC_ANACK { 195 return errI2CAckExpected 196 } else if val&nrf.TWIM_ERRORSRC_DNACK_Msk == nrf.TWIM_ERRORSRC_DNACK { 197 return errI2CAckExpected 198 } 199 200 return errI2CBusError 201 } 202 203 // twisError converts an I2C target error to Go 204 func twisError(val uint32) error { 205 if val == 0 { 206 return nil 207 } else if val&nrf.TWIS_ERRORSRC_OVERFLOW_Msk == nrf.TWIS_ERRORSRC_OVERFLOW { 208 return errI2COverflow 209 } else if val&nrf.TWIS_ERRORSRC_DNACK_Msk == nrf.TWIS_ERRORSRC_DNACK { 210 return errI2CAckExpected 211 } else if val&nrf.TWIS_ERRORSRC_OVERREAD_Msk == nrf.TWIS_ERRORSRC_OVERREAD { 212 return errI2COverread 213 } 214 215 return errI2CBusError 216 } 217 218 var ( 219 Watchdog = &watchdogImpl{} 220 ) 221 222 const ( 223 // WatchdogMaxTimeout in milliseconds (approx 36h) 224 WatchdogMaxTimeout = (0xffffffff * 1000) / 32768 225 ) 226 227 type watchdogImpl struct { 228 } 229 230 // Configure the watchdog. 231 // 232 // This method should not be called after the watchdog is started and on 233 // some platforms attempting to reconfigure after starting the watchdog 234 // is explicitly forbidden / will not work. 235 func (wd *watchdogImpl) Configure(config WatchdogConfig) error { 236 // 32.768kHz counter 237 crv := int32((int64(config.TimeoutMillis) * 32768) / 1000) 238 nrf.WDT.CRV.Set(uint32(crv)) 239 240 // One source 241 nrf.WDT.RREN.Set(0x1) 242 243 // Run during sleep 244 nrf.WDT.CONFIG.Set(nrf.WDT_CONFIG_SLEEP_Run) 245 246 return nil 247 } 248 249 // Starts the watchdog. 250 func (wd *watchdogImpl) Start() error { 251 nrf.WDT.TASKS_START.Set(nrf.WDT_TASKS_START_TASKS_START) 252 return nil 253 } 254 255 // Update the watchdog, indicating that `source` is healthy. 256 func (wd *watchdogImpl) Update() { 257 // 0x6E524635 = magic value from datasheet 258 nrf.WDT.RR[0].Set(0x6E524635) 259 }