diff --git a/src/machine/i2c.go b/src/machine/i2c.go index c8bd6d1b4f..5fdf2d5266 100644 --- a/src/machine/i2c.go +++ b/src/machine/i2c.go @@ -1,4 +1,4 @@ -//go:build atmega || nrf || sam || stm32 || fe310 || k210 || rp2040 +//go:build atmega || nrf || sam || stm32 || fe310 || k210 || rp2040 || mimxrt1062 package machine @@ -6,6 +6,17 @@ import ( "errors" ) +// If you are getting a compile error on this line please check to see you've +// correctly implemented the methods on the I2C type. They must match +// the i2cController interface method signatures type to type perfectly. +// If not implementing the I2C type please remove your target from the build tags +// at the top of this file. +var _ interface { // 2 + Configure(config I2CConfig) error + Tx(addr uint16, w, r []byte) error + SetBaudRate(br uint32) error +} = (*I2C)(nil) + // TWI_FREQ is the I2C bus speed. Normally either 100 kHz, or 400 kHz for high-speed bus. // // Deprecated: use 100 * machine.KHz or 400 * machine.KHz instead. @@ -25,6 +36,7 @@ var ( errI2CBusError = errors.New("I2C bus error") errI2COverflow = errors.New("I2C receive buffer overflow") errI2COverread = errors.New("I2C transmit buffer overflow") + errI2CNotImplemented = errors.New("I2C operation not yet implemented") ) // I2CTargetEvent reflects events on the I2C bus diff --git a/src/machine/machine_atmega.go b/src/machine/machine_atmega.go index 81a47c0dfa..c5d56b0316 100644 --- a/src/machine/machine_atmega.go +++ b/src/machine/machine_atmega.go @@ -31,6 +31,11 @@ func (i2c *I2C) Configure(config I2CConfig) error { // Activate internal pullups for twi. avr.PORTC.SetBits((avr.DIDR0_ADC4D | avr.DIDR0_ADC5D)) + return i2c.SetBaudRate(config.Frequency) +} + +// SetBaudRate sets the communication speed for I2C. +func (i2c *I2C) SetBaudRate(br uint32) error { // Initialize twi prescaler and bit rate. avr.TWSR.SetBits((avr.TWSR_TWPS0 | avr.TWSR_TWPS1)) @@ -38,7 +43,7 @@ func (i2c *I2C) Configure(config I2CConfig) error { // SCL Frequency = CPU Clock Frequency / (16 + (2 * TWBR)) // NOTE: TWBR should be 10 or higher for controller mode. // It is 72 for a 16mhz board with 100kHz TWI - avr.TWBR.Set(uint8(((CPUFrequency() / config.Frequency) - 16) / 2)) + avr.TWBR.Set(uint8(((CPUFrequency() / br) - 16) / 2)) // Enable twi module. avr.TWCR.Set(avr.TWCR_TWEN) diff --git a/src/machine/machine_atsamd21.go b/src/machine/machine_atsamd21.go index 443c7af56a..3ad93dccf0 100644 --- a/src/machine/machine_atsamd21.go +++ b/src/machine/machine_atsamd21.go @@ -732,12 +732,13 @@ func (i2c *I2C) Configure(config I2CConfig) error { return nil } -// SetBaudRate sets the communication speed for the I2C. -func (i2c *I2C) SetBaudRate(br uint32) { +// SetBaudRate sets the communication speed for I2C. +func (i2c *I2C) SetBaudRate(br uint32) error { // Synchronous arithmetic baudrate, via Arduino SAMD implementation: // SystemCoreClock / ( 2 * baudrate) - 5 - (((SystemCoreClock / 1000000) * WIRE_RISE_TIME_NANOSECONDS) / (2 * 1000)); baud := CPUFrequency()/(2*br) - 5 - (((CPUFrequency() / 1000000) * riseTimeNanoseconds) / (2 * 1000)) i2c.Bus.BAUD.Set(baud) + return nil } // Tx does a single I2C transaction at the specified address. diff --git a/src/machine/machine_atsamd51.go b/src/machine/machine_atsamd51.go index 8d37f2fa5f..bdc00c9aff 100644 --- a/src/machine/machine_atsamd51.go +++ b/src/machine/machine_atsamd51.go @@ -1228,12 +1228,13 @@ func (i2c *I2C) Configure(config I2CConfig) error { return nil } -// SetBaudRate sets the communication speed for the I2C. -func (i2c *I2C) SetBaudRate(br uint32) { +// SetBaudRate sets the communication speed for I2C. +func (i2c *I2C) SetBaudRate(br uint32) error { // Synchronous arithmetic baudrate, via Adafruit SAMD51 implementation: // sercom->I2CM.BAUD.bit.BAUD = SERCOM_FREQ_REF / ( 2 * baudrate) - 1 ; baud := SERCOM_FREQ_REF/(2*br) - 1 i2c.Bus.BAUD.Set(baud) + return nil } // Tx does a single I2C transaction at the specified address. diff --git a/src/machine/machine_fe310.go b/src/machine/machine_fe310.go index 85a2c5bd37..37f3ee07e8 100644 --- a/src/machine/machine_fe310.go +++ b/src/machine/machine_fe310.go @@ -229,9 +229,10 @@ type I2CConfig struct { SDA Pin } +var i2cClockFrequency uint32 = 32000000 + // Configure is intended to setup the I2C interface. func (i2c *I2C) Configure(config I2CConfig) error { - var i2cClockFrequency uint32 = 32000000 if config.Frequency == 0 { config.Frequency = 100 * KHz } @@ -241,7 +242,17 @@ func (i2c *I2C) Configure(config I2CConfig) error { config.SCL = I2C0_SCL_PIN } - var prescaler = i2cClockFrequency/(5*config.Frequency) - 1 + i2c.SetBaudRate(config.Frequency) + + config.SDA.Configure(PinConfig{Mode: PinI2C}) + config.SCL.Configure(PinConfig{Mode: PinI2C}) + + return nil +} + +// SetBaudRate sets the communication speed for I2C. +func (i2c *I2C) SetBaudRate(br uint32) error { + var prescaler = i2cClockFrequency/(5*br) - 1 // disable controller before setting the prescale registers i2c.Bus.CTR.ClearBits(sifive.I2C_CTR_EN) @@ -253,9 +264,6 @@ func (i2c *I2C) Configure(config I2CConfig) error { // enable controller i2c.Bus.CTR.SetBits(sifive.I2C_CTR_EN) - config.SDA.Configure(PinConfig{Mode: PinI2C}) - config.SCL.Configure(PinConfig{Mode: PinI2C}) - return nil } diff --git a/src/machine/machine_generic.go b/src/machine/machine_generic.go index b0aea80621..3b1f059389 100644 --- a/src/machine/machine_generic.go +++ b/src/machine/machine_generic.go @@ -107,6 +107,12 @@ func (i2c *I2C) Configure(config I2CConfig) error { return nil } +// SetBaudRate sets the I2C frequency. +func (i2c *I2C) SetBaudRate(br uint32) error { + i2cSetBaudRate(i2c.Bus, br) + return nil +} + // Tx does a single I2C transaction at the specified address. func (i2c *I2C) Tx(addr uint16, w, r []byte) error { i2cTransfer(i2c.Bus, &w[0], len(w), &r[0], len(r)) @@ -117,6 +123,9 @@ func (i2c *I2C) Tx(addr uint16, w, r []byte) error { //export __tinygo_i2c_configure func i2cConfigure(bus uint8, scl Pin, sda Pin) +//export __tinygo_i2c_set_baud_rate +func i2cSetBaudRate(bus uint8, br uint32) + //export __tinygo_i2c_transfer func i2cTransfer(bus uint8, w *byte, wlen int, r *byte, rlen int) int diff --git a/src/machine/machine_k210.go b/src/machine/machine_k210.go index e8a304c850..e0821670ba 100644 --- a/src/machine/machine_k210.go +++ b/src/machine/machine_k210.go @@ -563,7 +563,19 @@ func (i2c *I2C) Configure(config I2CConfig) error { config.SCL.SetFPIOAFunction(FUNC_I2C2_SCLK) } - div := CPUFrequency() / config.Frequency / 16 + i2c.SetBaudRate(config.Frequency) + + i2c.Bus.INTR_MASK.Set(0) + i2c.Bus.DMA_CR.Set(0x03) + i2c.Bus.DMA_RDLR.Set(0) + i2c.Bus.DMA_TDLR.Set(0x4) + + return nil +} + +// SetBaudRate sets the communication speed for I2C. +func (i2c *I2C) SetBaudRate(br uint32) error { + div := CPUFrequency() / br / 16 // Disable controller before setting the prescale register. i2c.Bus.ENABLE.Set(0) @@ -574,11 +586,6 @@ func (i2c *I2C) Configure(config I2CConfig) error { i2c.Bus.SS_SCL_HCNT.Set(uint32(div)) i2c.Bus.SS_SCL_LCNT.Set(uint32(div)) - i2c.Bus.INTR_MASK.Set(0) - i2c.Bus.DMA_CR.Set(0x03) - i2c.Bus.DMA_RDLR.Set(0) - i2c.Bus.DMA_TDLR.Set(0x4) - return nil } diff --git a/src/machine/machine_mimxrt1062_i2c.go b/src/machine/machine_mimxrt1062_i2c.go index d7ba82f558..f3c4636178 100644 --- a/src/machine/machine_mimxrt1062_i2c.go +++ b/src/machine/machine_mimxrt1062_i2c.go @@ -6,19 +6,6 @@ package machine import ( "device/nxp" - "errors" -) - -var ( - errI2CWriteTimeout = errors.New("I2C timeout during write") - errI2CReadTimeout = errors.New("I2C timeout during read") - errI2CBusReadyTimeout = errors.New("I2C timeout on bus ready") - errI2CSignalStartTimeout = errors.New("I2C timeout on signal start") - errI2CSignalReadTimeout = errors.New("I2C timeout on signal read") - errI2CSignalStopTimeout = errors.New("I2C timeout on signal stop") - errI2CAckExpected = errors.New("I2C error: expected ACK not NACK") - errI2CBusError = errors.New("I2C bus error") - errI2CNotConfigured = errors.New("I2C interface is not yet configured") ) // I2CConfig is used to store config info for I2C. @@ -150,7 +137,7 @@ func (i2c *I2C) setPins(c I2CConfig) (sda, scl Pin) { } // Configure is intended to setup an I2C interface for transmit/receive. -func (i2c *I2C) Configure(config I2CConfig) { +func (i2c *I2C) Configure(config I2CConfig) error { // init pins sda, scl := i2c.setPins(config) @@ -169,6 +156,14 @@ func (i2c *I2C) Configure(config I2CConfig) { // reset clock and registers, and enable LPI2C module interface i2c.reset(freq) + + return nil +} + +// SetBaudRate sets the communication speed for I2C. +func (i2c I2C) SetBaudRate(br uint32) error { + // TODO: implement + return errI2CNotImplemented } func (i2c I2C) Tx(addr uint16, w, r []byte) error { @@ -212,13 +207,13 @@ func (i2c I2C) Tx(addr uint16, w, r []byte) error { return nil } -// WriteRegister transmits first the register and then the data to the +// WriteRegisterEx transmits first the register and then the data to the // peripheral device. // // Many I2C-compatible devices are organized in terms of registers. This method // is a shortcut to easily write to such registers. Also, it only works for // devices with 7-bit addresses, which is the vast majority. -func (i2c I2C) WriteRegister(address uint8, register uint8, data []byte) error { +func (i2c I2C) WriteRegisterEx(address uint8, register uint8, data []byte) error { option := transferOption{ flags: transferDefault, // transfer options bit mask (0 = normal transfer) peripheral: uint16(address), // 7-bit peripheral address @@ -232,13 +227,13 @@ func (i2c I2C) WriteRegister(address uint8, register uint8, data []byte) error { return nil } -// ReadRegister transmits the register, restarts the connection as a read +// ReadRegisterEx transmits the register, restarts the connection as a read // operation, and reads the response. // // Many I2C-compatible devices are organized in terms of registers. This method // is a shortcut to easily read such registers. Also, it only works for devices // with 7-bit addresses, which is the vast majority. -func (i2c I2C) ReadRegister(address uint8, register uint8, data []byte) error { +func (i2c I2C) ReadRegisterEx(address uint8, register uint8, data []byte) error { option := transferOption{ flags: transferDefault, // transfer options bit mask (0 = normal transfer) peripheral: uint16(address), // 7-bit peripheral address @@ -560,7 +555,7 @@ func (i2c *I2C) controllerReceive(rxBuffer []byte) resultFlag { return result } -// controllerReceive performs a polling transmit transfer on the I2C bus. +// controllerTransmit performs a polling transmit transfer on the I2C bus. func (i2c *I2C) controllerTransmit(txBuffer []byte) resultFlag { txSize := len(txBuffer) for txSize > 0 { diff --git a/src/machine/machine_nrf.go b/src/machine/machine_nrf.go index d7b87d9aec..3b79e376a3 100644 --- a/src/machine/machine_nrf.go +++ b/src/machine/machine_nrf.go @@ -246,13 +246,8 @@ func (i2c *I2C) Configure(config I2CConfig) error { i2c.setPins(config.SCL, config.SDA) i2c.mode = config.Mode - if i2c.mode == I2CModeController { - if config.Frequency >= 400*KHz { - i2c.Bus.FREQUENCY.Set(nrf.TWI_FREQUENCY_FREQUENCY_K400) - } else { - i2c.Bus.FREQUENCY.Set(nrf.TWI_FREQUENCY_FREQUENCY_K100) - } + i2c.SetBaudRate(config.Frequency) i2c.enableAsController() } else { @@ -262,6 +257,23 @@ func (i2c *I2C) Configure(config I2CConfig) error { return nil } +// SetBaudRate sets the I2C frequency. It has the side effect of also +// enabling the I2C hardware if disabled beforehand. +// +//go:inline +func (i2c *I2C) SetBaudRate(br uint32) error { + switch { + case br >= 400*KHz: + i2c.Bus.SetFREQUENCY(nrf.TWI_FREQUENCY_FREQUENCY_K400) + case br >= 250*KHz: + i2c.Bus.SetFREQUENCY(nrf.TWI_FREQUENCY_FREQUENCY_K250) + default: + i2c.Bus.SetFREQUENCY(nrf.TWI_FREQUENCY_FREQUENCY_K100) + } + + return nil +} + // signalStop sends a stop signal to the I2C peripheral and waits for confirmation. func (i2c *I2C) signalStop() error { tries := 0 diff --git a/src/machine/machine_stm32_i2c_reva.go b/src/machine/machine_stm32_i2c_reva.go index 38ebdcdc42..1e4fd282e9 100644 --- a/src/machine/machine_stm32_i2c_reva.go +++ b/src/machine/machine_stm32_i2c_reva.go @@ -157,6 +157,12 @@ func (i2c *I2C) Configure(config I2CConfig) error { return nil } +// SetBaudRate sets the communication speed for I2C. +func (i2c *I2C) SetBaudRate(br uint32) error { + // TODO: implement + return errI2CNotImplemented +} + func (i2c *I2C) Tx(addr uint16, w, r []byte) error { if err := i2c.controllerTransmit(addr, w); nil != err { diff --git a/src/machine/machine_stm32_i2c_revb.go b/src/machine/machine_stm32_i2c_revb.go index 6adb704dbd..9253902940 100644 --- a/src/machine/machine_stm32_i2c_revb.go +++ b/src/machine/machine_stm32_i2c_revb.go @@ -84,6 +84,12 @@ func (i2c *I2C) Configure(config I2CConfig) error { return nil } +// SetBaudRate sets the communication speed for I2C. +func (i2c *I2C) SetBaudRate(br uint32) error { + // TODO: implement + return errI2CNotImplemented +} + func (i2c *I2C) Tx(addr uint16, w, r []byte) error { if len(w) > 0 { if err := i2c.controllerTransmit(addr, w); nil != err {