From 1343dc63e6e65b837ae7ba19d98864901928de0e Mon Sep 17 00:00:00 2001 From: ardnew Date: Thu, 3 Sep 2020 23:03:15 -0500 Subject: [PATCH 1/6] setup STM32F4 I2C framework --- src/machine/i2c.go | 2 +- src/machine/machine_stm32_i2c.go | 34 ++++++++++++++++++++++++++++++++ src/machine/machine_stm32f405.go | 3 +++ 3 files changed, 38 insertions(+), 1 deletion(-) create mode 100644 src/machine/machine_stm32_i2c.go diff --git a/src/machine/i2c.go b/src/machine/i2c.go index b465060630..4845d41e4d 100644 --- a/src/machine/i2c.go +++ b/src/machine/i2c.go @@ -1,4 +1,4 @@ -// +build avr nrf sam stm32,!stm32f4 fe310 k210 +// +build avr nrf sam stm32 fe310 k210 package machine diff --git a/src/machine/machine_stm32_i2c.go b/src/machine/machine_stm32_i2c.go new file mode 100644 index 0000000000..3e51639f54 --- /dev/null +++ b/src/machine/machine_stm32_i2c.go @@ -0,0 +1,34 @@ +// +build stm32 + +package machine + +// Peripheral abstraction layer for I2C on the stm32 family + +import ( + "unsafe" +) + +// I2CConfig is used to store config info for I2C. +type I2CConfig struct { + Frequency uint32 + SCL Pin + SDA Pin +} + +// Configure is intended to setup the STM32 I2C interface. +func (i2c I2C) Configure(config I2CConfig) { + + // enable clock for I2C + enableAltFuncClock(unsafe.Pointer(i2c.Bus)) + + // init pins + if config.SCL == 0 && config.SDA == 0 { + config.SCL = I2C0_SCL_PIN + config.SDA = I2C0_SDA_PIN + } + i2c.configurePins(config) + + // Get I2C baud rate based on the bus speed it's attached to + var conf uint32 = i2c.getBaudRate(config) + +} diff --git a/src/machine/machine_stm32f405.go b/src/machine/machine_stm32f405.go index e59941716c..5a218dc99d 100644 --- a/src/machine/machine_stm32f405.go +++ b/src/machine/machine_stm32f405.go @@ -55,3 +55,6 @@ type I2C struct { Bus *stm32.I2C_Type AltFuncSelector stm32.AltFunc } + +func (i2c I2C) configurePins(config I2CConfig) {} +func (i2c I2C) getBaudRate(config I2CConfig) uint32 { return 0 } From c6990d9c3375e679870efc198eeb15e4afbde653 Mon Sep 17 00:00:00 2001 From: ardnew Date: Sat, 5 Sep 2020 15:12:57 -0500 Subject: [PATCH 2/6] add initial I2C --- src/machine/board_feather-stm32f405.go | 24 +- src/machine/machine_stm32_i2c.go | 405 ++++++++++++++++++++++++- src/machine/machine_stm32f405.go | 84 ++++- 3 files changed, 505 insertions(+), 8 deletions(-) diff --git a/src/machine/board_feather-stm32f405.go b/src/machine/board_feather-stm32f405.go index 14c7d063f9..d1206b45aa 100644 --- a/src/machine/board_feather-stm32f405.go +++ b/src/machine/board_feather-stm32f405.go @@ -186,11 +186,11 @@ const ( // #===========#==========#==============#==============#=======#=======# // | Interface | Hardware | Bus(Freq) | SDA/SCL Pins | AltFn | Alias | // #===========#==========#==============#==============#=======#=======# - // | I2C1 | I2C1 | | D14/D15 | | ~ | - // | I2C2 | I2C2 | | D0/D1 | | ~ | - // | I2C3 | I2C1 | | D9/D10 | | ~ | + // | I2C1 | I2C1 | APB1(42 MHz) | D14/D15 | 4 | ~ | + // | I2C2 | I2C2 | APB1(42 MHz) | D0/D1 | 4 | ~ | + // | I2C3 | I2C1 | APB1(42 MHz) | D9/D10 | 4 | ~ | // | --------- | -------- | ------------ | ------------ | ----- | ----- | - // | I2C0 | I2C1 | | D14/D15 | | I2C1 | + // | I2C0 | I2C1 | APB1(42 MHz) | D14/D15 | 4 | I2C1 | // #===========#==========#==============#==============#=======#=======# NUM_I2C_INTERFACES = 3 @@ -210,4 +210,20 @@ const ( I2C_SCL_PIN = I2C0_SCL_PIN // ) +var ( + I2C1 = I2C{ + Bus: stm32.I2C1, + AltFuncSelector: stm32.AF4_I2C1_2_3, + } + I2C2 = I2C{ + Bus: stm32.I2C2, + AltFuncSelector: stm32.AF4_I2C1_2_3, + } + I2C3 = I2C{ + Bus: stm32.I2C1, + AltFuncSelector: stm32.AF4_I2C1_2_3, + } + I2C0 = I2C1 +) + func initI2C() {} diff --git a/src/machine/machine_stm32_i2c.go b/src/machine/machine_stm32_i2c.go index 3e51639f54..8916484433 100644 --- a/src/machine/machine_stm32_i2c.go +++ b/src/machine/machine_stm32_i2c.go @@ -5,19 +5,38 @@ package machine // Peripheral abstraction layer for I2C on the stm32 family import ( + "device/stm32" "unsafe" ) +// I2C fast mode (Fm) duty cycle +const ( + Duty2 = 0 + Duty16_9 = 1 +) + // I2CConfig is used to store config info for I2C. type I2CConfig struct { Frequency uint32 SCL Pin SDA Pin + DutyCycle uint8 } // Configure is intended to setup the STM32 I2C interface. func (i2c I2C) Configure(config I2CConfig) { + // The following is the required sequence in master mode. + // 1. Program the peripheral input clock in I2C_CR2 Register in order to + // generate correct timings + // 2. Configure the clock control registers + // 3. Configure the rise time register + // 4. Program the I2C_CR1 register to enable the peripheral + // 5. Set the START bit in the I2C_CR1 register to generate a Start condition + + // disable I2C interface before any configuration changes + i2c.Bus.CR1.ClearBits(stm32.I2C_CR1_PE) + // enable clock for I2C enableAltFuncClock(unsafe.Pointer(i2c.Bus)) @@ -28,7 +47,389 @@ func (i2c I2C) Configure(config I2CConfig) { } i2c.configurePins(config) - // Get I2C baud rate based on the bus speed it's attached to - var conf uint32 = i2c.getBaudRate(config) + // default to 100 kHz (Sm, standard mode) if no frequency is set + if config.Frequency == 0 { + config.Frequency = TWI_FREQ_100KHZ + } + + // configure I2C input clock + i2c.Bus.CR2.SetBits(i2c.getFreqRange(config)) + + // configure clock control + i2c.Bus.CCR.Set(i2c.getSpeed(config)) + + // configure rise time + i2c.Bus.TRISE.Set(i2c.getRiseTime(config)) + + // enable I2C interface + i2c.Bus.CR1.ClearBits(stm32.I2C_CR1_PE) +} + +// Tx does a single I2C transaction at the specified address. +// It clocks out the given address, writes the bytes in w, reads back len(r) +// bytes and stores them in r, and generates a stop condition on the bus. +func (i2c I2C) Tx(addr uint16, w, r []byte) error { + var err error + if len(w) != 0 { + // start transmission for writing + err = i2c.signalStart() + if err != nil { + return err + } + + // send address + err = i2c.sendAddress(uint8(addr), true) + if err != nil { + return err + } + + for _, b := range w { + err = i2c.WriteByte(b) + if err != nil { + return err + } + } + + // sending stop here for write + err = i2c.signalStop() + if err != nil { + return err + } + } + if len(r) != 0 { + // re-start transmission for reading + err = i2c.signalStart() + if err != nil { + return err + } + + // 1 byte + switch len(r) { + case 1: + // send address + err = i2c.sendAddress(uint8(addr), false) + if err != nil { + return err + } + + // Disable ACK of received data + i2c.Bus.CR1.ClearBits(stm32.I2C_CR1_ACK) + + // clear timeout here + timeout := i2cTimeout + for !i2c.Bus.SR2.HasBits(stm32.I2C_SR2_MSL | stm32.I2C_SR2_BUSY) { + timeout-- + if timeout == 0 { + return errI2CWriteTimeout + } + } + + // Generate stop condition + i2c.Bus.CR1.SetBits(stm32.I2C_CR1_STOP) + + timeout = i2cTimeout + for !i2c.Bus.SR1.HasBits(stm32.I2C_SR1_RxNE) { + timeout-- + if timeout == 0 { + return errI2CReadTimeout + } + } + + // Read and return data byte from I2C data register + r[0] = byte(i2c.Bus.DR.Get()) + + // wait for stop + return i2c.waitForStop() + + case 2: + // enable pos + i2c.Bus.CR1.SetBits(stm32.I2C_CR1_POS) + + // Enable ACK of received data + i2c.Bus.CR1.SetBits(stm32.I2C_CR1_ACK) + + // send address + err = i2c.sendAddress(uint8(addr), false) + if err != nil { + return err + } + + // clear address here + timeout := i2cTimeout + for !i2c.Bus.SR2.HasBits(stm32.I2C_SR2_MSL | stm32.I2C_SR2_BUSY) { + timeout-- + if timeout == 0 { + return errI2CWriteTimeout + } + } + + // Disable ACK of received data + i2c.Bus.CR1.ClearBits(stm32.I2C_CR1_ACK) + + // wait for btf. we need a longer timeout here than normal. + timeout = 1000 + for !i2c.Bus.SR1.HasBits(stm32.I2C_SR1_BTF) { + timeout-- + if timeout == 0 { + return errI2CReadTimeout + } + } + + // Generate stop condition + i2c.Bus.CR1.SetBits(stm32.I2C_CR1_STOP) + + // read the 2 bytes by reading twice. + r[0] = byte(i2c.Bus.DR.Get()) + r[1] = byte(i2c.Bus.DR.Get()) + + // wait for stop + err = i2c.waitForStop() + + //disable pos + i2c.Bus.CR1.ClearBits(stm32.I2C_CR1_POS) + + return err + + case 3: + // Enable ACK of received data + i2c.Bus.CR1.SetBits(stm32.I2C_CR1_ACK) + + // send address + err = i2c.sendAddress(uint8(addr), false) + if err != nil { + return err + } + + // clear address here + timeout := i2cTimeout + for !i2c.Bus.SR2.HasBits(stm32.I2C_SR2_MSL | stm32.I2C_SR2_BUSY) { + timeout-- + if timeout == 0 { + return errI2CWriteTimeout + } + } + + // Enable ACK of received data + i2c.Bus.CR1.SetBits(stm32.I2C_CR1_ACK) + + // wait for btf. we need a longer timeout here than normal. + timeout = 1000 + for !i2c.Bus.SR1.HasBits(stm32.I2C_SR1_BTF) { + timeout-- + if timeout == 0 { + return errI2CReadTimeout + } + } + + // Disable ACK of received data + i2c.Bus.CR1.ClearBits(stm32.I2C_CR1_ACK) + + // read the first byte + r[0] = byte(i2c.Bus.DR.Get()) + + timeout = 1000 + for !i2c.Bus.SR1.HasBits(stm32.I2C_SR1_BTF) { + timeout-- + if timeout == 0 { + return errI2CReadTimeout + } + } + + // Generate stop condition + i2c.Bus.CR1.SetBits(stm32.I2C_CR1_STOP) + + // read the last 2 bytes by reading twice. + r[1] = byte(i2c.Bus.DR.Get()) + r[2] = byte(i2c.Bus.DR.Get()) + + // wait for stop + return i2c.waitForStop() + + default: + // more than 3 bytes of data to read + + // send address + err = i2c.sendAddress(uint8(addr), false) + if err != nil { + return err + } + + // clear address here + timeout := i2cTimeout + for !i2c.Bus.SR2.HasBits(stm32.I2C_SR2_MSL | stm32.I2C_SR2_BUSY) { + timeout-- + if timeout == 0 { + return errI2CWriteTimeout + } + } + + for i := 0; i < len(r)-3; i++ { + // Enable ACK of received data + i2c.Bus.CR1.SetBits(stm32.I2C_CR1_ACK) + + // wait for btf. we need a longer timeout here than normal. + timeout = 1000 + for !i2c.Bus.SR1.HasBits(stm32.I2C_SR1_BTF) { + timeout-- + if timeout == 0 { + return errI2CReadTimeout + } + } + + // read the next byte + r[i] = byte(i2c.Bus.DR.Get()) + } + + // wait for btf. we need a longer timeout here than normal. + timeout = 1000 + for !i2c.Bus.SR1.HasBits(stm32.I2C_SR1_BTF) { + timeout-- + if timeout == 0 { + return errI2CReadTimeout + } + } + + // Disable ACK of received data + i2c.Bus.CR1.ClearBits(stm32.I2C_CR1_ACK) + + // get third from last byte + r[len(r)-3] = byte(i2c.Bus.DR.Get()) + + // Generate stop condition + i2c.Bus.CR1.SetBits(stm32.I2C_CR1_STOP) + + // get second from last byte + r[len(r)-2] = byte(i2c.Bus.DR.Get()) + + timeout = i2cTimeout + for !i2c.Bus.SR1.HasBits(stm32.I2C_SR1_RxNE) { + timeout-- + if timeout == 0 { + return errI2CReadTimeout + } + } + + // get last byte + r[len(r)-1] = byte(i2c.Bus.DR.Get()) + + // wait for stop + return i2c.waitForStop() + } + } + + return nil +} + +const i2cTimeout = 500 + +// signalStart sends a start signal. +func (i2c I2C) signalStart() error { + // Wait until I2C is not busy + timeout := i2cTimeout + for i2c.Bus.SR2.HasBits(stm32.I2C_SR2_BUSY) { + timeout-- + if timeout == 0 { + return errI2CSignalStartTimeout + } + } + + // clear stop + i2c.Bus.CR1.ClearBits(stm32.I2C_CR1_STOP) + + // Generate start condition + i2c.Bus.CR1.SetBits(stm32.I2C_CR1_START) + + // Wait for I2C EV5 aka SB flag. + timeout = i2cTimeout + for !i2c.Bus.SR1.HasBits(stm32.I2C_SR1_SB) { + timeout-- + if timeout == 0 { + return errI2CSignalStartTimeout + } + } + + return nil +} + +// signalStop sends a stop signal and waits for it to succeed. +func (i2c I2C) signalStop() error { + // Generate stop condition + i2c.Bus.CR1.SetBits(stm32.I2C_CR1_STOP) + + // wait for stop + return i2c.waitForStop() +} + +// waitForStop waits after a stop signal. +func (i2c I2C) waitForStop() error { + // Wait until I2C is stopped + timeout := i2cTimeout + for i2c.Bus.SR1.HasBits(stm32.I2C_SR1_STOPF) { + timeout-- + if timeout == 0 { + return errI2CSignalStopTimeout + } + } + + return nil +} + +// Send address of device we want to talk to +func (i2c I2C) sendAddress(address uint8, write bool) error { + data := (address << 1) + if !write { + data |= 1 // set read flag + } + + i2c.Bus.DR.Set(uint32(data)) + + // Wait for I2C EV6 event. + // Destination device acknowledges address + timeout := i2cTimeout + if write { + // EV6 which is ADDR flag. + for !i2c.Bus.SR1.HasBits(stm32.I2C_SR1_ADDR) { + timeout-- + if timeout == 0 { + return errI2CWriteTimeout + } + } + + timeout = i2cTimeout + for !i2c.Bus.SR2.HasBits(stm32.I2C_SR2_MSL | stm32.I2C_SR2_BUSY | stm32.I2C_SR2_TRA) { + timeout-- + if timeout == 0 { + return errI2CWriteTimeout + } + } + } else { + // I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED which is ADDR flag. + for !i2c.Bus.SR1.HasBits(stm32.I2C_SR1_ADDR) { + timeout-- + if timeout == 0 { + return errI2CWriteTimeout + } + } + } + + return nil +} + +// WriteByte writes a single byte to the I2C bus. +func (i2c I2C) WriteByte(data byte) error { + // Send data byte + i2c.Bus.DR.Set(uint32(data)) + + // Wait for I2C EV8_2 when data has been physically shifted out and + // output on the bus. + // I2C_EVENT_MASTER_BYTE_TRANSMITTED is TXE flag. + timeout := i2cTimeout + for !i2c.Bus.SR1.HasBits(stm32.I2C_SR1_TxE) { + timeout-- + if timeout == 0 { + return errI2CWriteTimeout + } + } + return nil } diff --git a/src/machine/machine_stm32f405.go b/src/machine/machine_stm32f405.go index 5a218dc99d..dd9f30beff 100644 --- a/src/machine/machine_stm32f405.go +++ b/src/machine/machine_stm32f405.go @@ -56,5 +56,85 @@ type I2C struct { AltFuncSelector stm32.AltFunc } -func (i2c I2C) configurePins(config I2CConfig) {} -func (i2c I2C) getBaudRate(config I2CConfig) uint32 { return 0 } +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 > 10000 { + 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 { + // getSpeed is based on the following STM32CubeMX macros: + // + // #define I2C_MIN_PCLK_FREQ(__PCLK__, __SPEED__) (((__SPEED__) <= 100000U) ? ((__PCLK__) < I2C_MIN_PCLK_FREQ_STANDARD) : ((__PCLK__) < I2C_MIN_PCLK_FREQ_FAST)) + // #define I2C_CCR_CALCULATION(__PCLK__, __SPEED__, __COEFF__) (((((__PCLK__) - 1U)/((__SPEED__) * (__COEFF__))) + 1U) & I2C_CCR_CCR) + // #define I2C_FREQRANGE(__PCLK__) ((__PCLK__)/1000000U) + // #define I2C_RISE_TIME(__FREQRANGE__, __SPEED__) (((__SPEED__) <= 100000U) ? ((__FREQRANGE__) + 1U) : ((((__FREQRANGE__) * 300U) / 1000U) + 1U)) + // #define I2C_SPEED_STANDARD(__PCLK__, __SPEED__) ((I2C_CCR_CALCULATION((__PCLK__), (__SPEED__), 2U) < 4U)? 4U:I2C_CCR_CALCULATION((__PCLK__), (__SPEED__), 2U)) + // #define I2C_SPEED_FAST(__PCLK__, __SPEED__, __DUTYCYCLE__) (((__DUTYCYCLE__) == I2C_DUTYCYCLE_2)? I2C_CCR_CALCULATION((__PCLK__), (__SPEED__), 3U) : (I2C_CCR_CALCULATION((__PCLK__), (__SPEED__), 25U) | I2C_DUTYCYCLE_16_9)) + // #define I2C_SPEED(__PCLK__, __SPEED__, __DUTYCYCLE__) (((__SPEED__) <= 100000U)? (I2C_SPEED_STANDARD((__PCLK__), (__SPEED__))) : \ + // ((I2C_SPEED_FAST((__PCLK__), (__SPEED__), (__DUTYCYCLE__)) & I2C_CCR_CCR) == 0U)? 1U : \ + // ((I2C_SPEED_FAST((__PCLK__), (__SPEED__), (__DUTYCYCLE__))) | I2C_CCR_FS)) + // + 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 == Duty2 { + 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 + } + } +} From dc960ecfd3627e6422058a79e0b0ef0f92ebd53a Mon Sep 17 00:00:00 2001 From: ardnew Date: Sun, 6 Sep 2020 14:13:32 -0500 Subject: [PATCH 3/6] exclude stm32f103xx from STM32 I2C, because it uses its own impl --- src/machine/machine_stm32_i2c.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/machine/machine_stm32_i2c.go b/src/machine/machine_stm32_i2c.go index 8916484433..352f2975bd 100644 --- a/src/machine/machine_stm32_i2c.go +++ b/src/machine/machine_stm32_i2c.go @@ -1,4 +1,4 @@ -// +build stm32 +// +build stm32,!stm32f103xx package machine From 800f2d7b0dea90b3d0cd71e1a3c1fb7156b6543f Mon Sep 17 00:00:00 2001 From: ardnew Date: Mon, 7 Sep 2020 17:30:07 -0500 Subject: [PATCH 4/6] initial I2C master support for STM32 family --- src/machine/machine_stm32_i2c.go | 640 +++++++++++++++++-------------- src/machine/machine_stm32f405.go | 14 +- 2 files changed, 344 insertions(+), 310 deletions(-) diff --git a/src/machine/machine_stm32_i2c.go b/src/machine/machine_stm32_i2c.go index 352f2975bd..54fffce668 100644 --- a/src/machine/machine_stm32_i2c.go +++ b/src/machine/machine_stm32_i2c.go @@ -9,10 +9,128 @@ import ( "unsafe" ) +const ( + flagOVR = 0x00010800 + flagAF = 0x00010400 + flagARLO = 0x00010200 + flagBERR = 0x00010100 + flagTXE = 0x00010080 + flagRXNE = 0x00010040 + flagSTOPF = 0x00010010 + flagADD10 = 0x00010008 + flagBTF = 0x00010004 + flagADDR = 0x00010002 + flagSB = 0x00010001 + flagDUALF = 0x00100080 + flagGENCALL = 0x00100010 + flagTRA = 0x00100004 + flagBUSY = 0x00100002 + flagMSL = 0x00100001 +) + +func (i2c I2C) hasFlag(flag uint32) bool { + const mask = 0x0000FFFF + if uint8(flag>>16) == 1 { + return i2c.Bus.SR1.HasBits(flag & mask) + } else { + return i2c.Bus.SR2.HasBits(flag & mask) + } +} + +func (i2c I2C) clearFlag(flag uint32) { + const mask = 0x0000FFFF + i2c.Bus.SR1.Set(^(flag & mask)) +} + +// clearFlagADDR reads both status registers to clear any pending ADDR flags. +func (i2c I2C) clearFlagADDR() { + i2c.Bus.SR1.Get() + i2c.Bus.SR2.Get() +} + +func (i2c I2C) waitForFlag(flag uint32, set bool) bool { + const tryMax = 10000 + hasFlag := false + for i := 0; !hasFlag && i < tryMax; i++ { + hasFlag = i2c.hasFlag(flag) == set + } + return hasFlag +} + +func (i2c I2C) waitForFlagOrError(flag uint32, set bool) bool { + const tryMax = 10000 + hasFlag := false + for i := 0; !hasFlag && i < tryMax; i++ { + if hasFlag = i2c.hasFlag(flag) == set; !hasFlag { + // check for ACK failure + if i2c.hasFlag(flagAF) { + // generate stop condition + i2c.Bus.CR1.SetBits(stm32.I2C_CR1_STOP) + // clear pending flags + i2c.clearFlag(flagAF) + return false + } else if i2c.hasFlag(flagSTOPF) { + // clear stop flag + i2c.clearFlag(flagSTOPF) + return false + } + } + } + return hasFlag +} + +type transferOption uint32 + +const ( + frameFirst = 0x00000001 + frameFirstAndNext = 0x00000002 + frameNext = 0x00000004 + frameFirstAndLast = 0x00000008 + frameLastNoStop = 0x00000010 + frameLast = 0x00000020 + frameNoOption = 0xFFFF0000 +) + +// addressable represents a type that can provide fully-formatted I2C slave +// addresses for both read operations and write operations. +type addressable interface { + toRead() uint32 + toWrite() uint32 + bitSize() uint8 +} + +// address7Bit and address10Bit stores the unshifted original I2C slave address +// in an unsigned integral data type and implements the addressable interface +// to reformat addresses as required for read/write operations. +// TODO: +// add 10-bit address support +type ( + address7Bit uint8 + //address10Bit uint16 +) + +func (sa address7Bit) toRead() uint32 { + return uint32(((uint8(sa) << 1) | uint8(stm32.I2C_OAR1_ADD0)) & 0xFF) +} +func (sa address7Bit) toWrite() uint32 { + return uint32(((uint8(sa) << 1) & ^(uint8(stm32.I2C_OAR1_ADD0))) & 0xFF) +} +func (sa address7Bit) bitSize() uint8 { return 7 } // 7-bit addresses + +//func (sa address10Bit) toRead() uint32 {} +//func (sa address10Bit) toWrite() uint32 {} +//func (sa address10Bit) bitSize() uint8 { return 10 } // 10-bit addresses + +func readAddress7Bit(addr uint8) uint32 { return address7Bit(addr).toRead() } +func writeAddress7Bit(addr uint8) uint32 { return address7Bit(addr).toWrite() } + +//func readAddress10Bit(addr uint16) uint32 { return address10Bit(addr).toRead() } +//func writeAddress10Bit(addr uint16) uint32 { return address10Bit(addr).toWrite() } + // I2C fast mode (Fm) duty cycle const ( - Duty2 = 0 - Duty16_9 = 1 + DutyCycle2 = 0 + DutyCycle16x9 = 1 ) // I2CConfig is used to store config info for I2C. @@ -37,6 +155,10 @@ func (i2c I2C) Configure(config I2CConfig) { // disable I2C interface before any configuration changes i2c.Bus.CR1.ClearBits(stm32.I2C_CR1_PE) + // reset I2C bus + i2c.Bus.CR1.SetBits(stm32.I2C_CR1_SWRST) + i2c.Bus.CR1.ClearBits(stm32.I2C_CR1_SWRST) + // enable clock for I2C enableAltFuncClock(unsafe.Pointer(i2c.Bus)) @@ -55,380 +177,304 @@ func (i2c I2C) Configure(config I2CConfig) { // configure I2C input clock i2c.Bus.CR2.SetBits(i2c.getFreqRange(config)) + // configure rise time + i2c.Bus.TRISE.Set(i2c.getRiseTime(config)) + // configure clock control i2c.Bus.CCR.Set(i2c.getSpeed(config)) - // configure rise time - i2c.Bus.TRISE.Set(i2c.getRiseTime(config)) + // disable GeneralCall and NoStretch modes + i2c.Bus.CR1.ClearBits(stm32.I2C_CR1_ENGC | stm32.I2C_CR1_NOSTRETCH) // enable I2C interface i2c.Bus.CR1.ClearBits(stm32.I2C_CR1_PE) } -// Tx does a single I2C transaction at the specified address. -// It clocks out the given address, writes the bytes in w, reads back len(r) -// bytes and stores them in r, and generates a stop condition on the bus. func (i2c I2C) Tx(addr uint16, w, r []byte) error { - var err error - if len(w) != 0 { - // start transmission for writing - err = i2c.signalStart() - if err != nil { - return err - } + a := address7Bit(addr) + if err := i2c.masterTransmit(a, w); nil != err { + return err + } + if err := i2c.masterReceive(a, r); nil != err { + return err + } + return nil +} - // send address - err = i2c.sendAddress(uint8(addr), true) - if err != nil { - return err - } +func (i2c I2C) masterTransmit(addr addressable, w []byte) error { - for _, b := range w { - err = i2c.WriteByte(b) - if err != nil { - return err - } - } + if !i2c.waitForFlag(flagBUSY, false) { + return errI2CBusReadyTimeout + } - // sending stop here for write - err = i2c.signalStop() - if err != nil { - return err - } + // ensure peripheral is enabled + if !i2c.Bus.CR1.HasBits(stm32.I2C_CR1_PE) { + i2c.Bus.CR1.SetBits(stm32.I2C_CR1_PE) } - if len(r) != 0 { - // re-start transmission for reading - err = i2c.signalStart() - if err != nil { - return err - } - // 1 byte - switch len(r) { - case 1: - // send address - err = i2c.sendAddress(uint8(addr), false) - if err != nil { - return err - } + // disable POS + i2c.Bus.CR1.ClearBits(stm32.I2C_CR1_POS) - // Disable ACK of received data - i2c.Bus.CR1.ClearBits(stm32.I2C_CR1_ACK) + pos := 0 + rem := len(w) - // clear timeout here - timeout := i2cTimeout - for !i2c.Bus.SR2.HasBits(stm32.I2C_SR2_MSL | stm32.I2C_SR2_BUSY) { - timeout-- - if timeout == 0 { - return errI2CWriteTimeout - } - } + // send slave address + if err := i2c.masterRequestWrite(addr, frameNoOption); nil != err { + return err + } - // Generate stop condition - i2c.Bus.CR1.SetBits(stm32.I2C_CR1_STOP) + // clear ADDR flag + i2c.clearFlagADDR() - timeout = i2cTimeout - for !i2c.Bus.SR1.HasBits(stm32.I2C_SR1_RxNE) { - timeout-- - if timeout == 0 { - return errI2CReadTimeout - } - } + for rem > 0 { + // wait for TXE flag set + if !i2c.waitForFlagOrError(flagTXE, true) { + return errI2CAckExpected + } - // Read and return data byte from I2C data register - r[0] = byte(i2c.Bus.DR.Get()) + // write data to DR + i2c.Bus.DR.Set(uint32(w[pos])) + // update counters + pos++ + rem-- + + if i2c.hasFlag(flagBTF) && rem != 0 { + // write data to DR + i2c.Bus.DR.Set(uint32(w[pos])) + // update counters + pos++ + rem-- + } - // wait for stop - return i2c.waitForStop() + // wait for transfer finished flag BTF set + if !i2c.waitForFlagOrError(flagBTF, true) { + return errI2CWriteTimeout + } + } - case 2: - // enable pos - i2c.Bus.CR1.SetBits(stm32.I2C_CR1_POS) + // generate stop condition + i2c.Bus.CR1.SetBits(stm32.I2C_CR1_STOP) - // Enable ACK of received data - i2c.Bus.CR1.SetBits(stm32.I2C_CR1_ACK) + return nil +} - // send address - err = i2c.sendAddress(uint8(addr), false) - if err != nil { - return err - } +func (i2c I2C) masterRequestWrite(addr addressable, option transferOption) error { - // clear address here - timeout := i2cTimeout - for !i2c.Bus.SR2.HasBits(stm32.I2C_SR2_MSL | stm32.I2C_SR2_BUSY) { - timeout-- - if timeout == 0 { - return errI2CWriteTimeout - } - } + if frameFirstAndLast == option || frameFirst == option || frameNoOption == option { + // generate start condition + i2c.Bus.CR1.SetBits(stm32.I2C_CR1_START) + } else if false /* (hi2c->PreviousState == I2C_STATE_MASTER_BUSY_RX) */ { + // generate restart condition + i2c.Bus.CR1.SetBits(stm32.I2C_CR1_START) + } - // Disable ACK of received data - i2c.Bus.CR1.ClearBits(stm32.I2C_CR1_ACK) + // ensure start bit is set + if !i2c.waitForFlag(flagSB, true) { + return errI2CSignalStartTimeout + } - // wait for btf. we need a longer timeout here than normal. - timeout = 1000 - for !i2c.Bus.SR1.HasBits(stm32.I2C_SR1_BTF) { - timeout-- - if timeout == 0 { - return errI2CReadTimeout - } - } + // send slave address + switch addr.bitSize() { + case 7: // 7-bit slave address + i2c.Bus.DR.Set(addr.toWrite()) - // Generate stop condition - i2c.Bus.CR1.SetBits(stm32.I2C_CR1_STOP) + case 10: // 10-bit slave address + // TODO + } - // read the 2 bytes by reading twice. - r[0] = byte(i2c.Bus.DR.Get()) - r[1] = byte(i2c.Bus.DR.Get()) + // wait for address ACK from slave + if !i2c.waitForFlagOrError(flagADDR, true) { + return errI2CSignalStartTimeout + } - // wait for stop - err = i2c.waitForStop() + return nil +} - //disable pos - i2c.Bus.CR1.ClearBits(stm32.I2C_CR1_POS) +func (i2c I2C) masterReceive(addr addressable, r []byte) error { - return err + if !i2c.waitForFlag(flagBUSY, false) { + return errI2CBusReadyTimeout + } - case 3: - // Enable ACK of received data - i2c.Bus.CR1.SetBits(stm32.I2C_CR1_ACK) + // ensure peripheral is enabled + if !i2c.Bus.CR1.HasBits(stm32.I2C_CR1_PE) { + i2c.Bus.CR1.SetBits(stm32.I2C_CR1_PE) + } - // send address - err = i2c.sendAddress(uint8(addr), false) - if err != nil { - return err - } + // disable POS + i2c.Bus.CR1.ClearBits(stm32.I2C_CR1_POS) - // clear address here - timeout := i2cTimeout - for !i2c.Bus.SR2.HasBits(stm32.I2C_SR2_MSL | stm32.I2C_SR2_BUSY) { - timeout-- - if timeout == 0 { - return errI2CWriteTimeout - } - } + pos := 0 + rem := len(r) + + // send slave address + if err := i2c.masterRequestRead(addr, frameNoOption); nil != err { + return err + } - // Enable ACK of received data - i2c.Bus.CR1.SetBits(stm32.I2C_CR1_ACK) + switch rem { + case 0: + // clear ADDR flag + i2c.clearFlagADDR() + // generate stop condition + i2c.Bus.CR1.SetBits(stm32.I2C_CR1_STOP) + + case 1: + // disable ACK + i2c.Bus.CR1.ClearBits(stm32.I2C_CR1_ACK) + // clear ADDR flag + i2c.clearFlagADDR() + // generate stop condition + i2c.Bus.CR1.SetBits(stm32.I2C_CR1_STOP) + + case 2: + // disable ACK + i2c.Bus.CR1.ClearBits(stm32.I2C_CR1_ACK) + // enable POS + i2c.Bus.CR1.SetBits(stm32.I2C_CR1_POS) + // clear ADDR flag + i2c.clearFlagADDR() + + default: + // enable ACK + i2c.Bus.CR1.SetBits(stm32.I2C_CR1_ACK) + // clear ADDR flag + i2c.clearFlagADDR() + } - // wait for btf. we need a longer timeout here than normal. - timeout = 1000 - for !i2c.Bus.SR1.HasBits(stm32.I2C_SR1_BTF) { - timeout-- - if timeout == 0 { - return errI2CReadTimeout - } + for rem > 0 { + switch rem { + case 1: + // wait until RXNE flag is set + if !i2c.waitForFlagOrError(flagRXNE, true) { + return errI2CReadTimeout } - // Disable ACK of received data - i2c.Bus.CR1.ClearBits(stm32.I2C_CR1_ACK) + // read data from DR + r[pos] = byte(i2c.Bus.DR.Get()) - // read the first byte - r[0] = byte(i2c.Bus.DR.Get()) + // update counters + pos++ + rem-- - timeout = 1000 - for !i2c.Bus.SR1.HasBits(stm32.I2C_SR1_BTF) { - timeout-- - if timeout == 0 { - return errI2CReadTimeout - } + case 2: + // wait until transfer finished flag BTF is set + if !i2c.waitForFlag(flagBTF, true) { + return errI2CReadTimeout } - // Generate stop condition + // generate stop condition i2c.Bus.CR1.SetBits(stm32.I2C_CR1_STOP) - // read the last 2 bytes by reading twice. - r[1] = byte(i2c.Bus.DR.Get()) - r[2] = byte(i2c.Bus.DR.Get()) + // read data from DR + r[pos] = byte(i2c.Bus.DR.Get()) - // wait for stop - return i2c.waitForStop() + // update counters + pos++ + rem-- - default: - // more than 3 bytes of data to read + // read data from DR + r[pos] = byte(i2c.Bus.DR.Get()) - // send address - err = i2c.sendAddress(uint8(addr), false) - if err != nil { - return err - } + // update counters + pos++ + rem-- - // clear address here - timeout := i2cTimeout - for !i2c.Bus.SR2.HasBits(stm32.I2C_SR2_MSL | stm32.I2C_SR2_BUSY) { - timeout-- - if timeout == 0 { - return errI2CWriteTimeout - } + case 3: + // wait until transfer finished flag BTF is set + if !i2c.waitForFlag(flagBTF, true) { + return errI2CReadTimeout } - for i := 0; i < len(r)-3; i++ { - // Enable ACK of received data - i2c.Bus.CR1.SetBits(stm32.I2C_CR1_ACK) - - // wait for btf. we need a longer timeout here than normal. - timeout = 1000 - for !i2c.Bus.SR1.HasBits(stm32.I2C_SR1_BTF) { - timeout-- - if timeout == 0 { - return errI2CReadTimeout - } - } - - // read the next byte - r[i] = byte(i2c.Bus.DR.Get()) - } + // disable ACK + i2c.Bus.CR1.ClearBits(stm32.I2C_CR1_ACK) - // wait for btf. we need a longer timeout here than normal. - timeout = 1000 - for !i2c.Bus.SR1.HasBits(stm32.I2C_SR1_BTF) { - timeout-- - if timeout == 0 { - return errI2CReadTimeout - } - } + // read data from DR + r[pos] = byte(i2c.Bus.DR.Get()) - // Disable ACK of received data - i2c.Bus.CR1.ClearBits(stm32.I2C_CR1_ACK) + // update counters + pos++ + rem-- - // get third from last byte - r[len(r)-3] = byte(i2c.Bus.DR.Get()) + // wait until transfer finished flag BTF is set + if !i2c.waitForFlag(flagBTF, true) { + return errI2CReadTimeout + } - // Generate stop condition + // generate stop condition i2c.Bus.CR1.SetBits(stm32.I2C_CR1_STOP) - // get second from last byte - r[len(r)-2] = byte(i2c.Bus.DR.Get()) - - timeout = i2cTimeout - for !i2c.Bus.SR1.HasBits(stm32.I2C_SR1_RxNE) { - timeout-- - if timeout == 0 { - return errI2CReadTimeout - } - } + // read data from DR + r[pos] = byte(i2c.Bus.DR.Get()) - // get last byte - r[len(r)-1] = byte(i2c.Bus.DR.Get()) + // update counters + pos++ + rem-- - // wait for stop - return i2c.waitForStop() - } - } + // read data from DR + r[pos] = byte(i2c.Bus.DR.Get()) - return nil -} + // update counters + pos++ + rem-- -const i2cTimeout = 500 + default: + // wait until RXNE flag is set + if !i2c.waitForFlagOrError(flagRXNE, true) { + return errI2CReadTimeout + } -// signalStart sends a start signal. -func (i2c I2C) signalStart() error { - // Wait until I2C is not busy - timeout := i2cTimeout - for i2c.Bus.SR2.HasBits(stm32.I2C_SR2_BUSY) { - timeout-- - if timeout == 0 { - return errI2CSignalStartTimeout - } - } + // read data from DR + r[pos] = byte(i2c.Bus.DR.Get()) - // clear stop - i2c.Bus.CR1.ClearBits(stm32.I2C_CR1_STOP) + // update counters + pos++ + rem-- - // Generate start condition - i2c.Bus.CR1.SetBits(stm32.I2C_CR1_START) + if i2c.hasFlag(flagBTF) { + // read data from DR + r[pos] = byte(i2c.Bus.DR.Get()) - // Wait for I2C EV5 aka SB flag. - timeout = i2cTimeout - for !i2c.Bus.SR1.HasBits(stm32.I2C_SR1_SB) { - timeout-- - if timeout == 0 { - return errI2CSignalStartTimeout + // update counters + pos++ + rem-- + } } } return nil } -// signalStop sends a stop signal and waits for it to succeed. -func (i2c I2C) signalStop() error { - // Generate stop condition - i2c.Bus.CR1.SetBits(stm32.I2C_CR1_STOP) +func (i2c I2C) masterRequestRead(addr addressable, option transferOption) error { - // wait for stop - return i2c.waitForStop() -} + // enable ACK + i2c.Bus.CR1.SetBits(stm32.I2C_CR1_ACK) -// waitForStop waits after a stop signal. -func (i2c I2C) waitForStop() error { - // Wait until I2C is stopped - timeout := i2cTimeout - for i2c.Bus.SR1.HasBits(stm32.I2C_SR1_STOPF) { - timeout-- - if timeout == 0 { - return errI2CSignalStopTimeout - } + if frameFirstAndLast == option || frameFirst == option || frameNoOption == option { + // generate start condition + i2c.Bus.CR1.SetBits(stm32.I2C_CR1_START) + } else if false /* (hi2c->PreviousState == I2C_STATE_MASTER_BUSY_TX) */ { + // generate restart condition + i2c.Bus.CR1.SetBits(stm32.I2C_CR1_START) } - return nil -} - -// Send address of device we want to talk to -func (i2c I2C) sendAddress(address uint8, write bool) error { - data := (address << 1) - if !write { - data |= 1 // set read flag + // ensure start bit is set + if !i2c.waitForFlag(flagSB, true) { + return errI2CSignalStartTimeout } - i2c.Bus.DR.Set(uint32(data)) - - // Wait for I2C EV6 event. - // Destination device acknowledges address - timeout := i2cTimeout - if write { - // EV6 which is ADDR flag. - for !i2c.Bus.SR1.HasBits(stm32.I2C_SR1_ADDR) { - timeout-- - if timeout == 0 { - return errI2CWriteTimeout - } - } + // send slave address + switch addr.bitSize() { + case 7: // 7-bit slave address + i2c.Bus.DR.Set(addr.toRead()) - timeout = i2cTimeout - for !i2c.Bus.SR2.HasBits(stm32.I2C_SR2_MSL | stm32.I2C_SR2_BUSY | stm32.I2C_SR2_TRA) { - timeout-- - if timeout == 0 { - return errI2CWriteTimeout - } - } - } else { - // I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED which is ADDR flag. - for !i2c.Bus.SR1.HasBits(stm32.I2C_SR1_ADDR) { - timeout-- - if timeout == 0 { - return errI2CWriteTimeout - } - } + case 10: // 10-bit slave address + // TODO } - return nil -} - -// WriteByte writes a single byte to the I2C bus. -func (i2c I2C) WriteByte(data byte) error { - // Send data byte - i2c.Bus.DR.Set(uint32(data)) - - // Wait for I2C EV8_2 when data has been physically shifted out and - // output on the bus. - // I2C_EVENT_MASTER_BYTE_TRANSMITTED is TXE flag. - timeout := i2cTimeout - for !i2c.Bus.SR1.HasBits(stm32.I2C_SR1_TxE) { - timeout-- - if timeout == 0 { - return errI2CWriteTimeout - } + // wait for address ACK from slave + if !i2c.waitForFlagOrError(flagADDR, true) { + return errI2CSignalStartTimeout } return nil diff --git a/src/machine/machine_stm32f405.go b/src/machine/machine_stm32f405.go index dd9f30beff..357cdc808a 100644 --- a/src/machine/machine_stm32f405.go +++ b/src/machine/machine_stm32f405.go @@ -96,18 +96,6 @@ func (i2c I2C) getRiseTime(config I2CConfig) uint32 { } func (i2c I2C) getSpeed(config I2CConfig) uint32 { - // getSpeed is based on the following STM32CubeMX macros: - // - // #define I2C_MIN_PCLK_FREQ(__PCLK__, __SPEED__) (((__SPEED__) <= 100000U) ? ((__PCLK__) < I2C_MIN_PCLK_FREQ_STANDARD) : ((__PCLK__) < I2C_MIN_PCLK_FREQ_FAST)) - // #define I2C_CCR_CALCULATION(__PCLK__, __SPEED__, __COEFF__) (((((__PCLK__) - 1U)/((__SPEED__) * (__COEFF__))) + 1U) & I2C_CCR_CCR) - // #define I2C_FREQRANGE(__PCLK__) ((__PCLK__)/1000000U) - // #define I2C_RISE_TIME(__FREQRANGE__, __SPEED__) (((__SPEED__) <= 100000U) ? ((__FREQRANGE__) + 1U) : ((((__FREQRANGE__) * 300U) / 1000U) + 1U)) - // #define I2C_SPEED_STANDARD(__PCLK__, __SPEED__) ((I2C_CCR_CALCULATION((__PCLK__), (__SPEED__), 2U) < 4U)? 4U:I2C_CCR_CALCULATION((__PCLK__), (__SPEED__), 2U)) - // #define I2C_SPEED_FAST(__PCLK__, __SPEED__, __DUTYCYCLE__) (((__DUTYCYCLE__) == I2C_DUTYCYCLE_2)? I2C_CCR_CALCULATION((__PCLK__), (__SPEED__), 3U) : (I2C_CCR_CALCULATION((__PCLK__), (__SPEED__), 25U) | I2C_DUTYCYCLE_16_9)) - // #define I2C_SPEED(__PCLK__, __SPEED__, __DUTYCYCLE__) (((__SPEED__) <= 100000U)? (I2C_SPEED_STANDARD((__PCLK__), (__SPEED__))) : \ - // ((I2C_SPEED_FAST((__PCLK__), (__SPEED__), (__DUTYCYCLE__)) & I2C_CCR_CCR) == 0U)? 1U : \ - // ((I2C_SPEED_FAST((__PCLK__), (__SPEED__), (__DUTYCYCLE__))) | I2C_CCR_FS)) - // ccr := func(pclk uint32, freq uint32, coeff uint32) uint32 { return (((pclk - 1) / (freq * coeff)) + 1) & stm32.I2C_CCR_CCR_Msk } @@ -119,7 +107,7 @@ func (i2c I2C) getSpeed(config I2CConfig) uint32 { } } fm := func(pclk uint32, freq uint32, duty uint8) uint32 { // fast mode (Fm) - if duty == Duty2 { + if duty == DutyCycle2 { return ccr(pclk, freq, 3) } else { return ccr(pclk, freq, 25) | stm32.I2C_CCR_DUTY From 21985c22434343b9f7b41cfa634cd72cd9f17a31 Mon Sep 17 00:00:00 2001 From: ardnew Date: Sun, 13 Sep 2020 16:45:14 -0500 Subject: [PATCH 5/6] exclude stm32f407 from I2C support for now, will integrate stm32f4disco board support in separate PR --- src/machine/i2c.go | 2 +- src/machine/machine_stm32_i2c.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/machine/i2c.go b/src/machine/i2c.go index 4845d41e4d..8b2862af40 100644 --- a/src/machine/i2c.go +++ b/src/machine/i2c.go @@ -1,4 +1,4 @@ -// +build avr nrf sam stm32 fe310 k210 +// +build avr nrf sam stm32,!stm32f407 fe310 k210 package machine diff --git a/src/machine/machine_stm32_i2c.go b/src/machine/machine_stm32_i2c.go index 54fffce668..dda9868175 100644 --- a/src/machine/machine_stm32_i2c.go +++ b/src/machine/machine_stm32_i2c.go @@ -1,4 +1,4 @@ -// +build stm32,!stm32f103xx +// +build stm32,!stm32f103xx,!stm32f407 package machine From 697a3b0664476b7a3f97d0a58aa88615c4445be1 Mon Sep 17 00:00:00 2001 From: ardnew Date: Tue, 13 Oct 2020 14:05:15 -0500 Subject: [PATCH 6/6] rename "master" to "controller" and "slave" to "peripheral" per #1216 --- src/machine/machine_stm32_i2c.go | 42 ++++++++++++++++---------------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/src/machine/machine_stm32_i2c.go b/src/machine/machine_stm32_i2c.go index dda9868175..68133a6e52 100644 --- a/src/machine/machine_stm32_i2c.go +++ b/src/machine/machine_stm32_i2c.go @@ -91,7 +91,7 @@ const ( frameNoOption = 0xFFFF0000 ) -// addressable represents a type that can provide fully-formatted I2C slave +// addressable represents a type that can provide fully-formatted I2C peripheral // addresses for both read operations and write operations. type addressable interface { toRead() uint32 @@ -99,7 +99,7 @@ type addressable interface { bitSize() uint8 } -// address7Bit and address10Bit stores the unshifted original I2C slave address +// address7Bit and address10Bit stores the unshifted original I2C peripheral address // in an unsigned integral data type and implements the addressable interface // to reformat addresses as required for read/write operations. // TODO: @@ -144,7 +144,7 @@ type I2CConfig struct { // Configure is intended to setup the STM32 I2C interface. func (i2c I2C) Configure(config I2CConfig) { - // The following is the required sequence in master mode. + // The following is the required sequence in controller mode. // 1. Program the peripheral input clock in I2C_CR2 Register in order to // generate correct timings // 2. Configure the clock control registers @@ -192,16 +192,16 @@ func (i2c I2C) Configure(config I2CConfig) { func (i2c I2C) Tx(addr uint16, w, r []byte) error { a := address7Bit(addr) - if err := i2c.masterTransmit(a, w); nil != err { + if err := i2c.controllerTransmit(a, w); nil != err { return err } - if err := i2c.masterReceive(a, r); nil != err { + if err := i2c.controllerReceive(a, r); nil != err { return err } return nil } -func (i2c I2C) masterTransmit(addr addressable, w []byte) error { +func (i2c I2C) controllerTransmit(addr addressable, w []byte) error { if !i2c.waitForFlag(flagBUSY, false) { return errI2CBusReadyTimeout @@ -218,8 +218,8 @@ func (i2c I2C) masterTransmit(addr addressable, w []byte) error { pos := 0 rem := len(w) - // send slave address - if err := i2c.masterRequestWrite(addr, frameNoOption); nil != err { + // send peripheral address + if err := i2c.controllerRequestWrite(addr, frameNoOption); nil != err { return err } @@ -258,7 +258,7 @@ func (i2c I2C) masterTransmit(addr addressable, w []byte) error { return nil } -func (i2c I2C) masterRequestWrite(addr addressable, option transferOption) error { +func (i2c I2C) controllerRequestWrite(addr addressable, option transferOption) error { if frameFirstAndLast == option || frameFirst == option || frameNoOption == option { // generate start condition @@ -273,16 +273,16 @@ func (i2c I2C) masterRequestWrite(addr addressable, option transferOption) error return errI2CSignalStartTimeout } - // send slave address + // send peripheral address switch addr.bitSize() { - case 7: // 7-bit slave address + case 7: // 7-bit peripheral address i2c.Bus.DR.Set(addr.toWrite()) - case 10: // 10-bit slave address + case 10: // 10-bit peripheral address // TODO } - // wait for address ACK from slave + // wait for address ACK from peripheral if !i2c.waitForFlagOrError(flagADDR, true) { return errI2CSignalStartTimeout } @@ -290,7 +290,7 @@ func (i2c I2C) masterRequestWrite(addr addressable, option transferOption) error return nil } -func (i2c I2C) masterReceive(addr addressable, r []byte) error { +func (i2c I2C) controllerReceive(addr addressable, r []byte) error { if !i2c.waitForFlag(flagBUSY, false) { return errI2CBusReadyTimeout @@ -307,8 +307,8 @@ func (i2c I2C) masterReceive(addr addressable, r []byte) error { pos := 0 rem := len(r) - // send slave address - if err := i2c.masterRequestRead(addr, frameNoOption); nil != err { + // send peripheral address + if err := i2c.controllerRequestRead(addr, frameNoOption); nil != err { return err } @@ -445,7 +445,7 @@ func (i2c I2C) masterReceive(addr addressable, r []byte) error { return nil } -func (i2c I2C) masterRequestRead(addr addressable, option transferOption) error { +func (i2c I2C) controllerRequestRead(addr addressable, option transferOption) error { // enable ACK i2c.Bus.CR1.SetBits(stm32.I2C_CR1_ACK) @@ -463,16 +463,16 @@ func (i2c I2C) masterRequestRead(addr addressable, option transferOption) error return errI2CSignalStartTimeout } - // send slave address + // send peripheral address switch addr.bitSize() { - case 7: // 7-bit slave address + case 7: // 7-bit peripheral address i2c.Bus.DR.Set(addr.toRead()) - case 10: // 10-bit slave address + case 10: // 10-bit peripheral address // TODO } - // wait for address ACK from slave + // wait for address ACK from peripheral if !i2c.waitForFlagOrError(flagADDR, true) { return errI2CSignalStartTimeout }