diff --git a/src/machine/board_stm32f4disco.go b/src/machine/board_stm32f4disco.go index 7c10b3ed..f1be4814 100644 --- a/src/machine/board_stm32f4disco.go +++ b/src/machine/board_stm32f4disco.go @@ -66,3 +66,15 @@ var ( } SPI1 = &SPI0 ) + +const ( + I2C0_SCL_PIN = PB6 + I2C0_SDA_PIN = PB9 +) + +var ( + I2C0 = I2C{ + Bus: stm32.I2C1, + AltFuncSelector: AF4_I2C1_2_3, + } +) diff --git a/src/machine/i2c.go b/src/machine/i2c.go index f4112317..497a0a79 100644 --- a/src/machine/i2c.go +++ b/src/machine/i2c.go @@ -1,4 +1,4 @@ -// +build avr nrf sam stm32,!stm32f407,!stm32f7x2,!stm32l5x2,!stm32l0 fe310 k210 +// +build avr nrf sam stm32,!stm32f7x2,!stm32l5x2,!stm32l0 fe310 k210 package machine diff --git a/src/machine/machine_stm32_i2c.go b/src/machine/machine_stm32_i2c.go index 0a944c7a..fbee11d8 100644 --- a/src/machine/machine_stm32_i2c.go +++ b/src/machine/machine_stm32_i2c.go @@ -1,4 +1,4 @@ -// +build stm32,!stm32f103,!stm32f407,!stm32f7x2,!stm32l5x2,!stm32l0 +// +build stm32,!stm32f103,!stm32f7x2,!stm32l5x2,!stm32l0 package machine @@ -151,7 +151,7 @@ func (i2c I2C) Configure(config I2CConfig) error { i2c.Bus.CR1.ClearBits(stm32.I2C_CR1_ENGC | stm32.I2C_CR1_NOSTRETCH) // enable I2C interface - i2c.Bus.CR1.ClearBits(stm32.I2C_CR1_PE) + i2c.Bus.CR1.SetBits(stm32.I2C_CR1_PE) return nil } @@ -161,9 +161,13 @@ func (i2c I2C) Tx(addr uint16, w, r []byte) error { if err := i2c.controllerTransmit(addr, w); nil != err { return err } - if err := i2c.controllerReceive(addr, r); nil != err { - return err + + if len(r) > 0 { + if err := i2c.controllerReceive(addr, r); nil != err { + return err + } } + return nil } @@ -173,11 +177,6 @@ func (i2c I2C) controllerTransmit(addr uint16, w []byte) error { return errI2CBusReadyTimeout } - // ensure peripheral is enabled - if !i2c.Bus.CR1.HasBits(stm32.I2C_CR1_PE) { - i2c.Bus.CR1.SetBits(stm32.I2C_CR1_PE) - } - // disable POS i2c.Bus.CR1.ClearBits(stm32.I2C_CR1_POS) @@ -256,11 +255,6 @@ func (i2c I2C) controllerReceive(addr uint16, r []byte) error { return errI2CBusReadyTimeout } - // ensure peripheral is enabled - if !i2c.Bus.CR1.HasBits(stm32.I2C_CR1_PE) { - i2c.Bus.CR1.SetBits(stm32.I2C_CR1_PE) - } - // disable POS i2c.Bus.CR1.ClearBits(stm32.I2C_CR1_POS) diff --git a/src/machine/machine_stm32f407.go b/src/machine/machine_stm32f407.go index a0d9e190..c33094f1 100644 --- a/src/machine/machine_stm32f407.go +++ b/src/machine/machine_stm32f407.go @@ -120,3 +120,81 @@ func (spi SPI) configurePins(config SPIConfig) { config.SDO.ConfigureAltFunc(PinConfig{Mode: PinModeSPISDO}, spi.AltFuncSelector) config.SDI.ConfigureAltFunc(PinConfig{Mode: PinModeSPISDI}, spi.AltFuncSelector) } + +// -- I2C ---------------------------------------------------------------------- + +type I2C struct { + Bus *stm32.I2C_Type + AltFuncSelector uint8 +} + +func (i2c I2C) configurePins(config I2CConfig) { + config.SCL.ConfigureAltFunc(PinConfig{Mode: PinModeI2CSCL}, i2c.AltFuncSelector) + config.SDA.ConfigureAltFunc(PinConfig{Mode: PinModeI2CSDA}, i2c.AltFuncSelector) +} + +func (i2c I2C) getFreqRange(config I2CConfig) uint32 { + // all I2C interfaces are on APB1 (42 MHz) + clock := CPUFrequency() / 4 + // convert to MHz + clock /= 1000000 + // must be between 2 MHz (or 4 MHz for fast mode (Fm)) and 50 MHz, inclusive + var min, max uint32 = 2, 50 + if config.Frequency > 100000 { + min = 4 // fast mode (Fm) + } + if clock < min { + clock = min + } else if clock > max { + clock = max + } + return clock << stm32.I2C_CR2_FREQ_Pos +} + +func (i2c I2C) getRiseTime(config I2CConfig) uint32 { + // These bits must be programmed with the maximum SCL rise time given in the + // I2C bus specification, incremented by 1. + // For instance: in Sm mode, the maximum allowed SCL rise time is 1000 ns. + // If, in the I2C_CR2 register, the value of FREQ[5:0] bits is equal to 0x08 + // and PCLK1 = 125 ns, therefore the TRISE[5:0] bits must be programmed with + // 09h (1000 ns / 125 ns = 8 + 1) + freqRange := i2c.getFreqRange(config) + if config.Frequency > 100000 { + // fast mode (Fm) adjustment + freqRange *= 300 + freqRange /= 1000 + } + return (freqRange + 1) << stm32.I2C_TRISE_TRISE_Pos +} + +func (i2c I2C) getSpeed(config I2CConfig) uint32 { + ccr := func(pclk uint32, freq uint32, coeff uint32) uint32 { + return (((pclk - 1) / (freq * coeff)) + 1) & stm32.I2C_CCR_CCR_Msk + } + sm := func(pclk uint32, freq uint32) uint32 { // standard mode (Sm) + if s := ccr(pclk, freq, 2); s < 4 { + return 4 + } else { + return s + } + } + fm := func(pclk uint32, freq uint32, duty uint8) uint32 { // fast mode (Fm) + if duty == DutyCycle2 { + return ccr(pclk, freq, 3) + } else { + return ccr(pclk, freq, 25) | stm32.I2C_CCR_DUTY + } + } + // all I2C interfaces are on APB1 (42 MHz) + clock := CPUFrequency() / 4 + if config.Frequency <= 100000 { + return sm(clock, config.Frequency) + } else { + s := fm(clock, config.Frequency, config.DutyCycle) + if (s & stm32.I2C_CCR_CCR_Msk) == 0 { + return 1 + } else { + return s | stm32.I2C_CCR_F_S + } + } +}