static uint16_t i2c_NormalizeAddr(I2C0_Type* I2Cx, uint16_t addr) { assert_param(IS_I2C_ALL_PERIPH(I2Cx)); if (I2Cx->CTRL_b.MODE == I2C_Mode_Master) { if (I2Cx->CTRL_b.MASTER_ADDR_WIDTH == I2C_ADDR_WIDTH_7BIT) { addr &= 0x007F; } else { addr &= 0x3FF; } } if (I2Cx->CTRL_b.MODE == I2C_Mode_Slave) { if (I2Cx->CTRL_b.SLAVE_ADDR_WIDTH == I2C_ADDR_WIDTH_7BIT) { addr &= 0x007F; } else { addr &= 0x3FF; } } return addr; }
/** * @brief Send data in master mode through the I2Cx peripheral. * @param I2Cx: where x can be 0 or 1 to select the I2C peripheral. * @param Data: Byte to be transmitted.. * @retval None */ void I2C_MasterWrite(I2C_TypeDef* I2Cx, uint8_t* pBuf, uint8_t len) { uint8_t cnt = 0; /* Check the parameters */ assert_param(IS_I2C_ALL_PERIPH(I2Cx)); /* Write in the DR register the data to be sent */ for(cnt = 0; cnt < len; cnt++) { if(cnt >= len - 1) { /*generate stop signal*/ I2Cx->IC_DATA_CMD = (*pBuf++) | (1 << 9); } else { I2Cx->IC_DATA_CMD = *pBuf++; } /* wait for flag of I2C_FLAG_MST_ACTIVITY */ while((I2Cx->IC_STATUS & (1 << 5)) == 1); } }
/** * @brief Checks whether the specified I2C flag is set or not. * @param I2Cx: where x can be 1 or 2 to select the I2C peripheral. * @param I2C_FLAG: specifies the flag to check. * This parameter can be one of the following values: * @arg I2C_FLAG_DUALF: Dual flag (Slave mode) * @arg I2C_FLAG_SMBHOST: SMBus host header (Slave mode) * @arg I2C_FLAG_SMBDEFAULT: SMBus default header (Slave mode) * @arg I2C_FLAG_GENCALL: General call header flag (Slave mode) * @arg I2C_FLAG_TRA: Transmitter/Receiver flag * @arg I2C_FLAG_BUSY: Bus busy flag * @arg I2C_FLAG_MSL: Master/Slave flag * @arg I2C_FLAG_SMBALERT: SMBus Alert flag * @arg I2C_FLAG_TIMEOUT: Timeout or Tlow error flag * @arg I2C_FLAG_PECERR: PEC error in reception flag * @arg I2C_FLAG_OVR: Overrun/Underrun flag (Slave mode) * @arg I2C_FLAG_AF: Acknowledge failure flag * @arg I2C_FLAG_ARLO: Arbitration lost flag (Master mode) * @arg I2C_FLAG_BERR: Bus error flag * @arg I2C_FLAG_TXE: Data register empty flag (Transmitter) * @arg I2C_FLAG_RXNE: Data register not empty (Receiver) flag * @arg I2C_FLAG_STOPF: Stop detection flag (Slave mode) * @arg I2C_FLAG_ADD10: 10-bit header sent flag (Master mode) * @arg I2C_FLAG_BTF: Byte transfer finished flag * @arg I2C_FLAG_ADDR: Address sent flag (Master mode) "ADSL" * Address matched flag (Slave mode)"ENDA" * @arg I2C_FLAG_SB: Start bit flag (Master mode) * @retval The new state of I2C_FLAG (SET or RESET). */ FlagStatus I2C_GetFlagStatus(I2C_TypeDef* I2Cx, uint32_t I2C_FLAG) { FlagStatus bitstatus = RESET; __IO uint32_t i2creg = 0, i2cxbase = 0; /* Check the parameters */ assert_param(IS_I2C_ALL_PERIPH(I2Cx)); assert_param(IS_I2C_GET_FLAG(I2C_FLAG)); /* Get the I2Cx peripheral base address */ i2cxbase = (uint32_t)I2Cx; /* Read flag register index */ i2creg = I2C_FLAG >> 28; /* Get bit[23:0] of the flag */ I2C_FLAG &= FLAG_Mask; if(i2creg != 0) { /* Get the I2Cx SR1 register address */ i2cxbase += 0x14; } else { /* Flag in I2Cx SR2 Register */ I2C_FLAG = (uint32_t)(I2C_FLAG >> 16); /* Get the I2Cx SR2 register address */ i2cxbase += 0x18; } if(((*(__IO uint32_t*)i2cxbase) & I2C_FLAG) != (uint32_t)RESET) { /* I2C_FLAG is set */ bitstatus = SET; } else { /* I2C_FLAG is reset */ bitstatus = RESET; } /* Return the I2C_FLAG status */ return bitstatus; }
void I2C_ClearStatus(I2C0_Type* I2Cx, uint32_t Status) { assert_param(IS_I2C_ALL_PERIPH(I2Cx)); assert_param(IS_I2C_STATUS(Status)); if (Status & I2C_STATUS_RX_FIFO_NOT_EMPTY) { // It can't be clear by sw but read } if (Status & I2C_STATUS_RD_REQUEST) { i2c_ReadClear(I2Cx->CLR_RD_REQ_b.CLEAR); } if (Status & I2C_STATUS_TX_ABORT) { i2c_ReadClear(I2Cx->CLR_TX_ABRT_b.CLEAR); } if (Status & I2C_STATUS_RX_DONE) { i2c_ReadClear(I2Cx->CLR_RX_DONE_b.CLEAR); } if (Status & I2C_STATUS_TX_DONE) { i2c_ReadClear(I2Cx->CLR_TX_DONE_b.CLEAR); } }
void I2C_ClearInt(I2C0_Type* I2Cx, uint32_t Int) { assert_param(IS_I2C_ALL_PERIPH(I2Cx)); assert_param(IS_I2C_INT(Int)); if (Int == I2C_INT_RX_FIFO_NOT_EMPTY) { // It can't be clear by sw but read data } if (Int == I2C_INT_RD_REQUEST) { i2c_ReadClear(I2Cx->CLR_RD_REQ_b.CLEAR); } if (Int == I2C_INT_TX_ABORT) { i2c_ReadClear(I2Cx->CLR_TX_ABRT_b.CLEAR); } if (Int == I2C_INT_RX_DONE) { i2c_ReadClear(I2Cx->CLR_RX_DONE_b.CLEAR); } if (Int == I2C_INT_TX_DONE) { i2c_ReadClear(I2Cx->CLR_TX_DONE_b.CLEAR); } }
/** * @brief Initializes the I2Cx peripheral according to the specified * parameters in the I2C_InitStruct. * @param I2Cx: where x can be 1 or 2 to select the I2C peripheral. * @param I2C_InitStruct: pointer to a I2C_InitTypeDef structure that * contains the configuration information for the specified I2C peripheral. * @retval None */ void I2C_Init(I2C_TypeDef* I2Cx, I2C_InitTypeDef* I2C_InitStruct) { uint16_t tmpreg = 0, freqrange = 0; uint16_t result = 0x04; uint32_t pclk1 = 8000000; RCC_ClocksTypeDef rcc_clocks; /* Check the parameters */ assert_param(IS_I2C_ALL_PERIPH(I2Cx)); assert_param(IS_I2C_CLOCK_SPEED(I2C_InitStruct->I2C_ClockSpeed)); assert_param(IS_I2C_MODE(I2C_InitStruct->I2C_Mode)); assert_param(IS_I2C_DUTY_CYCLE(I2C_InitStruct->I2C_DutyCycle)); assert_param(IS_I2C_OWN_ADDRESS1(I2C_InitStruct->I2C_OwnAddress1)); assert_param(IS_I2C_ACK_STATE(I2C_InitStruct->I2C_Ack)); assert_param(IS_I2C_ACKNOWLEDGE_ADDRESS(I2C_InitStruct->I2C_AcknowledgedAddress)); /*---------------------------- I2Cx CR2 Configuration ------------------------*/ /* Get the I2Cx CR2 value */ tmpreg = I2Cx->CR2; /* Clear frequency FREQ[5:0] bits */ tmpreg &= CR2_FREQ_Reset; /* Get pclk1 frequency value */ RCC_GetClocksFreq(&rcc_clocks); pclk1 = rcc_clocks.PCLK1_Frequency; /* Set frequency bits depending on pclk1 value */ freqrange = (uint16_t)(pclk1 / 1000000); tmpreg |= freqrange; /* Write to I2Cx CR2 */ I2Cx->CR2 = tmpreg; /*---------------------------- I2Cx CCR Configuration ------------------------*/ /* Disable the selected I2C peripheral to configure TRISE */ I2Cx->CR1 &= CR1_PE_Reset; /* Reset tmpreg value */ /* Clear F/S, DUTY and CCR[11:0] bits */ tmpreg = 0; /* Configure speed in standard mode */ if (I2C_InitStruct->I2C_ClockSpeed <= 100000) { /* Standard mode speed calculate */ result = (uint16_t)(pclk1 / (I2C_InitStruct->I2C_ClockSpeed << 1)); /* Test if CCR value is under 0x4*/ if (result < 0x04) { /* Set minimum allowed value */ result = 0x04; } /* Set speed value for standard mode */ tmpreg |= result; // [ILG] #if defined ( __GNUC__ ) #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wconversion" #endif /* Set Maximum Rise Time for standard mode */ I2Cx->TRISE = freqrange + 1; // [ILG] #if defined ( __GNUC__ ) #pragma GCC diagnostic pop #endif } /* Configure speed in fast mode */ else /*(I2C_InitStruct->I2C_ClockSpeed <= 400000)*/ { if (I2C_InitStruct->I2C_DutyCycle == I2C_DutyCycle_2) { /* Fast mode speed calculate: Tlow/Thigh = 2 */ result = (uint16_t)(pclk1 / (I2C_InitStruct->I2C_ClockSpeed * 3)); } else /*I2C_InitStruct->I2C_DutyCycle == I2C_DutyCycle_16_9*/ { /* Fast mode speed calculate: Tlow/Thigh = 16/9 */ result = (uint16_t)(pclk1 / (I2C_InitStruct->I2C_ClockSpeed * 25)); /* Set DUTY bit */ result |= I2C_DutyCycle_16_9; } /* Test if CCR value is under 0x1*/ if ((result & CCR_CCR_Set) == 0) { /* Set minimum allowed value */ result |= (uint16_t)0x0001; } /* Set speed value and set F/S bit for fast mode */ tmpreg |= (uint16_t)(result | CCR_FS_Set); /* Set Maximum Rise Time for fast mode */ I2Cx->TRISE = (uint16_t)(((freqrange * (uint16_t)300) / (uint16_t)1000) + (uint16_t)1); } /* Write to I2Cx CCR */ I2Cx->CCR = tmpreg; /* Enable the selected I2C peripheral */ I2Cx->CR1 |= CR1_PE_Set; /*---------------------------- I2Cx CR1 Configuration ------------------------*/ /* Get the I2Cx CR1 value */ tmpreg = I2Cx->CR1; /* Clear ACK, SMBTYPE and SMBUS bits */ tmpreg &= CR1_CLEAR_Mask; /* Configure I2Cx: mode and acknowledgement */ /* Set SMBTYPE and SMBUS bits according to I2C_Mode value */ /* Set ACK bit according to I2C_Ack value */ tmpreg |= (uint16_t)((uint32_t)I2C_InitStruct->I2C_Mode | I2C_InitStruct->I2C_Ack); /* Write to I2Cx CR1 */ I2Cx->CR1 = tmpreg; /*---------------------------- I2Cx OAR1 Configuration -----------------------*/ /* Set I2Cx Own Address1 and acknowledged address */ I2Cx->OAR1 = (I2C_InitStruct->I2C_AcknowledgedAddress | I2C_InitStruct->I2C_OwnAddress1); }
/** * @brief Initializes the I2Cx peripheral according to the specified * parameters in the I2C_InitStruct. * @param I2Cx: where x can be 0 or 1 to select the I2C peripheral. * @param I2C_InitStruct: pointer to a I2C_InitTypeDef structure that * contains the configuration information for the specified I2C peripheral. * @retval None */ void I2C_Init(I2C_TypeDef* I2Cx, I2C_InitTypeDef* I2C_InitStruct) { /* Check the parameters */ assert_param(IS_I2C_ALL_PERIPH(I2Cx)); assert_param(IS_I2C_CLOCK_SPEED(I2C_InitStruct->I2C_ClockSpeed)); /* Disable I2C device before change configuration */ I2Cx->IC_ENABLE &= ~0x0001; /* ------------------------------ Initialize I2C device ------------------------------*/ if(I2C_DeviveMode_Master == I2C_InitStruct->I2C_DeviveMode) { /*configure I2C device mode which can be selected for master or slave*/ I2Cx->IC_CON = I2C_InitStruct->I2C_DeviveMode |(I2C_InitStruct->I2C_AddressMode << 4)| BIT(5); /*set target address*/ I2Cx->IC_TAR = (I2C_InitStruct->I2C_SlaveAddress & 0x3ff) |(I2C_InitStruct->I2C_AddressMode << 12); /*set SDA hold time in master mode*/ I2Cx->IC_SDA_HOLD = 0x01; #if 1 /*set Tx empty level*/ I2Cx->IC_TX_TL = 0; /*set Rx full level*/ I2Cx->IC_RX_TL = 0; #endif } else { /* set to slave mode */ I2Cx->IC_CON = (I2C_InitStruct->I2C_DeviveMode) | (I2C_InitStruct->I2C_AddressMode << 3); /* set Ack in slave mode */ I2Cx->IC_ACK_GENERAL_CALL &= I2C_InitStruct->I2C_Ack; /* set slave address */ I2Cx->IC_SAR = I2C_InitStruct->I2C_SlaveAddress; /* set SDA hold time in slave mode */ I2Cx->IC_SDA_HOLD = 0x07; /* set SDA setup time delay only in slave mode(master greater than 2) ,delay time:[(IC_SDA_SETUP - 1) * (ic_clk_period)]*/ I2Cx->IC_SDA_SETUP = 0x02; } /*------------------------------ configure I2C speed ------------------------------*/ /*Configure I2C speed in standard mode*/ if (I2C_InitStruct->I2C_ClockSpeed < 100000) { I2Cx->IC_CON &= 0xfffb; /*configure I2C speed*/ I2Cx->IC_SS_SCL_HCNT = 20 + (4000*(PLATFORM_CLOCK/10000)) / (I2C_InitStruct->I2C_ClockSpeed); I2Cx->IC_SS_SCL_LCNT = 20 + (4700*(PLATFORM_CLOCK/10000)) / (I2C_InitStruct->I2C_ClockSpeed); } /*Configure I2C speed in fast mode*/ else if(I2C_InitStruct->I2C_ClockSpeed <= 400000) { I2Cx->IC_CON &= 0xfffd; if(I2C_InitStruct->I2C_ClockSpeed == 100000) { /*configure I2C speed*/ I2Cx->IC_FS_SCL_HCNT = 66 + (600*(PLATFORM_CLOCK/10000)*4) / (I2C_InitStruct->I2C_ClockSpeed); I2Cx->IC_FS_SCL_LCNT = 10 + (1300*(PLATFORM_CLOCK/10000)) / (I2C_InitStruct->I2C_ClockSpeed); } else if(I2C_InitStruct->I2C_ClockSpeed == 200000) { /*configure I2C speed*/ I2Cx->IC_FS_SCL_HCNT = 32 + (600*(PLATFORM_CLOCK/10000)*4) / (I2C_InitStruct->I2C_ClockSpeed); I2Cx->IC_FS_SCL_LCNT = (1300*(PLATFORM_CLOCK/10000)*4) / (I2C_InitStruct->I2C_ClockSpeed); } else { if(I2C_InitStruct->I2C_ClockSpeed == 400000) { /*configure I2C speed*/ I2Cx->IC_FS_SCL_HCNT = 8 + (600*(PLATFORM_CLOCK/10000)*4) / (I2C_InitStruct->I2C_ClockSpeed); I2Cx->IC_FS_SCL_LCNT = 1 + (1300*(PLATFORM_CLOCK/10000)*4) / (I2C_InitStruct->I2C_ClockSpeed); } } } /*Configure I2C speed in high mode*/ else { if(I2C_InitStruct->I2C_ClockSpeed <= 3400000) { /*configure I2C speed*/ I2Cx->IC_HS_SCL_HCNT = 8 + (60*(PLATFORM_CLOCK/10000)*30) / (I2C_InitStruct->I2C_ClockSpeed); I2Cx->IC_HS_SCL_LCNT = 1 + (120*(PLATFORM_CLOCK/10000)*30) / (I2C_InitStruct->I2C_ClockSpeed); } } }
/** * @brief Sends data and read data in master mode through the I2Cx peripheral.Attention:Read data with time out mechanism. * @param I2Cx: where x can be 0 or 1 to select the I2C peripheral. * @param Data: Byte to be transmitted.. * @retval Actual length of read data */ uint8_t I2C_RepeatRead(I2C_TypeDef* I2Cx, uint8_t* pWriteBuf, uint8_t Writelen, uint8_t* pReadBuf, uint8_t Readlen) { uint8_t cnt = 0; uint32_t reg_value = 0; uint8_t rev_len = 0; uint32_t time_out = 0xfffff; /* Check the parameters */ assert_param(IS_I2C_ALL_PERIPH(I2Cx)); /*------------------------------ write data section ------------------------------*/ /* write data in the IC_DATA_CMD register */ for(cnt = 0; cnt < Writelen; cnt++) { #if 0 /*wait for I2C_FLAG_TFNF flag that Tx FIFO is not full*/ while((I2Cx->IC_STATUS & BIT(1)) == 0); #endif I2Cx->IC_DATA_CMD = *pWriteBuf++; } /*------------------------------ read data section ------------------------------*/ for(cnt = 0; cnt < Readlen; cnt++) { if(cnt >= Readlen - 1) { /*generate stop singal in last byte which to be sent*/ I2Cx->IC_DATA_CMD = reg_value | BIT(8) |BIT(9); } else { I2Cx->IC_DATA_CMD = reg_value | BIT(8); } /*read data */ if(cnt > 0) { /*wait for I2C_FLAG_RFNE flag*/ time_out = 0xfffff; while(((I2Cx->IC_STATUS & BIT(3))==0) && (time_out!=0)) { time_out--; } if(time_out > 0) { *pReadBuf++ = (uint8_t)I2Cx->IC_DATA_CMD; rev_len++; } } } /*read data*/ time_out = 0xfffff; while(((I2Cx->IC_STATUS & BIT(3))==0) && (time_out!=0)) { time_out--; } if(time_out > 0) { *pReadBuf = (uint8_t)I2Cx->IC_DATA_CMD; rev_len++; } return rev_len; }
void I2C_Enable(I2C0_Type* I2Cx, BOOL enable) { assert_param(IS_I2C_ALL_PERIPH(I2Cx)); I2Cx->ENABLE_b.EN = enable; }
/** * @brief Returns the PEC value for the specified I2C. * @param I2Cx: where x can be 1 or 2 to select the I2C peripheral. * @retval The PEC value. */ uint8_t I2C_GetPEC(I2C_TypeDef* I2Cx) { /* Check the parameters */ assert_param(IS_I2C_ALL_PERIPH(I2Cx)); /* Return the selected I2C PEC value */ return ((I2Cx->SR2) >> 8); }
/** * @brief Returns the most recent received data by the I2Cx peripheral. * @param I2Cx: where x can be 1 or 2 to select the I2C peripheral. * @retval The value of the received data. */ uint8_t I2C_ReceiveData(I2C_TypeDef* I2Cx) { /* Check the parameters */ assert_param(IS_I2C_ALL_PERIPH(I2Cx)); /* Return the data in the DR register */ return (uint8_t)I2Cx->DR; }
/** * @brief Sends a data byte through the I2Cx peripheral. * @param I2Cx: where x can be 1 or 2 to select the I2C peripheral. * @param Data: Byte to be transmitted.. * @retval None */ void I2C_SendData(I2C_TypeDef* I2Cx, uint8_t Data) { /* Check the parameters */ assert_param(IS_I2C_ALL_PERIPH(I2Cx)); /* Write in the DR register the data to be sent */ I2Cx->DR = Data; }