github.com/tinygo-org/tinygo@v0.31.3-0.20240404173401-90b0bf646c27/src/machine/machine_stm32_i2c_revb.go (about) 1 //go:build stm32l5 || stm32f7 || stm32l4 || stm32l0 || stm32wlx 2 3 package machine 4 5 import ( 6 "device/stm32" 7 "unsafe" 8 ) 9 10 //go:linkname ticks runtime.ticks 11 func ticks() int64 12 13 // I2C implementation for 'newer' STM32 MCUs, including the F7, L5 and L4 14 // series of MCUs. 15 // 16 // Currently, only 100KHz mode is supported 17 18 const ( 19 flagBUSY = stm32.I2C_ISR_BUSY 20 flagTCR = stm32.I2C_ISR_TCR 21 flagRXNE = stm32.I2C_ISR_RXNE 22 flagSTOPF = stm32.I2C_ISR_STOPF 23 flagAF = stm32.I2C_ISR_NACKF 24 flagTXIS = stm32.I2C_ISR_TXIS 25 flagTXE = stm32.I2C_ISR_TXE 26 ) 27 28 const ( 29 MAX_NBYTE_SIZE = 255 30 31 // 100ms delay = 100e6ns / 16ns 32 // In runtime_stm32_timers.go, tick is fixed at 16ns per tick 33 TIMEOUT_TICKS = 100e6 / 16 34 35 I2C_NO_STARTSTOP = 0x0 36 I2C_GENERATE_START_WRITE = 0x80000000 | stm32.I2C_CR2_START 37 I2C_GENERATE_START_READ = 0x80000000 | stm32.I2C_CR2_START | stm32.I2C_CR2_RD_WRN 38 I2C_GENERATE_STOP = 0x80000000 | stm32.I2C_CR2_STOP 39 ) 40 41 type I2C struct { 42 Bus *stm32.I2C_Type 43 AltFuncSelector uint8 44 } 45 46 // I2CConfig is used to store config info for I2C. 47 type I2CConfig struct { 48 SCL Pin 49 SDA Pin 50 } 51 52 func (i2c *I2C) Configure(config I2CConfig) error { 53 // disable I2C interface before any configuration changes 54 i2c.Bus.CR1.ClearBits(stm32.I2C_CR1_PE) 55 56 // enable clock for I2C 57 enableAltFuncClock(unsafe.Pointer(i2c.Bus)) 58 59 // init pins 60 if config.SCL == 0 && config.SDA == 0 { 61 config.SCL = I2C0_SCL_PIN 62 config.SDA = I2C0_SDA_PIN 63 } 64 i2c.configurePins(config) 65 66 // Frequency range 67 i2c.Bus.TIMINGR.Set(i2c.getFreqRange()) 68 69 // Disable Own Address1 before set the Own Address1 configuration 70 i2c.Bus.OAR1.ClearBits(stm32.I2C_OAR1_OA1EN) 71 72 // 7 bit addressing, no self address 73 i2c.Bus.OAR1.Set(stm32.I2C_OAR1_OA1EN) 74 75 // Enable the AUTOEND by default, and enable NACK (should be disable only during Slave process 76 i2c.Bus.CR2.Set(stm32.I2C_CR2_AUTOEND | stm32.I2C_CR2_NACK) 77 78 // Disable Own Address2 / Dual Addressing 79 i2c.Bus.OAR2.Set(0) 80 81 // Disable Generalcall and NoStretch, Enable peripheral 82 i2c.Bus.CR1.Set(stm32.I2C_CR1_PE) 83 84 return nil 85 } 86 87 // SetBaudRate sets the communication speed for I2C. 88 func (i2c *I2C) SetBaudRate(br uint32) error { 89 // TODO: implement 90 return errI2CNotImplemented 91 } 92 93 func (i2c *I2C) Tx(addr uint16, w, r []byte) error { 94 if len(w) > 0 { 95 if err := i2c.controllerTransmit(addr, w); nil != err { 96 return err 97 } 98 } 99 100 if len(r) > 0 { 101 if err := i2c.controllerReceive(addr, r); nil != err { 102 return err 103 } 104 } 105 106 return nil 107 } 108 109 func (i2c *I2C) configurePins(config I2CConfig) { 110 config.SCL.ConfigureAltFunc(PinConfig{Mode: PinModeI2CSCL}, i2c.AltFuncSelector) 111 config.SDA.ConfigureAltFunc(PinConfig{Mode: PinModeI2CSDA}, i2c.AltFuncSelector) 112 } 113 114 func (i2c *I2C) controllerTransmit(addr uint16, w []byte) error { 115 start := ticks() 116 117 if !i2c.waitOnFlagUntilTimeout(flagBUSY, false, start) { 118 return errI2CBusReadyTimeout 119 } 120 121 pos := 0 122 xferCount := len(w) 123 xferSize := uint8(xferCount) 124 if xferCount > MAX_NBYTE_SIZE { 125 // Large write, indicate reload 126 xferSize = MAX_NBYTE_SIZE 127 i2c.transferConfig(addr, xferSize, stm32.I2C_CR2_RELOAD, I2C_GENERATE_START_WRITE) 128 } else { 129 // Small write, auto-end 130 i2c.transferConfig(addr, xferSize, stm32.I2C_CR2_AUTOEND, I2C_GENERATE_START_WRITE) 131 } 132 133 for xferCount > 0 { 134 if !i2c.waitOnTXISFlagUntilTimeout(start) { 135 return errI2CWriteTimeout 136 } 137 138 i2c.Bus.TXDR.Set(uint32(w[pos])) 139 pos++ 140 xferCount-- 141 xferSize-- 142 143 // If we've written the last byte of this chunk 144 if xferCount != 0 && xferSize == 0 { 145 // Wait for Transfer Complete Reload to be flagged 146 if !i2c.waitOnFlagUntilTimeout(flagTCR, true, start) { 147 return errI2CWriteTimeout 148 } 149 150 if xferCount > MAX_NBYTE_SIZE { 151 // Large write remaining, indicate reload 152 xferSize = MAX_NBYTE_SIZE 153 i2c.transferConfig(addr, xferSize, stm32.I2C_CR2_RELOAD, I2C_NO_STARTSTOP) 154 } else { 155 // Small write, auto-end 156 xferSize = uint8(xferCount) 157 i2c.transferConfig(addr, xferSize, stm32.I2C_CR2_AUTOEND, I2C_NO_STARTSTOP) 158 } 159 } 160 } 161 162 if !i2c.waitOnStopFlagUntilTimeout(start) { 163 return errI2CWriteTimeout 164 } 165 166 i2c.clearFlag(stm32.I2C_ISR_STOPF) 167 168 i2c.resetCR2() 169 170 return nil 171 } 172 173 func (i2c *I2C) controllerReceive(addr uint16, r []byte) error { 174 start := ticks() 175 176 if !i2c.waitOnFlagUntilTimeout(flagBUSY, false, start) { 177 return errI2CBusReadyTimeout 178 } 179 180 pos := 0 181 xferCount := len(r) 182 xferSize := uint8(xferCount) 183 if xferCount > MAX_NBYTE_SIZE { 184 // Large read, indicate reload 185 xferSize = MAX_NBYTE_SIZE 186 i2c.transferConfig(addr, xferSize, stm32.I2C_CR2_RELOAD, I2C_GENERATE_START_READ) 187 } else { 188 // Small read, auto-end 189 i2c.transferConfig(addr, xferSize, stm32.I2C_CR2_AUTOEND, I2C_GENERATE_START_READ) 190 } 191 192 for xferCount > 0 { 193 if !i2c.waitOnRXNEFlagUntilTimeout(start) { 194 return errI2CWriteTimeout 195 } 196 197 r[pos] = uint8(i2c.Bus.RXDR.Get()) 198 pos++ 199 xferCount-- 200 xferSize-- 201 202 // If we've read the last byte of this chunk 203 if xferCount != 0 && xferSize == 0 { 204 // Wait for Transfer Complete Reload to be flagged 205 if !i2c.waitOnFlagUntilTimeout(flagTCR, true, start) { 206 return errI2CWriteTimeout 207 } 208 209 if xferCount > MAX_NBYTE_SIZE { 210 // Large read remaining, indicate reload 211 xferSize = MAX_NBYTE_SIZE 212 i2c.transferConfig(addr, xferSize, stm32.I2C_CR2_RELOAD, I2C_NO_STARTSTOP) 213 } else { 214 // Small read, auto-end 215 xferSize = uint8(xferCount) 216 i2c.transferConfig(addr, xferSize, stm32.I2C_CR2_AUTOEND, I2C_NO_STARTSTOP) 217 } 218 } 219 } 220 221 if !i2c.waitOnStopFlagUntilTimeout(start) { 222 return errI2CWriteTimeout 223 } 224 225 i2c.clearFlag(stm32.I2C_ISR_STOPF) 226 227 i2c.resetCR2() 228 229 return nil 230 } 231 232 func (i2c *I2C) waitOnFlagUntilTimeout(flag uint32, set bool, startTicks int64) bool { 233 for i2c.hasFlag(flag) != set { 234 if (ticks() - startTicks) > TIMEOUT_TICKS { 235 return false 236 } 237 } 238 return true 239 } 240 241 func (i2c *I2C) waitOnRXNEFlagUntilTimeout(startTicks int64) bool { 242 for !i2c.hasFlag(flagRXNE) { 243 if i2c.isAcknowledgeFailed(startTicks) { 244 return false 245 } 246 247 if i2c.hasFlag(flagSTOPF) { 248 i2c.clearFlag(flagSTOPF) 249 i2c.resetCR2() 250 return false 251 } 252 253 if (ticks() - startTicks) > TIMEOUT_TICKS { 254 return false 255 } 256 } 257 258 return true 259 } 260 261 func (i2c *I2C) waitOnTXISFlagUntilTimeout(startTicks int64) bool { 262 for !i2c.hasFlag(flagTXIS) { 263 if i2c.isAcknowledgeFailed(startTicks) { 264 return false 265 } 266 267 if (ticks() - startTicks) > TIMEOUT_TICKS { 268 return false 269 } 270 } 271 272 return true 273 } 274 275 func (i2c *I2C) waitOnStopFlagUntilTimeout(startTicks int64) bool { 276 for !i2c.hasFlag(flagSTOPF) { 277 if i2c.isAcknowledgeFailed(startTicks) { 278 return false 279 } 280 281 if (ticks() - startTicks) > TIMEOUT_TICKS { 282 return false 283 } 284 } 285 286 return true 287 } 288 289 func (i2c *I2C) isAcknowledgeFailed(startTicks int64) bool { 290 if i2c.hasFlag(flagAF) { 291 // Wait until STOP Flag is reset 292 // AutoEnd should be initiate after AF 293 for !i2c.hasFlag(flagSTOPF) { 294 if (ticks() - startTicks) > TIMEOUT_TICKS { 295 return true 296 } 297 } 298 299 i2c.clearFlag(flagAF) 300 i2c.clearFlag(flagSTOPF) 301 i2c.flushTXDR() 302 i2c.resetCR2() 303 304 return true 305 } 306 307 return false 308 } 309 310 func (i2c *I2C) flushTXDR() { 311 // If a pending TXIS flag is set, write a dummy data in TXDR to clear it 312 if i2c.hasFlag(flagTXIS) { 313 i2c.Bus.TXDR.Set(0) 314 } 315 316 // Flush TX register if not empty 317 if !i2c.hasFlag(flagTXE) { 318 i2c.clearFlag(flagTXE) 319 } 320 } 321 322 func (i2c *I2C) resetCR2() { 323 i2c.Bus.CR2.ClearBits(stm32.I2C_CR2_SADD_Msk | 324 stm32.I2C_CR2_HEAD10R_Msk | 325 stm32.I2C_CR2_NBYTES_Msk | 326 stm32.I2C_CR2_RELOAD_Msk | 327 stm32.I2C_CR2_RD_WRN_Msk) 328 } 329 330 func (i2c *I2C) transferConfig(addr uint16, size uint8, mode uint32, request uint32) { 331 mask := uint32(stm32.I2C_CR2_SADD_Msk | 332 stm32.I2C_CR2_NBYTES_Msk | 333 stm32.I2C_CR2_RELOAD_Msk | 334 stm32.I2C_CR2_AUTOEND_Msk | 335 (stm32.I2C_CR2_RD_WRN & uint32(request>>(31-stm32.I2C_CR2_RD_WRN_Pos))) | 336 stm32.I2C_CR2_START_Msk | 337 stm32.I2C_CR2_STOP_Msk) 338 339 value := (uint32(addr<<1) & stm32.I2C_CR2_SADD_Msk) | 340 ((uint32(size) << stm32.I2C_CR2_NBYTES_Pos) & stm32.I2C_CR2_NBYTES_Msk) | 341 mode | request 342 343 i2c.Bus.CR2.ReplaceBits(value, mask, 0) 344 } 345 346 func (i2c *I2C) hasFlag(flag uint32) bool { 347 return i2c.Bus.ISR.HasBits(flag) 348 } 349 350 func (i2c *I2C) clearFlag(flag uint32) { 351 if flag == stm32.I2C_ISR_TXE { 352 i2c.Bus.ISR.SetBits(flag) 353 } else { 354 i2c.Bus.ICR.SetBits(flag) 355 } 356 }