github.com/tinygo-org/tinygo@v0.31.3-0.20240404173401-90b0bf646c27/src/machine/machine_esp32c3_i2c.go (about) 1 //go:build esp32c3 && !m5stamp_c3 2 3 package machine 4 5 import ( 6 "device/esp" 7 "runtime/volatile" 8 "unsafe" 9 ) 10 11 var ( 12 I2C0 = &I2C{} 13 ) 14 15 type I2C struct{} 16 17 // I2CConfig is used to store config info for I2C. 18 type I2CConfig struct { 19 Frequency uint32 // in Hz 20 SCL Pin 21 SDA Pin 22 } 23 24 const ( 25 clkXTAL = 0 26 clkFOSC = 1 27 clkXTALFrequency = uint32(40e6) 28 clkFOSCFrequency = uint32(17.5e6) 29 i2cClkSourceFrequency = clkXTALFrequency 30 i2cClkSource = clkXTAL 31 ) 32 33 func (i2c *I2C) Configure(config I2CConfig) error { 34 if config.Frequency == 0 { 35 config.Frequency = 400 * KHz 36 } 37 if config.SCL == 0 { 38 config.SCL = SCL_PIN 39 } 40 if config.SDA == 0 { 41 config.SDA = SDA_PIN 42 } 43 44 i2c.initClock(config) 45 i2c.initNoiseFilter() 46 i2c.initPins(config) 47 i2c.initFrequency(config) 48 i2c.startMaster() 49 return nil 50 } 51 52 //go:inline 53 func (i2c *I2C) initClock(config I2CConfig) { 54 // reset I2C clock 55 esp.SYSTEM.SetPERIP_RST_EN0_I2C_EXT0_RST(1) 56 esp.SYSTEM.SetPERIP_CLK_EN0_I2C_EXT0_CLK_EN(1) 57 esp.SYSTEM.SetPERIP_RST_EN0_I2C_EXT0_RST(0) 58 // disable interrupts 59 esp.I2C0.INT_ENA.ClearBits(0x3fff) 60 esp.I2C0.INT_CLR.ClearBits(0x3fff) 61 62 esp.I2C0.SetCLK_CONF_SCLK_SEL(i2cClkSource) 63 esp.I2C0.SetCLK_CONF_SCLK_ACTIVE(1) 64 esp.I2C0.SetCLK_CONF_SCLK_DIV_NUM(i2cClkSourceFrequency / (config.Frequency * 1024)) 65 esp.I2C0.SetCTR_CLK_EN(1) 66 } 67 68 //go:inline 69 func (i2c *I2C) initNoiseFilter() { 70 esp.I2C0.FILTER_CFG.Set(0x377) 71 } 72 73 //go:inline 74 func (i2c *I2C) initPins(config I2CConfig) { 75 var muxConfig uint32 76 const function = 1 // function 1 is just GPIO 77 78 // SDA 79 muxConfig = function << esp.IO_MUX_GPIO_MCU_SEL_Pos 80 // Make this pin an input pin (always). 81 muxConfig |= esp.IO_MUX_GPIO_FUN_IE 82 // Set drive strength: 0 is lowest, 3 is highest. 83 muxConfig |= 1 << esp.IO_MUX_GPIO_FUN_DRV_Pos 84 config.SDA.mux().Set(muxConfig) 85 config.SDA.outFunc().Set(54) 86 inFunc(54).Set(uint32(esp.GPIO_FUNC_IN_SEL_CFG_SEL | config.SDA)) 87 config.SDA.Set(true) 88 // Configure the pad with the given IO mux configuration. 89 config.SDA.pinReg().SetBits(esp.GPIO_PIN_PAD_DRIVER) 90 91 esp.GPIO.ENABLE.SetBits(1 << int(config.SDA)) 92 esp.I2C0.SetCTR_SDA_FORCE_OUT(1) 93 94 // SCL 95 muxConfig = function << esp.IO_MUX_GPIO_MCU_SEL_Pos 96 // Make this pin an input pin (always). 97 muxConfig |= esp.IO_MUX_GPIO_FUN_IE 98 // Set drive strength: 0 is lowest, 3 is highest. 99 muxConfig |= 1 << esp.IO_MUX_GPIO_FUN_DRV_Pos 100 config.SCL.mux().Set(muxConfig) 101 config.SCL.outFunc().Set(53) 102 inFunc(53).Set(uint32(config.SCL)) 103 config.SCL.Set(true) 104 // Configure the pad with the given IO mux configuration. 105 config.SCL.pinReg().SetBits(esp.GPIO_PIN_PAD_DRIVER) 106 107 esp.GPIO.ENABLE.SetBits(1 << int(config.SCL)) 108 esp.I2C0.SetCTR_SCL_FORCE_OUT(1) 109 } 110 111 //go:inline 112 func (i2c *I2C) initFrequency(config I2CConfig) { 113 114 clkmDiv := i2cClkSourceFrequency/(config.Frequency*1024) + 1 115 sclkFreq := i2cClkSourceFrequency / clkmDiv 116 halfCycle := sclkFreq / config.Frequency / 2 117 //SCL 118 sclLow := halfCycle 119 sclWaitHigh := uint32(0) 120 if config.Frequency > 50000 { 121 sclWaitHigh = halfCycle / 8 // compensate the time when freq > 50K 122 } 123 sclHigh := halfCycle - sclWaitHigh 124 // SDA 125 sdaHold := halfCycle / 4 126 sda_sample := halfCycle / 2 127 setup := halfCycle 128 hold := halfCycle 129 130 esp.I2C0.SetSCL_LOW_PERIOD(sclLow - 1) 131 esp.I2C0.SetSCL_HIGH_PERIOD(sclHigh) 132 esp.I2C0.SetSCL_HIGH_PERIOD_SCL_WAIT_HIGH_PERIOD(25) 133 esp.I2C0.SetSCL_RSTART_SETUP_TIME(setup) 134 esp.I2C0.SetSCL_STOP_SETUP_TIME(setup) 135 esp.I2C0.SetSCL_START_HOLD_TIME(hold - 1) 136 esp.I2C0.SetSCL_STOP_HOLD_TIME(hold - 1) 137 esp.I2C0.SetSDA_SAMPLE_TIME(sda_sample) 138 esp.I2C0.SetSDA_HOLD_TIME(sdaHold) 139 } 140 141 //go:inline 142 func (i2c *I2C) startMaster() { 143 // FIFO mode for data 144 esp.I2C0.SetFIFO_CONF_NONFIFO_EN(0) 145 // Reset TX & RX buffers 146 esp.I2C0.SetFIFO_CONF_RX_FIFO_RST(1) 147 esp.I2C0.SetFIFO_CONF_RX_FIFO_RST(0) 148 esp.I2C0.SetFIFO_CONF_TX_FIFO_RST(1) 149 esp.I2C0.SetFIFO_CONF_TX_FIFO_RST(0) 150 // set timeout value 151 esp.I2C0.TO.Set(0x10) 152 // enable master mode 153 esp.I2C0.CTR.Set(0x113) 154 esp.I2C0.SetCTR_CONF_UPGATE(1) 155 resetMaster() 156 } 157 158 //go:inline 159 func resetMaster() { 160 // reset FSM 161 esp.I2C0.SetCTR_FSM_RST(1) 162 // clear the bus 163 esp.I2C0.SetSCL_SP_CONF_SCL_RST_SLV_NUM(9) 164 esp.I2C0.SetSCL_SP_CONF_SCL_RST_SLV_EN(1) 165 esp.I2C0.SetSCL_STRETCH_CONF_SLAVE_SCL_STRETCH_EN(1) 166 esp.I2C0.SetCTR_CONF_UPGATE(1) 167 esp.I2C0.FILTER_CFG.Set(0x377) 168 // wait for SCL_RST_SLV_EN 169 for esp.I2C0.GetSCL_SP_CONF_SCL_RST_SLV_EN() != 0 { 170 } 171 esp.I2C0.SetSCL_SP_CONF_SCL_RST_SLV_NUM(0) 172 } 173 174 type i2cCommandType = uint32 175 type i2cAck = uint32 176 177 const ( 178 i2cCMD_RSTART i2cCommandType = 6 << 11 179 i2cCMD_WRITE i2cCommandType = 1<<11 | 1<<8 // WRITE + ack_check_en 180 i2cCMD_READ i2cCommandType = 3<<11 | 1<<8 // READ + ack_check_en 181 i2cCMD_READLAST i2cCommandType = 3<<11 | 5<<8 // READ + ack_check_en + NACK 182 i2cCMD_STOP i2cCommandType = 2 << 11 183 i2cCMD_END i2cCommandType = 4 << 11 184 ) 185 186 type i2cCommand struct { 187 cmd i2cCommandType 188 data []byte 189 head int 190 } 191 192 //go:linkname nanotime runtime.nanotime 193 func nanotime() int64 194 195 func (i2c *I2C) transmit(addr uint16, cmd []i2cCommand, timeoutMS int) error { 196 const intMask = esp.I2C_INT_STATUS_END_DETECT_INT_ST_Msk | esp.I2C_INT_STATUS_TRANS_COMPLETE_INT_ST_Msk | esp.I2C_INT_STATUS_TIME_OUT_INT_ST_Msk | esp.I2C_INT_STATUS_NACK_INT_ST_Msk 197 esp.I2C0.INT_CLR.SetBits(intMask) 198 esp.I2C0.INT_ENA.SetBits(intMask) 199 esp.I2C0.SetCTR_CONF_UPGATE(1) 200 201 defer func() { 202 esp.I2C0.INT_CLR.SetBits(intMask) 203 esp.I2C0.INT_ENA.ClearBits(intMask) 204 }() 205 206 timeoutNS := int64(timeoutMS) * 1000000 207 needAddress := true 208 needRestart := false 209 readLast := false 210 var readTo []byte 211 for cmdIdx, reg := 0, &esp.I2C0.COMD0; cmdIdx < len(cmd); { 212 c := &cmd[cmdIdx] 213 214 switch c.cmd { 215 case i2cCMD_RSTART: 216 reg.Set(i2cCMD_RSTART) 217 reg = nextAddress(reg) 218 cmdIdx++ 219 220 case i2cCMD_WRITE: 221 count := 32 222 if needAddress { 223 needAddress = false 224 esp.I2C0.SetDATA_FIFO_RDATA((uint32(addr) & 0x7f) << 1) 225 count-- 226 esp.I2C0.SLAVE_ADDR.Set(uint32(addr)) 227 esp.I2C0.SetCTR_CONF_UPGATE(1) 228 } 229 for ; count > 0 && c.head < len(c.data); count, c.head = count-1, c.head+1 { 230 esp.I2C0.SetDATA_FIFO_RDATA(uint32(c.data[c.head])) 231 } 232 reg.Set(i2cCMD_WRITE | uint32(32-count)) 233 reg = nextAddress(reg) 234 235 if c.head < len(c.data) { 236 reg.Set(i2cCMD_END) 237 reg = nil 238 } else { 239 cmdIdx++ 240 } 241 needRestart = true 242 243 case i2cCMD_READ: 244 if needAddress { 245 needAddress = false 246 esp.I2C0.SetDATA_FIFO_RDATA((uint32(addr)&0x7f)<<1 | 1) 247 esp.I2C0.SLAVE_ADDR.Set(uint32(addr)) 248 reg.Set(i2cCMD_WRITE | 1) 249 reg = nextAddress(reg) 250 } 251 if needRestart { 252 // We need to send RESTART again after i2cCMD_WRITE. 253 reg.Set(i2cCMD_RSTART) 254 255 reg = nextAddress(reg) 256 reg.Set(i2cCMD_WRITE | 1) 257 258 reg = nextAddress(reg) 259 esp.I2C0.SetDATA_FIFO_RDATA((uint32(addr)&0x7f)<<1 | 1) 260 needRestart = false 261 } 262 count := 32 263 bytes := len(c.data) - c.head 264 // Only last byte in sequence must be sent with ACK set to 1 to indicate end of data. 265 split := bytes <= count 266 if split { 267 bytes-- 268 } 269 if bytes > 32 { 270 bytes = 32 271 } 272 reg.Set(i2cCMD_READ | uint32(bytes)) 273 reg = nextAddress(reg) 274 275 if split { 276 readLast = true 277 reg.Set(i2cCMD_READLAST | 1) 278 reg = nextAddress(reg) 279 readTo = c.data[c.head : c.head+bytes+1] // read bytes + 1 last byte 280 cmdIdx++ 281 } else { 282 reg.Set(i2cCMD_END) 283 readTo = c.data[c.head : c.head+bytes] 284 reg = nil 285 } 286 287 case i2cCMD_STOP: 288 reg.Set(i2cCMD_STOP) 289 reg = nil 290 cmdIdx++ 291 } 292 if reg == nil { 293 // transmit now 294 esp.I2C0.SetCTR_CONF_UPGATE(1) 295 esp.I2C0.SetCTR_TRANS_START(1) 296 end := nanotime() + timeoutNS 297 var mask uint32 298 for mask = esp.I2C0.INT_STATUS.Get(); mask&intMask == 0; mask = esp.I2C0.INT_STATUS.Get() { 299 if nanotime() > end { 300 if readTo != nil { 301 return errI2CReadTimeout 302 } 303 return errI2CWriteTimeout 304 } 305 } 306 switch { 307 case mask&esp.I2C_INT_STATUS_NACK_INT_ST_Msk != 0 && !readLast: 308 return errI2CAckExpected 309 case mask&esp.I2C_INT_STATUS_TIME_OUT_INT_ST_Msk != 0: 310 if readTo != nil { 311 return errI2CReadTimeout 312 } 313 return errI2CWriteTimeout 314 } 315 esp.I2C0.INT_CLR.SetBits(intMask) 316 for i := 0; i < len(readTo); i++ { 317 readTo[i] = byte(esp.I2C0.GetDATA_FIFO_RDATA() & 0xff) 318 c.head++ 319 } 320 readTo = nil 321 reg = &esp.I2C0.COMD0 322 } 323 } 324 return nil 325 } 326 327 // Tx does a single I2C transaction at the specified address. 328 // It clocks out the given address, writes the bytes in w, reads back len(r) 329 // bytes and stores them in r, and generates a stop condition on the bus. 330 func (i2c *I2C) Tx(addr uint16, w, r []byte) (err error) { 331 // timeout in microseconds. 332 const timeout = 40 // 40ms is a reasonable time for a real-time system. 333 334 cmd := make([]i2cCommand, 0, 8) 335 cmd = append(cmd, i2cCommand{cmd: i2cCMD_RSTART}) 336 if len(w) > 0 { 337 cmd = append(cmd, i2cCommand{cmd: i2cCMD_WRITE, data: w}) 338 } 339 if len(r) > 0 { 340 cmd = append(cmd, i2cCommand{cmd: i2cCMD_READ, data: r}) 341 } 342 cmd = append(cmd, i2cCommand{cmd: i2cCMD_STOP}) 343 344 return i2c.transmit(addr, cmd, timeout) 345 } 346 347 func (i2c *I2C) SetBaudRate(br uint32) error { 348 return nil 349 } 350 351 func nextAddress(reg *volatile.Register32) *volatile.Register32 { 352 return (*volatile.Register32)(unsafe.Add(unsafe.Pointer(reg), 4)) 353 }