AnsweredAssumed Answered

STM32F4 I2C Interrupt reset in error case

Question asked by mirk.hjl on Nov 13, 2016
Hi,

I have an I2C bus in use, where from time to time an error can occur on the I2C bus. Now I need a proper error handling to reset the I2C in runtime, but how can I manage this? I tried to reinitialize the DMA and the I2C, and so I am able to write/read again from the I2C bus without the interrupt, but the interrupt routine goes crazy after the reset and is polled the whole time with error events when I use I2C_ITConfig(I2C2, I2C_IT_EVT, ENABLE); 

Now my question, how can I reset the I2C2_EV_IRQHandler() ? Reinitialization of the NVIC seems not to work.

Here my code for the whole I2C handling:


#include "I2C_DMA_INTERRUPT.h"
 
/*
 * private variables
 */
 
uint8_t MPU6050_RX_BUFF[MPU6050_BUFF_SIZE_RX];
uint8_t MPU6050_TX_BUFF[MPU6050_BUFF_SIZE_TX]; // We need only to write the register value for ACC -> 0x3B
 
uint8_t isNewData = 0; //For initialization
uint8_t dmaStarted=0;
uint8_t dataReadyMPU=0;
uint8_t tx_finish;
uint8_t interrupt_error=0;
uint8_t i2c_hard_failure=0;
 
/*
 * global functions
 */
 
uint8_t startMPU6050() {
    Fill_Buffer(MPU6050_RX_BUFF,MPU6050_BUFF_SIZE_RX);
    MPU6050_TX_BUFF[0]=(uint8_t)ACCEL_ADDR;
    uint8_t fail_flag=0;
 
    I2C_I2C_init();
    I2C_GPIO_init();
    I2C_DMA_init();
 
    //Power ON
    fail_flag|=writeI2C(MPU6050_ADDRESS_1,MPU6050_PWR,0x00); //Power up MPU6050_1
 
    //Gyro Mode
    fail_flag|=writeI2C(MPU6050_ADDRESS_1,0x1B,MPU6050_GYRO_MODE); //Gyro Mode: 1000°/s
 
    //Set Sampling mode filtered
    fail_flag|=writeI2C(MPU6050_ADDRESS_1,0x1A,MPU6050_DLPF);
 
 
 
 
    return fail_flag;
}
 
uint8_t restartMPU6050() {
    uint8_t fail_flag=0;
    dmaStarted=0;
    isNewData =0;
    i2c_hard_failure=0;
 
    //First solve problems:
    unlockI2C();
 
    I2C_I2C_init();
    I2C_GPIO_init();
    I2C_DMA_init();
 
    //Power ON
    fail_flag|=writeI2C(MPU6050_ADDRESS_1,MPU6050_PWR,0x00); //Power up MPU6050_1
 
    //Gyro Mode
    fail_flag|=writeI2C(MPU6050_ADDRESS_1,0x1B,MPU6050_GYRO_MODE); //Gyro Mode: 1000°/s
 
    //Set Sampling mode filtered
    fail_flag|=writeI2C(MPU6050_ADDRESS_1,0x1A,MPU6050_DLPF);
 
    /*int a1=0;
    int a2=0;
    readI2C1(MPU6050_ADDRESS_1,0,ACCEL_ADDR,&a1);
    readI2C1(MPU6050_ADDRESS_1,0,ACCEL_ADDR,&a2);
    int a = (a1<<8)|a2;*/
 
 
    return fail_flag;
}
 
void unlockI2C() {
    /*GPIO_InitTypeDef gpioInit;
    gpioInit.GPIO_Pin = I2Cx_SCL_PIN;
    gpioInit.GPIO_Mode = GPIO_Mode_OUT;
    gpioInit.GPIO_Speed = GPIO_Speed_100MHz;
    gpioInit.GPIO_OType = GPIO_OType_OD;
    gpioInit.GPIO_PuPd  = GPIO_PuPd_NOPULL;
    GPIO_Init(I2Cx_SCL_GPIO_PORT, &gpioInit);*/
 
    GPIO_InitTypeDef gpioInit;
    gpioInit.GPIO_Pin = I2Cx_SCL_PIN;
    gpioInit.GPIO_Mode = GPIO_Mode_OUT;
    gpioInit.GPIO_Speed = GPIO_Speed_100MHz;
    gpioInit.GPIO_OType = GPIO_OType_OD;
    gpioInit.GPIO_PuPd  = GPIO_PuPd_NOPULL;
    GPIO_Init(I2Cx_SCL_GPIO_PORT, &gpioInit);
 
    gpioInit.GPIO_Pin = I2Cx_SDA_PIN;
    gpioInit.GPIO_Mode = GPIO_Mode_IN;
    GPIO_Init(I2Cx_SCL_GPIO_PORT, &gpioInit);
 
    uint8_t j=GPIO_ReadInputDataBit(GPIOB, I2Cx_SDA_PIN);
 
    while(j==0) {
        GPIO_ToggleBits(GPIOB, I2Cx_SCL_PIN);
        for(int i=0;i<1000;i++); //little delay
        j=GPIO_ReadInputDataBit(GPIOB, I2Cx_SDA_PIN);
    }
    I2C_stop();
}
 
void I2C_I2C_init(void) {
 
    I2C_Cmd(I2C2, DISABLE);
    I2C_DeInit(I2C2);
    I2C_InitTypeDef i2cInit;
 
    clearAllI2CFlags();
 
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C2, ENABLE);
    RCC_APB1PeriphClockCmd(I2Cx_CLK, ENABLE);
    RCC_AHB1PeriphClockCmd(I2Cx_SDA_GPIO_CLK, ENABLE);
    RCC_AHB1PeriphClockCmd(I2Cx_SCL_GPIO_CLK, ENABLE);
    RCC_APB1PeriphResetCmd(I2Cx_CLK, ENABLE);
    RCC_APB1PeriphResetCmd(I2Cx_CLK, DISABLE);
    RCC_AHB1PeriphClockCmd(DMAx_CLK, ENABLE);
 
    // configure I2C2
    i2cInit.I2C_ClockSpeed = 400000;
    i2cInit.I2C_Mode = I2C_Mode_I2C;
    i2cInit.I2C_DutyCycle = I2C_DutyCycle_2;    // 50% duty cycle
    i2cInit.I2C_OwnAddress1 = 0x00;         // own address
    i2cInit.I2C_Ack = I2C_Ack_Enable;
    i2cInit.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit; // set address length to 7 bit addresses
    I2C_Init(I2C2, &i2cInit);
 
    // enable I2C2
    I2C_Cmd(I2C2, ENABLE);
 
    //I2C Interrupt Routine -> For events
    NVIC_InitTypeDef NVIC_InitStructure;
    NVIC_InitStructure.NVIC_IRQChannel                   = I2C2_EV_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; //GIVE HIGHEST PRIORITY FOR ALL INTERRUPTS
    NVIC_InitStructure.NVIC_IRQChannelSubPriority        = 0;
    NVIC_InitStructure.NVIC_IRQChannelCmd                = ENABLE;
    NVIC_Init(&NVIC_InitStructure);
}
 
void I2C_GPIO_init() {
    GPIO_InitTypeDef gpioInit;
 
    gpioInit.GPIO_Pin = I2Cx_SCL_PIN;
    gpioInit.GPIO_Mode = GPIO_Mode_AF;
    gpioInit.GPIO_Speed = GPIO_Speed_50MHz;
    gpioInit.GPIO_OType = GPIO_OType_OD;
    gpioInit.GPIO_PuPd  = GPIO_PuPd_NOPULL;
    GPIO_Init(I2Cx_SCL_GPIO_PORT, &gpioInit);
 
    gpioInit.GPIO_Pin = I2Cx_SDA_PIN;
    GPIO_Init(I2Cx_SDA_GPIO_PORT, &gpioInit);
    GPIO_PinAFConfig(I2Cx_SCL_GPIO_PORT, I2Cx_SCL_SOURCE, I2Cx_SCL_AF);
    GPIO_PinAFConfig(I2Cx_SDA_GPIO_PORT, I2Cx_SDA_SOURCE, I2Cx_SDA_AF);
}
 
 
void I2C_DMA_init() { // From the ST Standard Peripheral Library Example for I2C
    NVIC_InitTypeDef nvicInit;
    DMA_InitTypeDef  dmaInit;
 
    //Clear all flags and deinit before initialization
    DMA_ClearFlag(MPU6050_DMA_STREAM_RX, I2Cx_RX_DMA_TCFLAG | I2Cx_RX_DMA_FEIFLAG | I2Cx_RX_DMA_DMEIFLAG | \
                                       I2Cx_RX_DMA_TEIFLAG | I2Cx_RX_DMA_HTIFLAG);
    DMA_ClearFlag(MPU6050_DMA_STREAM_TX, I2Cx_TX_DMA_TCFLAG | I2Cx_TX_DMA_FEIFLAG | I2Cx_TX_DMA_DMEIFLAG | \
                                           I2Cx_TX_DMA_TEIFLAG | I2Cx_TX_DMA_HTIFLAG);
 
    DMA_Cmd(MPU6050_DMA_STREAM_RX, DISABLE);
    DMA_Cmd(MPU6050_DMA_STREAM_TX, DISABLE);
    DMA_DeInit(MPU6050_DMA_STREAM_RX);
    DMA_DeInit(MPU6050_DMA_STREAM_TX);
 
    // Initialization DMA
    dmaInit.DMA_Channel = MPU6050_DMA_CHANNEL;
    dmaInit.DMA_PeripheralBaseAddr = (uint32_t)MPU6050_DR_ADDRESS;
    dmaInit.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
    dmaInit.DMA_MemoryInc = DMA_MemoryInc_Enable;
    dmaInit.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
    dmaInit.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
    dmaInit.DMA_Mode = DMA_Mode_Normal;
    dmaInit.DMA_Priority = DMA_Priority_VeryHigh;
    dmaInit.DMA_FIFOMode = DMA_FIFOMode_Enable;
    dmaInit.DMA_FIFOThreshold = DMA_FIFOThreshold_Full;
    dmaInit.DMA_MemoryBurst = DMA_MemoryBurst_Single;
    dmaInit.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;
 
    //Init DMA Receiver
    dmaInit.DMA_DIR = DMA_DIR_PeripheralToMemory;
    dmaInit.DMA_Memory0BaseAddr = (uint32_t)MPU6050_RX_BUFF;
    dmaInit.DMA_BufferSize = MPU6050_BUFF_SIZE_RX;
    DMA_DeInit(MPU6050_DMA_STREAM_RX);
    DMA_Init(MPU6050_DMA_STREAM_RX, &dmaInit);
    DMA_ITConfig(MPU6050_DMA_STREAM_RX, DMA_IT_TC, ENABLE);
 
    //Init DMA transmitter
    dmaInit.DMA_DIR = DMA_DIR_MemoryToPeripheral;
    dmaInit.DMA_Memory0BaseAddr = (uint32_t)MPU6050_TX_BUFF;
    dmaInit.DMA_BufferSize = MPU6050_BUFF_SIZE_TX;
    DMA_DeInit(MPU6050_DMA_STREAM_TX);
    DMA_Init(MPU6050_DMA_STREAM_TX, &dmaInit);
    DMA_ITConfig(MPU6050_DMA_STREAM_TX, DMA_IT_TC, ENABLE);
 
    // DMA Interrupt initialization
    nvicInit.NVIC_IRQChannel = DMA1_Stream2_IRQn;   //RX Interrupt
    nvicInit.NVIC_IRQChannelPreemptionPriority = 1;
    nvicInit.NVIC_IRQChannelSubPriority = 1;
    nvicInit.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&nvicInit);
 
    nvicInit.NVIC_IRQChannel = DMA1_Stream7_IRQn;   //TX Interrupt
    NVIC_Init(&nvicInit);
 
    DMA_ClearFlag(DMA1_Stream2, DMA_FLAG_FEIF2|DMA_FLAG_DMEIF2|DMA_FLAG_TEIF2|DMA_FLAG_HTIF2|DMA_FLAG_TCIF2);
    DMA_Cmd(DMA1_Stream2, ENABLE);
 
    DMA_ClearFlag(DMA1_Stream7, DMA_FLAG_FEIF2|DMA_FLAG_DMEIF2|DMA_FLAG_TEIF2|DMA_FLAG_HTIF2|DMA_FLAG_TCIF2);
    DMA_Cmd(DMA1_Stream7, ENABLE);
 
}
 
void Fill_Buffer(uint8_t *pBuffer, uint16_t BufferLength) {
  uint16_t index = 0;
  for (index = 0; index < BufferLength; index++ )
  {
    pBuffer[index] = 0x00;
  }
}
 
void recovery() {
    I2C_ITConfig(I2C2, I2C_IT_EVT, DISABLE);
    I2C_ClearFlag(I2C2, I2C_FLAG_STOPF);
    I2C_Cmd(I2C2,ENABLE);
    I2C_Cmd(I2C2, DISABLE);
    I2C_GenerateSTOP(I2Cx, ENABLE);
    I2C_DMACmd(I2Cx,DISABLE);
 
    DMA_Cmd(MPU6050_DMA_STREAM_RX, DISABLE);
    DMA_ClearFlag(MPU6050_DMA_STREAM_RX, I2Cx_RX_DMA_TCFLAG | I2Cx_RX_DMA_FEIFLAG | I2Cx_RX_DMA_DMEIFLAG | \
                                           I2Cx_RX_DMA_TEIFLAG | I2Cx_RX_DMA_HTIFLAG);
 
    DMA_Cmd(MPU6050_DMA_STREAM_TX, DISABLE);
    DMA_ClearFlag(MPU6050_DMA_STREAM_TX, I2Cx_TX_DMA_TCFLAG | I2Cx_TX_DMA_FEIFLAG | I2Cx_TX_DMA_DMEIFLAG | \
                                           I2Cx_TX_DMA_TEIFLAG | I2Cx_TX_DMA_HTIFLAG);
 
    /*unlockI2C();
    dmaStarted=0;
    isNewData =0;
    i2c_hard_failure=0;*/
}
 
void DMA1_Stream2_IRQHandler(void) {
    if (DMA_GetFlagStatus(MPU6050_DMA_CHANNEL,DMA_FLAG_TCIF2)) {
        DMA_ClearITPendingBit(MPU6050_DMA_CHANNEL, DMA_FLAG_TCIF2);
 
        I2C_ITConfig(I2C2, I2C_IT_EVT, DISABLE);
        I2C_GenerateSTOP(I2Cx, ENABLE);
        DMA_Cmd(MPU6050_DMA_STREAM_RX, DISABLE);
        I2C_DMACmd(I2Cx,DISABLE);
        DMA_ClearFlag(MPU6050_DMA_STREAM_RX, I2Cx_RX_DMA_TCFLAG | I2Cx_RX_DMA_FEIFLAG | I2Cx_RX_DMA_DMEIFLAG | \
                                               I2Cx_RX_DMA_TEIFLAG | I2Cx_RX_DMA_HTIFLAG);
 
        isNewData=1;
        dmaStarted=0;
    }
}
 
void DMA1_Stream7_IRQHandler(void) {
    if (DMA_GetFlagStatus(MPU6050_DMA_CHANNEL,DMA_FLAG_TCIF7)) {
        DMA_ClearITPendingBit(MPU6050_DMA_CHANNEL, DMA_FLAG_TCIF7);
 
        I2C_DMACmd(I2Cx, DISABLE);
        I2C_GenerateSTOP(I2Cx, ENABLE);
        DMA_Cmd(MPU6050_DMA_STREAM_TX, DISABLE);
        DMA_ClearFlag(MPU6050_DMA_STREAM_TX, I2Cx_TX_DMA_TCFLAG | I2Cx_TX_DMA_FEIFLAG | I2Cx_TX_DMA_DMEIFLAG | \
                                               I2Cx_TX_DMA_TEIFLAG | I2Cx_TX_DMA_HTIFLAG);
 
        DMARead(); //Activate Read after successfully transfered register read command
    }
}
 
void clearAllI2CFlags() {
    I2C_ClearITPendingBit(I2C2,I2C_IT_SMBALERT);
    I2C_ClearITPendingBit(I2C2,I2C_IT_TIMEOUT);
    I2C_ClearITPendingBit(I2C2,I2C_IT_PECERR);
    I2C_ClearITPendingBit(I2C2,I2C_IT_OVR);
    I2C_ClearITPendingBit(I2C2,I2C_IT_AF);
    I2C_ClearITPendingBit(I2C2,I2C_IT_ARLO);
    I2C_ClearITPendingBit(I2C2,I2C_IT_BERR);
    I2C_ClearITPendingBit(I2C2,I2C_IT_TXE);
    I2C_ClearITPendingBit(I2C2,I2C_IT_RXNE);
    I2C_ClearITPendingBit(I2C2,I2C_IT_STOPF);
    I2C_ClearITPendingBit(I2C2,I2C_IT_ADD10);
    I2C_ClearITPendingBit(I2C2,I2C_IT_BTF);
    I2C_ClearITPendingBit(I2C2,I2C_IT_ADDR);
    I2C_ClearITPendingBit(I2C2,I2C_IT_SB);
 
    I2C_ClearFlag(I2C2,I2C_FLAG_SMBALERT);
    I2C_ClearFlag(I2C2,I2C_FLAG_TIMEOUT);
    I2C_ClearFlag(I2C2,I2C_FLAG_PECERR);
    I2C_ClearFlag(I2C2,I2C_FLAG_OVR);
    I2C_ClearFlag(I2C2,I2C_FLAG_AF);
    I2C_ClearFlag(I2C2,I2C_FLAG_ARLO);
    I2C_ClearFlag(I2C2,I2C_FLAG_BERR);
    I2C_ClearFlag(I2C2,I2C_FLAG_TXE);
    I2C_ClearFlag(I2C2,I2C_FLAG_RXNE);
    I2C_ClearFlag(I2C2,I2C_FLAG_STOPF);
    I2C_ClearFlag(I2C2,I2C_FLAG_ADD10);
    I2C_ClearFlag(I2C2,I2C_FLAG_BTF);
    I2C_ClearFlag(I2C2,I2C_FLAG_ADDR);
    I2C_ClearFlag(I2C2,I2C_FLAG_SB);
 
    I2C_ClearFlag(I2C2,I2C_FLAG_DUALF);
    I2C_ClearFlag(I2C2,I2C_FLAG_SMBHOST);
    I2C_ClearFlag(I2C2,I2C_FLAG_SMBDEFAULT);
    I2C_ClearFlag(I2C2,I2C_FLAG_GENCALL);
    I2C_ClearFlag(I2C2,I2C_FLAG_TRA);
    I2C_ClearFlag(I2C2,I2C_FLAG_BUSY);
    I2C_ClearFlag(I2C2,I2C_FLAG_MSL);
}
 
void I2C2_EV_IRQHandler(void)
{
    switch(I2C_GetLastEvent(I2C2))
    {
        case I2C_EVENT_MASTER_MODE_SELECT :
            if(!tx_finish) {
                I2C_Send7bitAddress(I2Cx, MPU6050_ADDRESS_1, I2C_Direction_Transmitter);
                I2C_DMACmd(I2Cx, ENABLE);
            } else {
                I2C_Send7bitAddress(I2Cx, MPU6050_ADDRESS_1, I2C_Direction_Receiver);
                I2C_DMACmd(I2Cx, ENABLE);
            }
            interrupt_error=0;
            break;
        case I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED:
                DMA_Cmd(MPU6050_DMA_STREAM_TX, ENABLE);
            break;
        case I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED:
                DMA_Cmd(MPU6050_DMA_STREAM_RX, ENABLE);
                I2C_ITConfig(I2C2, I2C_IT_EVT, DISABLE);
            break;
        case I2C_EVENT_SLAVE_STOP_DETECTED :
            break;
        case I2C_EVENT_SLAVE_TRANSMITTER_ADDRESS_MATCHED:
            break;
        case I2C_EVENT_SLAVE_BYTE_TRANSMITTED:
            break;
        case I2C_EVENT_SLAVE_ACK_FAILURE:
            break;
        case I2C_EVENT_SLAVE_RECEIVER_ADDRESS_MATCHED:
            break;
        case I2C_EVENT_SLAVE_TRANSMITTER_SECONDADDRESS_MATCHED:
            break;
        case I2C_EVENT_SLAVE_RECEIVER_SECONDADDRESS_MATCHED:
            break;
        case I2C_EVENT_SLAVE_BYTE_RECEIVED:
            break;
        case I2C_EVENT_MASTER_BYTE_RECEIVED:
            break;
        case I2C_EVENT_MASTER_BYTE_TRANSMITTING:
            break;
        case I2C_EVENT_MASTER_BYTE_TRANSMITTED:
            break;
        case I2C_EVENT_MASTER_MODE_ADDRESS10:
            break;
        case I2C_EVENT_SLAVE_GENERALCALLADDRESS_MATCHED:
            break;
        default:
            interrupt_error++;
            if(interrupt_error>10) {
                i2c_hard_failure=1;
                recovery();
                clearAllI2CFlags();
                interrupt_error=0;
            }
            break;
    }
}
 
 
uint8_t copyNewAccData(MPU6050Data *dataStruct, MPU6050DataOffset *offset, uint8_t sensor_numb) {
    if(isNewData) {
        int accX=(MPU6050_RX_BUFF[0]<<8) | MPU6050_RX_BUFF[1];
        int accY=(MPU6050_RX_BUFF[2]<<8) | MPU6050_RX_BUFF[3];
        int accZ=(MPU6050_RX_BUFF[4]<<8) | MPU6050_RX_BUFF[5];
        int temp=(MPU6050_RX_BUFF[6]<<8) | MPU6050_RX_BUFF[7];
        int gyroX=(MPU6050_RX_BUFF[8]<<8) | MPU6050_RX_BUFF[9];
        int gyroY=(MPU6050_RX_BUFF[10]<<8) | MPU6050_RX_BUFF[11];
        //int gyroZ=(MPU6050_RX_BUFF[12]<<8) | MPU6050_RX_BUFF[13];
 
        if(accX>32768)
            accX=accX-65546;
        if(accY>32768)
            accY=accY-65546;
        if(accZ>32768)
            accZ=accZ-65546;
 
        if(gyroX>=32768)
                gyroX=gyroX-65546;
        if(gyroY>=32768)
                gyroY=gyroY-65546;
        /*if(gyroZ>32768)
                gyroZ=gyroZ-65546;*/
 
        dataStruct->dataAccX = accX - offset->dataAccXOffset; //- offset->dataAccXOffset;
        dataStruct->dataAccY = accY - offset->dataAccYOffset; //- offset->dataAccYOffset;
        dataStruct->dataAccZ = accZ - offset->dataAccZOffset;
 
        dataStruct->dataGyroX= gyroX - offset->dataGyroXOffset; // - offset->dataGyroXOffset;
        dataStruct->dataGyroY= gyroY - offset->dataGyroYOffset; //- offset->dataGyroYOffset;
        //dataStruct->dataGyroZ=gyroZ;
 
        isNewData=0;
        return 0;
    } else {
        return 2;
    }
}
 
uint8_t DMAInitRead() {
    if(i2c_hard_failure)
        return 1;
 
    if(!isNewData && !dmaStarted) {
        dmaStarted=1;
        tx_finish=0;
 
        I2C_GenerateSTART(I2Cx, ENABLE);
        I2C_ITConfig(I2C2, I2C_IT_EVT, ENABLE);
 
 
        /*while(!I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_MODE_SELECT)) {
 
        }*/
 
        return 0;
    }
    return 0;
 
}
 
uint8_t DMARead() {
 
    //Start DMA Read process:
    I2C_DMALastTransferCmd(I2Cx, ENABLE); //Enable automatic NACK
    I2C_GenerateSTART(I2Cx, ENABLE);
 
    tx_finish=1;
 
    return 0;
 
}
 
//FUNCTIONS WITHOUT DMA: USE ONLY FOR INITIALIZATION
 
uint8_t readI2C1(uint8_t addr, uint8_t dir, uint8_t reg, uint8_t *data) {
    uint8_t fail_flag=0;
 
    fail_flag|=I2C_start(addr, 0, 0); //dir==0 is transmitter, no ack since only one write
    fail_flag|=I2C_write(reg);
    I2C_stop();
    fail_flag|=I2C_start(addr, 1, 0); //switch to receiver mode
    I2C_read_nack1(data);
 
    return fail_flag;
}
 
uint8_t I2C_read_ack1(uint8_t *data){
    uint16_t timeout = 20000; //Wait maximum 20000 cycles
    I2C_AcknowledgeConfig(I2C2, ENABLE);
 
    while( !I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_BYTE_RECEIVED) ) {
        if (--timeout == 0) {
            return 1;
        }
    }
    // read data from I2C data register and return data byte
    *data = I2C_ReceiveData(I2C2);
    return 0;
}
 
uint8_t I2C_read_nack1(uint8_t *data) {
    uint16_t timeout = 20000; //Wait maximum 20000 cycles
    I2C_AcknowledgeConfig(I2C2, DISABLE);
    I2C_GenerateSTOP(I2C2, ENABLE);
 
    while( !I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_BYTE_RECEIVED) ) {
        if (--timeout == 0) {
            return 1;
        }
    }
 
    *data = I2C_ReceiveData(I2C2);
    return 0;
}
 
uint8_t writeI2C(uint8_t addr, uint8_t reg, uint8_t data) {
    uint8_t fail_flag=0;
 
    fail_flag|=I2C_start(addr, 0, 0); //dir==0 is transmitter, no ack since only one write
    fail_flag|=I2C_write(reg);
    fail_flag|=I2C_write(data);
    I2C_stop();
 
    return fail_flag;
}
 
 
 
uint8_t I2C_start(uint8_t address, uint8_t direction, uint8_t ack) { //direction transmitter==0
    uint16_t timeout = TIMEOUT; //Wait maximum 20000 cycles
 
    while(I2C_GetFlagStatus(I2C2, I2C_FLAG_BUSY)) {
        if (--timeout == 0) {
            return 1;
        }
    }
 
    I2C_GenerateSTART(I2C2, ENABLE);
 
    while(!I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_MODE_SELECT)) {
        if (--timeout == 0) {
            return 1;
        }
    }
 
    //Ack enable
    if(ack)
        I2C2->CR1 |= I2C_CR1_ACK;
 
    //Send Adress
    I2C_Send7bitAddress(I2C2, address, direction);
    while (!(I2C2->SR1 & I2C_SR1_ADDR)) { //Wait until Address is received by slave
        if (--timeout == 0) {
            return 1;
        }
    }
 
    if(direction == I2C_Direction_Transmitter){
        while(!I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED)) {
            if (--timeout == 0) {
                return 1;
            }
        }
    }
    else if(direction == I2C_Direction_Receiver){
        while(!I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED)) {
            if (--timeout == 0) {
                return 1;
            }
        }
    }
 
    /* Read status register to clear ADDR flag */
    I2C2->SR2;
 
    return 0;
}
 
 
uint8_t I2C_write(uint8_t data) {
    uint16_t timeout = TIMEOUT; //Wait maximum 20000 cycles
 
    I2C_SendData(I2C2, data);
 
    while(!I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_BYTE_TRANSMITTED))  {
        if (--timeout == 0) {
            return 1;
        }
    }
 
    return 0;
}
 
void I2C_stop() {
    I2C_GenerateSTOP(I2C2, ENABLE);
}
 
void initOffset(MPU6050DataOffset *offset) {
    offset->dataAccXOffset=0;
    offset->dataAccYOffset=0;
    offset->dataAccZOffset=0;
    offset->dataGyroXOffset=0;
    offset->dataGyroYOffset=0;
    offset->dataGyroZOffset=0;
}
 
void setOffset(MPU6050Data *MPU1, MPU6050DataOffset *MPU1_Offset) {
    MPU1_Offset->dataAccXOffset=MPU1->dataAccX;
    MPU1_Offset->dataAccYOffset=MPU1->dataAccY;
    MPU1_Offset->dataAccZOffset=MPU1->dataAccZ;
    MPU1_Offset->dataGyroXOffset=MPU1->dataGyroX;
    MPU1_Offset->dataGyroYOffset=MPU1->dataGyroY;
}

Outcomes