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  }