diff --git a/conf/airframes/CDW/debug_i2c.xml b/conf/airframes/CDW/debug_i2c.xml
index d8b773214f..cbc48adfdb 100644
--- a/conf/airframes/CDW/debug_i2c.xml
+++ b/conf/airframes/CDW/debug_i2c.xml
@@ -216,7 +216,7 @@
-
+
diff --git a/conf/airframes/CDW/debug_i2c_lpc.xml b/conf/airframes/CDW/debug_i2c_lpc.xml
new file mode 100644
index 0000000000..18320f15cc
--- /dev/null
+++ b/conf/airframes/CDW/debug_i2c_lpc.xml
@@ -0,0 +1,215 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/conf/airframes/fraser_lisa_m_rotorcraft.xml b/conf/airframes/fraser_lisa_m_rotorcraft.xml
index 0761492743..1e50b49d2a 100644
--- a/conf/airframes/fraser_lisa_m_rotorcraft.xml
+++ b/conf/airframes/fraser_lisa_m_rotorcraft.xml
@@ -15,6 +15,7 @@
+
diff --git a/conf/autopilot/subsystems/shared/i2c_select.makefile b/conf/autopilot/subsystems/shared/i2c_select.makefile
index 75241931af..395a061bc0 100644
--- a/conf/autopilot/subsystems/shared/i2c_select.makefile
+++ b/conf/autopilot/subsystems/shared/i2c_select.makefile
@@ -4,8 +4,11 @@
$(TARGET).srcs += mcu_periph/i2c.c
ifeq ($(ARCH), stm32)
+ifeq ($(USE_NEW_I2C_DRIVER), 1)
+$(TARGET).srcs += $(SRC_ARCH)/mcu_periph/i2c_arch.rewritten.c
+else
$(TARGET).srcs += $(SRC_ARCH)/mcu_periph/i2c_arch.c
-#$(TARGET).srcs += $(SRC_ARCH)/mcu_periph/i2c_arch.rewritten.c
+endif
else
$(TARGET).srcs += $(SRC_ARCH)/mcu_periph/i2c_arch.c
endif
diff --git a/conf/modules/i2c_abuse_test.xml b/conf/modules/i2c_abuse_test.xml
index f0b8b6f316..7c0a772d53 100644
--- a/conf/modules/i2c_abuse_test.xml
+++ b/conf/modules/i2c_abuse_test.xml
@@ -8,11 +8,21 @@
+
-
-
+
+ifeq ($(ARCH), lpc21)
+$(TARGET).CFLAGS += -DI2C_ABUSE_LED=3
+$(TARGET).CFLAGS += -DUSE_I2C0
+$(TARGET).CFLAGS += -DI2C_ABUSE_PORT=i2c0
+else ifeq ($(ARCH), stm32)
+$(TARGET).CFLAGS += -DI2C_ABUSE_LED=7
+$(TARGET).CFLAGS += -DI2C_ABUSE_PORT=i2c2
+endif
+
+
diff --git a/conf/telemetry/default_rotorcraft.xml b/conf/telemetry/default_rotorcraft.xml
index 61cdfac796..60b05eea78 100644
--- a/conf/telemetry/default_rotorcraft.xml
+++ b/conf/telemetry/default_rotorcraft.xml
@@ -16,6 +16,7 @@
+
diff --git a/sw/airborne/arch/avr/mcu_periph/i2c_arch.c b/sw/airborne/arch/avr/mcu_periph/i2c_arch.c
index f427a64008..c3953dfb3a 100644
--- a/sw/airborne/arch/avr/mcu_periph/i2c_arch.c
+++ b/sw/airborne/arch/avr/mcu_periph/i2c_arch.c
@@ -161,3 +161,7 @@ void i2c_init(void) {
sbi(TWSR, TWPS0);
*/
}
+
+void i2c_event(void) { }
+void i2c2_setbitrate(int bitrate __attribute__ ((unused))) { }
+
diff --git a/sw/airborne/arch/lpc21/mcu_periph/i2c_arch.c b/sw/airborne/arch/lpc21/mcu_periph/i2c_arch.c
index 98f65140a9..eb990fdebe 100644
--- a/sw/airborne/arch/lpc21/mcu_periph/i2c_arch.c
+++ b/sw/airborne/arch/lpc21/mcu_periph/i2c_arch.c
@@ -340,3 +340,45 @@ bool_t i2c_submit(struct i2c_periph* p, struct i2c_transaction* t) {
return TRUE;
}
+
+void i2c_event(void) { }
+void i2c_setbitrate(struct i2c_periph* p, int bitrate)
+{
+ int period = 15000000 / 2 / bitrate;
+ // Max 400kpbs
+ if (period < 19)
+ period = 19;
+ // Min 5kbps
+ if (period > 1500)
+ period = 1500;
+
+/* default clock speed 37.5KHz with our 15MHz PCLK
+ I2C1_CLOCK = PCLK / (I2C1_SCLL + I2C1_SCLH) */
+
+#if (PCLK == 30000000)
+ period *= 2;
+#endif
+
+#if (PCLK == 60000000)
+ period *= 4;
+#endif
+
+#ifdef USE_I2C0
+ if (p == &i2c0)
+ {
+ /* set bitrate */
+ I2C0SCLL = period;
+ I2C0SCLH = period;
+ }
+#endif
+#ifdef USE_I2C1
+ if (p == &i2c1)
+ {
+ /* set bitrate */
+ I2C1SCLL = period;
+ I2C1SCLH = period;
+ }
+#endif
+}
+
+
diff --git a/sw/airborne/arch/sim/mcu_periph/i2c_arch.c b/sw/airborne/arch/sim/mcu_periph/i2c_arch.c
index ceb58123b6..34b43d9739 100644
--- a/sw/airborne/arch/sim/mcu_periph/i2c_arch.c
+++ b/sw/airborne/arch/sim/mcu_periph/i2c_arch.c
@@ -4,3 +4,6 @@ void i2c_hw_init ( void ) {}
bool_t i2c_idle(struct i2c_periph *p __attribute__ ((unused))) { return TRUE; }
bool_t i2c_submit(struct i2c_periph* p __attribute__ ((unused)), struct i2c_transaction* t __attribute__ ((unused))) { return TRUE;}
+void i2c_event(void) { }
+void i2c2_setbitrate(int bitrate __attribute__ ((unused))) { }
+
diff --git a/sw/airborne/arch/stm32/mcu_periph/i2c_arch.c b/sw/airborne/arch/stm32/mcu_periph/i2c_arch.c
index c3c6377f1e..b09cfb9415 100644
--- a/sw/airborne/arch/stm32/mcu_periph/i2c_arch.c
+++ b/sw/airborne/arch/stm32/mcu_periph/i2c_arch.c
@@ -287,9 +287,11 @@ static inline void on_status_restart_requested(struct i2c_periph *periph, struct
}
}
+void i2c_event(void)
+{
+}
-
-static inline void i2c_event(struct i2c_periph *p, uint32_t event)
+static inline void i2c_driver_event(struct i2c_periph *p, uint32_t event)
{
struct i2c_transaction* trans = p->trans[p->trans_extract_idx];
switch (p->status) {
@@ -509,7 +511,7 @@ void i2c1_hw_init(void) {
void i2c1_ev_irq_handler(void) {
uint32_t event = I2C_GetLastEvent(I2C1);
- i2c_event(&i2c1, event);
+ i2c_driver_event(&i2c1, event);
}
@@ -586,7 +588,7 @@ void i2c2_hw_init(void) {
void i2c2_ev_irq_handler(void) {
uint32_t event = I2C_GetLastEvent(I2C2);
- i2c_event(&i2c2, event);
+ i2c_driver_event(&i2c2, event);
}
void i2c2_er_irq_handler(void) {
diff --git a/sw/airborne/arch/stm32/mcu_periph/i2c_arch.h b/sw/airborne/arch/stm32/mcu_periph/i2c_arch.h
index 0274829fc1..50519ea24c 100644
--- a/sw/airborne/arch/stm32/mcu_periph/i2c_arch.h
+++ b/sw/airborne/arch/stm32/mcu_periph/i2c_arch.h
@@ -34,8 +34,6 @@
#ifdef USE_I2C1
-extern struct i2c_errors i2c1_errors;
-
extern void i2c1_hw_init(void);
extern void i2c1_ev_irq_handler(void);
extern void i2c1_er_irq_handler(void);
@@ -46,8 +44,6 @@ extern void i2c1_er_irq_handler(void);
#ifdef USE_I2C2
-extern struct i2c_errors i2c2_errors;
-
extern void i2c2_hw_init(void);
extern void i2c2_ev_irq_handler(void);
extern void i2c2_er_irq_handler(void);
diff --git a/sw/airborne/arch/stm32/mcu_periph/i2c_arch.rewritten.c b/sw/airborne/arch/stm32/mcu_periph/i2c_arch.rewritten.c
new file mode 100644
index 0000000000..09f19ff27d
--- /dev/null
+++ b/sw/airborne/arch/stm32/mcu_periph/i2c_arch.rewritten.c
@@ -0,0 +1,1452 @@
+#include "mcu_periph/i2c.h"
+
+#include
+#include
+#include
+#include
+
+//#define I2C_DEBUG_LED
+
+/////////// DEBUGGING //////////////
+// TODO: remove this
+
+
+#ifdef I2C_DEBUG_LED
+
+static inline void LED1_ON(void)
+{
+ GPIO_WriteBit(GPIOB, GPIO_Pin_6 , Bit_SET );
+}
+
+static inline void LED1_OFF(void)
+{
+ GPIO_WriteBit(GPIOB, GPIO_Pin_6 , !Bit_SET );
+}
+
+static inline void LED2_ON(void)
+{
+ GPIO_WriteBit(GPIOB, GPIO_Pin_7 , Bit_SET );
+}
+
+static inline void LED2_OFF(void)
+{
+ GPIO_WriteBit(GPIOB, GPIO_Pin_7 , !Bit_SET );
+}
+
+static inline void LED_INIT(void)
+{
+ GPIO_InitTypeDef GPIO_InitStructure;
+ RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOB, ENABLE);
+ GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7 | GPIO_Pin_6;
+ GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
+ GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
+ GPIO_Init(GPIOB, &GPIO_InitStructure);
+
+ LED1_OFF();
+ LED2_OFF();
+}
+
+
+static inline void LED_ERROR(uint8_t base, uint8_t nr)
+{
+ LED2_ON();
+ for (int i=0;i<(base+nr);i++)
+ {
+ LED1_ON();
+ LED1_OFF();
+ }
+ LED2_OFF();
+}
+#endif
+
+//////////////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////////////
+
+#ifdef USE_I2C1
+static I2C_InitTypeDef I2C1_InitStruct = {
+ .I2C_Mode = I2C_Mode_I2C,
+ .I2C_DutyCycle = I2C_DutyCycle_2,
+ .I2C_OwnAddress1 = 0x00,
+ .I2C_Ack = I2C_Ack_Enable,
+ .I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit,
+ .I2C_ClockSpeed = 40000
+};
+#endif
+
+#ifdef USE_I2C2
+static I2C_InitTypeDef I2C2_InitStruct = {
+ .I2C_Mode = I2C_Mode_I2C,
+ .I2C_DutyCycle = I2C_DutyCycle_2,
+ .I2C_OwnAddress1 = 0x00,
+ .I2C_Ack = I2C_Ack_Enable,
+ .I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit,
+// .I2C_ClockSpeed = 37500 // Like on LPC
+ .I2C_ClockSpeed = 300000
+};
+#endif
+
+//////////////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////////////
+
+// Bypassing the libSTM I2C functions to have more control over the reading of registers
+// e.g. SR1 and SR2 should not always be read together as it might unwantedly clear ADDR flags etc.
+
+// Referring to STM32 manual:
+// -Doc ID 13902 Rev 11
+
+// Status Register 1
+
+#define I2C_SR1_BIT_SB (1<<0) // Start Condition Met
+#define I2C_SR1_BIT_ADDR (1<<1) // Address Sent
+#define I2C_SR1_BIT_BTF (1<<2) // SCL held low
+#define I2C_SR1_BIT_RXNE (1<<6) // Data Read Available
+#define I2C_SR1_BIT_TXE (1<<7) // TX buffer space available
+
+#define I2C_SR1_BIT_ERR_BUS (1<<8) // Misplaced Start/Stop (usually interference)
+#define I2C_SR1_BIT_ERR_ARLO (1<<9) // Arbitration Lost (in multimaster) or SDA short-to-ground (in single master)
+#define I2C_SR1_BIT_ERR_AF (1<<10) // Ack Failure (too fast/too soon/no sensor/wiring break/...)
+#define I2C_SR1_BIT_ERR_OVR (1<<11) // Overrun [data loss] (in slave) or SCL short-to-ground (in single master)
+
+#define I2C_SR1_BITS_ERR ((1<<8)|(1<<9)|(1<<10)|(1<<11)|(1<<12)|(1<<14)|(1<<15))
+
+// Status Register 2
+
+#define I2C_SR2_BIT_TRA (1<<2) // Transmitting
+#define I2C_SR2_BIT_BUSY (1<<1) // Busy
+#define I2C_SR2_BIT_MSL (1<<0) // Master Selected
+
+// Control Register 1
+
+#define I2C_CR1_BIT_PE (1<<0) // Peripheral Enable
+#define I2C_CR1_BIT_START (1<<8) // Generate a Start
+#define I2C_CR1_BIT_STOP (1<<9) // Generate a Stop
+#define I2C_CR1_BIT_ACK (1<<10) // ACK / NACK
+#define I2C_CR1_BIT_POS (1<<11) // Ack will control not the next but secondnext received byte
+#define I2C_CR1_BIT_SWRST (1<<15) // Clear Busy Condition when no stop was detected
+
+// Control Register 2
+
+#define I2C_CR2_BIT_ITERREN (1<<8) // Error Interrupt
+#define I2C_CR2_BIT_ITEVTEN (1<<9) // Event Interrupt
+#define I2C_CR2_BIT_ITBUFEN (1<<10) // Buffer Interrupt
+
+
+// Bit Control
+
+#define BIT_X_IS_SET_IN_REG(X,REG) (((REG) & (X)) == (X))
+
+// Critical Zones
+
+#define __I2C_REG_CRITICAL_ZONE_START __disable_irq();
+#define __I2C_REG_CRITICAL_ZONE_STOP __enable_irq();
+
+
+//////////////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////////////
+
+// TODO: remove debug
+#ifdef I2C_DEBUG_LED
+
+static inline void LED_SHOW_ACTIVE_BITS(I2C_TypeDef *regs)
+{
+ uint16_t CR1 = regs->CR1;
+ uint16_t SR1 = regs->SR1;
+ uint16_t SR2 = regs->SR2;
+ // Note: reading SR1 and then SR2 will clear ADDR bits
+
+ LED1_ON();
+
+ // 1 Start
+ if (BIT_X_IS_SET_IN_REG( I2C_SR1_BIT_SB, SR1 ) )
+ LED2_ON();
+ else
+ LED2_OFF();
+ LED2_OFF();
+
+ // 2 Addr
+ if (BIT_X_IS_SET_IN_REG( I2C_SR1_BIT_ADDR, SR1 ) )
+ LED2_ON();
+ else
+ LED2_OFF();
+ LED2_OFF();
+
+ // 3 BTF
+ if (BIT_X_IS_SET_IN_REG( I2C_SR1_BIT_BTF, SR1 ) )
+ LED2_ON();
+ else
+ LED2_OFF();
+ LED2_OFF();
+
+ // 4 ERROR
+ if (( SR1 & I2C_SR1_BITS_ERR ) != 0x0000)
+ LED2_ON();
+ else
+ LED2_OFF();
+ LED2_OFF();
+
+ // Anything?
+ if (( SR1 + SR2) != 0x0000)
+ LED2_ON();
+ else
+ LED2_OFF();
+ LED2_OFF();
+
+ LED1_OFF();
+
+
+ LED1_ON();
+
+ // 1 Start
+ if (BIT_X_IS_SET_IN_REG( I2C_CR1_BIT_START, CR1 ) )
+ LED2_ON();
+ else
+ LED2_OFF();
+ LED2_OFF();
+
+ // 2 Stop
+ if (BIT_X_IS_SET_IN_REG( I2C_CR1_BIT_STOP, CR1 ) )
+ LED2_ON();
+ else
+ LED2_OFF();
+ LED2_OFF();
+
+ // 3 Busy
+ if (BIT_X_IS_SET_IN_REG( I2C_SR2_BIT_BUSY, SR2 ) )
+ LED2_ON();
+ else
+ LED2_OFF();
+ LED2_OFF();
+
+ // 4 Tra
+ if (BIT_X_IS_SET_IN_REG( I2C_SR2_BIT_TRA, SR2 ) )
+ LED2_ON();
+ else
+ LED2_OFF();
+ LED2_OFF();
+
+ // 5 Master
+ if (BIT_X_IS_SET_IN_REG( I2C_SR2_BIT_MSL, SR2 ) )
+ LED2_ON();
+ else
+ LED2_OFF();
+ LED2_OFF();
+ LED1_OFF();
+
+//#define I2C_DEBUG_LED_CONTROL
+#ifdef I2C_DEBUG_LED_CONTROL
+
+
+ LED1_ON();
+
+ // 1 Anything CR?
+ if (( CR1) != 0x0000)
+ LED2_ON();
+ else
+ LED2_OFF();
+ LED2_OFF();
+
+ // 2 PE
+ if (BIT_X_IS_SET_IN_REG( I2C_CR1_BIT_PE, CR1 ) )
+ LED2_ON();
+ else
+ LED2_OFF();
+ LED2_OFF();
+
+ // 3 SWRESET
+ if (BIT_X_IS_SET_IN_REG( I2C_CR1_BIT_SWRST, CR1 ) )
+ LED2_ON();
+ else
+ LED2_OFF();
+ LED2_OFF();
+
+ LED1_OFF();
+#endif
+
+}
+#endif
+
+static inline void PPRZ_I2C_SEND_STOP(I2C_TypeDef *regs)
+{
+ // Man: p722: Stop generation after the current byte transfer or after the current Start condition is sent.
+ regs->CR1 |= I2C_CR1_BIT_STOP;
+
+#ifdef I2C_DEBUG_LED
+ LED2_ON();
+ LED1_ON();
+ LED1_OFF();
+ LED2_OFF();
+#endif
+}
+
+// (RE)START
+
+static inline void PPRZ_I2C_SEND_START(struct i2c_periph *periph)
+{
+ I2C_TypeDef *regs = (I2C_TypeDef *) periph->reg_addr;
+
+ // Reset the buffer pointer to the first byte
+ periph->idx_buf = 0;
+
+#ifdef I2C_DEBUG_LED
+ LED_SHOW_ACTIVE_BITS(regs);
+
+ LED2_ON();
+ LED1_ON();
+ LED1_OFF();
+ LED1_ON();
+ LED1_OFF();
+ LED1_ON();
+ LED1_OFF();
+ LED2_OFF();
+
+#endif
+
+ // Enable Error IRQ, Event IRQ but disable Buffer IRQ
+ regs->CR2 |= I2C_CR2_BIT_ITERREN;
+ regs->CR2 |= I2C_CR2_BIT_ITEVTEN;
+ regs->CR2 &= ~ I2C_CR2_BIT_ITBUFEN;
+
+ // Issue a new start
+ regs->CR1 = (I2C_CR1_BIT_START | I2C_CR1_BIT_PE);
+ periph->status = I2CStartRequested;
+
+}
+
+// STOP
+
+///////////////////////////////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////////////////////////////
+//
+// SUBTRANSACTION SEQUENCES
+// -We arrive here every time a ISR is called with no error
+
+enum STMI2CSubTransactionStatus {
+ STMI2C_SubTra_Busy,
+ STMI2C_SubTra_Ready_StopRequested,
+ STMI2C_SubTra_Ready,
+ STMI2C_SubTra_Error
+};
+
+// Doc ID 13902 Rev 11 p 710/1072
+// Transfer Sequence Diagram for Master Transmitter
+static inline enum STMI2CSubTransactionStatus stmi2c_send(I2C_TypeDef *regs, struct i2c_periph *periph, struct i2c_transaction *trans)
+{
+ uint16_t SR1 = regs->SR1;
+
+ // Start Condition Was Just Generated
+ if (BIT_X_IS_SET_IN_REG( I2C_SR1_BIT_SB, SR1 ) )
+ {
+ // Disable buffer interrupt
+ regs->CR2 &= ~ I2C_CR2_BIT_ITBUFEN;
+ // Send Slave address and wait for ADDR interrupt
+ regs->DR = trans->slave_addr;
+ // Document the current Status
+ periph->status = I2CAddrWrSent;
+ }
+ // Address Was Sent
+ else if (BIT_X_IS_SET_IN_REG(I2C_SR1_BIT_ADDR, SR1) )
+ {
+ // Now read SR2 to clear the ADDR status Bit
+ uint16_t SR2 __attribute__ ((unused)) = regs->SR2;
+
+ // Maybe check we are transmitting (did not loose arbitration for instance)
+ // if (! BIT_X_IS_SET_IN_REG(I2C_SR2_BIT_TRA, SR2)) { }
+ // update: this should be caught by the ARLO error: so we will not arrive here
+
+ // Send First max 2 bytes
+ regs->DR = trans->buf[0];
+ if (trans->len_w > 1)
+ {
+ regs->DR = trans->buf[1];
+ periph->idx_buf = 2;
+ }
+ else
+ {
+ periph->idx_buf = 1;
+ }
+
+ // Enable buffer-space available interrupt
+ // only if there is more to send: wait for TXE, no more to send: wait for BTF
+ if ( periph->idx_buf < trans->len_w)
+ regs->CR2 |= I2C_CR2_BIT_ITBUFEN;
+
+ // Document the current Status
+ periph->status = I2CSendingByte;
+ }
+ // The buffer is not full anymore AND we were not waiting for BTF
+ else if ((BIT_X_IS_SET_IN_REG(I2C_SR1_BIT_TXE, SR1) ) && (BIT_X_IS_SET_IN_REG(I2C_CR2_BIT_ITBUFEN, regs->CR2)) )
+ {
+ // Send the next byte
+ regs->DR = trans->buf[periph->idx_buf];
+ periph->idx_buf++;
+
+ // All bytes Sent? Then wait for BTF instead
+ if ( periph->idx_buf >= trans->len_w)
+ {
+ // Not interested anymore to know the buffer has space left
+ regs->CR2 &= ~ I2C_CR2_BIT_ITBUFEN;
+ // Next interrupt will be BTF (or error)
+ }
+ }
+ // BTF: means last byte was sent
+ else if (BIT_X_IS_SET_IN_REG(I2C_SR1_BIT_BTF, SR1) )
+ {
+ if (trans->type == I2CTransTx)
+ {
+ // Tell the driver we are ready
+ trans->status = I2CTransSuccess;
+ }
+ // Otherwise we still need to do the receiving part
+
+ return STMI2C_SubTra_Ready;
+ }
+ else // Event Logic Error
+ {
+ return STMI2C_SubTra_Error;
+ }
+
+ return STMI2C_SubTra_Busy;
+}
+
+// Doc ID 13902 Rev 11 p 714/1072
+// Transfer Sequence Diagram for Master Receiver for N=1
+static inline enum STMI2CSubTransactionStatus stmi2c_read1(I2C_TypeDef *regs, struct i2c_periph *periph, struct i2c_transaction *trans)
+{
+ uint16_t SR1 = regs->SR1;
+
+ // Start Condition Was Just Generated
+ if (BIT_X_IS_SET_IN_REG( I2C_SR1_BIT_SB, SR1 ) )
+ {
+ regs->CR2 &= ~ I2C_CR2_BIT_ITBUFEN;
+ regs->DR = trans->slave_addr | 0x01;
+
+ // Document the current Status
+ periph->status = I2CAddrRdSent;
+ }
+ // Address Was Sent
+ else if (BIT_X_IS_SET_IN_REG(I2C_SR1_BIT_ADDR, SR1) )
+ {
+ // First Clear the ACK bit: after the next byte we do not want new bytes
+ regs->CR1 &= ~ I2C_CR1_BIT_POS;
+ regs->CR1 &= ~ I2C_CR1_BIT_ACK;
+
+ // --- next to steps MUST be executed together to avoid missing the stop
+ __I2C_REG_CRITICAL_ZONE_START;
+
+ // Only after setting ACK, read SR2 to clear the ADDR (next byte will start arriving)
+ uint16_t SR2 __attribute__ ((unused)) = regs->SR2;
+
+ // Schedule a Stop
+ PPRZ_I2C_SEND_STOP(regs);
+
+ __I2C_REG_CRITICAL_ZONE_STOP;
+ // --- end of critical zone -----------
+
+ // Enable the RXNE: it will trigger as soon as the 1 byte is received to get the result
+ regs->CR2 |= I2C_CR2_BIT_ITBUFEN;
+
+ // Document the current Status
+ periph->status = I2CReadingLastByte;
+ }
+ // As soon as there is 1 byte ready to read, we have our byte
+ else if (BIT_X_IS_SET_IN_REG(I2C_SR1_BIT_RXNE, SR1) )
+ {
+ regs->CR2 &= ~ I2C_CR2_BIT_ITBUFEN;
+ trans->buf[0] = regs->DR;
+
+ // We got all the results (stop condition might still be in progress but this is the last interrupt)
+ trans->status = I2CTransSuccess;
+
+ // Document the current Status:
+ // -the stop was actually already requested in the previous step
+ periph->status = I2CStopRequested;
+
+ return STMI2C_SubTra_Ready_StopRequested;
+ }
+ else // Event Logic Error
+ {
+ return STMI2C_SubTra_Error;
+ }
+
+ return STMI2C_SubTra_Busy;
+}
+
+// Doc ID 13902 Rev 11 p 713/1072
+// Transfer Sequence Diagram for Master Receiver for N=2
+static inline enum STMI2CSubTransactionStatus stmi2c_read2(I2C_TypeDef *regs, struct i2c_periph *periph, struct i2c_transaction *trans)
+{
+ uint16_t SR1 = regs->SR1;
+
+ // Start Condition Was Just Generated
+ if (BIT_X_IS_SET_IN_REG( I2C_SR1_BIT_SB, SR1 ) )
+ {
+ // according to the datasheet: instantly shedule a NAK on the second received byte:
+ regs->CR2 &= ~ I2C_CR2_BIT_ITBUFEN;
+ regs->CR1 |= I2C_CR1_BIT_ACK;
+ regs->CR1 |= I2C_CR1_BIT_POS;
+ regs->DR = trans->slave_addr | 0x01;
+
+ // Document the current Status
+ periph->status = I2CAddrRdSent;
+ }
+ // Address Was Sent
+ else if (BIT_X_IS_SET_IN_REG(I2C_SR1_BIT_ADDR, SR1) )
+ {
+ // --- make absolutely sure this command is not delayed too much after the previous:
+ // --- the NAK bits must be set before the first byte arrived: allow other interrupts here
+ __I2C_REG_CRITICAL_ZONE_START;
+
+ // if transfer of DR was finished already then we will get too many bytes
+ // BEFORE clearing ACK, read SR2 to clear the ADDR (next byte will start arriving)
+ // clearing ACK after the byte transfer has already started will NACK the next (2nd)
+ uint16_t SR2 __attribute__ ((unused)) = regs->SR2;
+
+ // NOT First Clear the ACK bit but only AFTER clearing ADDR
+ regs->CR1 &= ~ I2C_CR1_BIT_ACK;
+
+ // Disable the RXNE and wait for BTF
+ regs->CR2 &= ~ I2C_CR2_BIT_ITBUFEN;
+
+ __I2C_REG_CRITICAL_ZONE_STOP;
+ // --- end of critical zone -----------
+
+ // We do not set the RxE but wait for both bytes to arrive using BTF
+
+ // Document the current Status
+ periph->status = I2CReadingByte;
+ }
+ // Receive buffer if full, master is halted: BTF
+ else if (BIT_X_IS_SET_IN_REG(I2C_SR1_BIT_BTF, SR1) )
+ {
+ // Stop condition MUST be set BEFORE reading the DR
+ // otherwise since there is new buffer space a new byte will be read
+ PPRZ_I2C_SEND_STOP(regs);
+
+ // Document the current Status
+ periph->status = I2CStopRequested;
+
+ trans->buf[0] = regs->DR;
+ trans->buf[1] = regs->DR;
+
+ // We got all the results
+ trans->status = I2CTransSuccess;
+
+ return STMI2C_SubTra_Ready_StopRequested;
+ }
+ else // Event Logic Error
+ {
+ return STMI2C_SubTra_Error;
+ }
+
+ return STMI2C_SubTra_Busy;
+}
+
+// Doc ID 13902 Rev 11 p 712/1072
+// Transfer Sequence Diagram for Master Receiver for N>2
+static inline enum STMI2CSubTransactionStatus stmi2c_readmany(I2C_TypeDef *regs, struct i2c_periph *periph, struct i2c_transaction *trans)
+{
+ uint16_t SR1 = regs->SR1;
+
+ // Start Condition Was Just Generated
+ if (BIT_X_IS_SET_IN_REG( I2C_SR1_BIT_SB, SR1 ) )
+ {
+ regs->CR2 &= ~ I2C_CR2_BIT_ITBUFEN;
+ // The first data byte will be acked in read many so the slave knows it should send more
+ regs->CR1 &= ~ I2C_CR1_BIT_POS;
+ regs->CR1 |= I2C_CR1_BIT_ACK;
+ // Clear the SB flag
+ regs->DR = trans->slave_addr | 0x01;
+
+ // Document the current Status
+ periph->status = I2CAddrRdSent;
+ }
+ // Address Was Sent
+ else if (BIT_X_IS_SET_IN_REG(I2C_SR1_BIT_ADDR, SR1) )
+ {
+ periph->idx_buf = 0;
+
+ // Enable RXNE: receive an interrupt any time a byte is available
+ // only enable if MORE than 3 bytes need to be read
+ if (periph->idx_buf < (trans->len_r - 3))
+ {
+ regs->CR2 |= I2C_CR2_BIT_ITBUFEN;
+ }
+
+ // ACK is still on to get more DATA
+ // Read SR2 to clear the ADDR (next byte will start arriving)
+ uint16_t SR2 __attribute__ ((unused)) = regs->SR2;
+
+ // Document the current Status
+ periph->status = I2CReadingByte;
+ }
+ // one or more bytes are available AND we were interested in Buffer interrupts
+ else if ( (BIT_X_IS_SET_IN_REG(I2C_SR1_BIT_RXNE, SR1) ) && (BIT_X_IS_SET_IN_REG(I2C_CR2_BIT_ITBUFEN, regs->CR2)) )
+ {
+ // read byte until 3 bytes remain to be read (e.g. len_r = 6, -> idx=3 means idx 3,4,5 = 3 remain to be read
+ if (periph->idx_buf < (trans->len_r - 3))
+ {
+ trans->buf[periph->idx_buf] = regs->DR;
+ periph->idx_buf ++;
+ }
+ // from : 3bytes -> last byte: do nothing
+ //
+ // finally: this was the last byte
+ else if (periph->idx_buf >= (trans->len_r - 1))
+ {
+ regs->CR2 &= ~ I2C_CR2_BIT_ITBUFEN;
+
+ // Last Value
+ trans->buf[periph->idx_buf] = regs->DR;
+ periph->idx_buf ++;
+
+ // We got all the results
+ trans->status = I2CTransSuccess;
+
+ return STMI2C_SubTra_Ready_StopRequested;
+ }
+
+ // Check for end of transaction: start waiting for BTF instead of RXNE
+ if (periph->idx_buf < (trans->len_r - 3))
+ {
+ regs->CR2 |= I2C_CR2_BIT_ITBUFEN;
+ }
+ else // idx >= len-3: there are 3 bytes to be read
+ {
+ // We want to halt I2C to have sufficient time to clear ACK, so:
+ // Stop listening to RXNE as it will be triggered infinitely since we did not empty the buffer
+ // on the next (second in buffer) received byte BTF will be set (buffer full and I2C halted)
+ regs->CR2 &= ~ I2C_CR2_BIT_ITBUFEN;
+ }
+ }
+ // Buffer is full while this was not a RXNE interrupt
+ else if (BIT_X_IS_SET_IN_REG(I2C_SR1_BIT_BTF, SR1) )
+ {
+ // Now the shift register and data register contain data(n-2) and data(n-1)
+ // And I2C is halted so we have time
+
+ // --- Make absolutely sure the next 2 I2C actions are performed with no delay
+ __I2C_REG_CRITICAL_ZONE_START;
+
+ // First we clear the ACK while the SCL is held low by BTF
+ regs->CR1 &= ~ I2C_CR1_BIT_ACK;
+
+ // Now that ACK is cleared we read one byte: instantly the last byte is being clocked in...
+ trans->buf[periph->idx_buf] = regs->DR;
+ periph->idx_buf ++;
+
+ // Now the last byte is being clocked. Stop in MUST be set BEFORE the transfer of the last byte is complete
+ PPRZ_I2C_SEND_STOP(regs);
+
+ __I2C_REG_CRITICAL_ZONE_STOP;
+ // --- end of critical zone -----------
+
+ // Document the current Status
+ periph->status = I2CStopRequested;
+
+ // read the byte2 we had in the buffer (BTF means 2 bytes available)
+ trans->buf[periph->idx_buf] = regs->DR;
+ periph->idx_buf ++;
+
+ // Ask for an interrupt to read the last byte (which is normally still busy now)
+ // The last byte will be received with RXNE
+ regs->CR2 |= I2C_CR2_BIT_ITBUFEN;
+ }
+ else // Event Logic Error
+ {
+ return STMI2C_SubTra_Error;
+ }
+
+ return STMI2C_SubTra_Busy;
+}
+
+////////////////////////////////////////////////
+// Restore bus conditions to normal after errors
+
+static inline void i2c_error(struct i2c_periph *periph)
+{
+ uint8_t err_nr = 0;
+ periph->errors->er_irq_cnt;
+ if (I2C_GetITStatus(periph->reg_addr, I2C_IT_AF)) { /* Acknowledge failure */
+ periph->errors->ack_fail_cnt++;
+ I2C_ClearITPendingBit(periph->reg_addr, I2C_IT_AF);
+ err_nr = 1;
+ }
+ if (I2C_GetITStatus(periph->reg_addr, I2C_IT_BERR)) { /* Misplaced Start or Stop condition */
+ periph->errors->miss_start_stop_cnt++;
+ I2C_ClearITPendingBit(periph->reg_addr, I2C_IT_BERR);
+ err_nr = 2;
+ }
+ if (I2C_GetITStatus(periph->reg_addr, I2C_IT_ARLO)) { /* Arbitration lost */
+ periph->errors->arb_lost_cnt++;
+ I2C_ClearITPendingBit(periph->reg_addr, I2C_IT_ARLO);
+ err_nr = 3;
+ }
+ if (I2C_GetITStatus(periph->reg_addr, I2C_IT_OVR)) { /* Overrun/Underrun */
+ periph->errors->over_under_cnt++;
+ I2C_ClearITPendingBit(periph->reg_addr, I2C_IT_OVR);
+ err_nr = 4;
+ }
+ if (I2C_GetITStatus(periph->reg_addr, I2C_IT_PECERR)) { /* PEC Error in reception */
+ periph->errors->pec_recep_cnt++;
+ I2C_ClearITPendingBit(periph->reg_addr, I2C_IT_PECERR);
+ err_nr = 5;
+ }
+ if (I2C_GetITStatus(periph->reg_addr, I2C_IT_TIMEOUT)) { /* Timeout or Tlow error */
+ periph->errors->timeout_tlow_cnt++;
+ I2C_ClearITPendingBit(periph->reg_addr, I2C_IT_TIMEOUT);
+ err_nr = 6;
+ }
+ if (I2C_GetITStatus(periph->reg_addr, I2C_IT_SMBALERT)) { /* SMBus alert */
+ periph->errors->smbus_alert_cnt++;
+ I2C_ClearITPendingBit(periph->reg_addr, I2C_IT_SMBALERT);
+ err_nr = 7;
+ }
+
+#ifdef I2C_DEBUG_LED
+ LED_ERROR(20, err_nr);
+#endif
+
+ return;
+}
+
+
+static inline void stmi2c_clear_pending_interrupts(I2C_TypeDef *regs)
+{
+ uint16_t SR1 = regs->SR1;
+
+ // Certainly do not wait for buffer interrupts:
+ // -------------------------------------------
+ regs->CR2 &= ~ I2C_CR2_BIT_ITBUFEN; // Disable TXE, RXNE
+
+ // Error interrupts are handled separately:
+ // ---------------------------------------
+
+ // Clear Event interrupt conditions:
+ // --------------------------------
+
+ // Start Condition Was Generated
+ if (BIT_X_IS_SET_IN_REG( I2C_SR1_BIT_SB, SR1 ) )
+ {
+ // SB: cleared by software when reading SR1 and writing to DR
+ regs->DR = 0x00;
+ }
+ // Address Was Sent
+ if (BIT_X_IS_SET_IN_REG(I2C_SR1_BIT_ADDR, SR1) )
+ {
+ // ADDR: Cleared by software when reading SR1 and then SR2
+ uint16_t SR2 __attribute__ ((unused)) = regs->SR2;
+ }
+ // Byte Transfer Finished
+ if (BIT_X_IS_SET_IN_REG(I2C_SR1_BIT_BTF, SR1) )
+ {
+ // SB: cleared by software when reading SR1 and reading/writing to DR
+ uint8_t dummy __attribute__ ((unused)) = regs->DR;
+ regs->DR = 0x00;
+ }
+
+}
+
+
+////////////////////////////////////////////////
+// Restore bus conditions to normal after errors
+
+static inline void i2c_irq(struct i2c_periph *periph)
+{
+
+ /*
+ There are 7 possible event reasons to get here + all errors
+
+ If IT_EV_FEN
+ -------------------------
+
+ We are always interested in all IT_EV_FEV: all are required.
+
+ 1) SB // Start Condition Success in Master mode
+ 2) ADDR // Address sent received Acknoledge
+ [ADDR10] // -- 10bit address stuff: not used
+ [STOPF] // -- only for slaves: master has no stop interrupt: not used
+ 3) BTF // I2C has stopped working (it is waiting for new data, all buffers are tx_empty/rx_full)
+
+ // Beware: using the buffered I2C has some interesting properties:
+ -in master receive mode: BTF only occurs after the 2nd received byte: after the first byte is received it is
+ in RD but the I2C can still receive a second byte. Only when the 2nd byte is received while the RxNE is 1
+ then a BTF occurs (I2C can not continue receiving bytes or they will get lost). During BTF I2C is halted (SCL held low)
+ -in master transmit mode: when writing a byte to WD, you instantly get a new TxE interrupt while the first is not
+ transmitted yet. The byte was pushed to the I2C shift register and the buffer is ready for more. You can already
+ fill new data in the buffer while the first is still being transmitted for max performance transmission.
+
+ // Beware: besides data buffering you can/must plan several consecutive actions. You can send 2 bytes to the buffer, ask for a stop and
+ a new start in one go.
+
+ -thanks to / because of this buffering and event sheduling there is not 1 interrupt per start / byte / stop
+ This also means you must think more in advance and a transaction could be popped from the transaction stack even before it's
+ stop condition is actually generated.
+
+ // Beware: the order in which Status (and other register) is read determines how flags are cleared.
+ You should NOT simply read SR1 & SR2 every time
+
+ If IT_EV_FEN AND IT_EV_BUF
+ --------------------------
+
+ Buffer event are not always wanted and are typically switched on during longer data transfers. Make sure to turn off in time.
+
+ 4) RxNE
+ 5) TxE
+
+ --------------------------------------------------------------------------------------------------
+
+ The STM waits indefinately (holding SCL low) for user interaction:
+ a) after a master-start (waiting for address)
+ b) after an address (waiting for data)
+ not during data sending when using buffered
+ c) after the last byte is transmitted (waiting for either stop or restart)
+ not during data receiving when using buffered
+ not after the last byte is received
+
+ -The STM I2C stalls indefinately when a stop condition was attempted that
+ did not succeed. The BUSY flag remains on.
+ -There is no STOP interrupt.
+
+ Caution Reading the status:
+ - Caution: this clears several flags and can start transmissions etc...
+ - Certain flags like STOP / (N)ACK need to be guaranteed to be set before
+ the transmission of the byte is finished. At higher clock rates that can be
+ quite fast: so we allow no other interrupt to be triggered in between
+ reading the status and setting all needed flags
+
+ */
+
+ // Here we go ...
+
+ // Apparently we got an I2C interrupt: EVT BUF or ERR
+
+#ifdef I2C_DEBUG_LED
+ // Notify ISR is triggered
+ LED1_ON();
+ LED1_OFF();
+#endif
+
+ // Save Some Direct Access to the I2C Registers ...
+ I2C_TypeDef *regs = (I2C_TypeDef *) periph->reg_addr;
+
+ /////////////////////////////
+ // Check if we were ready ...
+ if (periph->trans_extract_idx == periph->trans_insert_idx)
+ {
+ // Nothing Left To Do
+
+#ifdef I2C_DEBUG_LED
+ LED2_ON();
+ LED1_ON();
+ LED2_OFF();
+ LED1_OFF();
+
+ // no transaction and also an error?
+ LED_SHOW_ACTIVE_BITS(regs);
+#endif
+
+ // If we still get an interrupt but there are no more things to do
+ // (which can happen if an event was sheduled just before a bus error occurs)
+ // (or can happen if both error and event interrupts were called together [the 2nd will then get this error])
+
+ // since there is nothing more to do: its easy: just stop: clear all interrupt generating bits
+
+ // Count The Errors
+ i2c_error(periph);
+
+ // Clear Running Events
+ stmi2c_clear_pending_interrupts(regs);
+
+ // Mark this as a special error
+ periph->errors->last_unexpected_event++;
+
+ // Document the current Status
+ periph->status = I2CIdle;
+
+ // There are no transactions anymore: return
+ // further-on in this routine we need a transaction pointer: so we are not allowed to continue
+ return;
+ }
+
+ // get the I2C transaction we were working on ...
+
+ enum STMI2CSubTransactionStatus ret = 0;
+ struct i2c_transaction* trans = periph->trans[periph->trans_extract_idx];
+
+ ///////////////////////////
+ // If there was an error:
+ if (( regs->SR1 & I2C_SR1_BITS_ERR ) != 0x0000)
+ {
+
+#ifdef I2C_DEBUG_LED
+ LED1_ON();
+ LED2_ON();
+ LED1_OFF();
+ LED2_OFF();
+
+ LED_SHOW_ACTIVE_BITS(regs);
+#endif
+
+ // Notify everyone about the error ...
+
+ // Set result in transaction
+ trans->status = I2CTransFailed;
+
+ // Document the current Status
+ periph->status = I2CFailed;
+
+ // Make sure a TxRx does not Restart
+ trans->type = I2CTransRx;
+
+ // Count The Errors
+ i2c_error(periph);
+
+ // Clear Running Events
+ stmi2c_clear_pending_interrupts(regs);
+
+ // Now continue as if everything was normal from now on
+ ret = STMI2C_SubTra_Ready;
+
+ }
+
+ ///////////////////////////
+ // Normal Event:
+ else
+ {
+
+ ///////////////////////////////////////////////////////////////////////////////////////////////////////
+ ///////////////////////////////////////////////////////////////////////////////////////////////////////
+ //
+ // SUB-TRANSACTION HANDLER
+
+ if (trans->type == I2CTransRx) // TxRx are converted to Rx after the Tx Part
+ {
+ switch (trans->len_r)
+ {
+ case 1:
+ ret = stmi2c_read1(regs,periph,trans);
+ break;
+ case 2:
+ ret = stmi2c_read2(regs,periph,trans);
+ break;
+ default:
+ ret = stmi2c_readmany(regs,periph,trans);
+ break;
+ }
+ }
+ else // TxRx or Tx
+ {
+ ret = stmi2c_send(regs,periph,trans);
+ }
+ }
+
+ /////////////////////////////////
+ // Sub-transaction has finished
+ if (ret != STMI2C_SubTra_Busy)
+ {
+ // Ready or SubTraError
+ // -ready: with or without stop already asked
+
+ // In case of unexpected event condition during subtransaction handling:
+ if (ret == STMI2C_SubTra_Error)
+ {
+ // Tell everyone about the subtransaction error:
+ // this is the previously called SPURRIOUS INTERRUPT
+ periph->status = I2CFailed;
+ trans->type = I2CTransRx; // Avoid possible restart
+ trans->status = I2CTransFailed; // Notify Ready
+ periph->errors->unexpected_event_cnt++;
+
+ // Error
+#ifdef I2C_DEBUG_LED
+ LED2_ON();
+ LED1_ON();
+ LED2_OFF();
+ LED1_OFF();
+
+ LED_SHOW_ACTIVE_BITS(regs);
+#endif
+
+ // Clear Running Events
+ stmi2c_clear_pending_interrupts(regs);
+ }
+
+ // RxTx -> Restart and do Rx part
+ if (trans->type == I2CTransTxRx)
+ {
+ trans->type = I2CTransRx;
+ periph->status = I2CStartRequested;
+ regs->CR1 |= I2C_CR1_BIT_START;
+
+ // Silent any BTF that would occur before SB
+ regs->DR = 0x00;
+ }
+ // If a restart is not needed: Rx part or Tx-only
+ else
+ {
+ // Ready, no stop condition set yet
+ if (ret == STMI2C_SubTra_Ready)
+ {
+
+ // Program a stop
+ PPRZ_I2C_SEND_STOP(regs);
+
+ // Silent any BTF that would occur before STOP is executed
+ regs->DR = 0x00;
+ }
+
+ // Jump to the next transaction
+ periph->trans_extract_idx++;
+ if (periph->trans_extract_idx >= I2C_TRANSACTION_QUEUE_LEN)
+ periph->trans_extract_idx = 0;
+
+ // Tell everyone we are ready
+ periph->status = I2CIdle;
+
+
+ // if we have no more transaction to process, stop here
+ if (periph->trans_extract_idx == periph->trans_insert_idx)
+ {
+
+#ifdef I2C_DEBUG_LED
+ LED2_ON();
+ LED1_ON();
+ LED1_OFF();
+ LED1_ON();
+ LED1_OFF();
+ LED2_OFF();
+#endif
+ }
+ // if not, start next transaction
+ else
+ {
+ // Restart transaction doing the Rx part now
+// --- moved to idle function
+ PPRZ_I2C_SEND_START(periph);
+// ------
+ }
+ }
+ }
+
+ return;
+}
+
+
+/*
+ // Make sure the bus is free before resetting (p722)
+ if (regs->SR2 & (I2C_FLAG_BUSY >> 16)) {
+ // Reset the I2C block
+ I2C_SoftwareResetCmd(periph->reg_addr, ENABLE);
+ I2C_SoftwareResetCmd(periph->reg_addr, DISABLE);
+ }
+*/
+
+
+#ifdef USE_I2C1
+
+struct i2c_errors i2c1_errors;
+volatile uint32_t i2c1_watchdog_counter;
+
+void i2c1_hw_init(void) {
+
+ i2c1.reg_addr = I2C1;
+ i2c1.init_struct = &I2C1_InitStruct;
+ i2c1.scl_pin = GPIO_Pin_6;
+ i2c1.sda_pin = GPIO_Pin_7;
+ i2c1.errors = &i2c1_errors;
+ i2c1_watchdog_counter = 0;
+
+ /* zeros error counter */
+ ZEROS_ERR_COUNTER(i2c1_errors);
+
+ // Extra
+#ifdef I2C_DEBUG_LED
+ LED_INIT();
+#else
+
+ /* reset peripheral to default state ( sometimes not achieved on reset :( ) */
+ //I2C_DeInit(I2C1);
+
+ NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0);
+ NVIC_InitTypeDef NVIC_InitStructure;
+
+ /* Configure and enable I2C1 event interrupt --------------------------------*/
+ NVIC_InitStructure.NVIC_IRQChannel = I2C1_EV_IRQn;
+ NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
+ NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
+ NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
+ NVIC_Init(&NVIC_InitStructure);
+
+ /* Configure and enable I2C1 err interrupt ----------------------------------*/
+ NVIC_InitStructure.NVIC_IRQChannel = I2C1_ER_IRQn;
+ NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
+ NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
+ NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
+ NVIC_Init(&NVIC_InitStructure);
+
+ /* Enable peripheral clocks -------------------------------------------------*/
+ /* Enable I2C1 clock */
+ RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1, ENABLE);
+ /* Enable GPIOB clock */
+ RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
+
+ GPIO_InitTypeDef GPIO_InitStructure;
+ GPIO_InitStructure.GPIO_Pin = i2c1.scl_pin | i2c1.sda_pin;
+ GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;
+ GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_OD;
+ GPIO_Init(GPIOB, &GPIO_InitStructure);
+
+ I2C_DeInit(I2C1);
+
+ // enable peripheral
+ I2C_Cmd(I2C1, ENABLE);
+
+ I2C_Init(I2C1, i2c1.init_struct);
+
+ // enable error interrupts
+ I2C_ITConfig(I2C1, I2C_IT_ERR, ENABLE);
+
+ i2c_setbitrate(&i2c2, I2C2_InitStruct.I2C_ClockSpeed);
+#endif
+}
+
+void i2c1_ev_irq_handler(void) {
+ I2C_TypeDef *regs = (I2C_TypeDef *) i2c1.reg_addr;
+ regs->CR2 &= ~ I2C_CR2_BIT_ITERREN;
+ i2c_irq(&i2c1);
+ i2c1_watchdog_counter = 0;
+ regs->CR2 |= I2C_CR2_BIT_ITERREN;
+}
+
+void i2c1_er_irq_handler(void) {
+ I2C_TypeDef *regs = (I2C_TypeDef *) i2c1.reg_addr;
+ regs->CR2 &= ~ I2C_CR2_BIT_ITEVTEN;
+ i2c_irq(&i2c1);
+ i2c1_watchdog_counter = 0;
+ regs->CR2 |= I2C_CR2_BIT_ITEVTEN;
+}
+
+#endif /* USE_I2C1 */
+
+#ifdef USE_I2C2
+
+struct i2c_errors i2c2_errors;
+volatile uint32_t i2c2_watchdog_counter;
+
+void i2c2_hw_init(void) {
+
+ i2c2.reg_addr = I2C2;
+ i2c2.init_struct = &I2C2_InitStruct;
+ i2c2.scl_pin = GPIO_Pin_10;
+ i2c2.sda_pin = GPIO_Pin_11;
+ i2c2.errors = &i2c2_errors;
+ i2c2_watchdog_counter = 0;
+
+ /* zeros error counter */
+ ZEROS_ERR_COUNTER(i2c2_errors);
+
+ /* reset peripheral to default state ( sometimes not achieved on reset :( ) */
+ //I2C_DeInit(I2C2);
+
+ NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0);
+ NVIC_InitTypeDef NVIC_InitStructure;
+
+ /* Configure and enable I2C2 event interrupt --------------------------------*/
+ NVIC_InitStructure.NVIC_IRQChannel = I2C2_EV_IRQn;
+ NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
+ NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
+ NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
+ NVIC_Init(&NVIC_InitStructure);
+
+ /* Configure and enable I2C2 err interrupt ----------------------------------*/
+ NVIC_InitStructure.NVIC_IRQChannel = I2C2_ER_IRQn;
+ NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
+ NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
+ NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
+ NVIC_Init(&NVIC_InitStructure);
+
+ /* Enable peripheral clocks -------------------------------------------------*/
+ /* Enable I2C2 clock */
+ RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C2, ENABLE);
+ /* Enable GPIOB clock */
+ RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
+
+ GPIO_InitTypeDef GPIO_InitStructure;
+ GPIO_InitStructure.GPIO_Pin = i2c2.scl_pin | i2c2.sda_pin;
+ GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;
+ GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_OD;
+ GPIO_Init(GPIOB, &GPIO_InitStructure);
+
+ I2C_DeInit(I2C2);
+
+ // enable peripheral
+ I2C_Cmd(I2C2, ENABLE);
+
+ I2C_Init(I2C2, i2c2.init_struct);
+
+ // enable error interrupts
+ I2C_ITConfig(I2C2, I2C_IT_ERR, ENABLE);
+
+ i2c_setbitrate(&i2c2, I2C2_InitStruct.I2C_ClockSpeed);
+}
+
+void i2c2_ev_irq_handler(void) {
+ I2C_TypeDef *regs = (I2C_TypeDef *) i2c2.reg_addr;
+ regs->CR2 &= ~ I2C_CR2_BIT_ITERREN;
+ i2c_irq(&i2c2);
+ i2c2_watchdog_counter = 0;
+ regs->CR2 |= I2C_CR2_BIT_ITERREN;
+}
+
+void i2c2_er_irq_handler(void) {
+ I2C_TypeDef *regs = (I2C_TypeDef *) i2c2.reg_addr;
+ regs->CR2 &= ~ I2C_CR2_BIT_ITEVTEN;
+ i2c_irq(&i2c2);
+ i2c2_watchdog_counter = 0;
+ regs->CR2 |= I2C_CR2_BIT_ITEVTEN;
+}
+
+#endif /* USE_I2C2 */
+
+//////////////////////////////////////////////////
+// Set Bitrate to Match your application:
+// -short wires, low capacitance bus: IMU: high speed
+// -long wires with a lot of capacitance: motor controller: put speed as low as possible
+
+void i2c_setbitrate(struct i2c_periph *periph, int bitrate)
+{
+ // If NOT Busy
+ if (i2c_idle(periph))
+ {
+ volatile int devider;
+ volatile int risetime;
+
+ I2C_TypeDef *regs = (I2C_TypeDef *) periph->reg_addr;
+
+ // store (just for fun)
+ I2C2_InitStruct.I2C_ClockSpeed = bitrate;
+
+/*****************************************************
+ Bitrate:
+
+ -CR2 + CCR + TRISE registers
+ -only change when PE=0
+
+ e.g.
+
+ 10kHz: 36MHz + Standard 0x708 + 0x25
+ 70kHz: 36MHz + Standard 0x101 +
+ 400kHz: 36MHz + Fast 0x1E + 0xb
+
+ // 1) Program peripheral input clock CR2: to get correct timings
+ // 2) Configure clock control registers
+ // 3) Configure rise time register
+******************************************************/
+
+ if (bitrate < 3000)
+ bitrate = 3000;
+
+ // 36MHz, fast scl: 2counts low 1 count high -> / 3:
+ devider = 18000 / (bitrate/1000);
+
+ // never allow faster than 600kbps
+ if (devider < 20)
+ devider = 20;
+
+ // no overflow either
+ if (devider >=4095)
+ devider = 4095;
+
+ // risetime can be up to 1/6th of the period
+ risetime = 1000000 / (bitrate/1000) / 6 / 28;
+
+ if (risetime < 10)
+ risetime = 10;
+
+ // more will overflow the register: for more you should lower the FREQ
+ if (risetime >=31)
+ risetime = 31;
+
+ // we do not expect an interrupt as the interface should have been idle, but just in case...
+ __disable_irq(); // this code is in user space:
+
+ // CCR can only be written when PE is disabled
+ // p731 note 5
+ regs->CR1 &= ~ I2C_CR1_BIT_PE;
+
+ // 1)
+ regs->CR2 = 0x0324;
+ // 2)
+ //regs->CCR = 0x8000 + devider;
+ regs->CCR = 0x0000 + devider;
+ // 3)
+ regs->TRISE = risetime;
+
+ // Re-Enable
+ regs->CR1 |= I2C_CR1_BIT_PE;
+
+ __enable_irq();
+
+#ifdef I2C_DEBUG_LED
+ __disable_irq(); // this code is in user space:
+
+ LED2_ON();
+ LED1_ON();
+ LED2_OFF();
+ LED1_OFF();
+ LED2_ON();
+ LED1_ON();
+ LED2_OFF();
+ LED1_OFF();
+
+ __enable_irq();
+#endif
+
+ }
+}
+
+
+// TODO: TODO: TODO:
+// Watchdog timer
+void i2c_event(void)
+{
+#ifdef USE_I2C1
+ i2c1_watchdog_counter++;
+#endif
+
+#ifdef USE_I2C2
+ i2c2_watchdog_counter++;
+
+ if (i2c2_watchdog_counter > 10000)
+ {
+ i2c2.errors->timeout_tlow_cnt++;
+ i2c2_watchdog_counter = 0;
+ }
+
+
+#ifdef I2C_DEBUG_LED
+ if (i2c2_watchdog_counter == 0)
+ {
+ __disable_irq();
+
+ LED2_ON();
+ LED1_ON();
+ LED1_OFF();
+ LED1_ON();
+ LED1_OFF();
+ LED1_ON();
+ LED1_OFF();
+ LED1_ON();
+ LED1_OFF();
+ if (i2c2.status == I2CIdle)
+ {
+ LED1_ON();
+ LED1_OFF();
+ }
+ else if (i2c2.status == I2CStartRequested)
+ {
+ LED1_ON();
+ LED1_OFF();
+ LED1_ON();
+ LED1_OFF();
+
+ }
+ LED2_OFF();
+
+ //regs = (I2C_TypeDef *) i2c2.reg_addr;
+ //LED_SHOW_ACTIVE_BITS(regs);
+
+ __enable_irq();
+ }
+#endif
+
+
+ //if (i2c2.status == I2CIdle)
+ {
+ //if (i2c_idle(&i2c2))
+ {
+ //__disable_irq();
+ // More work to do
+ //if (i2c2.trans_extract_idx != i2c2.trans_insert_idx)
+ {
+ // Restart transaction doing the Rx part now
+ //PPRZ_I2C_SEND_START(&i2c2);
+ }
+ //__enable_irq();
+ }
+ }
+#endif
+}
+
+/////////////////////////////////////////////////////////
+// Implement Interface Functions
+
+bool_t i2c_submit(struct i2c_periph* periph, struct i2c_transaction* t) {
+
+ uint8_t temp;
+ temp = periph->trans_insert_idx + 1;
+ if (temp >= I2C_TRANSACTION_QUEUE_LEN) temp = 0;
+ if (temp == periph->trans_extract_idx)
+ return FALSE; // queue full
+
+ t->status = I2CTransPending;
+
+ __disable_irq();
+ /* put transacation in queue */
+ periph->trans[periph->trans_insert_idx] = t;
+ periph->trans_insert_idx = temp;
+
+ /* if peripheral is idle, start the transaction */
+ // if (PPRZ_I2C_IS_IDLE(p))
+ if (periph->status == I2CIdle)
+ {
+ //if (i2c_idle(periph))
+ {
+#ifdef I2C_DEBUG_LED
+#ifdef USE_I2C1
+ if (periph == &i2c1)
+ {
+
+ }
+ else
+#endif
+#endif
+ {
+#ifdef I2C_DEBUG_LED
+ LED2_ON();
+ LED2_OFF();
+#endif
+ PPRZ_I2C_SEND_START(periph);
+ }
+ }
+ }
+ /* else it will be started by the interrupt handler when the previous transactions completes */
+ __enable_irq();
+
+ return TRUE;
+}
+
+bool_t i2c_idle(struct i2c_periph* periph)
+{
+ // This is actually a difficult function:
+ // -simply reading the status flags can clear bits and corrupt the transaction
+
+ I2C_TypeDef *regs = (I2C_TypeDef *) periph->reg_addr;
+
+#ifdef I2C_DEBUG_LED
+#ifdef USE_I2C1
+ if (periph == &i2c1)
+ {
+ return TRUE;
+ }
+#endif
+#endif
+
+ // First we check if the software thinks it is ready
+ if (periph->status == I2CIdle)
+ return ! (BIT_X_IS_SET_IN_REG( I2C_SR2_BIT_BUSY, regs->SR2 ) );
+ else
+ return FALSE;
+}
+
+
diff --git a/sw/airborne/arch/stm32/mcu_periph/obsolete/i2c_attempt1.c b/sw/airborne/arch/stm32/mcu_periph/obsolete/i2c_attempt1.c
new file mode 100644
index 0000000000..5a0f71c84d
--- /dev/null
+++ b/sw/airborne/arch/stm32/mcu_periph/obsolete/i2c_attempt1.c
@@ -0,0 +1,659 @@
+#include "mcu_periph/i2c.h"
+
+#include
+#include
+#include
+#include
+
+//#include "led.h"
+
+/////////// DEBUGGING //////////////
+
+static inline void LED1_ON(void)
+{
+ GPIO_WriteBit(GPIOB, GPIO_Pin_6 , Bit_SET );
+}
+
+static inline void LED1_OFF(void)
+{
+ GPIO_WriteBit(GPIOB, GPIO_Pin_6 , !Bit_SET );
+}
+
+static inline void LED2_ON()
+{
+ GPIO_WriteBit(GPIOB, GPIO_Pin_7 , Bit_SET );
+}
+
+static inline void LED2_OFF(void)
+{
+ GPIO_WriteBit(GPIOB, GPIO_Pin_7 , !Bit_SET );
+}
+
+static inline void LED_INIT(void)
+{
+ GPIO_InitTypeDef GPIO_InitStructure;
+ RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOB, ENABLE);
+ GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7 | GPIO_Pin_6;
+ GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
+ GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
+ GPIO_Init(GPIOB, &GPIO_InitStructure);
+
+ LED1_OFF();
+ LED2_OFF();
+}
+
+
+static inline void LED_ERROR(uint8_t nr)
+{
+ for (int i=0;i<20;i++)
+ {
+ LED1_ON();
+ LED1_OFF();
+ if (nr == i)
+ LED2_OFF();
+ else
+ LED2_ON();
+ LED2_OFF();
+ }
+}
+
+static inline void LED_STROBE2(void)
+{
+LED2_ON();
+LED2_OFF();
+LED1_ON();
+LED1_OFF();
+LED2_ON();
+LED2_OFF();
+LED1_ON();
+LED1_OFF();
+LED1_OFF();
+LED1_OFF();
+LED1_OFF();
+
+}
+
+//////////////////////////////////////
+
+#ifdef DEBUG_I2C
+#define SPURIOUS_INTERRUPT(_periph, _status, _event) { while(1); }
+#define OUT_OF_SYNC_STATE_MACHINE(_periph, _status, _event) { while(1); }
+#else
+#define SPURIOUS_INTERRUPT(_periph, _status, _event) { }
+#define OUT_OF_SYNC_STATE_MACHINE(_periph, _status, _event) { }
+#endif
+
+#ifdef USE_I2C1
+static I2C_InitTypeDef I2C1_InitStruct = {
+ .I2C_Mode = I2C_Mode_I2C,
+ .I2C_DutyCycle = I2C_DutyCycle_2,
+ .I2C_OwnAddress1 = 0x00,
+ .I2C_Ack = I2C_Ack_Enable,
+ .I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit,
+ .I2C_ClockSpeed = 200000
+};
+#endif
+
+#ifdef USE_I2C2
+static I2C_InitTypeDef I2C2_InitStruct = {
+ .I2C_Mode = I2C_Mode_I2C,
+ .I2C_DutyCycle = I2C_DutyCycle_2,
+ .I2C_OwnAddress1 = 0x00,
+ .I2C_Ack = I2C_Ack_Enable,
+ .I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit,
+ .I2C_ClockSpeed = 300000
+};
+#endif
+
+
+#ifdef USE_I2C2
+
+
+
+//////////////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////////////
+
+// IDLE CHECK
+
+static bool_t PPRZ_I2C_IS_IDLE(struct i2c_periph* periph)
+{
+ return I2C_GetFlagStatus(periph->reg_addr, I2C_FLAG_BUSY) == RESET;
+}
+
+// (RE)START
+
+static inline void PPRZ_I2C_SEND_START(struct i2c_periph *periph)
+{
+ periph->idx_buf = 0;
+ I2C_GenerateSTART(periph->reg_addr, ENABLE);
+ I2C_ITConfig(periph->reg_addr, I2C_IT_EVT | I2C_IT_ERR, ENABLE);
+ I2C_ITConfig(periph->reg_addr, I2C_IT_BUF, DISABLE);
+}
+
+static void PPRZ_I2C_START_NEXT_TRANSACTION(struct i2c_periph* periph)
+{
+ /* if we have no more transaction to process, stop here */
+ if (periph->trans_extract_idx == periph->trans_insert_idx)
+ {
+ // Should we disable just in case? normally not. So if more interrupts are
+ // triggered there is a problem and we want to know.
+ // I2C_ITConfig(periph->reg_addr, I2C_IT_EVT | I2C_IT_BUF | I2C_IT_ERR, DISABLE);
+ periph->status = I2CIdle;
+ }
+ /* if not, start next transaction */
+ else
+ {
+ periph->status = I2CStartRequested;
+ PPRZ_I2C_SEND_START(periph);
+ }
+}
+
+static inline void PPRZ_I2C_RESTART(struct i2c_periph *periph)
+{
+//LED2_ON();
+// I2C_GenerateSTOP(periph->reg_addr, ENABLE);
+// I2C_SendData(periph->reg_addr, 0);
+// I2C_ClearITPendingBit(periph->reg_addr, I2C_IT_BTF);
+ periph->status = I2CRestartRequested;
+ PPRZ_I2C_SEND_START(periph);
+}
+
+// STOP
+
+static inline void PPRZ_I2C_HAS_FINISHED(struct i2c_periph *periph, struct i2c_transaction *trans, enum I2CTransactionStatus _status)
+{
+ // Finish Current
+ trans->status = _status;
+
+ // When finished successfully the I2C_FLAG_MLS will be cleared after the stop condition was issued.
+ // However: we do not need to wait for it to go the the next step, but if no stop condition was
+ // sent yet than we are still talking to the same slave...
+ // When we are here all paths to this function with success have already issued a STOP, the others not.
+ // Man: p722: Stop generation after the current byte transfer or after the current Start condition is sent.
+ if (_status != I2CTransSuccess)
+ {
+ // TODO: we might need to do much more here: see reset functions of antoine...
+ I2C_GenerateSTOP(periph->reg_addr, ENABLE);
+ }
+
+ // Jump to the next
+ periph->trans_extract_idx++;
+ if (periph->trans_extract_idx >= I2C_TRANSACTION_QUEUE_LEN)
+ periph->trans_extract_idx = 0;
+
+ PPRZ_I2C_START_NEXT_TRANSACTION(periph);
+}
+
+//////////////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////////////
+
+static inline void i2c_event(struct i2c_periph *periph)
+{
+ // Referring to manual:
+ // -Doc ID 13902 Rev 11
+
+
+ // Check to make sure that user space has an active transaction pending
+ if (periph->trans_extract_idx == periph->trans_insert_idx)
+ {
+ // no transaction?
+ periph->errors->unexpected_event_cnt++;
+ return;
+ }
+
+ struct i2c_transaction* trans = periph->trans[periph->trans_extract_idx];
+
+ /*
+ There are 7 possible reasons to get here:
+
+ If IT_EV_FEN
+ -------------------------
+
+ We are always interested in all IT_EV_FEV: all are required.
+
+ 1) SB // Start Condition Success in Master mode
+ 2) ADDR // Address sent received Acknoledge
+ [3 ADDR10] // -- 10bit address stuff
+ [4 STOPF] // -- only for slaves: master has no stop interrupt
+ 5) BTF // I2C has stopped working (it is waiting for new data, all buffers are tx_empty/rx_full)
+
+ // Beware: using the buffered I2C has some interesting properties:
+ -when receiving BTF only occurs after the 2nd received byte: after the first byte is received it is
+ in RD but the I2C can still receive a second byte. Only when the 2nd byte is received while the RxNE is 1
+ then a BTF occurs (I2C can not continue receiving bytes or they will get lost)
+ -when transmitting, and writing a byte to WD, you instantly get a new TxE interrupt while the first is not
+ transmitted yet. The byte was pushed to the I2C serializer and the buffer is ready for more. You can already
+ fill new data in the buffer while the first is still being transmitted for max performance transmission.
+
+ // Beware: the order in which Status is read determines how flags are cleared.
+
+ If IT_EV_FEN AND IT_EV_BUF
+ --------------------------
+
+ We are always interested in buffer interrupts IT_EV_BUF except in transmission when all data was sent
+
+ 6) RxNE
+ 7) TxE
+
+ --------------------------------------------------------------------------------------------------
+ // This driver uses only a subset of the pprz_i2c_states for several reasons:
+ // -we have less interrupts than the I2CStatus states (for efficiency)
+ // -status register flags better correspond to reality, especially in case of I2C errors
+
+ enum I2CStatus {
+ I2CIdle, // Dummy: Actual I2C Peripheral idle detection is safer with the
+ // hardware status register flag I2C_FLAG_BUSY.
+
+ I2CStartRequested, // EV5: used to differentiate S en Sr
+ I2CRestartRequested, // EV5: used to differentiate S en Sr
+
+ I2CSendingByte, // Not used: using the hardware status reg I2C_FLAG_TRA
+ I2CReadingByte,
+ I2CAddrWrSent, // Since we can do many things at once and we
+ I2CAddrRdSent, // have buffered sending, these states
+ I2CSendingLastByte, // do not correspond to the real state of the
+ I2CReadingLastByte, // STM I2C driver so they are not used
+ I2CStopRequested,
+
+ I2CComplete, // Used to provide the result
+ I2CFailed
+ };
+
+ ---------
+
+ The STM waits (holding SCL low) for user interaction:
+ a) after a master-start (waiting for address)
+ b) after an address (waiting for data)
+ not during data sending when using buffered
+ c) after the last byte is transmitted (waiting for either stop or restart)
+ not during data receiving when using buffered
+ not after the last byte is received
+
+ */
+
+
+ ///////////////////////////////////////////////////////////////////////////////////
+ // Reading the status:
+ // - Caution: this clears several flags and can start transmissions etc...
+ // - Certain flags like STOP / (N)ACK need to be guaranteed to be set before
+ // the transmission of the byte is finished. At higher clock rates that can be
+ // quite fast: so we allow no other interrupt to be triggered in between
+ // reading the status and setting all needed flags
+
+
+ LED1_ON();
+
+ //I2C_TypeDef *regs = (I2C_TypeDef *) periph->reg_addr;
+
+ //__disable_irq();
+ uint32_t event = I2C_GetLastEvent(periph->reg_addr);
+
+ //uint32_t event = (((uint32_t)(regs->SR2)) << 16) + regs->SR1;
+
+ if (event & I2C_FLAG_TXE)
+ {
+ LED2_ON();
+ }
+
+
+ ///////////////////////////////////////////////////////////////////////////////////
+ ///////////////////////////////////////////////////////////////////////////////////
+ // START: Start Condition in Master Mode:
+ // STM Manual Ev5
+ if (event & I2C_FLAG_SB)
+ {
+ // Periph was waiting for Start
+ if (periph->status == I2CStartRequested)
+ {
+ // Send Read Slave Address
+ if(trans->type == I2CTransRx)
+ {
+ I2C_Send7bitAddress(periph->reg_addr, trans->slave_addr, I2C_Direction_Receiver);
+ }
+ // Send Write Slave Address
+ else
+ {
+ I2C_Send7bitAddress(periph->reg_addr, trans->slave_addr, I2C_Direction_Transmitter);
+ }
+ I2C_ITConfig(periph->reg_addr, I2C_IT_BUF, ENABLE);
+ }
+ // Waiting for Restart: Always Rx
+ else if (periph->status == I2CRestartRequested)
+ {
+ I2C_Send7bitAddress(periph->reg_addr, trans->slave_addr, I2C_Direction_Receiver);
+ I2C_ITConfig(periph->reg_addr, I2C_IT_BUF, ENABLE);
+ }
+ // Problem: this problem need to be triggerd as if the
+ // status was not OK then the buf size is also bad
+ else
+ {
+ PPRZ_I2C_HAS_FINISHED(periph, trans, I2CTransFailed);
+ }
+ periph->status = I2CAddrWrSent;
+ }
+
+ ///////////////////////////////////////////////////////////////////////////////////
+ ///////////////////////////////////////////////////////////////////////////////////
+ // TRANSMIT: Buffer Can accept the next byte for transmission
+ // --> this means we HAVE TO fill the buffer and/or disable buf interrupts (otherwise this interrupt
+ // will be triggered until a start/stop occurs which can be quite long = many spurrious interrupts)
+ // STM Manual Ev8
+ else if (event & I2C_FLAG_TXE) // only possible when TRA(nsmitter) and no flag tra/start/stop/addr
+ {
+ if (periph->status == I2CRestartRequested)
+ {
+ // Neglect this interrupt: We just issued the restart last session already
+ PPRZ_I2C_RESTART(periph);
+ }
+
+ // Do we have more data? and there is buffer room?
+ // (neglect BTF: if it was set it just means we were too slow)
+ else if (periph->idx_buf < trans->len_w)
+ {
+ I2C_SendData(periph->reg_addr, trans->buf[periph->idx_buf]);
+ periph->idx_buf++;
+ // Was this one the Last? -> Disable the buf interrupt (until next start) and wait for BTF
+ // -we could gain a bit of efficiency by already starting the next action but for
+ // code-readability we will wait until the last tx-byte is sent
+ if (periph->idx_buf >= trans->len_w)
+ {
+ I2C_ITConfig(periph->reg_addr, I2C_IT_BUF, DISABLE);
+ // If this is followed by a restart: then we need to set the startbit to avoid extra interrupts.
+ if (trans->type != I2CTransTx)
+ {
+ I2C_GenerateSTOP(periph->reg_addr, ENABLE);
+ }
+ }
+ }
+
+ else if (event & I2C_FLAG_BTF)
+ {
+ // Ready -> Stop
+ if (trans->type == I2CTransTx)
+ {
+ // STM Manual Ev8_2
+ I2C_GenerateSTOP(periph->reg_addr, ENABLE);
+ PPRZ_I2C_HAS_FINISHED(periph, trans, I2CTransSuccess);
+ }
+ // Rx/Trans -> Restart:
+ // Do not wait for BTF
+ }
+ // If we had no more data but got no BTF then there is a problem
+ else
+ {
+ PPRZ_I2C_HAS_FINISHED(periph, trans, I2CTransFailed);
+ }
+ }
+
+ ///////////////////////////////////////////////////////////////////////////////////
+ ///////////////////////////////////////////////////////////////////////////////////
+ // RECEIVE:
+ // while receiving: the master needs to signal to the slave if more data is needed
+ else if ((event & I2C_FLAG_ADDR) || (event & I2C_FLAG_RXNE))
+ {
+ // data is available every time RXNE is set. If BTF is set it means that 2 bytes are
+ // ready to read (one in shift register) and I2C has stopped until the buffer can accept new data.
+ if (event & I2C_FLAG_RXNE)
+ {
+ uint8_t read_byte = I2C_ReceiveData(periph->reg_addr);
+ if (periph->idx_buf < trans->len_r)
+ {
+ trans->buf[periph->idx_buf] = read_byte;
+ periph->idx_buf++;
+ }
+ }
+
+ // This last byte has arrived
+ if (periph->idx_buf >= trans->len_r)
+ {
+ PPRZ_I2C_HAS_FINISHED(periph, trans, I2CTransSuccess);
+ }
+ // Tell the Slave it will be the last one
+ else if (periph->idx_buf >= trans->len_r-1)
+ {
+ I2C_AcknowledgeConfig(periph->reg_addr, DISABLE); // give them a nack once it's done
+ I2C_GenerateSTOP(periph->reg_addr, ENABLE); // and follow with a stop
+ }
+ // Ask the Slave to send more
+ else
+ {
+ I2C_AcknowledgeConfig(periph->reg_addr, ENABLE);
+ }
+
+ }
+
+ // Now re-enable IRQ... it's been too long
+ // __enable_irq();
+
+
+
+ LED2_OFF();
+ LED1_OFF();
+
+
+}
+
+static inline void i2c_error(struct i2c_periph *periph)
+{
+ uint8_t err_nr = 0;
+ periph->errors->er_irq_cnt;
+ if (I2C_GetITStatus(periph->reg_addr, I2C_IT_AF)) { /* Acknowledge failure */
+ periph->errors->ack_fail_cnt++;
+ I2C_ClearITPendingBit(periph->reg_addr, I2C_IT_AF);
+ err_nr = 1;
+ }
+ if (I2C_GetITStatus(periph->reg_addr, I2C_IT_BERR)) { /* Misplaced Start or Stop condition */
+ periph->errors->miss_start_stop_cnt++;
+ I2C_ClearITPendingBit(periph->reg_addr, I2C_IT_BERR);
+ err_nr = 2;
+ }
+ if (I2C_GetITStatus(periph->reg_addr, I2C_IT_ARLO)) { /* Arbitration lost */
+ periph->errors->arb_lost_cnt++;
+ I2C_ClearITPendingBit(periph->reg_addr, I2C_IT_ARLO);
+ // I2C_AcknowledgeConfig(I2C2, DISABLE);
+ // uint8_t dummy __attribute__ ((unused)) = I2C_ReceiveData(I2C2);
+ // I2C_GenerateSTOP(I2C2, ENABLE);
+ err_nr = 3;
+ }
+ if (I2C_GetITStatus(periph->reg_addr, I2C_IT_OVR)) { /* Overrun/Underrun */
+ periph->errors->over_under_cnt++;
+ I2C_ClearITPendingBit(periph->reg_addr, I2C_IT_OVR);
+ err_nr = 4;
+ }
+ if (I2C_GetITStatus(periph->reg_addr, I2C_IT_PECERR)) { /* PEC Error in reception */
+ periph->errors->pec_recep_cnt++;
+ I2C_ClearITPendingBit(periph->reg_addr, I2C_IT_PECERR);
+ err_nr = 5;
+ }
+ if (I2C_GetITStatus(periph->reg_addr, I2C_IT_TIMEOUT)) { /* Timeout or Tlow error */
+ periph->errors->timeout_tlow_cnt++;
+ I2C_ClearITPendingBit(periph->reg_addr, I2C_IT_TIMEOUT);
+ err_nr = 6;
+ }
+ if (I2C_GetITStatus(periph->reg_addr, I2C_IT_SMBALERT)) { /* SMBus alert */
+ periph->errors->smbus_alert_cnt++;
+ I2C_ClearITPendingBit(periph->reg_addr, I2C_IT_SMBALERT);
+ err_nr = 7;
+ }
+
+
+ LED_ERROR(err_nr);
+
+
+ // Check to make sure that user space has an active transaction pending
+ if (periph->trans_extract_idx == periph->trans_insert_idx)
+ {
+ // no transaction?
+ periph->errors->unexpected_event_cnt++;
+ err_nr = 8;
+ return;
+ }
+
+ struct i2c_transaction* trans = periph->trans[periph->trans_extract_idx];
+ //abort_and_reset(p);
+
+
+
+ PPRZ_I2C_HAS_FINISHED(periph, trans, I2CTransFailed);
+
+
+}
+
+
+/*
+ // Make sure the bus is free before resetting (p722)
+ if (regs->SR2 & (I2C_FLAG_BUSY >> 16)) {
+ // Reset the I2C block
+ I2C_SoftwareResetCmd(periph->reg_addr, ENABLE);
+ I2C_SoftwareResetCmd(periph->reg_addr, DISABLE);
+ }
+*/
+
+#endif /* USE_I2C2 */
+
+
+
+
+#ifdef USE_I2C1
+
+struct i2c_errors i2c1_errors;
+
+void i2c1_hw_init(void) {
+
+ i2c1.reg_addr = I2C1;
+ i2c1.init_struct = &I2C1_InitStruct;
+ i2c1.scl_pin = GPIO_Pin_6;
+ i2c1.sda_pin = GPIO_Pin_7;
+ i2c1.errors = &i2c1_errors;
+
+ /* zeros error counter */
+ ZEROS_ERR_COUNTER(i2c1_errors);
+
+ // Extra
+ LED_INIT();
+}
+
+void i2c1_ev_irq_handler(void) {
+ i2c_event(&i2c1);
+}
+
+void i2c1_er_irq_handler(void) {
+ i2c_error(&i2c1);
+}
+
+#endif /* USE_I2C1 */
+
+#ifdef USE_I2C2
+
+struct i2c_errors i2c2_errors;
+
+void i2c2_hw_init(void) {
+
+ i2c2.reg_addr = I2C2;
+ i2c2.init_struct = &I2C2_InitStruct;
+ i2c2.scl_pin = GPIO_Pin_10;
+ i2c2.sda_pin = GPIO_Pin_11;
+ i2c2.errors = &i2c2_errors;
+
+ /* zeros error counter */
+ ZEROS_ERR_COUNTER(i2c2_errors);
+
+ /* reset peripheral to default state ( sometimes not achieved on reset :( ) */
+ //I2C_DeInit(I2C2);
+
+ NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0);
+ NVIC_InitTypeDef NVIC_InitStructure;
+
+ /* Configure and enable I2C2 event interrupt --------------------------------*/
+ NVIC_InitStructure.NVIC_IRQChannel = I2C2_EV_IRQn;
+ NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
+ NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
+ NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
+ NVIC_Init(&NVIC_InitStructure);
+
+ /* Configure and enable I2C2 err interrupt ----------------------------------*/
+ NVIC_InitStructure.NVIC_IRQChannel = I2C2_ER_IRQn;
+ NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
+ NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
+ NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
+ NVIC_Init(&NVIC_InitStructure);
+
+ /* Enable peripheral clocks -------------------------------------------------*/
+ /* Enable I2C2 clock */
+ RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C2, ENABLE);
+ /* Enable GPIOB clock */
+ RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
+
+ GPIO_InitTypeDef GPIO_InitStructure;
+ GPIO_InitStructure.GPIO_Pin = i2c2.scl_pin | i2c2.sda_pin;
+ GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;
+ GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_OD;
+ GPIO_Init(GPIOB, &GPIO_InitStructure);
+
+ I2C_DeInit(I2C2);
+
+ // enable peripheral
+ I2C_Cmd(I2C2, ENABLE);
+
+ I2C_Init(I2C2, i2c2.init_struct);
+
+// I2C_SoftwareResetCmd(I2C2, ENABLE);
+// I2C_SoftwareResetCmd(I2C2, DISABLE);
+
+ // Reset and initialize I2C HW
+ // enable error interrupts
+ I2C_ITConfig(I2C2, I2C_IT_ERR, ENABLE);
+
+// i2c_reset_init(&i2c2);
+
+}
+
+
+void i2c2_ev_irq_handler(void) {
+ i2c_event(&i2c2);
+}
+
+void i2c2_er_irq_handler(void) {
+ i2c_error(&i2c2);
+}
+
+#endif /* USE_I2C2 */
+
+
+
+/////////////////////////////////////////////////////////
+// Implement Interface Functions
+
+bool_t i2c_submit(struct i2c_periph* periph, struct i2c_transaction* t) {
+
+ uint8_t temp;
+ temp = periph->trans_insert_idx + 1;
+ if (temp >= I2C_TRANSACTION_QUEUE_LEN) temp = 0;
+ if (temp == periph->trans_extract_idx)
+ return FALSE; // queue full
+
+ t->status = I2CTransPending;
+
+ __disable_irq();
+ /* put transacation in queue */
+ periph->trans[periph->trans_insert_idx] = t;
+ periph->trans_insert_idx = temp;
+
+ /* if peripheral is idle, start the transaction */
+ // if (PPRZ_I2C_IS_IDLE(p))
+ if (periph->status == I2CIdle)
+ PPRZ_I2C_START_NEXT_TRANSACTION(periph);
+ /* else it will be started by the interrupt handler when the previous transactions completes */
+ __enable_irq();
+
+ return TRUE;
+}
+
+bool_t i2c_idle(struct i2c_periph* periph)
+{
+ return PPRZ_I2C_IS_IDLE(periph);
+ //return periph->status == I2CIdle;
+}
+
+
diff --git a/sw/airborne/arch/stm32/mcu_periph/obsolete/i2c_attempt2_nolib.c b/sw/airborne/arch/stm32/mcu_periph/obsolete/i2c_attempt2_nolib.c
new file mode 100644
index 0000000000..852cd2d535
--- /dev/null
+++ b/sw/airborne/arch/stm32/mcu_periph/obsolete/i2c_attempt2_nolib.c
@@ -0,0 +1,1064 @@
+#include "mcu_periph/i2c.h"
+
+#include
+#include
+#include
+#include
+
+//#include "led.h"
+
+//#define I2C_DEBUG_LED
+
+/////////// DEBUGGING //////////////
+// TODO: remove this
+
+
+#ifdef I2C_DEBUG_LED
+static inline void LED1_ON(void)
+{
+ GPIO_WriteBit(GPIOB, GPIO_Pin_6 , Bit_SET );
+}
+
+static inline void LED1_OFF(void)
+{
+ GPIO_WriteBit(GPIOB, GPIO_Pin_6 , !Bit_SET );
+}
+
+static inline void LED2_ON(void)
+{
+ GPIO_WriteBit(GPIOB, GPIO_Pin_7 , Bit_SET );
+}
+
+static inline void LED2_OFF(void)
+{
+ GPIO_WriteBit(GPIOB, GPIO_Pin_7 , !Bit_SET );
+}
+
+static inline void LED_INIT(void)
+{
+ GPIO_InitTypeDef GPIO_InitStructure;
+ RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOB, ENABLE);
+ GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7 | GPIO_Pin_6;
+ GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
+ GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
+ GPIO_Init(GPIOB, &GPIO_InitStructure);
+
+ LED1_OFF();
+ LED2_OFF();
+}
+
+
+static inline void LED_ERROR(uint8_t base, uint8_t nr)
+{
+ LED2_ON();
+ for (int i=0;i<(base+nr);i++)
+ {
+ LED1_ON();
+ LED1_OFF();
+ }
+ LED2_OFF();
+}
+#endif
+
+//////////////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////////////
+
+#ifdef USE_I2C1
+static I2C_InitTypeDef I2C1_InitStruct = {
+ .I2C_Mode = I2C_Mode_I2C,
+ .I2C_DutyCycle = I2C_DutyCycle_2,
+ .I2C_OwnAddress1 = 0x00,
+ .I2C_Ack = I2C_Ack_Enable,
+ .I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit,
+ .I2C_ClockSpeed = 200000
+};
+#endif
+
+#ifdef USE_I2C2
+static I2C_InitTypeDef I2C2_InitStruct = {
+ .I2C_Mode = I2C_Mode_I2C,
+ .I2C_DutyCycle = I2C_DutyCycle_2,
+ .I2C_OwnAddress1 = 0x00,
+ .I2C_Ack = I2C_Ack_Enable,
+ .I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit,
+// .I2C_ClockSpeed = 37000
+ .I2C_ClockSpeed = 400000
+};
+#endif
+
+//////////////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////////////
+
+// Bypassing the libSTM I2C functions to have more control over the reading of registers
+// e.g. SR1 and SR2 should not always be read together as it might unwantedly clear ADDR flags etc.
+
+// Referring to STM32 manual:
+// -Doc ID 13902 Rev 11
+
+// Status Register 1
+
+#define I2C_SR1_BIT_SB (1<<0) // Start Condition Met
+#define I2C_SR1_BIT_ADDR (1<<1) // Address Sent
+#define I2C_SR1_BIT_BTF (1<<2) // SCL held low
+#define I2C_SR1_BIT_RXNE (1<<6) // Data Read Available
+#define I2C_SR1_BIT_TXE (1<<7) // TX buffer space available
+
+#define I2C_SR1_BIT_ERR_BUS (1<<8) // Misplaced Start/Stop (usually interference)
+#define I2C_SR1_BIT_ERR_ARLO (1<<9) // Arbitration Lost (in multimaster) or SDA short-to-ground (in single master)
+#define I2C_SR1_BIT_ERR_AF (1<<10) // Ack Failure (too fast/too soon/no sensor/wiring break/...)
+#define I2C_SR1_BIT_ERR_OVR (1<<11) // Overrun [data loss] (in slave) or SCL short-to-ground (in single master)
+
+#define I2C_SR1_BITS_ERR ((1<<8)|(1<<9)|(1<<10)|(1<<11)|(1<<12)|(1<<14)|(1<<15))
+
+// Status Register 2
+
+#define I2C_SR2_BIT_TRA (1<<2) // Transmitting
+#define I2C_SR2_BIT_BUSY (1<<1) // Busy
+#define I2C_SR2_BIT_MSL (1<<0) // Master Selected
+
+// Control Register 1
+
+#define I2C_CR1_BIT_PE (1<<0) // Peripheral Enable
+#define I2C_CR1_BIT_START (1<<8) // Generate a Start
+#define I2C_CR1_BIT_STOP (1<<9) // Generate a Stop
+#define I2C_CR1_BIT_ACK (1<<10) // ACK / NACK
+#define I2C_CR1_BIT_POS (1<<11) // Ack will control not the next but secondnext received byte
+#define I2C_CR1_BIT_SWRST (1<<15) // Clear Busy Condition when no stop was detected
+
+// Control Register 2
+
+#define I2C_CR2_BIT_ITERREN (1<<8) // Error Interrupt
+#define I2C_CR2_BIT_ITEVTEN (1<<9) // Event Interrupt
+#define I2C_CR2_BIT_ITBUFEN (1<<10) // Buffer Interrupt
+
+
+// Bit Control
+
+#define BIT_X_IS_SET_IN_REG(X,REG) (((REG) & (X)) == (X))
+
+//////////////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////////////
+
+// (RE)START
+
+static inline void PPRZ_I2C_SEND_START(struct i2c_periph *periph)
+{
+ I2C_TypeDef *regs = (I2C_TypeDef *) periph->reg_addr;
+
+ periph->idx_buf = 0;
+ periph->status = I2CStartRequested;
+
+ if (BIT_X_IS_SET_IN_REG( I2C_CR1_BIT_STOP, regs->CR1 ) )
+ {
+ regs->CR1 &= ~ I2C_CR1_BIT_STOP;
+
+#ifdef I2C_DEBUG_LED
+ LED2_ON();
+ LED1_ON();
+ LED1_OFF();
+ LED1_ON();
+ LED1_OFF();
+ LED1_ON();
+ LED1_OFF();
+ LED1_ON();
+ LED1_OFF();
+ LED2_OFF();
+#endif
+ }
+ else
+ {
+#ifdef I2C_DEBUG_LED
+ LED2_ON();
+ LED1_ON();
+ LED1_OFF();
+ LED1_ON();
+ LED1_OFF();
+ LED1_ON();
+ LED1_OFF();
+ LED2_OFF();
+#endif
+ }
+
+ // Issue a new start
+ regs->CR1 |= I2C_CR1_BIT_START;
+
+ // Enable Error IRQ, Event IRQ but disable Buffer IRQ
+ regs->CR2 |= I2C_CR2_BIT_ITERREN;
+ regs->CR2 |= I2C_CR2_BIT_ITEVTEN;
+ regs->CR2 &= ~ I2C_CR2_BIT_ITBUFEN;
+}
+
+// TODO: remove debug
+#ifdef I2C_DEBUG_LED
+
+static inline void LED_SHOW_ACTIVE_BITS(uint16_t SR1)
+{
+ LED1_ON();
+
+ // Start
+ if (BIT_X_IS_SET_IN_REG( I2C_SR1_BIT_SB, SR1 ) )
+ LED2_ON();
+ else
+ LED2_OFF();
+ LED2_OFF();
+
+ // Addr
+ if (BIT_X_IS_SET_IN_REG( I2C_SR1_BIT_ADDR, SR1 ) )
+ LED2_ON();
+ else
+ LED2_OFF();
+ LED2_OFF();
+
+ // BTF
+ if (BIT_X_IS_SET_IN_REG( I2C_SR1_BIT_BTF, SR1 ) )
+ LED2_ON();
+ else
+ LED2_OFF();
+ LED2_OFF();
+
+ // ERROR
+ if (( SR1 & I2C_SR1_BITS_ERR ) != 0x0000)
+ LED2_ON();
+ else
+ LED2_OFF();
+ LED2_OFF();
+
+
+ LED1_OFF();
+}
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////////////////////////////
+//
+// SUBTRANSACTION SEQUENCES
+
+enum STMI2CSubTransactionStatus {
+ STMI2C_SubTra_Busy,
+ STMI2C_SubTra_Ready_StopRequested,
+ STMI2C_SubTra_Ready
+};
+
+static inline enum STMI2CSubTransactionStatus stmi2c_send(I2C_TypeDef *regs, struct i2c_periph *periph, struct i2c_transaction *trans)
+{
+ uint16_t SR1 = regs->SR1;
+
+ // Start Condition Was Just Generated
+ if (BIT_X_IS_SET_IN_REG( I2C_SR1_BIT_SB, SR1 ) )
+ {
+ // Disable buffer interrupt
+ regs->CR2 &= ~ I2C_CR2_BIT_ITBUFEN;
+ // Send Slave address and wait for ADDR interrupt
+ regs->DR = trans->slave_addr;
+ }
+ // Address Was Sent
+ else if (BIT_X_IS_SET_IN_REG(I2C_SR1_BIT_ADDR, SR1) )
+ {
+ // Now read SR2 to clear the ADDR
+ uint16_t SR2 __attribute__ ((unused)) = regs->SR2;
+
+ // Maybe check we are transmitting (did not loose arbitration for instance)
+ // if (! BIT_X_IS_SET_IN_REG(I2C_SR2_BIT_TRA, SR2)) { }
+
+ // Send First max 2 bytes
+ regs->DR = trans->buf[0];
+ if (trans->len_w > 1)
+ {
+ regs->DR = trans->buf[1];
+ periph->idx_buf = 2;
+ }
+ else
+ {
+ periph->idx_buf = 1;
+ }
+
+ // Enable buffer-space available interrupt
+ // only if there is more to send: wait for TXE, no more to send: wait for BTF
+ if ( periph->idx_buf < trans->len_w)
+ regs->CR2 |= I2C_CR2_BIT_ITBUFEN;
+ }
+ // The buffer is not full anymore AND we were not waiting for BTF
+ else if ((BIT_X_IS_SET_IN_REG(I2C_SR1_BIT_TXE, SR1) ) && (BIT_X_IS_SET_IN_REG(I2C_CR2_BIT_ITBUFEN, regs->CR2)) )
+ {
+ // Send the next byte
+ regs->DR = trans->buf[periph->idx_buf];
+ periph->idx_buf++;
+
+ // All bytes Sent? Then wait for BTF instead
+ if ( periph->idx_buf >= trans->len_w)
+ {
+ // Not interested anymore to know the buffer has space left
+ regs->CR2 &= ~ I2C_CR2_BIT_ITBUFEN;
+ // Next interrupt will be BTF (or error)
+ }
+ }
+ // BTF: means last byte was sent
+ else if (BIT_X_IS_SET_IN_REG(I2C_SR1_BIT_BTF, SR1) )
+ {
+ if (trans->type == I2CTransTx)
+ {
+ // Tell the driver we are ready
+ trans->status = I2CTransSuccess;
+ }
+
+ return STMI2C_SubTra_Ready;
+ }
+
+ return STMI2C_SubTra_Busy;
+}
+
+static inline enum STMI2CSubTransactionStatus stmi2c_read1(I2C_TypeDef *regs, struct i2c_transaction *trans)
+{
+ uint16_t SR1 = regs->SR1;
+
+ // Start Condition Was Just Generated
+ if (BIT_X_IS_SET_IN_REG( I2C_SR1_BIT_SB, SR1 ) )
+ {
+ regs->CR2 &= ~ I2C_CR2_BIT_ITBUFEN;
+ regs->DR = trans->slave_addr | 0x01;
+ }
+ // Address Was Sent
+ else if (BIT_X_IS_SET_IN_REG(I2C_SR1_BIT_ADDR, SR1) )
+ {
+ // First Clear the ACK bit: after the next byte we do not want new bytes
+ regs->CR1 &= ~ I2C_CR1_BIT_POS;
+ regs->CR1 &= ~ I2C_CR1_BIT_ACK;
+
+ // --- next to steps MUST be executed together to avoid missing the stop
+ __disable_irq();
+
+ // Only after setting ACK, read SR2 to clear the ADDR (next byte will start arriving)
+ uint16_t SR2 __attribute__ ((unused)) = regs->SR2;
+
+ // Schedule a Stop
+ regs->CR1 |= I2C_CR1_BIT_STOP;
+
+ __enable_irq();
+ // --- end of critical zone -----------
+
+#ifdef I2C_DEBUG_LED
+ // Program a stop
+ LED2_ON();
+ LED1_ON();
+ LED1_OFF();
+ LED2_OFF();
+#endif
+
+ // Enable the RXNE to get the result
+ regs->CR2 |= I2C_CR2_BIT_ITBUFEN;
+ }
+ else if (BIT_X_IS_SET_IN_REG(I2C_SR1_BIT_RXNE, SR1) )
+ {
+ regs->CR2 &= ~ I2C_CR2_BIT_ITBUFEN;
+ trans->buf[0] = regs->DR;
+
+ // We got all the results (stop condition might still be in progress but this is the last interrupt)
+ trans->status = I2CTransSuccess;
+
+ return STMI2C_SubTra_Ready_StopRequested;
+ }
+
+ return STMI2C_SubTra_Busy;
+}
+
+static inline enum STMI2CSubTransactionStatus stmi2c_read2(I2C_TypeDef *regs, struct i2c_transaction *trans)
+{
+ uint16_t SR1 = regs->SR1;
+
+ // Start Condition Was Just Generated
+ if (BIT_X_IS_SET_IN_REG( I2C_SR1_BIT_SB, SR1 ) )
+ {
+ regs->CR2 &= ~ I2C_CR2_BIT_ITBUFEN;
+ regs->CR1 |= I2C_CR1_BIT_ACK;
+ regs->CR1 |= I2C_CR1_BIT_POS;
+ regs->DR = trans->slave_addr | 0x01;
+ }
+ // Address Was Sent
+ else if (BIT_X_IS_SET_IN_REG(I2C_SR1_BIT_ADDR, SR1) )
+ {
+ // BEFORE clearing ACK, read SR2 to clear the ADDR (next byte will start arriving)
+ // clearing ACK after the byte transfer has already started will NACK the next (2nd)
+ uint16_t SR2 __attribute__ ((unused)) = regs->SR2;
+
+ // --- make absolutely sure this command is not delayed too much after the previous:
+ __disable_irq();
+ // if transfer of DR was finished already then we will get too many bytes
+ // NOT First Clear the ACK bit but only AFTER clearing ADDR
+ regs->CR1 &= ~ I2C_CR1_BIT_ACK;
+
+ // Disable the RXNE and wait for BTF
+ regs->CR2 &= ~ I2C_CR2_BIT_ITBUFEN;
+
+ __enable_irq();
+ // --- end of critical zone -----------
+ }
+ // Receive buffer if full, master is halted: BTF
+ else if (BIT_X_IS_SET_IN_REG(I2C_SR1_BIT_BTF, SR1) )
+ {
+ // Stop condition MUST be set BEFORE reading the DR
+ // otherwise since there is new buffer space a new byte will be read
+ regs->CR1 |= I2C_CR1_BIT_STOP;
+ // Program a stop
+#ifdef I2C_DEBUG_LED
+ LED2_ON();
+ LED1_ON();
+ LED1_OFF();
+ LED2_OFF();
+#endif
+
+ trans->buf[0] = regs->DR;
+ trans->buf[1] = regs->DR;
+
+ // We got all the results
+ trans->status = I2CTransSuccess;
+
+ return STMI2C_SubTra_Ready_StopRequested;
+ }
+
+ return STMI2C_SubTra_Busy;
+}
+
+static inline enum STMI2CSubTransactionStatus stmi2c_readmany(I2C_TypeDef *regs, struct i2c_periph *periph, struct i2c_transaction *trans)
+{
+ uint16_t SR1 = regs->SR1;
+
+ // Start Condition Was Just Generated
+ if (BIT_X_IS_SET_IN_REG( I2C_SR1_BIT_SB, SR1 ) )
+ {
+ regs->CR2 &= ~ I2C_CR2_BIT_ITBUFEN;
+ // The first data byte will be acked in read many so the slave knows it should send more
+ regs->CR1 &= ~ I2C_CR1_BIT_POS;
+ regs->CR1 |= I2C_CR1_BIT_ACK;
+ // Clear the SB flag
+ regs->DR = trans->slave_addr | 0x01;
+ }
+ // Address Was Sent
+ else if (BIT_X_IS_SET_IN_REG(I2C_SR1_BIT_ADDR, SR1) )
+ {
+ periph->idx_buf = 0;
+
+ // Enable RXNE: receive an interrupt any time a byte is available
+ // only enable if MORE than 3 bytes need to be read
+ if (periph->idx_buf < (trans->len_r - 3))
+ {
+ regs->CR2 |= I2C_CR2_BIT_ITBUFEN;
+ }
+
+ // ACK is still on to get more DATA
+ // Read SR2 to clear the ADDR (next byte will start arriving)
+ uint16_t SR2 __attribute__ ((unused)) = regs->SR2;
+ }
+ // one or more bytes are available AND we were interested in Buffer interrupts
+ else if ( (BIT_X_IS_SET_IN_REG(I2C_SR1_BIT_RXNE, SR1) ) && (BIT_X_IS_SET_IN_REG(I2C_CR2_BIT_ITBUFEN, regs->CR2)) )
+ {
+ // read byte until 3 bytes remain to be read (e.g. len_r = 6, -> idx=3 means idx 3,4,5 = 3 remain to be read
+ if (periph->idx_buf < (trans->len_r - 3))
+ {
+ trans->buf[periph->idx_buf] = regs->DR;
+ periph->idx_buf ++;
+ }
+ // from : 3bytes -> last byte: do nothing
+ //
+ // finally: this was the last byte
+ else if (periph->idx_buf >= (trans->len_r - 1))
+ {
+ regs->CR2 &= ~ I2C_CR2_BIT_ITBUFEN;
+
+ // Last Value
+ trans->buf[periph->idx_buf] = regs->DR;
+ periph->idx_buf ++;
+
+ // We got all the results
+ trans->status = I2CTransSuccess;
+
+ return STMI2C_SubTra_Ready_StopRequested;
+ }
+
+ // Check for end of transaction: start waiting for BTF instead of RXNE
+ if (periph->idx_buf < (trans->len_r - 3))
+ {
+ regs->CR2 |= I2C_CR2_BIT_ITBUFEN;
+ }
+ else // idx >= len-3: there are 3 bytes to be read
+ {
+ // We want to halt I2C to have sufficient time to clear ACK, so:
+ // Stop listening to RXNE as it will be triggered infinitely since we did not empty the buffer
+ // on the next (second in buffer) received byte BTF will be set (buffer full and I2C halted)
+ regs->CR2 &= ~ I2C_CR2_BIT_ITBUFEN;
+ }
+ }
+ // Buffer is full while this was not a RXNE interrupt
+ else if (BIT_X_IS_SET_IN_REG(I2C_SR1_BIT_BTF, SR1) )
+ {
+ // Now the shift register and data register contain data(n-2) and data(n-1)
+ // And I2C is halted so we have time
+
+ // --- Make absolutely sure the next 2 I2C actions are performed with no delay
+ __disable_irq();
+
+ // First we clear the ACK while the SCL is held low by BTF
+ regs->CR1 &= ~ I2C_CR1_BIT_ACK;
+
+ // Now that ACK is cleared we read one byte: instantly the last byte is being clocked in...
+ trans->buf[periph->idx_buf] = regs->DR;
+ periph->idx_buf ++;
+
+ // Now the last byte is being clocked. Stop in MUST be set BEFORE the transfer of the last byte is complete
+ regs->CR1 |= I2C_CR1_BIT_STOP;
+ // Program a stop
+#ifdef I2C_DEBUG_LED
+ LED2_ON();
+ LED1_ON();
+ LED1_OFF();
+ LED2_OFF();
+#endif
+
+ __enable_irq();
+ // --- end of critical zone -----------
+
+ // read the byte2 we had in the buffer (BTF means 2 bytes available)
+ trans->buf[periph->idx_buf] = regs->DR;
+ periph->idx_buf ++;
+
+ // Ask for an interrupt to read the last byte (which is normally still busy now)
+ // The last byte will be received with RXNE
+ regs->CR2 |= I2C_CR2_BIT_ITBUFEN;
+ }
+ else
+ {
+ // Error
+#ifdef I2C_DEBUG_LED
+ LED2_ON();
+ LED1_ON();
+ LED2_OFF();
+ LED1_OFF();
+#endif
+ }
+
+ return STMI2C_SubTra_Busy;
+}
+
+
+static inline void stmi2c_clear_pending_interrupts(I2C_TypeDef *regs)
+{
+ uint16_t SR1 = regs->SR1;
+
+ regs->CR2 &= ~ I2C_CR2_BIT_ITBUFEN;
+
+ // Start Condition Was Generated
+ if (BIT_X_IS_SET_IN_REG( I2C_SR1_BIT_SB, SR1 ) )
+ {
+ // SB: cleared by software when reading SR1 and writing to DR
+ regs->DR = 0x00;
+ }
+ // Address Was Sent
+ if (BIT_X_IS_SET_IN_REG(I2C_SR1_BIT_ADDR, SR1) )
+ {
+ // ADDR: Cleared by software when reading SR1 and then SR2
+ uint16_t SR2 __attribute__ ((unused)) = regs->SR2;
+ }
+ // Byte Transfer Finished
+ if (BIT_X_IS_SET_IN_REG(I2C_SR1_BIT_BTF, SR1) )
+ {
+ // SB: cleared by software when reading SR1 and reading/writing to DR
+ uint8_t dummy __attribute__ ((unused)) = regs->DR;
+ regs->DR = 0x00;
+ }
+}
+
+
+static inline void i2c_error(struct i2c_periph *periph);
+
+static inline void i2c_event(struct i2c_periph *periph)
+{
+
+ /*
+ There are 7 possible reasons to get here:
+
+ If IT_EV_FEN
+ -------------------------
+
+ We are always interested in all IT_EV_FEV: all are required.
+
+ 1) SB // Start Condition Success in Master mode
+ 2) ADDR // Address sent received Acknoledge
+ [3 ADDR10] // -- 10bit address stuff
+ [4 STOPF] // -- only for slaves: master has no stop interrupt
+ 5) BTF // I2C has stopped working (it is waiting for new data, all buffers are tx_empty/rx_full)
+
+ // Beware: using the buffered I2C has some interesting properties:
+ -in master receive mode: BTF only occurs after the 2nd received byte: after the first byte is received it is
+ in RD but the I2C can still receive a second byte. Only when the 2nd byte is received while the RxNE is 1
+ then a BTF occurs (I2C can not continue receiving bytes or they will get lost). During BTF I2C is halted (SCL held low)
+ -in master transmitmode: when writing a byte to WD, you instantly get a new TxE interrupt while the first is not
+ transmitted yet. The byte was pushed to the I2C shift register and the buffer is ready for more. You can already
+ fill new data in the buffer while the first is still being transmitted for max performance transmission.
+
+ // Beware: besides data buffering you can/must plan several consecutive actions. You can send 2 bytes to the buffer, ask for a stop and
+ a new start in one go.
+
+ -thanks to / because of this buffering and event sheduling there is not 1 interrupt per start / byte / stop
+ This also means you must think more in advance and a transaction could be popped from the stack even before it is
+ actually completely transmitted. But then you would not know the result yet so you have to keep it until the result
+ is known.
+
+ // Beware: the order in which Status is read determines how flags are cleared. You should not just read SR1 & SR2 every time
+
+ If IT_EV_FEN AND IT_EV_BUF
+ --------------------------
+
+ Buffer event are not always wanted and are tipically switched on during longer data transfers. Make sure to turn off in time.
+
+ 6) RxNE
+ 7) TxE
+
+ --------------------------------------------------------------------------------------------------
+ // This driver uses only a subset of the pprz_i2c_states for several reasons:
+ // -we have less interrupts than the I2CStatus states (for efficiency)
+ // -STM32 has such a powerfull I2C engine with plenty of status register flags that
+ only little extra status information needs to be stored.
+
+ // Status is re-used (abused) to remember the last COMMAND THAT WAS SENT to the STM I2C hardware.
+
+// TODO: check which are used
+ enum I2CStatus {
+ I2CIdle, // No more last command
+
+ I2CStartRequested, // Last command was start
+ I2CRestartRequested, // Last command was restart
+ I2CStopRequested, // Very important to not send double stop conditions
+
+ I2CSendingByte, // Some address/data operation
+
+ // Following are not used
+ I2CReadingByte,
+ I2CAddrWrSent,
+ I2CAddrRdSent,
+ I2CSendingLastByte,
+ I2CReadingLastByte,
+ I2CComplete,
+ I2CFailed
+ };
+
+ ---------
+
+ The STM waits indefinately (holding SCL low) for user interaction:
+ a) after a master-start (waiting for address)
+ b) after an address (waiting for data)
+ not during data sending when using buffered
+ c) after the last byte is transmitted (waiting for either stop or restart)
+ not during data receiving when using buffered
+ not after the last byte is received
+
+ -The STM I2C stalls indefinately when a stop condition was attempted that
+ did not succeed. The BUSY flag remains on.
+ -There is no STOP interrupt: use needs another way to finish.
+
+ */
+
+
+ ///////////////////////////////////////////////////////////////////////////////////
+ // Reading the status:
+ // - Caution: this clears several flags and can start transmissions etc...
+ // - Certain flags like STOP / (N)ACK need to be guaranteed to be set before
+ // the transmission of the byte is finished. At higher clock rates that can be
+ // quite fast: so we allow no other interrupt to be triggered in between
+ // reading the status and setting all needed flags
+
+ // Direct Access to the I2C Registers
+ // Do not read SR2 as it might start the reading while an (n)ack bit might be needed first
+ I2C_TypeDef *regs = (I2C_TypeDef *) periph->reg_addr;
+
+#ifdef I2C_DEBUG_LED
+ LED1_ON();
+ LED1_OFF();
+#endif
+
+
+ ///////////////////////////////////////////////////////////////////////////////////////////////////////
+ ///////////////////////////////////////////////////////////////////////////////////////////////////////
+ //
+ // TRANSACTION HANDLER
+
+ enum STMI2CSubTransactionStatus ret = 0;
+ uint8_t restart = 0;
+
+ // Nothing Left To Do
+ if (periph->trans_extract_idx == periph->trans_insert_idx)
+ {
+ periph->status = I2CIdle;
+ periph->errors->unexpected_event_cnt++;
+
+ regs->CR2 &= ~ I2C_CR2_BIT_ITBUFEN; // Disable TXE, RXNE
+#ifdef I2C_DEBUG_LED
+ LED2_ON();
+ LED1_ON();
+ LED2_OFF();
+ LED1_OFF();
+
+ // no transaction and also an error?
+ LED_SHOW_ACTIVE_BITS(regs->SR1);
+#endif
+
+ stmi2c_clear_pending_interrupts(regs);
+ i2c_error(periph);
+
+ // There are no transactions anymore: so we are not allowed to continue
+ return;
+ }
+
+ struct i2c_transaction* trans = periph->trans[periph->trans_extract_idx];
+
+ if (( regs->SR1 & I2C_SR1_BITS_ERR ) != 0x0000)
+ {
+ // Set result in transaction
+ trans->status = I2CTransFailed;
+
+ // Close the Bus
+ regs->CR2 &= ~ I2C_CR2_BIT_ITBUFEN; // Disable TXE RXNE
+
+#ifdef I2C_DEBUG_LED
+ LED1_ON();
+ LED2_ON();
+ LED1_OFF();
+ LED2_OFF();
+#endif
+
+ // Prepare for next
+ ret = STMI2C_SubTra_Ready;
+ restart = 0;
+
+ stmi2c_clear_pending_interrupts(regs);
+
+ // Count it
+ i2c_error(periph);
+ }
+ else
+ {
+
+ if (trans->type == I2CTransRx) // TxRx are converted to Rx after the Tx Part
+ {
+ switch (trans->len_r)
+ {
+ case 1:
+ ret = stmi2c_read1(regs,trans);
+ break;
+ case 2:
+ ret = stmi2c_read2(regs,trans);
+ break;
+ default:
+ ret = stmi2c_readmany(regs,periph, trans);
+ break;
+ }
+ }
+ else // TxRx or Tx
+ {
+ ret = stmi2c_send(regs,periph,trans);
+ if (trans->type == I2CTransTxRx)
+ {
+ restart = 1;
+ }
+ }
+ }
+
+ // Sub-transaction not finished
+ if (ret == STMI2C_SubTra_Busy)
+ {
+ // Remember the last command was not start or stop
+ periph->status = I2CSendingByte;
+ }
+ else // Finished?
+ {
+ if (restart == 0)
+ {
+ if (ret == STMI2C_SubTra_Ready)
+ {
+ // Program a stop
+#ifdef I2C_DEBUG_LED
+ LED2_ON();
+ LED1_ON();
+ LED1_OFF();
+ LED2_OFF();
+#endif
+ // Man: p722: Stop generation after the current byte transfer or after the current Start condition is sent.
+ regs->CR1 |= I2C_CR1_BIT_STOP;
+
+ // Silent any BTF that would occur before STOP is executed
+ regs->DR = 0x00;
+
+ periph->status = I2CStopRequested;
+ }
+
+ // Jump to the next transaction
+ periph->trans_extract_idx++;
+ if (periph->trans_extract_idx >= I2C_TRANSACTION_QUEUE_LEN)
+ periph->trans_extract_idx = 0;
+
+ // if we have no more transaction to process, stop here
+ if (periph->trans_extract_idx == periph->trans_insert_idx)
+ {
+ periph->status = I2CIdle;
+#ifdef I2C_DEBUG_LED
+ LED2_ON();
+ LED1_ON();
+ LED1_OFF();
+ LED1_ON();
+ LED1_OFF();
+ LED2_OFF();
+#endif
+ }
+ // if not, start next transaction
+ else
+ {
+ // Restart transaction doing the Rx part now
+ periph->status = I2CStartRequested;
+ PPRZ_I2C_SEND_START(periph);
+ }
+
+ }
+ // RxTx -> Restart and do Rx part
+ else
+ {
+ trans->type = I2CTransRx;
+ periph->status = I2CStartRequested;
+ regs->CR1 |= I2C_CR1_BIT_START;
+
+ // Silent any BTF that would occur before SB
+ regs->DR = 0x00;
+ }
+ }
+
+ return;
+}
+
+static inline void i2c_error(struct i2c_periph *periph)
+{
+ uint8_t err_nr = 0;
+ periph->errors->er_irq_cnt;
+ if (I2C_GetITStatus(periph->reg_addr, I2C_IT_AF)) { /* Acknowledge failure */
+ periph->errors->ack_fail_cnt++;
+ I2C_ClearITPendingBit(periph->reg_addr, I2C_IT_AF);
+ err_nr = 1;
+ }
+ if (I2C_GetITStatus(periph->reg_addr, I2C_IT_BERR)) { /* Misplaced Start or Stop condition */
+ periph->errors->miss_start_stop_cnt++;
+ I2C_ClearITPendingBit(periph->reg_addr, I2C_IT_BERR);
+ err_nr = 2;
+ }
+ if (I2C_GetITStatus(periph->reg_addr, I2C_IT_ARLO)) { /* Arbitration lost */
+ periph->errors->arb_lost_cnt++;
+ I2C_ClearITPendingBit(periph->reg_addr, I2C_IT_ARLO);
+ err_nr = 3;
+ }
+ if (I2C_GetITStatus(periph->reg_addr, I2C_IT_OVR)) { /* Overrun/Underrun */
+ periph->errors->over_under_cnt++;
+ I2C_ClearITPendingBit(periph->reg_addr, I2C_IT_OVR);
+ err_nr = 4;
+ }
+ if (I2C_GetITStatus(periph->reg_addr, I2C_IT_PECERR)) { /* PEC Error in reception */
+ periph->errors->pec_recep_cnt++;
+ I2C_ClearITPendingBit(periph->reg_addr, I2C_IT_PECERR);
+ err_nr = 5;
+ }
+ if (I2C_GetITStatus(periph->reg_addr, I2C_IT_TIMEOUT)) { /* Timeout or Tlow error */
+ periph->errors->timeout_tlow_cnt++;
+ I2C_ClearITPendingBit(periph->reg_addr, I2C_IT_TIMEOUT);
+ err_nr = 6;
+ }
+ if (I2C_GetITStatus(periph->reg_addr, I2C_IT_SMBALERT)) { /* SMBus alert */
+ periph->errors->smbus_alert_cnt++;
+ I2C_ClearITPendingBit(periph->reg_addr, I2C_IT_SMBALERT);
+ err_nr = 7;
+ }
+
+#ifdef I2C_DEBUG_LED
+ LED_ERROR(20, err_nr);
+#endif
+
+ return;
+
+}
+
+
+/*
+ // Make sure the bus is free before resetting (p722)
+ if (regs->SR2 & (I2C_FLAG_BUSY >> 16)) {
+ // Reset the I2C block
+ I2C_SoftwareResetCmd(periph->reg_addr, ENABLE);
+ I2C_SoftwareResetCmd(periph->reg_addr, DISABLE);
+ }
+*/
+
+//#endif /* USE_I2C2 */
+
+
+
+
+#ifdef USE_I2C1
+
+struct i2c_errors i2c1_errors;
+
+void i2c1_hw_init(void) {
+
+ i2c1.reg_addr = I2C1;
+ i2c1.init_struct = &I2C1_InitStruct;
+ i2c1.scl_pin = GPIO_Pin_6;
+ i2c1.sda_pin = GPIO_Pin_7;
+ i2c1.errors = &i2c1_errors;
+
+ /* zeros error counter */
+ ZEROS_ERR_COUNTER(i2c1_errors);
+
+ // Extra
+#ifdef I2C_DEBUG_LED
+ LED_INIT();
+#endif
+}
+
+void i2c1_ev_irq_handler(void) {
+ i2c_event(&i2c1);
+}
+
+void i2c1_er_irq_handler(void) {
+ i2c_event(&i2c1);
+}
+
+#endif /* USE_I2C1 */
+
+#ifdef USE_I2C2
+
+struct i2c_errors i2c2_errors;
+
+void i2c2_hw_init(void) {
+
+ i2c2.reg_addr = I2C2;
+ i2c2.init_struct = &I2C2_InitStruct;
+ i2c2.scl_pin = GPIO_Pin_10;
+ i2c2.sda_pin = GPIO_Pin_11;
+ i2c2.errors = &i2c2_errors;
+
+ /* zeros error counter */
+ ZEROS_ERR_COUNTER(i2c2_errors);
+
+ /* reset peripheral to default state ( sometimes not achieved on reset :( ) */
+ //I2C_DeInit(I2C2);
+
+ NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0);
+ NVIC_InitTypeDef NVIC_InitStructure;
+
+ /* Configure and enable I2C2 event interrupt --------------------------------*/
+ NVIC_InitStructure.NVIC_IRQChannel = I2C2_EV_IRQn;
+ NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
+ NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
+ NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
+ NVIC_Init(&NVIC_InitStructure);
+
+ /* Configure and enable I2C2 err interrupt ----------------------------------*/
+ NVIC_InitStructure.NVIC_IRQChannel = I2C2_ER_IRQn;
+ NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
+ NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
+ NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
+ NVIC_Init(&NVIC_InitStructure);
+
+ /* Enable peripheral clocks -------------------------------------------------*/
+ /* Enable I2C2 clock */
+ RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C2, ENABLE);
+ /* Enable GPIOB clock */
+ RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
+
+ GPIO_InitTypeDef GPIO_InitStructure;
+ GPIO_InitStructure.GPIO_Pin = i2c2.scl_pin | i2c2.sda_pin;
+ GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;
+ GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_OD;
+ GPIO_Init(GPIOB, &GPIO_InitStructure);
+
+ I2C_DeInit(I2C2);
+
+ // enable peripheral
+ I2C_Cmd(I2C2, ENABLE);
+
+ I2C_Init(I2C2, i2c2.init_struct);
+
+ // enable error interrupts
+ I2C_ITConfig(I2C2, I2C_IT_ERR, ENABLE);
+
+}
+
+
+// TODO: this was a testing routine
+void i2c2_setbitrate(int bitrate)
+{
+ I2C2_InitStruct.I2C_ClockSpeed = bitrate;
+ I2C_Init(I2C2, i2c2.init_struct);
+}
+
+
+
+void i2c2_ev_irq_handler(void) {
+ i2c_event(&i2c2);
+}
+
+void i2c2_er_irq_handler(void) {
+ i2c_event(&i2c2);
+}
+
+#endif /* USE_I2C2 */
+
+
+
+/////////////////////////////////////////////////////////
+// Implement Interface Functions
+
+bool_t i2c_submit(struct i2c_periph* periph, struct i2c_transaction* t) {
+
+ uint8_t temp;
+ temp = periph->trans_insert_idx + 1;
+ if (temp >= I2C_TRANSACTION_QUEUE_LEN) temp = 0;
+ if (temp == periph->trans_extract_idx)
+ return FALSE; // queue full
+
+ t->status = I2CTransPending;
+
+ __disable_irq();
+ /* put transacation in queue */
+ periph->trans[periph->trans_insert_idx] = t;
+ periph->trans_insert_idx = temp;
+
+ /* if peripheral is idle, start the transaction */
+ // if (PPRZ_I2C_IS_IDLE(p))
+ if (periph->status == I2CIdle)
+ {
+ // TODO: re-enable I2C1
+ if (periph == &i2c1)
+ {
+/*
+ LED2_ON();
+ LED1_ON();
+ LED1_OFF();
+ LED1_ON();
+ LED1_OFF();
+ LED1_ON();
+ LED1_OFF();
+ LED1_ON();
+ LED1_OFF();
+ LED2_OFF();
+*/
+ }
+ else
+ {
+ PPRZ_I2C_SEND_START(periph);
+ }
+ }
+ /* else it will be started by the interrupt handler when the previous transactions completes */
+ __enable_irq();
+
+ return TRUE;
+}
+
+bool_t i2c_idle(struct i2c_periph* periph)
+{
+ return I2C_GetFlagStatus(periph->reg_addr, I2C_FLAG_BUSY) == RESET;
+ //return periph->status == I2CIdle;
+}
+
+
diff --git a/sw/airborne/arch/stm32/mcu_periph/obsolete/i2c_attempt3_subtra.c b/sw/airborne/arch/stm32/mcu_periph/obsolete/i2c_attempt3_subtra.c
new file mode 100644
index 0000000000..91988428bd
--- /dev/null
+++ b/sw/airborne/arch/stm32/mcu_periph/obsolete/i2c_attempt3_subtra.c
@@ -0,0 +1,1286 @@
+#include "mcu_periph/i2c.h"
+
+#include
+#include
+#include
+#include
+
+#define I2C_DEBUG_LED
+
+/////////// DEBUGGING //////////////
+// TODO: remove this
+
+
+#ifdef I2C_DEBUG_LED
+
+static inline void LED1_ON(void)
+{
+ GPIO_WriteBit(GPIOB, GPIO_Pin_6 , Bit_SET );
+}
+
+static inline void LED1_OFF(void)
+{
+ GPIO_WriteBit(GPIOB, GPIO_Pin_6 , !Bit_SET );
+}
+
+static inline void LED2_ON(void)
+{
+ GPIO_WriteBit(GPIOB, GPIO_Pin_7 , Bit_SET );
+}
+
+static inline void LED2_OFF(void)
+{
+ GPIO_WriteBit(GPIOB, GPIO_Pin_7 , !Bit_SET );
+}
+
+static inline void LED_INIT(void)
+{
+ GPIO_InitTypeDef GPIO_InitStructure;
+ RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOB, ENABLE);
+ GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7 | GPIO_Pin_6;
+ GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
+ GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
+ GPIO_Init(GPIOB, &GPIO_InitStructure);
+
+ LED1_OFF();
+ LED2_OFF();
+}
+
+
+static inline void LED_ERROR(uint8_t base, uint8_t nr)
+{
+ LED2_ON();
+ for (int i=0;i<(base+nr);i++)
+ {
+ LED1_ON();
+ LED1_OFF();
+ }
+ LED2_OFF();
+}
+#endif
+
+//////////////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////////////
+
+#ifdef USE_I2C1
+static I2C_InitTypeDef I2C1_InitStruct = {
+ .I2C_Mode = I2C_Mode_I2C,
+ .I2C_DutyCycle = I2C_DutyCycle_2,
+ .I2C_OwnAddress1 = 0x00,
+ .I2C_Ack = I2C_Ack_Enable,
+ .I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit,
+ .I2C_ClockSpeed = 40000
+};
+#endif
+
+#ifdef USE_I2C2
+static I2C_InitTypeDef I2C2_InitStruct = {
+ .I2C_Mode = I2C_Mode_I2C,
+ .I2C_DutyCycle = I2C_DutyCycle_2,
+ .I2C_OwnAddress1 = 0x00,
+ .I2C_Ack = I2C_Ack_Enable,
+ .I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit,
+// .I2C_ClockSpeed = 37000
+ .I2C_ClockSpeed = 400000
+};
+#endif
+
+//////////////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////////////
+
+// Bypassing the libSTM I2C functions to have more control over the reading of registers
+// e.g. SR1 and SR2 should not always be read together as it might unwantedly clear ADDR flags etc.
+
+// Referring to STM32 manual:
+// -Doc ID 13902 Rev 11
+
+// Status Register 1
+
+#define I2C_SR1_BIT_SB (1<<0) // Start Condition Met
+#define I2C_SR1_BIT_ADDR (1<<1) // Address Sent
+#define I2C_SR1_BIT_BTF (1<<2) // SCL held low
+#define I2C_SR1_BIT_RXNE (1<<6) // Data Read Available
+#define I2C_SR1_BIT_TXE (1<<7) // TX buffer space available
+
+#define I2C_SR1_BIT_ERR_BUS (1<<8) // Misplaced Start/Stop (usually interference)
+#define I2C_SR1_BIT_ERR_ARLO (1<<9) // Arbitration Lost (in multimaster) or SDA short-to-ground (in single master)
+#define I2C_SR1_BIT_ERR_AF (1<<10) // Ack Failure (too fast/too soon/no sensor/wiring break/...)
+#define I2C_SR1_BIT_ERR_OVR (1<<11) // Overrun [data loss] (in slave) or SCL short-to-ground (in single master)
+
+#define I2C_SR1_BITS_ERR ((1<<8)|(1<<9)|(1<<10)|(1<<11)|(1<<12)|(1<<14)|(1<<15))
+
+// Status Register 2
+
+#define I2C_SR2_BIT_TRA (1<<2) // Transmitting
+#define I2C_SR2_BIT_BUSY (1<<1) // Busy
+#define I2C_SR2_BIT_MSL (1<<0) // Master Selected
+
+// Control Register 1
+
+#define I2C_CR1_BIT_PE (1<<0) // Peripheral Enable
+#define I2C_CR1_BIT_START (1<<8) // Generate a Start
+#define I2C_CR1_BIT_STOP (1<<9) // Generate a Stop
+#define I2C_CR1_BIT_ACK (1<<10) // ACK / NACK
+#define I2C_CR1_BIT_POS (1<<11) // Ack will control not the next but secondnext received byte
+#define I2C_CR1_BIT_SWRST (1<<15) // Clear Busy Condition when no stop was detected
+
+// Control Register 2
+
+#define I2C_CR2_BIT_ITERREN (1<<8) // Error Interrupt
+#define I2C_CR2_BIT_ITEVTEN (1<<9) // Event Interrupt
+#define I2C_CR2_BIT_ITBUFEN (1<<10) // Buffer Interrupt
+
+
+// Bit Control
+
+#define BIT_X_IS_SET_IN_REG(X,REG) (((REG) & (X)) == (X))
+
+//////////////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////////////
+
+// TODO: remove debug
+#ifdef I2C_DEBUG_LED
+
+static inline void LED_SHOW_ACTIVE_BITS(I2C_TypeDef *regs)
+{
+ uint16_t CR1 = regs->CR1;
+ uint16_t SR1 = regs->SR1;
+ uint16_t SR2 = regs->SR2;
+ // Note: reading SR1 and then SR2 will clear ADDR bits
+
+ LED1_ON();
+
+ // 1 Start
+ if (BIT_X_IS_SET_IN_REG( I2C_SR1_BIT_SB, SR1 ) )
+ LED2_ON();
+ else
+ LED2_OFF();
+ LED2_OFF();
+
+ // 2 Addr
+ if (BIT_X_IS_SET_IN_REG( I2C_SR1_BIT_ADDR, SR1 ) )
+ LED2_ON();
+ else
+ LED2_OFF();
+ LED2_OFF();
+
+ // 3 BTF
+ if (BIT_X_IS_SET_IN_REG( I2C_SR1_BIT_BTF, SR1 ) )
+ LED2_ON();
+ else
+ LED2_OFF();
+ LED2_OFF();
+
+ // 4 ERROR
+ if (( SR1 & I2C_SR1_BITS_ERR ) != 0x0000)
+ LED2_ON();
+ else
+ LED2_OFF();
+ LED2_OFF();
+
+ // Anything?
+ if (( SR1 + SR2) != 0x0000)
+ LED2_ON();
+ else
+ LED2_OFF();
+ LED2_OFF();
+
+ LED1_OFF();
+
+
+ LED1_ON();
+
+ // 1 Start
+ if (BIT_X_IS_SET_IN_REG( I2C_CR1_BIT_START, CR1 ) )
+ LED2_ON();
+ else
+ LED2_OFF();
+ LED2_OFF();
+
+ // 2 Stop
+ if (BIT_X_IS_SET_IN_REG( I2C_CR1_BIT_STOP, CR1 ) )
+ LED2_ON();
+ else
+ LED2_OFF();
+ LED2_OFF();
+
+ // 3 Busy
+ if (BIT_X_IS_SET_IN_REG( I2C_SR2_BIT_BUSY, SR2 ) )
+ LED2_ON();
+ else
+ LED2_OFF();
+ LED2_OFF();
+
+ // 4 Tra
+ if (BIT_X_IS_SET_IN_REG( I2C_SR2_BIT_TRA, SR2 ) )
+ LED2_ON();
+ else
+ LED2_OFF();
+ LED2_OFF();
+
+ // 5 Master
+ if (BIT_X_IS_SET_IN_REG( I2C_SR2_BIT_MSL, SR2 ) )
+ LED2_ON();
+ else
+ LED2_OFF();
+ LED2_OFF();
+ LED1_OFF();
+
+ LED1_ON();
+
+ // 1 Anything CR?
+ if (( CR1) != 0x0000)
+ LED2_ON();
+ else
+ LED2_OFF();
+ LED2_OFF();
+
+ // 2 PE
+ if (BIT_X_IS_SET_IN_REG( I2C_CR1_BIT_PE, CR1 ) )
+ LED2_ON();
+ else
+ LED2_OFF();
+ LED2_OFF();
+
+ // 3 SWRESET
+ if (BIT_X_IS_SET_IN_REG( I2C_CR1_BIT_SWRST, CR1 ) )
+ LED2_ON();
+ else
+ LED2_OFF();
+ LED2_OFF();
+
+ LED1_OFF();
+
+}
+#endif
+
+static inline void PPRZ_I2C_SEND_STOP(I2C_TypeDef *regs)
+{
+ // Man: p722: Stop generation after the current byte transfer or after the current Start condition is sent.
+ regs->CR1 |= I2C_CR1_BIT_STOP;
+
+#ifdef I2C_DEBUG_LED
+ LED2_ON();
+ LED1_ON();
+ LED1_OFF();
+ LED2_OFF();
+#endif
+}
+
+// (RE)START
+
+static inline void PPRZ_I2C_SEND_START(struct i2c_periph *periph)
+{
+ I2C_TypeDef *regs = (I2C_TypeDef *) periph->reg_addr;
+
+ periph->idx_buf = 0;
+
+#ifdef I2C_DEBUG_LED
+ LED_SHOW_ACTIVE_BITS(regs);
+
+ LED2_ON();
+ LED1_ON();
+ LED1_OFF();
+ LED1_ON();
+ LED1_OFF();
+ LED1_ON();
+ LED1_OFF();
+ LED2_OFF();
+
+#endif
+
+/*
+ if (BIT_X_IS_SET_IN_REG( I2C_CR1_BIT_STOP, regs->CR1 ) )
+ {
+ regs->CR1 &= ~ I2C_CR1_BIT_STOP;
+ }
+*/
+
+ // Enable Error IRQ, Event IRQ but disable Buffer IRQ
+ regs->CR2 |= I2C_CR2_BIT_ITERREN;
+ regs->CR2 |= I2C_CR2_BIT_ITEVTEN;
+ regs->CR2 &= ~ I2C_CR2_BIT_ITBUFEN;
+
+ // Issue a new start
+ regs->CR1 = (I2C_CR1_BIT_START | I2C_CR1_BIT_PE);
+ periph->status = I2CStartRequested;
+
+
+#ifdef I2C_DEBUG_LED
+ LED_SHOW_ACTIVE_BITS(regs);
+#endif
+}
+
+// STOP
+
+///////////////////////////////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////////////////////////////
+//
+// SUBTRANSACTION SEQUENCES
+
+enum STMI2CSubTransactionStatus {
+ STMI2C_SubTra_Busy,
+ STMI2C_SubTra_Ready_StopRequested,
+ STMI2C_SubTra_Ready
+};
+
+static inline enum STMI2CSubTransactionStatus stmi2c_send(I2C_TypeDef *regs, struct i2c_periph *periph, struct i2c_transaction *trans)
+{
+ uint16_t SR1 = regs->SR1;
+
+ // Start Condition Was Just Generated
+ if (BIT_X_IS_SET_IN_REG( I2C_SR1_BIT_SB, SR1 ) )
+ {
+ // Disable buffer interrupt
+ regs->CR2 &= ~ I2C_CR2_BIT_ITBUFEN;
+ // Send Slave address and wait for ADDR interrupt
+ regs->DR = trans->slave_addr;
+ }
+ // Address Was Sent
+ else if (BIT_X_IS_SET_IN_REG(I2C_SR1_BIT_ADDR, SR1) )
+ {
+ // Now read SR2 to clear the ADDR
+ uint16_t SR2 __attribute__ ((unused)) = regs->SR2;
+
+ // Maybe check we are transmitting (did not loose arbitration for instance)
+ // if (! BIT_X_IS_SET_IN_REG(I2C_SR2_BIT_TRA, SR2)) { }
+
+ // Send First max 2 bytes
+ regs->DR = trans->buf[0];
+ if (trans->len_w > 1)
+ {
+ regs->DR = trans->buf[1];
+ periph->idx_buf = 2;
+ }
+ else
+ {
+ periph->idx_buf = 1;
+ }
+
+ // Enable buffer-space available interrupt
+ // only if there is more to send: wait for TXE, no more to send: wait for BTF
+ if ( periph->idx_buf < trans->len_w)
+ regs->CR2 |= I2C_CR2_BIT_ITBUFEN;
+ }
+ // The buffer is not full anymore AND we were not waiting for BTF
+ else if ((BIT_X_IS_SET_IN_REG(I2C_SR1_BIT_TXE, SR1) ) && (BIT_X_IS_SET_IN_REG(I2C_CR2_BIT_ITBUFEN, regs->CR2)) )
+ {
+ // Send the next byte
+ regs->DR = trans->buf[periph->idx_buf];
+ periph->idx_buf++;
+
+ // All bytes Sent? Then wait for BTF instead
+ if ( periph->idx_buf >= trans->len_w)
+ {
+ // Not interested anymore to know the buffer has space left
+ regs->CR2 &= ~ I2C_CR2_BIT_ITBUFEN;
+ // Next interrupt will be BTF (or error)
+ }
+ }
+ // BTF: means last byte was sent
+ else if (BIT_X_IS_SET_IN_REG(I2C_SR1_BIT_BTF, SR1) )
+ {
+ if (trans->type == I2CTransTx)
+ {
+ // Tell the driver we are ready
+ trans->status = I2CTransSuccess;
+ }
+
+ return STMI2C_SubTra_Ready;
+ }
+
+ return STMI2C_SubTra_Busy;
+}
+
+static inline enum STMI2CSubTransactionStatus stmi2c_read1(I2C_TypeDef *regs, struct i2c_transaction *trans)
+{
+ uint16_t SR1 = regs->SR1;
+
+ // Start Condition Was Just Generated
+ if (BIT_X_IS_SET_IN_REG( I2C_SR1_BIT_SB, SR1 ) )
+ {
+ regs->CR2 &= ~ I2C_CR2_BIT_ITBUFEN;
+ regs->DR = trans->slave_addr | 0x01;
+ }
+ // Address Was Sent
+ else if (BIT_X_IS_SET_IN_REG(I2C_SR1_BIT_ADDR, SR1) )
+ {
+ // First Clear the ACK bit: after the next byte we do not want new bytes
+ regs->CR1 &= ~ I2C_CR1_BIT_POS;
+ regs->CR1 &= ~ I2C_CR1_BIT_ACK;
+
+ // --- next to steps MUST be executed together to avoid missing the stop
+ __disable_irq();
+
+ // Only after setting ACK, read SR2 to clear the ADDR (next byte will start arriving)
+ uint16_t SR2 __attribute__ ((unused)) = regs->SR2;
+
+ // Schedule a Stop
+ PPRZ_I2C_SEND_STOP(regs);
+
+ __enable_irq();
+ // --- end of critical zone -----------
+
+ // Enable the RXNE to get the result
+ regs->CR2 |= I2C_CR2_BIT_ITBUFEN;
+ }
+ else if (BIT_X_IS_SET_IN_REG(I2C_SR1_BIT_RXNE, SR1) )
+ {
+ regs->CR2 &= ~ I2C_CR2_BIT_ITBUFEN;
+ trans->buf[0] = regs->DR;
+
+ // We got all the results (stop condition might still be in progress but this is the last interrupt)
+ trans->status = I2CTransSuccess;
+
+ return STMI2C_SubTra_Ready_StopRequested;
+ }
+
+ return STMI2C_SubTra_Busy;
+}
+
+static inline enum STMI2CSubTransactionStatus stmi2c_read2(I2C_TypeDef *regs, struct i2c_transaction *trans)
+{
+ uint16_t SR1 = regs->SR1;
+
+ // Start Condition Was Just Generated
+ if (BIT_X_IS_SET_IN_REG( I2C_SR1_BIT_SB, SR1 ) )
+ {
+ regs->CR2 &= ~ I2C_CR2_BIT_ITBUFEN;
+ regs->CR1 |= I2C_CR1_BIT_ACK;
+ regs->CR1 |= I2C_CR1_BIT_POS;
+ regs->DR = trans->slave_addr | 0x01;
+ }
+ // Address Was Sent
+ else if (BIT_X_IS_SET_IN_REG(I2C_SR1_BIT_ADDR, SR1) )
+ {
+ // BEFORE clearing ACK, read SR2 to clear the ADDR (next byte will start arriving)
+ // clearing ACK after the byte transfer has already started will NACK the next (2nd)
+ uint16_t SR2 __attribute__ ((unused)) = regs->SR2;
+
+ // --- make absolutely sure this command is not delayed too much after the previous:
+ __disable_irq();
+ // if transfer of DR was finished already then we will get too many bytes
+ // NOT First Clear the ACK bit but only AFTER clearing ADDR
+ regs->CR1 &= ~ I2C_CR1_BIT_ACK;
+
+ // Disable the RXNE and wait for BTF
+ regs->CR2 &= ~ I2C_CR2_BIT_ITBUFEN;
+
+ __enable_irq();
+ // --- end of critical zone -----------
+ }
+ // Receive buffer if full, master is halted: BTF
+ else if (BIT_X_IS_SET_IN_REG(I2C_SR1_BIT_BTF, SR1) )
+ {
+ // Stop condition MUST be set BEFORE reading the DR
+ // otherwise since there is new buffer space a new byte will be read
+ PPRZ_I2C_SEND_STOP(regs);
+
+ trans->buf[0] = regs->DR;
+ trans->buf[1] = regs->DR;
+
+ // We got all the results
+ trans->status = I2CTransSuccess;
+
+ return STMI2C_SubTra_Ready_StopRequested;
+ }
+
+ return STMI2C_SubTra_Busy;
+}
+
+static inline enum STMI2CSubTransactionStatus stmi2c_readmany(I2C_TypeDef *regs, struct i2c_periph *periph, struct i2c_transaction *trans)
+{
+ uint16_t SR1 = regs->SR1;
+
+ // Start Condition Was Just Generated
+ if (BIT_X_IS_SET_IN_REG( I2C_SR1_BIT_SB, SR1 ) )
+ {
+ regs->CR2 &= ~ I2C_CR2_BIT_ITBUFEN;
+ // The first data byte will be acked in read many so the slave knows it should send more
+ regs->CR1 &= ~ I2C_CR1_BIT_POS;
+ regs->CR1 |= I2C_CR1_BIT_ACK;
+ // Clear the SB flag
+ regs->DR = trans->slave_addr | 0x01;
+ }
+ // Address Was Sent
+ else if (BIT_X_IS_SET_IN_REG(I2C_SR1_BIT_ADDR, SR1) )
+ {
+ periph->idx_buf = 0;
+
+ // Enable RXNE: receive an interrupt any time a byte is available
+ // only enable if MORE than 3 bytes need to be read
+ if (periph->idx_buf < (trans->len_r - 3))
+ {
+ regs->CR2 |= I2C_CR2_BIT_ITBUFEN;
+ }
+
+ // ACK is still on to get more DATA
+ // Read SR2 to clear the ADDR (next byte will start arriving)
+ uint16_t SR2 __attribute__ ((unused)) = regs->SR2;
+ }
+ // one or more bytes are available AND we were interested in Buffer interrupts
+ else if ( (BIT_X_IS_SET_IN_REG(I2C_SR1_BIT_RXNE, SR1) ) && (BIT_X_IS_SET_IN_REG(I2C_CR2_BIT_ITBUFEN, regs->CR2)) )
+ {
+ // read byte until 3 bytes remain to be read (e.g. len_r = 6, -> idx=3 means idx 3,4,5 = 3 remain to be read
+ if (periph->idx_buf < (trans->len_r - 3))
+ {
+ trans->buf[periph->idx_buf] = regs->DR;
+ periph->idx_buf ++;
+ }
+ // from : 3bytes -> last byte: do nothing
+ //
+ // finally: this was the last byte
+ else if (periph->idx_buf >= (trans->len_r - 1))
+ {
+ regs->CR2 &= ~ I2C_CR2_BIT_ITBUFEN;
+
+ // Last Value
+ trans->buf[periph->idx_buf] = regs->DR;
+ periph->idx_buf ++;
+
+ // We got all the results
+ trans->status = I2CTransSuccess;
+
+ return STMI2C_SubTra_Ready_StopRequested;
+ }
+
+ // Check for end of transaction: start waiting for BTF instead of RXNE
+ if (periph->idx_buf < (trans->len_r - 3))
+ {
+ regs->CR2 |= I2C_CR2_BIT_ITBUFEN;
+ }
+ else // idx >= len-3: there are 3 bytes to be read
+ {
+ // We want to halt I2C to have sufficient time to clear ACK, so:
+ // Stop listening to RXNE as it will be triggered infinitely since we did not empty the buffer
+ // on the next (second in buffer) received byte BTF will be set (buffer full and I2C halted)
+ regs->CR2 &= ~ I2C_CR2_BIT_ITBUFEN;
+ }
+ }
+ // Buffer is full while this was not a RXNE interrupt
+ else if (BIT_X_IS_SET_IN_REG(I2C_SR1_BIT_BTF, SR1) )
+ {
+ // Now the shift register and data register contain data(n-2) and data(n-1)
+ // And I2C is halted so we have time
+
+ // --- Make absolutely sure the next 2 I2C actions are performed with no delay
+ __disable_irq();
+
+ // First we clear the ACK while the SCL is held low by BTF
+ regs->CR1 &= ~ I2C_CR1_BIT_ACK;
+
+ // Now that ACK is cleared we read one byte: instantly the last byte is being clocked in...
+ trans->buf[periph->idx_buf] = regs->DR;
+ periph->idx_buf ++;
+
+ // Now the last byte is being clocked. Stop in MUST be set BEFORE the transfer of the last byte is complete
+ PPRZ_I2C_SEND_STOP(regs);
+
+ __enable_irq();
+ // --- end of critical zone -----------
+
+ // read the byte2 we had in the buffer (BTF means 2 bytes available)
+ trans->buf[periph->idx_buf] = regs->DR;
+ periph->idx_buf ++;
+
+ // Ask for an interrupt to read the last byte (which is normally still busy now)
+ // The last byte will be received with RXNE
+ regs->CR2 |= I2C_CR2_BIT_ITBUFEN;
+ }
+ else
+ {
+ // Error
+#ifdef I2C_DEBUG_LED
+ LED2_ON();
+ LED1_ON();
+ LED2_OFF();
+ LED1_OFF();
+#endif
+ }
+
+ return STMI2C_SubTra_Busy;
+}
+
+
+static inline void stmi2c_clear_pending_interrupts(I2C_TypeDef *regs)
+{
+ uint16_t SR1 = regs->SR1;
+
+ regs->CR2 &= ~ I2C_CR2_BIT_ITBUFEN; // Disable TXE, RXNE
+
+
+ // Start Condition Was Generated
+ if (BIT_X_IS_SET_IN_REG( I2C_SR1_BIT_SB, SR1 ) )
+ {
+ // SB: cleared by software when reading SR1 and writing to DR
+ regs->DR = 0x00;
+ }
+ // Address Was Sent
+ if (BIT_X_IS_SET_IN_REG(I2C_SR1_BIT_ADDR, SR1) )
+ {
+ // ADDR: Cleared by software when reading SR1 and then SR2
+ uint16_t SR2 __attribute__ ((unused)) = regs->SR2;
+ }
+ // Byte Transfer Finished
+ if (BIT_X_IS_SET_IN_REG(I2C_SR1_BIT_BTF, SR1) )
+ {
+ // SB: cleared by software when reading SR1 and reading/writing to DR
+ uint8_t dummy __attribute__ ((unused)) = regs->DR;
+ regs->DR = 0x00;
+ }
+}
+
+
+static inline void i2c_error(struct i2c_periph *periph);
+
+static inline void i2c_irq(struct i2c_periph *periph)
+{
+
+ /*
+ There are 7 possible reasons to get here:
+
+ If IT_EV_FEN
+ -------------------------
+
+ We are always interested in all IT_EV_FEV: all are required.
+
+ 1) SB // Start Condition Success in Master mode
+ 2) ADDR // Address sent received Acknoledge
+ [3 ADDR10] // -- 10bit address stuff
+ [4 STOPF] // -- only for slaves: master has no stop interrupt
+ 5) BTF // I2C has stopped working (it is waiting for new data, all buffers are tx_empty/rx_full)
+
+ // Beware: using the buffered I2C has some interesting properties:
+ -in master receive mode: BTF only occurs after the 2nd received byte: after the first byte is received it is
+ in RD but the I2C can still receive a second byte. Only when the 2nd byte is received while the RxNE is 1
+ then a BTF occurs (I2C can not continue receiving bytes or they will get lost). During BTF I2C is halted (SCL held low)
+ -in master transmitmode: when writing a byte to WD, you instantly get a new TxE interrupt while the first is not
+ transmitted yet. The byte was pushed to the I2C shift register and the buffer is ready for more. You can already
+ fill new data in the buffer while the first is still being transmitted for max performance transmission.
+
+ // Beware: besides data buffering you can/must plan several consecutive actions. You can send 2 bytes to the buffer, ask for a stop and
+ a new start in one go.
+
+ -thanks to / because of this buffering and event sheduling there is not 1 interrupt per start / byte / stop
+ This also means you must think more in advance and a transaction could be popped from the stack even before it is
+ actually completely transmitted. But then you would not know the result yet so you have to keep it until the result
+ is known.
+
+ // Beware: the order in which Status is read determines how flags are cleared. You should not just read SR1 & SR2 every time
+
+ If IT_EV_FEN AND IT_EV_BUF
+ --------------------------
+
+ Buffer event are not always wanted and are tipically switched on during longer data transfers. Make sure to turn off in time.
+
+ 6) RxNE
+ 7) TxE
+
+ --------------------------------------------------------------------------------------------------
+ // This driver uses only a subset of the pprz_i2c_states for several reasons:
+ // -we have less interrupts than the I2CStatus states (for efficiency)
+ // -STM32 has such a powerfull I2C engine with plenty of status register flags that
+ only little extra status information needs to be stored.
+
+ // Status is re-used (abused) to remember the last COMMAND THAT WAS SENT to the STM I2C hardware.
+
+// TODO: check which are used
+ enum I2CStatus {
+ I2CIdle, // No more last command
+
+ I2CStartRequested, // Last command was start
+ I2CRestartRequested, // Last command was restart
+ I2CStopRequested, // Very important to not send double stop conditions
+
+ I2CSendingByte, // Some address/data operation
+
+ // Following are not used
+ I2CReadingByte,
+ I2CAddrWrSent,
+ I2CAddrRdSent,
+ I2CSendingLastByte,
+ I2CReadingLastByte,
+ I2CComplete,
+ I2CFailed
+ };
+
+ ---------
+
+ The STM waits indefinately (holding SCL low) for user interaction:
+ a) after a master-start (waiting for address)
+ b) after an address (waiting for data)
+ not during data sending when using buffered
+ c) after the last byte is transmitted (waiting for either stop or restart)
+ not during data receiving when using buffered
+ not after the last byte is received
+
+ -The STM I2C stalls indefinately when a stop condition was attempted that
+ did not succeed. The BUSY flag remains on.
+ -There is no STOP interrupt: use needs another way to finish.
+
+ */
+
+
+ ///////////////////////////////////////////////////////////////////////////////////
+ // Reading the status:
+ // - Caution: this clears several flags and can start transmissions etc...
+ // - Certain flags like STOP / (N)ACK need to be guaranteed to be set before
+ // the transmission of the byte is finished. At higher clock rates that can be
+ // quite fast: so we allow no other interrupt to be triggered in between
+ // reading the status and setting all needed flags
+
+ // Direct Access to the I2C Registers
+ // Do not read SR2 as it might start the reading while an (n)ack bit might be needed first
+ I2C_TypeDef *regs = (I2C_TypeDef *) periph->reg_addr;
+
+#ifdef I2C_DEBUG_LED
+ LED1_ON();
+ LED1_OFF();
+#endif
+
+
+ ///////////////////////////////////////////////////////////////////////////////////////////////////////
+ ///////////////////////////////////////////////////////////////////////////////////////////////////////
+ //
+ // TRANSACTION HANDLER
+
+ enum STMI2CSubTransactionStatus ret = 0;
+
+ ///////////////////////
+ // Nothing Left To Do
+ if (periph->trans_extract_idx == periph->trans_insert_idx)
+ {
+#ifdef I2C_DEBUG_LED
+ LED2_ON();
+ LED1_ON();
+ LED2_OFF();
+ LED1_OFF();
+
+ // no transaction and also an error?
+ LED_SHOW_ACTIVE_BITS(regs);
+#endif
+
+ // If we still get an interrupt but there are no more things to do
+ // (which can happen if an event was sheduled just before a bus error occurs)
+ // then its easy: just stop: clear all interrupt generating bits
+
+ // Clear Running Events
+ stmi2c_clear_pending_interrupts(regs);
+
+ // Count The Errors
+ i2c_error(periph);
+
+ // Mark this as a special error
+ periph->errors->unexpected_event_cnt++;
+
+ periph->status = I2CIdle;
+
+ // There are no transactions anymore:
+ // furtheron we need a transaction pointer: so we are not allowed to continue
+ return;
+ }
+
+ struct i2c_transaction* trans = periph->trans[periph->trans_extract_idx];
+
+ ///////////////////////////
+ // If there was an error:
+ if (( regs->SR1 & I2C_SR1_BITS_ERR ) != 0x0000)
+ {
+
+#ifdef I2C_DEBUG_LED
+ LED1_ON();
+ LED2_ON();
+ LED1_OFF();
+ LED2_OFF();
+
+ LED_SHOW_ACTIVE_BITS(regs);
+#endif
+
+ // Set result in transaction
+ trans->status = I2CTransFailed;
+
+ // Prepare for next
+ ret = STMI2C_SubTra_Ready;
+
+ // Make sure a TxRx does not Restart
+ trans->type = I2CTransRx;
+
+ // Clear Running Events
+ stmi2c_clear_pending_interrupts(regs);
+
+ // Count The Errors
+ i2c_error(periph);
+ }
+
+
+ ///////////////////////////
+ // Normal Event:
+ else
+ {
+
+ if (trans->type == I2CTransRx) // TxRx are converted to Rx after the Tx Part
+ {
+ switch (trans->len_r)
+ {
+ case 1:
+ ret = stmi2c_read1(regs,trans);
+ break;
+ case 2:
+ ret = stmi2c_read2(regs,trans);
+ break;
+ default:
+ ret = stmi2c_readmany(regs,periph, trans);
+ break;
+ }
+ }
+ else // TxRx or Tx
+ {
+ ret = stmi2c_send(regs,periph,trans);
+ }
+ }
+
+ /////////////////////////////////
+ // Sub-transaction has finished
+ if (ret != STMI2C_SubTra_Busy)
+ {
+ // If a restart is not needed
+ if (trans->type != I2CTransTxRx)
+ {
+ // Ready, no stop condition set yet
+ if (ret == STMI2C_SubTra_Ready)
+ {
+
+ // Program a stop
+ PPRZ_I2C_SEND_STOP(regs);
+
+ // Silent any BTF that would occur before STOP is executed
+ regs->DR = 0x00;
+ }
+
+ // Jump to the next transaction
+ periph->trans_extract_idx++;
+ if (periph->trans_extract_idx >= I2C_TRANSACTION_QUEUE_LEN)
+ periph->trans_extract_idx = 0;
+
+ // Tell everyone we are ready
+ periph->status = I2CIdle;
+
+
+ // if we have no more transaction to process, stop here
+ if (periph->trans_extract_idx == periph->trans_insert_idx)
+ {
+
+#ifdef I2C_DEBUG_LED
+ LED2_ON();
+ LED1_ON();
+ LED1_OFF();
+ LED1_ON();
+ LED1_OFF();
+ LED2_OFF();
+#endif
+ }
+ // if not, start next transaction
+ else
+ {
+ // Restart transaction doing the Rx part now
+// --- moved to idle function
+ PPRZ_I2C_SEND_START(periph);
+// ------
+ }
+
+ }
+ // RxTx -> Restart and do Rx part
+ else
+ {
+ trans->type = I2CTransRx;
+ periph->status = I2CStartRequested;
+ regs->CR1 |= I2C_CR1_BIT_START;
+
+ // Silent any BTF that would occur before SB
+ regs->DR = 0x00;
+ }
+ }
+
+ return;
+}
+
+static inline void i2c_error(struct i2c_periph *periph)
+{
+ uint8_t err_nr = 0;
+ periph->errors->er_irq_cnt;
+ if (I2C_GetITStatus(periph->reg_addr, I2C_IT_AF)) { /* Acknowledge failure */
+ periph->errors->ack_fail_cnt++;
+ I2C_ClearITPendingBit(periph->reg_addr, I2C_IT_AF);
+ err_nr = 1;
+ }
+ if (I2C_GetITStatus(periph->reg_addr, I2C_IT_BERR)) { /* Misplaced Start or Stop condition */
+ periph->errors->miss_start_stop_cnt++;
+ I2C_ClearITPendingBit(periph->reg_addr, I2C_IT_BERR);
+ err_nr = 2;
+ }
+ if (I2C_GetITStatus(periph->reg_addr, I2C_IT_ARLO)) { /* Arbitration lost */
+ periph->errors->arb_lost_cnt++;
+ I2C_ClearITPendingBit(periph->reg_addr, I2C_IT_ARLO);
+ err_nr = 3;
+ }
+ if (I2C_GetITStatus(periph->reg_addr, I2C_IT_OVR)) { /* Overrun/Underrun */
+ periph->errors->over_under_cnt++;
+ I2C_ClearITPendingBit(periph->reg_addr, I2C_IT_OVR);
+ err_nr = 4;
+ }
+ if (I2C_GetITStatus(periph->reg_addr, I2C_IT_PECERR)) { /* PEC Error in reception */
+ periph->errors->pec_recep_cnt++;
+ I2C_ClearITPendingBit(periph->reg_addr, I2C_IT_PECERR);
+ err_nr = 5;
+ }
+ if (I2C_GetITStatus(periph->reg_addr, I2C_IT_TIMEOUT)) { /* Timeout or Tlow error */
+ periph->errors->timeout_tlow_cnt++;
+ I2C_ClearITPendingBit(periph->reg_addr, I2C_IT_TIMEOUT);
+ err_nr = 6;
+ }
+ if (I2C_GetITStatus(periph->reg_addr, I2C_IT_SMBALERT)) { /* SMBus alert */
+ periph->errors->smbus_alert_cnt++;
+ I2C_ClearITPendingBit(periph->reg_addr, I2C_IT_SMBALERT);
+ err_nr = 7;
+ }
+
+#ifdef I2C_DEBUG_LED
+ LED_ERROR(20, err_nr);
+#endif
+
+ return;
+
+}
+
+
+/*
+ // Make sure the bus is free before resetting (p722)
+ if (regs->SR2 & (I2C_FLAG_BUSY >> 16)) {
+ // Reset the I2C block
+ I2C_SoftwareResetCmd(periph->reg_addr, ENABLE);
+ I2C_SoftwareResetCmd(periph->reg_addr, DISABLE);
+ }
+*/
+
+//#endif /* USE_I2C2 */
+
+
+
+
+#ifdef USE_I2C1
+
+struct i2c_errors i2c1_errors;
+
+void i2c1_hw_init(void) {
+
+ i2c1.reg_addr = I2C1;
+ i2c1.init_struct = &I2C1_InitStruct;
+ i2c1.scl_pin = GPIO_Pin_6;
+ i2c1.sda_pin = GPIO_Pin_7;
+ i2c1.errors = &i2c1_errors;
+
+ /* zeros error counter */
+ ZEROS_ERR_COUNTER(i2c1_errors);
+
+ // Extra
+#ifdef I2C_DEBUG_LED
+ LED_INIT();
+#else
+
+ /* reset peripheral to default state ( sometimes not achieved on reset :( ) */
+ //I2C_DeInit(I2C1);
+
+ NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0);
+ NVIC_InitTypeDef NVIC_InitStructure;
+
+ /* Configure and enable I2C1 event interrupt --------------------------------*/
+ NVIC_InitStructure.NVIC_IRQChannel = I2C1_EV_IRQn;
+ NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
+ NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
+ NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
+ NVIC_Init(&NVIC_InitStructure);
+
+ /* Configure and enable I2C1 err interrupt ----------------------------------*/
+ NVIC_InitStructure.NVIC_IRQChannel = I2C1_ER_IRQn;
+ NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
+ NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
+ NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
+ NVIC_Init(&NVIC_InitStructure);
+
+ /* Enable peripheral clocks -------------------------------------------------*/
+ /* Enable I2C1 clock */
+ RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1, ENABLE);
+ /* Enable GPIOB clock */
+ RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
+
+ GPIO_InitTypeDef GPIO_InitStructure;
+ GPIO_InitStructure.GPIO_Pin = i2c1.scl_pin | i2c1.sda_pin;
+ GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;
+ GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_OD;
+ GPIO_Init(GPIOB, &GPIO_InitStructure);
+
+ I2C_DeInit(I2C1);
+
+ // enable peripheral
+ I2C_Cmd(I2C1, ENABLE);
+
+ I2C_Init(I2C1, i2c1.init_struct);
+
+ // enable error interrupts
+ I2C_ITConfig(I2C1, I2C_IT_ERR, ENABLE);
+
+#endif
+}
+
+void i2c1_ev_irq_handler(void) {
+ i2c_irq(&i2c1);
+}
+
+void i2c1_er_irq_handler(void) {
+ i2c_irq(&i2c1);
+}
+
+#endif /* USE_I2C1 */
+
+#ifdef USE_I2C2
+
+struct i2c_errors i2c2_errors;
+
+void i2c2_hw_init(void) {
+
+ i2c2.reg_addr = I2C2;
+ i2c2.init_struct = &I2C2_InitStruct;
+ i2c2.scl_pin = GPIO_Pin_10;
+ i2c2.sda_pin = GPIO_Pin_11;
+ i2c2.errors = &i2c2_errors;
+
+ /* zeros error counter */
+ ZEROS_ERR_COUNTER(i2c2_errors);
+
+ /* reset peripheral to default state ( sometimes not achieved on reset :( ) */
+ //I2C_DeInit(I2C2);
+
+ NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0);
+ NVIC_InitTypeDef NVIC_InitStructure;
+
+ /* Configure and enable I2C2 event interrupt --------------------------------*/
+ NVIC_InitStructure.NVIC_IRQChannel = I2C2_EV_IRQn;
+ NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
+ NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
+ NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
+ NVIC_Init(&NVIC_InitStructure);
+
+ /* Configure and enable I2C2 err interrupt ----------------------------------*/
+ NVIC_InitStructure.NVIC_IRQChannel = I2C2_ER_IRQn;
+ NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
+ NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
+ NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
+ NVIC_Init(&NVIC_InitStructure);
+
+ /* Enable peripheral clocks -------------------------------------------------*/
+ /* Enable I2C2 clock */
+ RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C2, ENABLE);
+ /* Enable GPIOB clock */
+ RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
+
+ GPIO_InitTypeDef GPIO_InitStructure;
+ GPIO_InitStructure.GPIO_Pin = i2c2.scl_pin | i2c2.sda_pin;
+ GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;
+ GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_OD;
+ GPIO_Init(GPIOB, &GPIO_InitStructure);
+
+ I2C_DeInit(I2C2);
+
+ // enable peripheral
+ I2C_Cmd(I2C2, ENABLE);
+
+ I2C_Init(I2C2, i2c2.init_struct);
+
+ // enable error interrupts
+ I2C_ITConfig(I2C2, I2C_IT_ERR, ENABLE);
+
+}
+
+
+
+void i2c2_ev_irq_handler(void) {
+ i2c_irq(&i2c2);
+}
+
+void i2c2_er_irq_handler(void) {
+ i2c_irq(&i2c2);
+}
+
+#endif /* USE_I2C2 */
+
+
+void i2c_setbitrate(struct i2c_periph *periph, int bitrate)
+{
+ if (i2c_idle(periph))
+ {
+ if (periph == &i2c2)
+ {
+ I2C2_InitStruct.I2C_ClockSpeed = bitrate;
+ I2C_Init(I2C2, i2c2.init_struct);
+ }
+
+#ifdef I2C_DEBUG_LED
+ __disable_irq();
+
+ LED2_ON();
+ LED1_ON();
+ LED2_OFF();
+ LED1_OFF();
+ LED2_ON();
+ LED1_ON();
+ LED2_OFF();
+ LED1_OFF();
+
+ __enable_irq();
+#endif
+
+ }
+}
+
+
+void i2c_event(void)
+{
+ static uint32_t cnt = 0;
+ I2C_TypeDef *regs;
+ cnt++;
+ if (cnt > 10000) cnt = 0;
+
+#ifndef I2C_DEBUG_LED
+#ifdef USE_I2C1
+ if (i2c1.status == I2CIdle)
+ {
+ if (i2c_idle(&i2c1))
+ {
+ __disable_irq();
+ // More work to do
+ if (i2c1.trans_extract_idx != i2c1.trans_insert_idx)
+ {
+ // Restart transaction doing the Rx part now
+ PPRZ_I2C_SEND_START(&i2c1);
+ }
+ __enable_irq();
+ }
+ }
+#endif
+#endif
+
+#ifdef USE_I2C2
+
+#ifdef I2C_DEBUG_LED
+ if (cnt == 0)
+ {
+ __disable_irq();
+
+ LED2_ON();
+ LED1_ON();
+ LED1_OFF();
+ LED1_ON();
+ LED1_OFF();
+ LED1_ON();
+ LED1_OFF();
+ LED1_ON();
+ LED1_OFF();
+ if (i2c2.status == I2CIdle)
+ {
+ LED1_ON();
+ LED1_OFF();
+ }
+ else if (i2c2.status == I2CStartRequested)
+ {
+ LED1_ON();
+ LED1_OFF();
+ LED1_ON();
+ LED1_OFF();
+
+ }
+ LED2_OFF();
+
+ //regs = (I2C_TypeDef *) i2c2.reg_addr;
+ //LED_SHOW_ACTIVE_BITS(regs);
+
+ __enable_irq();
+ }
+#endif
+
+
+ //if (i2c2.status == I2CIdle)
+ {
+ //if (i2c_idle(&i2c2))
+ {
+ //__disable_irq();
+ // More work to do
+ //if (i2c2.trans_extract_idx != i2c2.trans_insert_idx)
+ {
+ // Restart transaction doing the Rx part now
+ //PPRZ_I2C_SEND_START(&i2c2);
+ }
+ //__enable_irq();
+ }
+ }
+#endif
+}
+
+/////////////////////////////////////////////////////////
+// Implement Interface Functions
+
+bool_t i2c_submit(struct i2c_periph* periph, struct i2c_transaction* t) {
+
+ uint8_t temp;
+ temp = periph->trans_insert_idx + 1;
+ if (temp >= I2C_TRANSACTION_QUEUE_LEN) temp = 0;
+ if (temp == periph->trans_extract_idx)
+ return FALSE; // queue full
+
+ t->status = I2CTransPending;
+
+ __disable_irq();
+ /* put transacation in queue */
+ periph->trans[periph->trans_insert_idx] = t;
+ periph->trans_insert_idx = temp;
+
+ /* if peripheral is idle, start the transaction */
+ // if (PPRZ_I2C_IS_IDLE(p))
+ if (periph->status == I2CIdle)
+ {
+ //if (i2c_idle(periph))
+ {
+#ifdef I2C_DEBUG_LED
+ if (periph == &i2c1)
+ {
+
+ }
+ else
+#endif
+ {
+ PPRZ_I2C_SEND_START(periph);
+ }
+ }
+ }
+ /* else it will be started by the interrupt handler when the previous transactions completes */
+ __enable_irq();
+
+ return TRUE;
+}
+
+bool_t i2c_idle(struct i2c_periph* periph)
+{
+ I2C_TypeDef *regs = (I2C_TypeDef *) periph->reg_addr;
+
+#ifdef I2C_DEBUG_LED
+ if (periph == &i2c1)
+ {
+ return TRUE;
+ }
+#endif
+ if (periph->status == I2CIdle)
+ return ! (BIT_X_IS_SET_IN_REG( I2C_SR2_BIT_BUSY, regs->SR2 ) );
+ else
+ return FALSE;
+}
+
+
diff --git a/sw/airborne/arch/stm32/mcu_periph/obsolete/i2c_attempt4_nodouble_isr.c b/sw/airborne/arch/stm32/mcu_periph/obsolete/i2c_attempt4_nodouble_isr.c
new file mode 100644
index 0000000000..8fb1a4da48
--- /dev/null
+++ b/sw/airborne/arch/stm32/mcu_periph/obsolete/i2c_attempt4_nodouble_isr.c
@@ -0,0 +1,1358 @@
+#include "mcu_periph/i2c.h"
+
+#include
+#include
+#include
+#include
+
+#define I2C_DEBUG_LED
+
+/////////// DEBUGGING //////////////
+// TODO: remove this
+
+
+#ifdef I2C_DEBUG_LED
+
+static inline void LED1_ON(void)
+{
+ GPIO_WriteBit(GPIOB, GPIO_Pin_6 , Bit_SET );
+}
+
+static inline void LED1_OFF(void)
+{
+ GPIO_WriteBit(GPIOB, GPIO_Pin_6 , !Bit_SET );
+}
+
+static inline void LED2_ON(void)
+{
+ GPIO_WriteBit(GPIOB, GPIO_Pin_7 , Bit_SET );
+}
+
+static inline void LED2_OFF(void)
+{
+ GPIO_WriteBit(GPIOB, GPIO_Pin_7 , !Bit_SET );
+}
+
+static inline void LED_INIT(void)
+{
+ GPIO_InitTypeDef GPIO_InitStructure;
+ RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOB, ENABLE);
+ GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7 | GPIO_Pin_6;
+ GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
+ GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
+ GPIO_Init(GPIOB, &GPIO_InitStructure);
+
+ LED1_OFF();
+ LED2_OFF();
+}
+
+
+static inline void LED_ERROR(uint8_t base, uint8_t nr)
+{
+ LED2_ON();
+ for (int i=0;i<(base+nr);i++)
+ {
+ LED1_ON();
+ LED1_OFF();
+ }
+ LED2_OFF();
+}
+#endif
+
+//////////////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////////////
+
+#ifdef USE_I2C1
+static I2C_InitTypeDef I2C1_InitStruct = {
+ .I2C_Mode = I2C_Mode_I2C,
+ .I2C_DutyCycle = I2C_DutyCycle_2,
+ .I2C_OwnAddress1 = 0x00,
+ .I2C_Ack = I2C_Ack_Enable,
+ .I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit,
+ .I2C_ClockSpeed = 40000
+};
+#endif
+
+#ifdef USE_I2C2
+static I2C_InitTypeDef I2C2_InitStruct = {
+ .I2C_Mode = I2C_Mode_I2C,
+ .I2C_DutyCycle = I2C_DutyCycle_2,
+ .I2C_OwnAddress1 = 0x00,
+ .I2C_Ack = I2C_Ack_Enable,
+ .I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit,
+// .I2C_ClockSpeed = 37000
+ .I2C_ClockSpeed = 400000
+};
+#endif
+
+//////////////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////////////
+
+// Bypassing the libSTM I2C functions to have more control over the reading of registers
+// e.g. SR1 and SR2 should not always be read together as it might unwantedly clear ADDR flags etc.
+
+// Referring to STM32 manual:
+// -Doc ID 13902 Rev 11
+
+// Status Register 1
+
+#define I2C_SR1_BIT_SB (1<<0) // Start Condition Met
+#define I2C_SR1_BIT_ADDR (1<<1) // Address Sent
+#define I2C_SR1_BIT_BTF (1<<2) // SCL held low
+#define I2C_SR1_BIT_RXNE (1<<6) // Data Read Available
+#define I2C_SR1_BIT_TXE (1<<7) // TX buffer space available
+
+#define I2C_SR1_BIT_ERR_BUS (1<<8) // Misplaced Start/Stop (usually interference)
+#define I2C_SR1_BIT_ERR_ARLO (1<<9) // Arbitration Lost (in multimaster) or SDA short-to-ground (in single master)
+#define I2C_SR1_BIT_ERR_AF (1<<10) // Ack Failure (too fast/too soon/no sensor/wiring break/...)
+#define I2C_SR1_BIT_ERR_OVR (1<<11) // Overrun [data loss] (in slave) or SCL short-to-ground (in single master)
+
+#define I2C_SR1_BITS_ERR ((1<<8)|(1<<9)|(1<<10)|(1<<11)|(1<<12)|(1<<14)|(1<<15))
+
+// Status Register 2
+
+#define I2C_SR2_BIT_TRA (1<<2) // Transmitting
+#define I2C_SR2_BIT_BUSY (1<<1) // Busy
+#define I2C_SR2_BIT_MSL (1<<0) // Master Selected
+
+// Control Register 1
+
+#define I2C_CR1_BIT_PE (1<<0) // Peripheral Enable
+#define I2C_CR1_BIT_START (1<<8) // Generate a Start
+#define I2C_CR1_BIT_STOP (1<<9) // Generate a Stop
+#define I2C_CR1_BIT_ACK (1<<10) // ACK / NACK
+#define I2C_CR1_BIT_POS (1<<11) // Ack will control not the next but secondnext received byte
+#define I2C_CR1_BIT_SWRST (1<<15) // Clear Busy Condition when no stop was detected
+
+// Control Register 2
+
+#define I2C_CR2_BIT_ITERREN (1<<8) // Error Interrupt
+#define I2C_CR2_BIT_ITEVTEN (1<<9) // Event Interrupt
+#define I2C_CR2_BIT_ITBUFEN (1<<10) // Buffer Interrupt
+
+
+// Bit Control
+
+#define BIT_X_IS_SET_IN_REG(X,REG) (((REG) & (X)) == (X))
+
+// Critical Zones
+
+#define __I2C_REG_CRITICAL_ZONE_START
+#define __I2C_REG_CRITICAL_ZONE_STOP
+
+
+//////////////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////////////
+
+// TODO: remove debug
+#ifdef I2C_DEBUG_LED
+
+static inline void LED_SHOW_ACTIVE_BITS(I2C_TypeDef *regs)
+{
+ uint16_t CR1 = regs->CR1;
+ uint16_t SR1 = regs->SR1;
+ uint16_t SR2 = regs->SR2;
+ // Note: reading SR1 and then SR2 will clear ADDR bits
+
+ LED1_ON();
+
+ // 1 Start
+ if (BIT_X_IS_SET_IN_REG( I2C_SR1_BIT_SB, SR1 ) )
+ LED2_ON();
+ else
+ LED2_OFF();
+ LED2_OFF();
+
+ // 2 Addr
+ if (BIT_X_IS_SET_IN_REG( I2C_SR1_BIT_ADDR, SR1 ) )
+ LED2_ON();
+ else
+ LED2_OFF();
+ LED2_OFF();
+
+ // 3 BTF
+ if (BIT_X_IS_SET_IN_REG( I2C_SR1_BIT_BTF, SR1 ) )
+ LED2_ON();
+ else
+ LED2_OFF();
+ LED2_OFF();
+
+ // 4 ERROR
+ if (( SR1 & I2C_SR1_BITS_ERR ) != 0x0000)
+ LED2_ON();
+ else
+ LED2_OFF();
+ LED2_OFF();
+
+ // Anything?
+ if (( SR1 + SR2) != 0x0000)
+ LED2_ON();
+ else
+ LED2_OFF();
+ LED2_OFF();
+
+ LED1_OFF();
+
+
+ LED1_ON();
+
+ // 1 Start
+ if (BIT_X_IS_SET_IN_REG( I2C_CR1_BIT_START, CR1 ) )
+ LED2_ON();
+ else
+ LED2_OFF();
+ LED2_OFF();
+
+ // 2 Stop
+ if (BIT_X_IS_SET_IN_REG( I2C_CR1_BIT_STOP, CR1 ) )
+ LED2_ON();
+ else
+ LED2_OFF();
+ LED2_OFF();
+
+ // 3 Busy
+ if (BIT_X_IS_SET_IN_REG( I2C_SR2_BIT_BUSY, SR2 ) )
+ LED2_ON();
+ else
+ LED2_OFF();
+ LED2_OFF();
+
+ // 4 Tra
+ if (BIT_X_IS_SET_IN_REG( I2C_SR2_BIT_TRA, SR2 ) )
+ LED2_ON();
+ else
+ LED2_OFF();
+ LED2_OFF();
+
+ // 5 Master
+ if (BIT_X_IS_SET_IN_REG( I2C_SR2_BIT_MSL, SR2 ) )
+ LED2_ON();
+ else
+ LED2_OFF();
+ LED2_OFF();
+ LED1_OFF();
+
+//#define I2C_DEBUG_LED_CONTROL
+#ifdef I2C_DEBUG_LED_CONTROL
+
+
+ LED1_ON();
+
+ // 1 Anything CR?
+ if (( CR1) != 0x0000)
+ LED2_ON();
+ else
+ LED2_OFF();
+ LED2_OFF();
+
+ // 2 PE
+ if (BIT_X_IS_SET_IN_REG( I2C_CR1_BIT_PE, CR1 ) )
+ LED2_ON();
+ else
+ LED2_OFF();
+ LED2_OFF();
+
+ // 3 SWRESET
+ if (BIT_X_IS_SET_IN_REG( I2C_CR1_BIT_SWRST, CR1 ) )
+ LED2_ON();
+ else
+ LED2_OFF();
+ LED2_OFF();
+
+ LED1_OFF();
+#endif
+
+}
+#endif
+
+static inline void PPRZ_I2C_SEND_STOP(I2C_TypeDef *regs)
+{
+ // Man: p722: Stop generation after the current byte transfer or after the current Start condition is sent.
+ regs->CR1 |= I2C_CR1_BIT_STOP;
+
+#ifdef I2C_DEBUG_LED
+ LED2_ON();
+ LED1_ON();
+ LED1_OFF();
+ LED2_OFF();
+#endif
+}
+
+// (RE)START
+
+static inline void PPRZ_I2C_SEND_START(struct i2c_periph *periph)
+{
+ I2C_TypeDef *regs = (I2C_TypeDef *) periph->reg_addr;
+
+ periph->idx_buf = 0;
+
+#ifdef I2C_DEBUG_LED
+ LED_SHOW_ACTIVE_BITS(regs);
+
+ LED2_ON();
+ LED1_ON();
+ LED1_OFF();
+ LED1_ON();
+ LED1_OFF();
+ LED1_ON();
+ LED1_OFF();
+ LED2_OFF();
+
+#endif
+
+/*
+ if (BIT_X_IS_SET_IN_REG( I2C_CR1_BIT_STOP, regs->CR1 ) )
+ {
+ regs->CR1 &= ~ I2C_CR1_BIT_STOP;
+ }
+*/
+
+ // Enable Error IRQ, Event IRQ but disable Buffer IRQ
+ regs->CR2 |= I2C_CR2_BIT_ITERREN;
+ regs->CR2 |= I2C_CR2_BIT_ITEVTEN;
+ regs->CR2 &= ~ I2C_CR2_BIT_ITBUFEN;
+
+ // Issue a new start
+ regs->CR1 = (I2C_CR1_BIT_START | I2C_CR1_BIT_PE);
+ periph->status = I2CStartRequested;
+
+
+#ifdef I2C_DEBUG_LED
+ LED_SHOW_ACTIVE_BITS(regs);
+#endif
+}
+
+// STOP
+
+///////////////////////////////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////////////////////////////
+//
+// SUBTRANSACTION SEQUENCES
+
+enum STMI2CSubTransactionStatus {
+ STMI2C_SubTra_Busy,
+ STMI2C_SubTra_Ready_StopRequested,
+ STMI2C_SubTra_Ready,
+ STMI2C_SubTra_Error
+};
+
+static inline enum STMI2CSubTransactionStatus stmi2c_send(I2C_TypeDef *regs, struct i2c_periph *periph, struct i2c_transaction *trans)
+{
+ uint16_t SR1 = regs->SR1;
+
+ // Start Condition Was Just Generated
+ if (BIT_X_IS_SET_IN_REG( I2C_SR1_BIT_SB, SR1 ) )
+ {
+ // Disable buffer interrupt
+ regs->CR2 &= ~ I2C_CR2_BIT_ITBUFEN;
+ // Send Slave address and wait for ADDR interrupt
+ regs->DR = trans->slave_addr;
+ }
+ // Address Was Sent
+ else if (BIT_X_IS_SET_IN_REG(I2C_SR1_BIT_ADDR, SR1) )
+ {
+ // Now read SR2 to clear the ADDR
+ uint16_t SR2 __attribute__ ((unused)) = regs->SR2;
+
+ // Maybe check we are transmitting (did not loose arbitration for instance)
+ // if (! BIT_X_IS_SET_IN_REG(I2C_SR2_BIT_TRA, SR2)) { }
+
+ // Send First max 2 bytes
+ regs->DR = trans->buf[0];
+ if (trans->len_w > 1)
+ {
+ regs->DR = trans->buf[1];
+ periph->idx_buf = 2;
+ }
+ else
+ {
+ periph->idx_buf = 1;
+ }
+
+ // Enable buffer-space available interrupt
+ // only if there is more to send: wait for TXE, no more to send: wait for BTF
+ if ( periph->idx_buf < trans->len_w)
+ regs->CR2 |= I2C_CR2_BIT_ITBUFEN;
+ }
+ // The buffer is not full anymore AND we were not waiting for BTF
+ else if ((BIT_X_IS_SET_IN_REG(I2C_SR1_BIT_TXE, SR1) ) && (BIT_X_IS_SET_IN_REG(I2C_CR2_BIT_ITBUFEN, regs->CR2)) )
+ {
+ // Send the next byte
+ regs->DR = trans->buf[periph->idx_buf];
+ periph->idx_buf++;
+
+ // All bytes Sent? Then wait for BTF instead
+ if ( periph->idx_buf >= trans->len_w)
+ {
+ // Not interested anymore to know the buffer has space left
+ regs->CR2 &= ~ I2C_CR2_BIT_ITBUFEN;
+ // Next interrupt will be BTF (or error)
+ }
+ }
+ // BTF: means last byte was sent
+ else if (BIT_X_IS_SET_IN_REG(I2C_SR1_BIT_BTF, SR1) )
+ {
+ if (trans->type == I2CTransTx)
+ {
+ // Tell the driver we are ready
+ trans->status = I2CTransSuccess;
+ }
+
+ return STMI2C_SubTra_Ready;
+ }
+ else // Hardware error
+ {
+ return STMI2C_SubTra_Error;
+ }
+
+ return STMI2C_SubTra_Busy;
+}
+
+static inline enum STMI2CSubTransactionStatus stmi2c_read1(I2C_TypeDef *regs, struct i2c_transaction *trans)
+{
+ uint16_t SR1 = regs->SR1;
+
+ // Start Condition Was Just Generated
+ if (BIT_X_IS_SET_IN_REG( I2C_SR1_BIT_SB, SR1 ) )
+ {
+ regs->CR2 &= ~ I2C_CR2_BIT_ITBUFEN;
+ regs->DR = trans->slave_addr | 0x01;
+ }
+ // Address Was Sent
+ else if (BIT_X_IS_SET_IN_REG(I2C_SR1_BIT_ADDR, SR1) )
+ {
+ // First Clear the ACK bit: after the next byte we do not want new bytes
+ regs->CR1 &= ~ I2C_CR1_BIT_POS;
+ regs->CR1 &= ~ I2C_CR1_BIT_ACK;
+
+ // --- next to steps MUST be executed together to avoid missing the stop
+ __I2C_REG_CRITICAL_ZONE_START;
+
+ // Only after setting ACK, read SR2 to clear the ADDR (next byte will start arriving)
+ uint16_t SR2 __attribute__ ((unused)) = regs->SR2;
+
+ // Schedule a Stop
+ PPRZ_I2C_SEND_STOP(regs);
+
+ __I2C_REG_CRITICAL_ZONE_STOP;
+ // --- end of critical zone -----------
+
+ // Enable the RXNE to get the result
+ regs->CR2 |= I2C_CR2_BIT_ITBUFEN;
+ }
+ else if (BIT_X_IS_SET_IN_REG(I2C_SR1_BIT_RXNE, SR1) )
+ {
+ regs->CR2 &= ~ I2C_CR2_BIT_ITBUFEN;
+ trans->buf[0] = regs->DR;
+
+ // We got all the results (stop condition might still be in progress but this is the last interrupt)
+ trans->status = I2CTransSuccess;
+
+ return STMI2C_SubTra_Ready_StopRequested;
+ }
+ else // Hardware error
+ {
+ return STMI2C_SubTra_Error;
+ }
+
+ return STMI2C_SubTra_Busy;
+}
+
+static inline enum STMI2CSubTransactionStatus stmi2c_read2(I2C_TypeDef *regs, struct i2c_transaction *trans)
+{
+ uint16_t SR1 = regs->SR1;
+
+ // Start Condition Was Just Generated
+ if (BIT_X_IS_SET_IN_REG( I2C_SR1_BIT_SB, SR1 ) )
+ {
+ regs->CR2 &= ~ I2C_CR2_BIT_ITBUFEN;
+ regs->CR1 |= I2C_CR1_BIT_ACK;
+ regs->CR1 |= I2C_CR1_BIT_POS;
+ regs->DR = trans->slave_addr | 0x01;
+ }
+ // Address Was Sent
+ else if (BIT_X_IS_SET_IN_REG(I2C_SR1_BIT_ADDR, SR1) )
+ {
+ // BEFORE clearing ACK, read SR2 to clear the ADDR (next byte will start arriving)
+ // clearing ACK after the byte transfer has already started will NACK the next (2nd)
+ uint16_t SR2 __attribute__ ((unused)) = regs->SR2;
+
+ // --- make absolutely sure this command is not delayed too much after the previous:
+ __I2C_REG_CRITICAL_ZONE_START;
+ // if transfer of DR was finished already then we will get too many bytes
+ // NOT First Clear the ACK bit but only AFTER clearing ADDR
+ regs->CR1 &= ~ I2C_CR1_BIT_ACK;
+
+ // Disable the RXNE and wait for BTF
+ regs->CR2 &= ~ I2C_CR2_BIT_ITBUFEN;
+
+ __I2C_REG_CRITICAL_ZONE_STOP;
+ // --- end of critical zone -----------
+ }
+ // Receive buffer if full, master is halted: BTF
+ else if (BIT_X_IS_SET_IN_REG(I2C_SR1_BIT_BTF, SR1) )
+ {
+ // Stop condition MUST be set BEFORE reading the DR
+ // otherwise since there is new buffer space a new byte will be read
+ PPRZ_I2C_SEND_STOP(regs);
+
+ trans->buf[0] = regs->DR;
+ trans->buf[1] = regs->DR;
+
+ // We got all the results
+ trans->status = I2CTransSuccess;
+
+ return STMI2C_SubTra_Ready_StopRequested;
+ }
+ else // Hardware error
+ {
+ return STMI2C_SubTra_Error;
+ }
+
+ return STMI2C_SubTra_Busy;
+}
+
+static inline enum STMI2CSubTransactionStatus stmi2c_readmany(I2C_TypeDef *regs, struct i2c_periph *periph, struct i2c_transaction *trans)
+{
+ uint16_t SR1 = regs->SR1;
+
+ // Start Condition Was Just Generated
+ if (BIT_X_IS_SET_IN_REG( I2C_SR1_BIT_SB, SR1 ) )
+ {
+ regs->CR2 &= ~ I2C_CR2_BIT_ITBUFEN;
+ // The first data byte will be acked in read many so the slave knows it should send more
+ regs->CR1 &= ~ I2C_CR1_BIT_POS;
+ regs->CR1 |= I2C_CR1_BIT_ACK;
+ // Clear the SB flag
+ regs->DR = trans->slave_addr | 0x01;
+ }
+ // Address Was Sent
+ else if (BIT_X_IS_SET_IN_REG(I2C_SR1_BIT_ADDR, SR1) )
+ {
+ periph->idx_buf = 0;
+
+ // Enable RXNE: receive an interrupt any time a byte is available
+ // only enable if MORE than 3 bytes need to be read
+ if (periph->idx_buf < (trans->len_r - 3))
+ {
+ regs->CR2 |= I2C_CR2_BIT_ITBUFEN;
+ }
+
+ // ACK is still on to get more DATA
+ // Read SR2 to clear the ADDR (next byte will start arriving)
+ uint16_t SR2 __attribute__ ((unused)) = regs->SR2;
+ }
+ // one or more bytes are available AND we were interested in Buffer interrupts
+ else if ( (BIT_X_IS_SET_IN_REG(I2C_SR1_BIT_RXNE, SR1) ) && (BIT_X_IS_SET_IN_REG(I2C_CR2_BIT_ITBUFEN, regs->CR2)) )
+ {
+ // read byte until 3 bytes remain to be read (e.g. len_r = 6, -> idx=3 means idx 3,4,5 = 3 remain to be read
+ if (periph->idx_buf < (trans->len_r - 3))
+ {
+ trans->buf[periph->idx_buf] = regs->DR;
+ periph->idx_buf ++;
+ }
+ // from : 3bytes -> last byte: do nothing
+ //
+ // finally: this was the last byte
+ else if (periph->idx_buf >= (trans->len_r - 1))
+ {
+ regs->CR2 &= ~ I2C_CR2_BIT_ITBUFEN;
+
+ // Last Value
+ trans->buf[periph->idx_buf] = regs->DR;
+ periph->idx_buf ++;
+
+ // We got all the results
+ trans->status = I2CTransSuccess;
+
+ return STMI2C_SubTra_Ready_StopRequested;
+ }
+
+ // Check for end of transaction: start waiting for BTF instead of RXNE
+ if (periph->idx_buf < (trans->len_r - 3))
+ {
+ regs->CR2 |= I2C_CR2_BIT_ITBUFEN;
+ }
+ else // idx >= len-3: there are 3 bytes to be read
+ {
+ // We want to halt I2C to have sufficient time to clear ACK, so:
+ // Stop listening to RXNE as it will be triggered infinitely since we did not empty the buffer
+ // on the next (second in buffer) received byte BTF will be set (buffer full and I2C halted)
+ regs->CR2 &= ~ I2C_CR2_BIT_ITBUFEN;
+ }
+ }
+ // Buffer is full while this was not a RXNE interrupt
+ else if (BIT_X_IS_SET_IN_REG(I2C_SR1_BIT_BTF, SR1) )
+ {
+ // Now the shift register and data register contain data(n-2) and data(n-1)
+ // And I2C is halted so we have time
+
+ // --- Make absolutely sure the next 2 I2C actions are performed with no delay
+ __I2C_REG_CRITICAL_ZONE_START;
+
+ // First we clear the ACK while the SCL is held low by BTF
+ regs->CR1 &= ~ I2C_CR1_BIT_ACK;
+
+ // Now that ACK is cleared we read one byte: instantly the last byte is being clocked in...
+ trans->buf[periph->idx_buf] = regs->DR;
+ periph->idx_buf ++;
+
+ // Now the last byte is being clocked. Stop in MUST be set BEFORE the transfer of the last byte is complete
+ PPRZ_I2C_SEND_STOP(regs);
+
+ __I2C_REG_CRITICAL_ZONE_STOP;
+ // --- end of critical zone -----------
+
+ // read the byte2 we had in the buffer (BTF means 2 bytes available)
+ trans->buf[periph->idx_buf] = regs->DR;
+ periph->idx_buf ++;
+
+ // Ask for an interrupt to read the last byte (which is normally still busy now)
+ // The last byte will be received with RXNE
+ regs->CR2 |= I2C_CR2_BIT_ITBUFEN;
+ }
+ else // Hardware error
+ {
+ // Error
+#ifdef I2C_DEBUG_LED
+ LED2_ON();
+ LED1_ON();
+ LED2_OFF();
+ LED1_OFF();
+#endif
+ return STMI2C_SubTra_Error;
+ }
+
+ return STMI2C_SubTra_Busy;
+}
+
+
+static inline void stmi2c_clear_pending_interrupts(I2C_TypeDef *regs)
+{
+ uint16_t SR1 = regs->SR1;
+
+ regs->CR2 &= ~ I2C_CR2_BIT_ITBUFEN; // Disable TXE, RXNE
+
+ //regs->CR1 &= ~ I2C_CR1_BIT_PE; // Disable Periferial
+ //regs->CR1 |= I2C_CR1_BIT_PE; // Enable Periferial
+
+ // Start Condition Was Generated
+ if (BIT_X_IS_SET_IN_REG( I2C_SR1_BIT_SB, SR1 ) )
+ {
+ // SB: cleared by software when reading SR1 and writing to DR
+ regs->DR = 0x00;
+ }
+ // Address Was Sent
+ if (BIT_X_IS_SET_IN_REG(I2C_SR1_BIT_ADDR, SR1) )
+ {
+ // ADDR: Cleared by software when reading SR1 and then SR2
+ uint16_t SR2 __attribute__ ((unused)) = regs->SR2;
+ }
+ // Byte Transfer Finished
+ if (BIT_X_IS_SET_IN_REG(I2C_SR1_BIT_BTF, SR1) )
+ {
+ // SB: cleared by software when reading SR1 and reading/writing to DR
+ uint8_t dummy __attribute__ ((unused)) = regs->DR;
+ regs->DR = 0x00;
+ }
+
+
+ // Still have a start sheduled
+// if (BIT_X_IS_SET_IN_REG(I2C_CR1_BIT_START, regs->CR1) )
+ {
+ // Clear pending start conditions
+// regs->CR1 &= ~ I2C_CR1_BIT_START;
+ }
+
+}
+
+
+static inline void i2c_error(struct i2c_periph *periph);
+
+static inline void i2c_irq(struct i2c_periph *periph)
+{
+
+ /*
+ There are 7 possible reasons to get here:
+
+ If IT_EV_FEN
+ -------------------------
+
+ We are always interested in all IT_EV_FEV: all are required.
+
+ 1) SB // Start Condition Success in Master mode
+ 2) ADDR // Address sent received Acknoledge
+ [3 ADDR10] // -- 10bit address stuff
+ [4 STOPF] // -- only for slaves: master has no stop interrupt
+ 5) BTF // I2C has stopped working (it is waiting for new data, all buffers are tx_empty/rx_full)
+
+ // Beware: using the buffered I2C has some interesting properties:
+ -in master receive mode: BTF only occurs after the 2nd received byte: after the first byte is received it is
+ in RD but the I2C can still receive a second byte. Only when the 2nd byte is received while the RxNE is 1
+ then a BTF occurs (I2C can not continue receiving bytes or they will get lost). During BTF I2C is halted (SCL held low)
+ -in master transmitmode: when writing a byte to WD, you instantly get a new TxE interrupt while the first is not
+ transmitted yet. The byte was pushed to the I2C shift register and the buffer is ready for more. You can already
+ fill new data in the buffer while the first is still being transmitted for max performance transmission.
+
+ // Beware: besides data buffering you can/must plan several consecutive actions. You can send 2 bytes to the buffer, ask for a stop and
+ a new start in one go.
+
+ -thanks to / because of this buffering and event sheduling there is not 1 interrupt per start / byte / stop
+ This also means you must think more in advance and a transaction could be popped from the stack even before it is
+ actually completely transmitted. But then you would not know the result yet so you have to keep it until the result
+ is known.
+
+ // Beware: the order in which Status is read determines how flags are cleared. You should not just read SR1 & SR2 every time
+
+ If IT_EV_FEN AND IT_EV_BUF
+ --------------------------
+
+ Buffer event are not always wanted and are tipically switched on during longer data transfers. Make sure to turn off in time.
+
+ 6) RxNE
+ 7) TxE
+
+ --------------------------------------------------------------------------------------------------
+ // This driver uses only a subset of the pprz_i2c_states for several reasons:
+ // -we have less interrupts than the I2CStatus states (for efficiency)
+ // -STM32 has such a powerfull I2C engine with plenty of status register flags that
+ only little extra status information needs to be stored.
+
+ // Status is re-used (abused) to remember the last COMMAND THAT WAS SENT to the STM I2C hardware.
+
+// TODO: check which are used
+ enum I2CStatus {
+ I2CIdle, // No more last command
+
+ I2CStartRequested, // Last command was start
+ I2CRestartRequested, // Last command was restart
+ I2CStopRequested, // Very important to not send double stop conditions
+
+ I2CSendingByte, // Some address/data operation
+
+ // Following are not used
+ I2CReadingByte,
+ I2CAddrWrSent,
+ I2CAddrRdSent,
+ I2CSendingLastByte,
+ I2CReadingLastByte,
+ I2CComplete,
+ I2CFailed
+ };
+
+ ---------
+
+ The STM waits indefinately (holding SCL low) for user interaction:
+ a) after a master-start (waiting for address)
+ b) after an address (waiting for data)
+ not during data sending when using buffered
+ c) after the last byte is transmitted (waiting for either stop or restart)
+ not during data receiving when using buffered
+ not after the last byte is received
+
+ -The STM I2C stalls indefinately when a stop condition was attempted that
+ did not succeed. The BUSY flag remains on.
+ -There is no STOP interrupt: use needs another way to finish.
+
+ */
+
+
+ ///////////////////////////////////////////////////////////////////////////////////
+ // Reading the status:
+ // - Caution: this clears several flags and can start transmissions etc...
+ // - Certain flags like STOP / (N)ACK need to be guaranteed to be set before
+ // the transmission of the byte is finished. At higher clock rates that can be
+ // quite fast: so we allow no other interrupt to be triggered in between
+ // reading the status and setting all needed flags
+
+ // Direct Access to the I2C Registers
+ // Do not read SR2 as it might start the reading while an (n)ack bit might be needed first
+ I2C_TypeDef *regs = (I2C_TypeDef *) periph->reg_addr;
+
+#ifdef I2C_DEBUG_LED
+ LED1_ON();
+ LED1_OFF();
+#endif
+
+
+ ///////////////////////////////////////////////////////////////////////////////////////////////////////
+ ///////////////////////////////////////////////////////////////////////////////////////////////////////
+ //
+ // TRANSACTION HANDLER
+
+ enum STMI2CSubTransactionStatus ret = 0;
+
+ ///////////////////////
+ // Nothing Left To Do
+ if (periph->trans_extract_idx == periph->trans_insert_idx)
+ {
+#ifdef I2C_DEBUG_LED
+ LED2_ON();
+ LED1_ON();
+ LED2_OFF();
+ LED1_OFF();
+
+ // no transaction and also an error?
+ LED_SHOW_ACTIVE_BITS(regs);
+#endif
+
+ // If we still get an interrupt but there are no more things to do
+ // (which can happen if an event was sheduled just before a bus error occurs)
+ // then its easy: just stop: clear all interrupt generating bits
+
+ // Count The Errors
+ i2c_error(periph);
+
+ // Clear Running Events
+ stmi2c_clear_pending_interrupts(regs);
+
+ // Mark this as a special error
+ periph->errors->unexpected_event_cnt++;
+
+ periph->status = I2CIdle;
+
+ // There are no transactions anymore:
+ // furtheron we need a transaction pointer: so we are not allowed to continue
+ return;
+ }
+
+ struct i2c_transaction* trans = periph->trans[periph->trans_extract_idx];
+
+ ///////////////////////////
+ // If there was an error:
+ if (( regs->SR1 & I2C_SR1_BITS_ERR ) != 0x0000)
+ {
+
+#ifdef I2C_DEBUG_LED
+ LED1_ON();
+ LED2_ON();
+ LED1_OFF();
+ LED2_OFF();
+
+ LED_SHOW_ACTIVE_BITS(regs);
+#endif
+
+ // Set result in transaction
+ trans->status = I2CTransFailed;
+
+ // Prepare for next
+ ret = STMI2C_SubTra_Ready;
+
+ // Make sure a TxRx does not Restart
+ trans->type = I2CTransRx;
+
+/*
+ // There are 2 types of errors: some need a STOP, some better do without: Following will not get an extra stop
+ if (
+ // Lost Arbitration
+ (BIT_X_IS_SET_IN_REG( I2C_SR1_BIT_ERR_ARLO, regs->SR1 ) )
+ // Buss Error When Master Only
+ || ((BIT_X_IS_SET_IN_REG( I2C_SR1_BIT_ERR_BUS, regs->SR1 ) ) && (!BIT_X_IS_SET_IN_REG( I2C_SR2_BIT_MSL, regs->SR2 ) ))
+ || (BIT_X_IS_SET_IN_REG( I2C_SR1_BIT_ERR_OVR, regs->SR1 ) )
+ )
+ {
+ ret = STMI2C_SubTra_Error;
+ }
+*/
+
+ // Count The Errors
+ i2c_error(periph);
+
+ // Clear Running Events
+ stmi2c_clear_pending_interrupts(regs);
+
+ }
+
+
+ ///////////////////////////
+ // Normal Event:
+ else
+ {
+
+ if (trans->type == I2CTransRx) // TxRx are converted to Rx after the Tx Part
+ {
+ switch (trans->len_r)
+ {
+ case 1:
+ ret = stmi2c_read1(regs,trans);
+ break;
+ case 2:
+ ret = stmi2c_read2(regs,trans);
+ break;
+ default:
+ ret = stmi2c_readmany(regs,periph, trans);
+ break;
+ }
+ }
+ else // TxRx or Tx
+ {
+ ret = stmi2c_send(regs,periph,trans);
+ }
+ }
+
+ /////////////////////////////////
+ // Sub-transaction has finished
+ if (ret != STMI2C_SubTra_Busy)
+ {
+ // If a restart is not needed
+ if (trans->type != I2CTransTxRx)
+ {
+ // Ready, no stop condition set yet
+ if (ret == STMI2C_SubTra_Ready)
+ {
+
+ // Program a stop
+ PPRZ_I2C_SEND_STOP(regs);
+
+ // Silent any BTF that would occur before STOP is executed
+ regs->DR = 0x00;
+ }
+
+ // In case of unexpected condition: e.g. not slave, no event
+ if (ret == STMI2C_SubTra_Error)
+ {
+
+ trans->status = I2CTransFailed;
+
+ // Error
+#ifdef I2C_DEBUG_LED
+ LED2_ON();
+ LED1_ON();
+ LED2_OFF();
+ LED1_OFF();
+#endif
+
+ LED_SHOW_ACTIVE_BITS(regs);
+
+ // Clear Running Events
+ stmi2c_clear_pending_interrupts(regs);
+
+ }
+
+
+ // Jump to the next transaction
+ periph->trans_extract_idx++;
+ if (periph->trans_extract_idx >= I2C_TRANSACTION_QUEUE_LEN)
+ periph->trans_extract_idx = 0;
+
+ // Tell everyone we are ready
+ periph->status = I2CIdle;
+
+
+ // if we have no more transaction to process, stop here
+ if (periph->trans_extract_idx == periph->trans_insert_idx)
+ {
+
+#ifdef I2C_DEBUG_LED
+ LED2_ON();
+ LED1_ON();
+ LED1_OFF();
+ LED1_ON();
+ LED1_OFF();
+ LED2_OFF();
+#endif
+ }
+ // if not, start next transaction
+ else
+ {
+ // Restart transaction doing the Rx part now
+// --- moved to idle function
+ PPRZ_I2C_SEND_START(periph);
+// ------
+ }
+
+ }
+ // RxTx -> Restart and do Rx part
+ else
+ {
+ trans->type = I2CTransRx;
+ periph->status = I2CStartRequested;
+ regs->CR1 |= I2C_CR1_BIT_START;
+
+ // Silent any BTF that would occur before SB
+ regs->DR = 0x00;
+ }
+ }
+
+ return;
+}
+
+static inline void i2c_error(struct i2c_periph *periph)
+{
+ uint8_t err_nr = 0;
+ periph->errors->er_irq_cnt;
+ if (I2C_GetITStatus(periph->reg_addr, I2C_IT_AF)) { /* Acknowledge failure */
+ periph->errors->ack_fail_cnt++;
+ I2C_ClearITPendingBit(periph->reg_addr, I2C_IT_AF);
+ err_nr = 1;
+ }
+ if (I2C_GetITStatus(periph->reg_addr, I2C_IT_BERR)) { /* Misplaced Start or Stop condition */
+ periph->errors->miss_start_stop_cnt++;
+ I2C_ClearITPendingBit(periph->reg_addr, I2C_IT_BERR);
+ err_nr = 2;
+ }
+ if (I2C_GetITStatus(periph->reg_addr, I2C_IT_ARLO)) { /* Arbitration lost */
+ periph->errors->arb_lost_cnt++;
+ I2C_ClearITPendingBit(periph->reg_addr, I2C_IT_ARLO);
+ err_nr = 3;
+ }
+ if (I2C_GetITStatus(periph->reg_addr, I2C_IT_OVR)) { /* Overrun/Underrun */
+ periph->errors->over_under_cnt++;
+ I2C_ClearITPendingBit(periph->reg_addr, I2C_IT_OVR);
+ err_nr = 4;
+ }
+ if (I2C_GetITStatus(periph->reg_addr, I2C_IT_PECERR)) { /* PEC Error in reception */
+ periph->errors->pec_recep_cnt++;
+ I2C_ClearITPendingBit(periph->reg_addr, I2C_IT_PECERR);
+ err_nr = 5;
+ }
+ if (I2C_GetITStatus(periph->reg_addr, I2C_IT_TIMEOUT)) { /* Timeout or Tlow error */
+ periph->errors->timeout_tlow_cnt++;
+ I2C_ClearITPendingBit(periph->reg_addr, I2C_IT_TIMEOUT);
+ err_nr = 6;
+ }
+ if (I2C_GetITStatus(periph->reg_addr, I2C_IT_SMBALERT)) { /* SMBus alert */
+ periph->errors->smbus_alert_cnt++;
+ I2C_ClearITPendingBit(periph->reg_addr, I2C_IT_SMBALERT);
+ err_nr = 7;
+ }
+
+#ifdef I2C_DEBUG_LED
+ LED_ERROR(20, err_nr);
+#endif
+
+ return;
+
+}
+
+
+/*
+ // Make sure the bus is free before resetting (p722)
+ if (regs->SR2 & (I2C_FLAG_BUSY >> 16)) {
+ // Reset the I2C block
+ I2C_SoftwareResetCmd(periph->reg_addr, ENABLE);
+ I2C_SoftwareResetCmd(periph->reg_addr, DISABLE);
+ }
+*/
+
+//#endif /* USE_I2C2 */
+
+
+
+
+#ifdef USE_I2C1
+
+struct i2c_errors i2c1_errors;
+
+void i2c1_hw_init(void) {
+
+ i2c1.reg_addr = I2C1;
+ i2c1.init_struct = &I2C1_InitStruct;
+ i2c1.scl_pin = GPIO_Pin_6;
+ i2c1.sda_pin = GPIO_Pin_7;
+ i2c1.errors = &i2c1_errors;
+
+ /* zeros error counter */
+ ZEROS_ERR_COUNTER(i2c1_errors);
+
+ // Extra
+#ifdef I2C_DEBUG_LED
+ LED_INIT();
+#else
+
+ /* reset peripheral to default state ( sometimes not achieved on reset :( ) */
+ //I2C_DeInit(I2C1);
+
+ NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0);
+ NVIC_InitTypeDef NVIC_InitStructure;
+
+ /* Configure and enable I2C1 event interrupt --------------------------------*/
+ NVIC_InitStructure.NVIC_IRQChannel = I2C1_EV_IRQn;
+ NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
+ NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
+ NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
+ NVIC_Init(&NVIC_InitStructure);
+
+ /* Configure and enable I2C1 err interrupt ----------------------------------*/
+ NVIC_InitStructure.NVIC_IRQChannel = I2C1_ER_IRQn;
+ NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
+ NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
+ NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
+ NVIC_Init(&NVIC_InitStructure);
+
+ /* Enable peripheral clocks -------------------------------------------------*/
+ /* Enable I2C1 clock */
+ RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1, ENABLE);
+ /* Enable GPIOB clock */
+ RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
+
+ GPIO_InitTypeDef GPIO_InitStructure;
+ GPIO_InitStructure.GPIO_Pin = i2c1.scl_pin | i2c1.sda_pin;
+ GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;
+ GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_OD;
+ GPIO_Init(GPIOB, &GPIO_InitStructure);
+
+ I2C_DeInit(I2C1);
+
+ // enable peripheral
+ I2C_Cmd(I2C1, ENABLE);
+
+ I2C_Init(I2C1, i2c1.init_struct);
+
+ // enable error interrupts
+ I2C_ITConfig(I2C1, I2C_IT_ERR, ENABLE);
+
+#endif
+}
+
+void i2c1_ev_irq_handler(void) {
+ i2c_irq(&i2c1);
+}
+
+void i2c1_er_irq_handler(void) {
+ i2c_irq(&i2c1);
+}
+
+#endif /* USE_I2C1 */
+
+#ifdef USE_I2C2
+
+struct i2c_errors i2c2_errors;
+
+void i2c2_hw_init(void) {
+
+ i2c2.reg_addr = I2C2;
+ i2c2.init_struct = &I2C2_InitStruct;
+ i2c2.scl_pin = GPIO_Pin_10;
+ i2c2.sda_pin = GPIO_Pin_11;
+ i2c2.errors = &i2c2_errors;
+
+ /* zeros error counter */
+ ZEROS_ERR_COUNTER(i2c2_errors);
+
+ /* reset peripheral to default state ( sometimes not achieved on reset :( ) */
+ //I2C_DeInit(I2C2);
+
+ NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0);
+ NVIC_InitTypeDef NVIC_InitStructure;
+
+ /* Configure and enable I2C2 event interrupt --------------------------------*/
+ NVIC_InitStructure.NVIC_IRQChannel = I2C2_EV_IRQn;
+ NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
+ NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
+ NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
+ NVIC_Init(&NVIC_InitStructure);
+
+ /* Configure and enable I2C2 err interrupt ----------------------------------*/
+ NVIC_InitStructure.NVIC_IRQChannel = I2C2_ER_IRQn;
+ NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
+ NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
+ NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
+ NVIC_Init(&NVIC_InitStructure);
+
+ /* Enable peripheral clocks -------------------------------------------------*/
+ /* Enable I2C2 clock */
+ RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C2, ENABLE);
+ /* Enable GPIOB clock */
+ RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
+
+ GPIO_InitTypeDef GPIO_InitStructure;
+ GPIO_InitStructure.GPIO_Pin = i2c2.scl_pin | i2c2.sda_pin;
+ GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;
+ GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_OD;
+ GPIO_Init(GPIOB, &GPIO_InitStructure);
+
+ I2C_DeInit(I2C2);
+
+ // enable peripheral
+ I2C_Cmd(I2C2, ENABLE);
+
+ I2C_Init(I2C2, i2c2.init_struct);
+
+ // enable error interrupts
+ I2C_ITConfig(I2C2, I2C_IT_ERR, ENABLE);
+
+}
+
+
+
+void i2c2_ev_irq_handler(void) {
+ i2c_irq(&i2c2);
+}
+
+void i2c2_er_irq_handler(void) {
+ i2c_irq(&i2c2);
+}
+
+#endif /* USE_I2C2 */
+
+
+void i2c_setbitrate(struct i2c_periph *periph, int bitrate)
+{
+ if (i2c_idle(periph))
+ {
+ if (periph == &i2c2)
+ {
+ I2C2_InitStruct.I2C_ClockSpeed = bitrate;
+ I2C_Init(I2C2, i2c2.init_struct);
+ }
+
+#ifdef I2C_DEBUG_LED
+ __disable_irq();
+
+ LED2_ON();
+ LED1_ON();
+ LED2_OFF();
+ LED1_OFF();
+ LED2_ON();
+ LED1_ON();
+ LED2_OFF();
+ LED1_OFF();
+
+ __enable_irq();
+#endif
+
+ }
+}
+
+void i2c_event(void)
+{
+ static uint32_t cnt = 0;
+ //I2C_TypeDef *regs;
+ cnt++;
+ if (cnt > 10000) cnt = 0;
+
+#ifndef I2C_DEBUG_LED
+#ifdef USE_I2C1
+ if (i2c1.status == I2CIdle)
+ {
+ if (i2c_idle(&i2c1))
+ {
+ __disable_irq();
+ // More work to do
+ if (i2c1.trans_extract_idx != i2c1.trans_insert_idx)
+ {
+ // Restart transaction doing the Rx part now
+ PPRZ_I2C_SEND_START(&i2c1);
+ }
+ __enable_irq();
+ }
+ }
+#endif
+#endif
+
+#ifdef USE_I2C2
+
+#ifdef I2C_DEBUG_LED
+ if (cnt == 0)
+ {
+ __disable_irq();
+
+ LED2_ON();
+ LED1_ON();
+ LED1_OFF();
+ LED1_ON();
+ LED1_OFF();
+ LED1_ON();
+ LED1_OFF();
+ LED1_ON();
+ LED1_OFF();
+ if (i2c2.status == I2CIdle)
+ {
+ LED1_ON();
+ LED1_OFF();
+ }
+ else if (i2c2.status == I2CStartRequested)
+ {
+ LED1_ON();
+ LED1_OFF();
+ LED1_ON();
+ LED1_OFF();
+
+ }
+ LED2_OFF();
+
+ //regs = (I2C_TypeDef *) i2c2.reg_addr;
+ //LED_SHOW_ACTIVE_BITS(regs);
+
+ __enable_irq();
+ }
+#endif
+
+
+ //if (i2c2.status == I2CIdle)
+ {
+ //if (i2c_idle(&i2c2))
+ {
+ //__disable_irq();
+ // More work to do
+ //if (i2c2.trans_extract_idx != i2c2.trans_insert_idx)
+ {
+ // Restart transaction doing the Rx part now
+ //PPRZ_I2C_SEND_START(&i2c2);
+ }
+ //__enable_irq();
+ }
+ }
+#endif
+}
+
+/////////////////////////////////////////////////////////
+// Implement Interface Functions
+
+bool_t i2c_submit(struct i2c_periph* periph, struct i2c_transaction* t) {
+
+ uint8_t temp;
+ temp = periph->trans_insert_idx + 1;
+ if (temp >= I2C_TRANSACTION_QUEUE_LEN) temp = 0;
+ if (temp == periph->trans_extract_idx)
+ return FALSE; // queue full
+
+ t->status = I2CTransPending;
+
+ __disable_irq();
+ /* put transacation in queue */
+ periph->trans[periph->trans_insert_idx] = t;
+ periph->trans_insert_idx = temp;
+
+ /* if peripheral is idle, start the transaction */
+ // if (PPRZ_I2C_IS_IDLE(p))
+ if (periph->status == I2CIdle)
+ {
+ //if (i2c_idle(periph))
+ {
+#ifdef I2C_DEBUG_LED
+ if (periph == &i2c1)
+ {
+
+ }
+ else
+#endif
+ {
+ PPRZ_I2C_SEND_START(periph);
+ }
+ }
+ }
+ /* else it will be started by the interrupt handler when the previous transactions completes */
+ __enable_irq();
+
+ return TRUE;
+}
+
+bool_t i2c_idle(struct i2c_periph* periph)
+{
+ I2C_TypeDef *regs = (I2C_TypeDef *) periph->reg_addr;
+
+#ifdef I2C_DEBUG_LED
+ if (periph == &i2c1)
+ {
+ return TRUE;
+ }
+#endif
+ if (periph->status == I2CIdle)
+ return ! (BIT_X_IS_SET_IN_REG( I2C_SR2_BIT_BUSY, regs->SR2 ) );
+ else
+ return FALSE;
+}
+
+
diff --git a/sw/airborne/boards/lisa_l/baro_board.c b/sw/airborne/boards/lisa_l/baro_board.c
index 30699d68f2..63f85722e9 100644
--- a/sw/airborne/boards/lisa_l/baro_board.c
+++ b/sw/airborne/boards/lisa_l/baro_board.c
@@ -26,6 +26,7 @@ void baro_init(void) {
void baro_periodic(void) {
// check i2c_done
if (!i2c_idle(&i2c2)) return;
+
switch (baro_board.status) {
case LBS_UNINITIALIZED:
baro_board_send_reset();
diff --git a/sw/airborne/boards/lisa_l/test_baro.c b/sw/airborne/boards/lisa_l/test_baro.c
index 6dad99c825..7acc75d542 100644
--- a/sw/airborne/boards/lisa_l/test_baro.c
+++ b/sw/airborne/boards/lisa_l/test_baro.c
@@ -1,6 +1,4 @@
/*
- * $Id$
- *
* Copyright (C) 2009 Antoine Drouin
*
* This file is part of paparazzi.
@@ -32,6 +30,7 @@
#include "mcu.h"
#include "mcu_periph/sys_time.h"
#include "mcu_periph/uart.h"
+#include "mcu_periph/i2c.h"
#include "led.h"
@@ -47,7 +46,6 @@ static inline void main_event_task( void );
static inline void main_on_baro_diff(void);
static inline void main_on_baro_abs(void);
-
int main(void) {
main_init();
@@ -81,15 +79,15 @@ static inline void main_periodic_task( void ) {
RunOnceEvery(256,
{
DOWNLINK_SEND_I2C_ERRORS(DefaultChannel, DefaultDevice,
- &i2c2_errors.ack_fail_cnt,
- &i2c2_errors.miss_start_stop_cnt,
- &i2c2_errors.arb_lost_cnt,
- &i2c2_errors.over_under_cnt,
- &i2c2_errors.pec_recep_cnt,
- &i2c2_errors.timeout_tlow_cnt,
- &i2c2_errors.smbus_alert_cnt,
- &i2c2_errors.unexpected_event_cnt,
- &i2c2_errors.last_unexpected_event);
+ &i2c2.errors->ack_fail_cnt,
+ &i2c2.errors->miss_start_stop_cnt,
+ &i2c2.errors->arb_lost_cnt,
+ &i2c2.errors->over_under_cnt,
+ &i2c2.errors->pec_recep_cnt,
+ &i2c2.errors->timeout_tlow_cnt,
+ &i2c2.errors->smbus_alert_cnt,
+ &i2c2.errors->unexpected_event_cnt,
+ &i2c2.errors->last_unexpected_event);
});
}
diff --git a/sw/airborne/firmwares/fixedwing/main_ap.c b/sw/airborne/firmwares/fixedwing/main_ap.c
index a6e0c6a37b..1859d46ffc 100644
--- a/sw/airborne/firmwares/fixedwing/main_ap.c
+++ b/sw/airborne/firmwares/fixedwing/main_ap.c
@@ -583,6 +583,10 @@ void monitor_task( void ) {
/*********** EVENT ***********************************************************/
void event_task_ap( void ) {
+#ifndef SINGLE_MCU
+ i2c_event();
+#endif
+
#if USE_AHRS
#if USE_IMU
ImuEvent(on_gyro_event, on_accel_event, on_mag_event);
diff --git a/sw/airborne/firmwares/fixedwing/main_fbw.c b/sw/airborne/firmwares/fixedwing/main_fbw.c
index cce4d39533..6fd9d48cda 100644
--- a/sw/airborne/firmwares/fixedwing/main_fbw.c
+++ b/sw/airborne/firmwares/fixedwing/main_fbw.c
@@ -43,6 +43,7 @@
#include "firmwares/fixedwing/autopilot.h"
#include "fbw_downlink.h"
#include "paparazzi.h"
+#include "mcu_periph/i2c.h"
#ifdef MCU_SPI_LINK
#include "link_mcu.h"
@@ -119,6 +120,7 @@ void event_task_fbw( void) {
RadioControlEvent(handle_rc_frame);
#endif
+ i2c_event();
#ifdef INTER_MCU
#ifdef MCU_SPI_LINK
diff --git a/sw/airborne/firmwares/rotorcraft/main.c b/sw/airborne/firmwares/rotorcraft/main.c
index 6c77647499..ed193506ff 100644
--- a/sw/airborne/firmwares/rotorcraft/main.c
+++ b/sw/airborne/firmwares/rotorcraft/main.c
@@ -196,6 +196,8 @@ STATIC_INLINE void failsafe_check( void ) {
STATIC_INLINE void main_event( void ) {
+ i2c_event();
+
DatalinkEvent();
if (autopilot_rc) {
diff --git a/sw/airborne/firmwares/rotorcraft/telemetry.h b/sw/airborne/firmwares/rotorcraft/telemetry.h
index 88e22748d6..11686c0513 100644
--- a/sw/airborne/firmwares/rotorcraft/telemetry.h
+++ b/sw/airborne/firmwares/rotorcraft/telemetry.h
@@ -48,8 +48,8 @@
#endif
#include "subsystems/ins.h"
#include "subsystems/ahrs.h"
-//FIXME: wtf ??!!
-#include "mcu_periph/i2c_arch.h"
+// I2C Error counters
+#include "mcu_periph/i2c.h"
#define PERIODIC_SEND_ALIVE(_trans, _dev) DOWNLINK_SEND_ALIVE(_trans, _dev, 16, MD5SUM)
@@ -736,16 +736,43 @@
&ahrs.ltp_to_body_euler.psi); \
}
-#define PERIODIC_SEND_I2C_ERRORS(_trans, _dev) { \
- DOWNLINK_SEND_I2C_ERRORS(_trans, _dev, \
- &i2c_errc_ack_fail, \
- &i2c_errc_miss_start_stop, \
- &i2c_errc_arb_lost, \
- &i2c_errc_over_under, \
- &i2c_errc_pec_recep, \
- &i2c_errc_timeout_tlow, \
- &i2c_errc_smbus_alert \
- ); \
+#ifdef USE_I2C1
+#define PERIODIC_SEND_I2C1_ERRORS(_trans, _dev) { \
+ DOWNLINK_SEND_I2C_ERRORS(_trans, _dev, \
+ &i2c1.errors->ack_fail_cnt, \
+ &i2c1.errors->miss_start_stop_cnt, \
+ &i2c1.errors->arb_lost_cnt, \
+ &i2c1.errors->over_under_cnt, \
+ &i2c1.errors->pec_recep_cnt, \
+ &i2c1.errors->timeout_tlow_cnt, \
+ &i2c1.errors->smbus_alert_cnt, \
+ &i2c1.errors->unexpected_event_cnt, \
+ &i2c1.errors->last_unexpected_event); \
+ }
+#else
+#define PERIODIC_SEND_I2C1_ERRORS(_trans, _dev) {}
+#endif
+
+#ifdef USE_I2C2
+#define PERIODIC_SEND_I2C2_ERRORS(_trans, _dev) { \
+ DOWNLINK_SEND_I2C_ERRORS(_trans, _dev, \
+ &i2c2.errors->ack_fail_cnt, \
+ &i2c2.errors->miss_start_stop_cnt, \
+ &i2c2.errors->arb_lost_cnt, \
+ &i2c2.errors->over_under_cnt, \
+ &i2c2.errors->pec_recep_cnt, \
+ &i2c2.errors->timeout_tlow_cnt, \
+ &i2c2.errors->smbus_alert_cnt, \
+ &i2c2.errors->unexpected_event_cnt, \
+ &i2c2.errors->last_unexpected_event); \
+ }
+#else
+#define PERIODIC_SEND_I2C2_ERRORS(_trans, _dev) {}
+#endif
+
+#define PERIODIC_SEND_I2C_ERRORS(_trans, _dev) { \
+ PERIODIC_SEND_I2C1_ERRORS(_trans, _dev); \
+ PERIODIC_SEND_I2C2_ERRORS(_trans, _dev); \
}
// FIXME: still used?? or replace by EXTRA_ADC
diff --git a/sw/airborne/lisa/test/lisa_test_hmc5843.c b/sw/airborne/lisa/test/lisa_test_hmc5843.c
index 7fa7117b92..4b12e8afc8 100644
--- a/sw/airborne/lisa/test/lisa_test_hmc5843.c
+++ b/sw/airborne/lisa/test/lisa_test_hmc5843.c
@@ -41,6 +41,7 @@
#include "led.h"
#include "mcu_periph/uart.h"
+#include "mcu_periph/i2c.h"
#include "peripherals/hmc5843.h"
#include "my_debug_servo.h"
#include "math/pprz_algebra_int.h"
@@ -91,15 +92,15 @@ static inline void main_periodic_task( void ) {
RunOnceEvery(256,
{
DOWNLINK_SEND_I2C_ERRORS(DefaultChannel, DefaultDevice,
- &i2c2_errors.ack_fail_cnt,
- &i2c2_errors.miss_start_stop_cnt,
- &i2c2_errors.arb_lost_cnt,
- &i2c2_errors.over_under_cnt,
- &i2c2_errors.pec_recep_cnt,
- &i2c2_errors.timeout_tlow_cnt,
- &i2c2_errors.smbus_alert_cnt,
- &i2c2_errors.unexpected_event_cnt,
- &i2c2_errors.last_unexpected_event);
+ &i2c2.errors->ack_fail_cnt,
+ &i2c2.errors->miss_start_stop_cnt,
+ &i2c2.errors->arb_lost_cnt,
+ &i2c2.errors->over_under_cnt,
+ &i2c2.errors->pec_recep_cnt,
+ &i2c2.errors->timeout_tlow_cnt,
+ &i2c2.errors->smbus_alert_cnt,
+ &i2c2.errors->unexpected_event_cnt,
+ &i2c2.errors->last_unexpected_event);
});
if (mag_state == 2) send_config();
diff --git a/sw/airborne/lisa/test/lisa_test_itg3200.c b/sw/airborne/lisa/test/lisa_test_itg3200.c
index e52ec68a87..34db0cfc73 100644
--- a/sw/airborne/lisa/test/lisa_test_itg3200.c
+++ b/sw/airborne/lisa/test/lisa_test_itg3200.c
@@ -88,15 +88,15 @@ static inline void main_periodic_task( void ) {
});
RunOnceEvery(256, {
DOWNLINK_SEND_I2C_ERRORS(DefaultChannel, DefaultDevice,
- &i2c2_errors.ack_fail_cnt,
- &i2c2_errors.miss_start_stop_cnt,
- &i2c2_errors.arb_lost_cnt,
- &i2c2_errors.over_under_cnt,
- &i2c2_errors.pec_recep_cnt,
- &i2c2_errors.timeout_tlow_cnt,
- &i2c2_errors.smbus_alert_cnt,
- &i2c2_errors.unexpected_event_cnt,
- &i2c2_errors.last_unexpected_event);
+ &i2c2.errors->ack_fail_cnt,
+ &i2c2.errors->miss_start_stop_cnt,
+ &i2c2.errors->arb_lost_cnt,
+ &i2c2.errors->over_under_cnt,
+ &i2c2.errors->pec_recep_cnt,
+ &i2c2.errors->timeout_tlow_cnt,
+ &i2c2.errors->smbus_alert_cnt,
+ &i2c2.errors->unexpected_event_cnt,
+ &i2c2.errors->last_unexpected_event);
});
switch (gyro_state) {
diff --git a/sw/airborne/lisa/test/test_board.c b/sw/airborne/lisa/test/test_board.c
index 4f9b27744d..7e01422dd3 100644
--- a/sw/airborne/lisa/test/test_board.c
+++ b/sw/airborne/lisa/test/test_board.c
@@ -1,6 +1,4 @@
/*
- * $Id$
- *
* Copyright (C) 2008-2009 Antoine Drouin
*
* This file is part of paparazzi.
@@ -31,6 +29,7 @@
#include "std.h"
#include "mcu.h"
#include "mcu_periph/uart.h"
+#include "mcu_periph/i2c.h"
#include "mcu_periph/sys_time.h"
#include "subsystems/datalink/downlink.h"
#include "led.h"
@@ -157,15 +156,15 @@ static void test_baro_periodic(void) {
RunOnceEvery(2, {baro_periodic();});
RunOnceEvery(100,{
DOWNLINK_SEND_I2C_ERRORS(DefaultChannel, DefaultDevice,
- &i2c2_errors.ack_fail_cnt,
- &i2c2_errors.miss_start_stop_cnt,
- &i2c2_errors.arb_lost_cnt,
- &i2c2_errors.over_under_cnt,
- &i2c2_errors.pec_recep_cnt,
- &i2c2_errors.timeout_tlow_cnt,
- &i2c2_errors.smbus_alert_cnt,
- &i2c2_errors.unexpected_event_cnt,
- &i2c2_errors.last_unexpected_event);
+ &i2c2.errors->ack_fail_cnt,
+ &i2c2.errors->miss_start_stop_cnt,
+ &i2c2.errors->arb_lost_cnt,
+ &i2c2.errors->over_under_cnt,
+ &i2c2.errors->pec_recep_cnt,
+ &i2c2.errors->timeout_tlow_cnt,
+ &i2c2.errors->smbus_alert_cnt,
+ &i2c2.errors->unexpected_event_cnt,
+ &i2c2.errors->last_unexpected_event);
});
}
static void test_baro_event(void) {BaroEvent(test_baro_on_baro_abs, test_baro_on_baro_diff);}
@@ -191,15 +190,15 @@ static void test_bldc_periodic(void) {
RunOnceEvery(100,{
DOWNLINK_SEND_I2C_ERRORS(DefaultChannel, DefaultDevice,
- &i2c1_errors.ack_fail_cnt,
- &i2c1_errors.miss_start_stop_cnt,
- &i2c1_errors.arb_lost_cnt,
- &i2c1_errors.over_under_cnt,
- &i2c1_errors.pec_recep_cnt,
- &i2c1_errors.timeout_tlow_cnt,
- &i2c1_errors.smbus_alert_cnt,
- &i2c1_errors.unexpected_event_cnt,
- &i2c1_errors.last_unexpected_event);
+ &i2c1.errors->ack_fail_cnt,
+ &i2c1.errors->miss_start_stop_cnt,
+ &i2c1.errors->arb_lost_cnt,
+ &i2c1.errors->over_under_cnt,
+ &i2c1.errors->pec_recep_cnt,
+ &i2c1.errors->timeout_tlow_cnt,
+ &i2c1.errors->smbus_alert_cnt,
+ &i2c1.errors->unexpected_event_cnt,
+ &i2c1.errors->last_unexpected_event);
});
}
diff --git a/sw/airborne/mcu_periph/i2c.h b/sw/airborne/mcu_periph/i2c.h
index 93bd0f77ba..b0df164c10 100644
--- a/sw/airborne/mcu_periph/i2c.h
+++ b/sw/airborne/mcu_periph/i2c.h
@@ -133,6 +133,9 @@ extern void i2c2_init(void);
extern void i2c_init(struct i2c_periph* p);
extern bool_t i2c_idle(struct i2c_periph* p);
extern bool_t i2c_submit(struct i2c_periph* p, struct i2c_transaction* t);
+extern void i2c_setbitrate(struct i2c_periph* p, int bitrate);
+extern void i2c_event(void);
+
#define I2CReceive(_p, _t, _s_addr, _len) { \
_t.type = I2CTransRx; \
diff --git a/sw/airborne/modules/benchmark/i2c_abuse_test.c b/sw/airborne/modules/benchmark/i2c_abuse_test.c
index 7a9b078caa..d5bee73822 100644
--- a/sw/airborne/modules/benchmark/i2c_abuse_test.c
+++ b/sw/airborne/modules/benchmark/i2c_abuse_test.c
@@ -1,7 +1,7 @@
/*
* $Id$
*
- * Copyright (C) 2009 Gautier Hattenberger
+ * Copyright (C) 2011 Christophe De Wagter
*
* This file is part of paparazzi.
*
@@ -29,8 +29,8 @@
struct i2c_transaction i2c_test1;
struct i2c_transaction i2c_test2;
-uint8_t i2c_abuse_test_counter = 0;
-uint16_t i2c_abuse_test_bitrate = 1000;
+volatile uint8_t i2c_abuse_test_counter = 0;
+volatile uint32_t i2c_abuse_test_bitrate = 1000;
void init_i2c_abuse_test(void) {
//LED_INIT(DEMO_MODULE_LED);
@@ -62,59 +62,59 @@ static void i2c_abuse_send_transaction(uint8_t _init)
i2c_test1.buf[2] = 0x01<<5;
i2c_test1.buf[3] = 0x00;
i2c_test1.len_w = 4;
- i2c_submit(&i2c2,&i2c_test1);
+ i2c_submit(&I2C_ABUSE_PORT,&i2c_test1);
break;
case 2:
i2c_test1.type = I2CTransTx;
i2c_test1.buf[0] = 0x01; // set to gain to 1 Gauss
i2c_test1.buf[1] = 0x01<<5;
i2c_test1.len_w = 2;
- i2c_submit(&i2c2,&i2c_test1);
+ i2c_submit(&I2C_ABUSE_PORT,&i2c_test1);
break;
case 3:
i2c_test1.type = I2CTransTx;
i2c_test1.buf[0] = 0x00; // set to continuous mode
i2c_test1.len_w = 1;
- i2c_submit(&i2c2,&i2c_test1);
+ i2c_submit(&I2C_ABUSE_PORT,&i2c_test1);
break;
case 4:
i2c_test1.type = I2CTransRx;
i2c_test1.len_r = 1;
- i2c_submit(&i2c2,&i2c_test1);
+ i2c_submit(&I2C_ABUSE_PORT,&i2c_test1);
break;
case 5:
i2c_test1.type = I2CTransRx;
i2c_test1.len_r = 2;
- i2c_submit(&i2c2,&i2c_test1);
+ i2c_submit(&I2C_ABUSE_PORT,&i2c_test1);
break;
case 6:
i2c_test1.type = I2CTransRx;
i2c_test1.len_r = 3;
- i2c_submit(&i2c2,&i2c_test1);
+ i2c_submit(&I2C_ABUSE_PORT,&i2c_test1);
break;
case 7:
i2c_test1.type = I2CTransRx;
i2c_test1.len_r = 4;
- i2c_submit(&i2c2,&i2c_test1);
+ i2c_submit(&I2C_ABUSE_PORT,&i2c_test1);
break;
case 8:
i2c_test1.type = I2CTransRx;
i2c_test1.len_r = 5;
- i2c_submit(&i2c2,&i2c_test1);
+ i2c_submit(&I2C_ABUSE_PORT,&i2c_test1);
break;
case 9:
// bad addr
i2c_test1.slave_addr = 0x3C + 2;
i2c_test1.type = I2CTransTx;
i2c_test1.len_w = 1;
- i2c_submit(&i2c2,&i2c_test1);
+ i2c_submit(&I2C_ABUSE_PORT,&i2c_test1);
break;
case 10:
// 2 consecutive
i2c_test1.type = I2CTransTx;
i2c_test1.buf[0] = 0x00; // set to continuous mode
i2c_test1.len_w = 1;
- i2c_submit(&i2c2,&i2c_test1);
+ i2c_submit(&I2C_ABUSE_PORT,&i2c_test1);
break;
case 11:
i2c_test1.slave_addr = 0x3C;
@@ -122,7 +122,7 @@ static void i2c_abuse_send_transaction(uint8_t _init)
i2c_test1.len_r = 1;
i2c_test1.len_w = 1;
i2c_test1.buf[0] = 0x03;
- i2c_submit(&i2c2, &i2c_test1);
+ i2c_submit(&I2C_ABUSE_PORT, &i2c_test1);
break;
case 12:
i2c_test1.slave_addr = 0x3C;
@@ -130,7 +130,7 @@ static void i2c_abuse_send_transaction(uint8_t _init)
i2c_test1.len_r = 2;
i2c_test1.len_w = 1;
i2c_test1.buf[0] = 0x03;
- i2c_submit(&i2c2, &i2c_test1);
+ i2c_submit(&I2C_ABUSE_PORT, &i2c_test1);
break;
case 13:
i2c_test1.slave_addr = 0x3C;
@@ -138,7 +138,7 @@ static void i2c_abuse_send_transaction(uint8_t _init)
i2c_test1.len_r = 3;
i2c_test1.len_w = 1;
i2c_test1.buf[0] = 0x03;
- i2c_submit(&i2c2, &i2c_test1);
+ i2c_submit(&I2C_ABUSE_PORT, &i2c_test1);
break;
case 14:
i2c_test1.slave_addr = 0x3C;
@@ -146,7 +146,7 @@ static void i2c_abuse_send_transaction(uint8_t _init)
i2c_test1.len_r = 4;
i2c_test1.len_w = 1;
i2c_test1.buf[0] = 0x03;
- i2c_submit(&i2c2, &i2c_test1);
+ i2c_submit(&I2C_ABUSE_PORT, &i2c_test1);
break;
case 15:
i2c_test1.slave_addr = 0x3C;
@@ -154,7 +154,7 @@ static void i2c_abuse_send_transaction(uint8_t _init)
i2c_test1.len_r = 4;
i2c_test1.len_w = 2;
i2c_test1.buf[0] = 0x03;
- i2c_submit(&i2c2, &i2c_test1);
+ i2c_submit(&I2C_ABUSE_PORT, &i2c_test1);
break;
default:
i2c_test1.slave_addr = 0x3C;
@@ -162,25 +162,14 @@ static void i2c_abuse_send_transaction(uint8_t _init)
i2c_test1.len_r = 5;
i2c_test1.len_w = 1;
i2c_test1.buf[0] = 0x03;
- i2c_submit(&i2c2, &i2c_test1);
+ i2c_submit(&I2C_ABUSE_PORT, &i2c_test1);
}
}
void event_i2c_abuse_test(void)
{
- if (i2c_idle(&i2c1))
- {
- LED_ON(7); // green = idle
- LED_OFF(6);
- }
- else
- {
- LED_ON(6); // red = busy
- LED_OFF(7);
- }
-
- if (i2c_idle(&i2c2))
+ if (i2c_idle(&I2C_ABUSE_PORT))
{
LED_ON(5); // green = idle
LED_OFF(4);
@@ -200,7 +189,7 @@ void event_i2c_abuse_test(void)
i2c_test2.type = I2CTransRx;
i2c_test2.slave_addr = 0x92;
i2c_test2.len_r = 2;
- i2c_submit(&i2c2,&i2c_test2);
+ i2c_submit(&I2C_ABUSE_PORT,&i2c_test2);
}
}
@@ -214,31 +203,29 @@ void event_i2c_abuse_test(void)
else
{
// wait until ready:
- if (i2c_idle(&i2c2))
+ if (i2c_idle(&I2C_ABUSE_PORT))
{
i2c_abuse_test_counter = 1;
- i2c_setbitrate(&i2c2, i2c_abuse_test_bitrate);
+ i2c_setbitrate(&I2C_ABUSE_PORT, i2c_abuse_test_bitrate);
i2c_abuse_test_bitrate += 17000;
- if (i2c_abuse_test_bitrate > 500000)
+ if (i2c_abuse_test_bitrate > 410000)
{
- i2c_abuse_test_bitrate -= 500000;
+ i2c_abuse_test_bitrate -= 410000;
}
- LED_TOGGLE(4);
}
}
if (i2c_abuse_test_counter < 16)
{
+ RunOnceEvery(100,LED_TOGGLE(I2C_ABUSE_LED));
i2c_abuse_send_transaction( i2c_abuse_test_counter );
- LED_TOGGLE(5);
}
}
}
void periodic_50Hz_i2c_abuse_test(void) {
- // LED_TOGGLE(DEMO_MODULE_LED);
}
diff --git a/sw/airborne/modules/benchmark/i2c_abuse_test.h b/sw/airborne/modules/benchmark/i2c_abuse_test.h
index e6e7b0634a..bc58dc900d 100644
--- a/sw/airborne/modules/benchmark/i2c_abuse_test.h
+++ b/sw/airborne/modules/benchmark/i2c_abuse_test.h
@@ -1,7 +1,7 @@
/*
* $Id$
*
- * Copyright (C) 2009 C. De Wagter
+ * Copyright (C) 2011 Christophe De Wagter
*
* This file is part of paparazzi.
*
diff --git a/sw/airborne/subsystems/imu/imu_aspirin.h b/sw/airborne/subsystems/imu/imu_aspirin.h
index b96e2bf167..a00c60371b 100644
--- a/sw/airborne/subsystems/imu/imu_aspirin.h
+++ b/sw/airborne/subsystems/imu/imu_aspirin.h
@@ -151,6 +151,9 @@ extern void imu_aspirin_arch_init(void);
static inline void gyro_read_i2c(void)
{
+ imu_aspirin.i2c_trans_gyro.type = I2CTransTxRx;
+ imu_aspirin.i2c_trans_gyro.len_w = 1;
+ imu_aspirin.i2c_trans_gyro.len_r = 6;
imu_aspirin.i2c_trans_gyro.buf[0] = ITG3200_REG_GYRO_XOUT_H;
i2c_submit(&i2c2,&imu_aspirin.i2c_trans_gyro);
imu_aspirin.reading_gyro = 1;
diff --git a/sw/airborne/test/subsystems/test_ahrs.c b/sw/airborne/test/subsystems/test_ahrs.c
index 797ef517ee..2bb6d1b67b 100644
--- a/sw/airborne/test/subsystems/test_ahrs.c
+++ b/sw/airborne/test/subsystems/test_ahrs.c
@@ -28,6 +28,7 @@
#include "mcu_periph/sys_time.h"
#include "led.h"
#include "mcu_periph/uart.h"
+#include "mcu_periph/i2c.h"
#include "messages.h"
#include "subsystems/datalink/downlink.h"
@@ -161,15 +162,15 @@ static inline void main_report(void) {
{
#ifdef USE_I2C2
DOWNLINK_SEND_I2C_ERRORS(DefaultChannel, DefaultDevice,
- &i2c2_errors.ack_fail_cnt,
- &i2c2_errors.miss_start_stop_cnt,
- &i2c2_errors.arb_lost_cnt,
- &i2c2_errors.over_under_cnt,
- &i2c2_errors.pec_recep_cnt,
- &i2c2_errors.timeout_tlow_cnt,
- &i2c2_errors.smbus_alert_cnt,
- &i2c2_errors.unexpected_event_cnt,
- &i2c2_errors.last_unexpected_event);
+ &i2c2.errors->ack_fail_cnt,
+ &i2c2.errors->miss_start_stop_cnt,
+ &i2c2.errors->arb_lost_cnt,
+ &i2c2.errors->over_under_cnt,
+ &i2c2.errors->pec_recep_cnt,
+ &i2c2.errors->timeout_tlow_cnt,
+ &i2c2.errors->smbus_alert_cnt,
+ &i2c2.errors->unexpected_event_cnt,
+ &i2c2.errors->last_unexpected_event);
#endif
},
{
diff --git a/sw/airborne/test/subsystems/test_imu.c b/sw/airborne/test/subsystems/test_imu.c
index 0791bd086f..b7f439bfb2 100644
--- a/sw/airborne/test/subsystems/test_imu.c
+++ b/sw/airborne/test/subsystems/test_imu.c
@@ -31,6 +31,7 @@
#include "mcu_periph/sys_time.h"
#include "led.h"
#include "mcu_periph/uart.h"
+#include "mcu_periph/i2c.h"
#include "messages.h"
#include "subsystems/datalink/downlink.h"
@@ -82,18 +83,18 @@ static inline void main_periodic_task( void ) {
#ifdef USE_I2C2
RunOnceEvery(111, {
DOWNLINK_SEND_I2C_ERRORS(DefaultChannel, DefaultDevice,
- &i2c2_errors.ack_fail_cnt,
- &i2c2_errors.miss_start_stop_cnt,
- &i2c2_errors.arb_lost_cnt,
- &i2c2_errors.over_under_cnt,
- &i2c2_errors.pec_recep_cnt,
- &i2c2_errors.timeout_tlow_cnt,
- &i2c2_errors.smbus_alert_cnt,
- &i2c2_errors.unexpected_event_cnt,
- &i2c2_errors.last_unexpected_event);
+ &i2c2.errors->ack_fail_cnt,
+ &i2c2.errors->miss_start_stop_cnt,
+ &i2c2.errors->arb_lost_cnt,
+ &i2c2.errors->over_under_cnt,
+ &i2c2.errors->pec_recep_cnt,
+ &i2c2.errors->timeout_tlow_cnt,
+ &i2c2.errors->smbus_alert_cnt,
+ &i2c2.errors->unexpected_event_cnt,
+ &i2c2.errors->last_unexpected_event);
});
#endif
- if (cpu_time_sec > 1) imu_periodic();
+ if (sys_time.nb_sec > 1) imu_periodic();
RunOnceEvery(10, { LED_PERIODIC();});
}