/* ****************************************************************************** * @file fxx_i2c.c * @version V1.0.0 * @date 2021 * @brief I2C module driver. * This file provides firmware functions to manage the following * functionalities of the Inter Integrated Circuit (I2C) peripheral: * @ Initialization and de-initialization functions * @ IO operation functions * @ Peripheral Control functions ****************************************************************************** */ #include "fxx_std.h" /************************************************************************ * function : I2C_IRQHandler * Description: This function handles I2C interrupt request. * input : I2Cx: where x can be 1 or 2 to select the I2C peripheral. * input : Slave_Comm : Slave Communication Structure ************************************************************************/ __weak void _I2Cx_IRQHandler(I2C_TypeDef* I2Cx,Slave_Comm_TypeDef* Slave_Comm) { uint32_t i; /* Slave ADDR1 Interrupt */ if (I2C_GetFlagStatus(I2Cx, I2C_SR_RX_ADDR1)) { /* Clear ADDR1 Interrupt Flag */ I2C_ClearFlag(I2Cx,I2C_SR_RX_ADDR1); /* Slave Transmit */ if (I2C_GetFlagStatus(I2Cx, I2C_SR_SRW)) { i = 1; /* Wait for transmission End*/ while(!I2C_GetFlagStatus(I2Cx, I2C_SR_MTF)); /* Clear MTF */ I2C_ClearFlag(I2Cx,I2C_SR_MTF); /* BUS BUSY */ while(I2C_GetFlagStatus(I2Cx, I2C_SR_BUS_BUSY)) { if (i >= Slave_Comm->Tx_Size && Slave_Comm->Tx_Size != 0) { break; } if (I2C_GetFlagStatus(I2Cx, I2C_SR_MTF)) { /* Clear MTF */ I2C_ClearFlag(I2Cx,I2C_SR_MTF); } if (I2C_GetFlagStatus(I2Cx, I2C_SR_TXE)) { I2Cx->DR = Slave_Comm->Tx_Buffer[i++]; Slave_Comm->Tx_Count++; } } /* Set Slave machine is DILE */ Slave_Comm->Slave_TxState = SLAVE_TX_STATE_IDLE; } /* Slave Receive */ else { i = 0; /* Wait for transmission End*/ while(!I2C_GetFlagStatus(I2Cx, I2C_SR_MTF)); /* Clear MTF */ I2C_ClearFlag(I2Cx,I2C_SR_MTF); /* BUS BUSY */ while(I2C_GetFlagStatus(I2Cx, I2C_SR_BUS_BUSY)) { /* Receive Data */ if (I2C_GetFlagStatus(I2Cx, I2C_SR_RXNE)) { Slave_Comm->Rx_Buffer[i++] = I2Cx->DR; /* Wait for transmission End*/ while(!I2C_GetFlagStatus(I2Cx, I2C_SR_MTF)); /* Clear MTF */ I2C_ClearFlag(I2Cx,I2C_SR_MTF); Slave_Comm->Rx_Count++; if (Slave_Comm->Rx_Size != 0) { if (i >= Slave_Comm->Rx_Size) { break; } } } } /* Set Slave machine is DILE */ Slave_Comm->Slave_RxState = SLAVE_RX_STATE_IDLE; } if (Slave_Comm->Slave_RxState == SLAVE_RX_STATE_IDLE && Slave_Comm->Slave_TxState == SLAVE_TX_STATE_IDLE) { /* Disable RX_ADDR1_INT_EN */ I2C_ITConfig(I2Cx,I2C_CR_RX_ADDR1_INT_EN,DISABLE); } } /* STOP Flag Interrupt */ if (READ_BIT(I2Cx->SR, I2C_SR_STOPF)) { /* Clear STOPF Interrupt Flag */ I2Cx->SR = READ_BIT(I2Cx->SR, I2C_SR_STOPF); /* Clear STOPF */ CLEAR_BIT(I2Cx->CR, I2C_CR_STOPF_INTEN); if (Slave_Comm->I2C_STOPF_Callback != NULL) { Slave_Comm->I2C_STOPF_Callback(); } } } /************************************************************************ * function : I2C_Set_Clock_Speed * Description: Set I2C Clock Speed * input : I2Cx: where x can be 1 or 2 to select the I2C peripheral. * ClockSpeed: I2C Clock Speed ************************************************************************/ void I2C_Set_Clock_Speed(I2C_TypeDef *hi2c, uint32_t ClockSpeed) { uint32_t APB_Clock; APB_Clock = System_Get_APBClock(); hi2c->CLK_DIV = APB_Clock / (4 * ClockSpeed) - 1; } /************************************************************************ * function : I2C_Init * Description: I2c initial with parameters. * input : I2Cx: where x can be 1 or 2 to select the I2C peripheral. * input : I2C_InitStruct: pointer to a I2C_InitTypeDef structure that * contains the configuration information for the specified I2C peripheral. ************************************************************************/ void I2C_Init(I2C_TypeDef* I2Cx, I2C_InitTypeDef* I2C_InitStruct) { #if (USE_FULL_ASSERT == 1) /* 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)); #endif /* Disable the selected I2C peripheral */ CLEAR_BIT(I2Cx->CR, I2C_CR_MEN); switch(I2C_InitStruct->I2C_Mode) { /* Master Mode */ case I2C_MODE_MASTER: { /* Set Master Mode */ SET_BIT(I2Cx->CR, I2C_CR_MASTER); /* Set Clock Speed */ I2C_Set_Clock_Speed(I2Cx, I2C_InitStruct->I2C_ClockSpeed); /* Set SDA auto change the direction */ if (I2C_InitStruct->I2C_Tx_Auto_En == TX_AUTO_EN_ENABLE) SET_BIT(I2Cx->CR, I2C_CR_TX_AUTO_EN); else CLEAR_BIT(I2Cx->CR, I2C_CR_TX_AUTO_EN); }break; /* Slave Mode */ case I2C_MODE_SLAVE: { SET_BIT(I2Cx->CR, I2C_CR_TXE_SEL); /* Set SDA auto change the direction */ if (I2C_InitStruct->I2C_Tx_Auto_En == TX_AUTO_EN_ENABLE) SET_BIT(I2Cx->CR, I2C_CR_TX_AUTO_EN); else CLEAR_BIT(I2Cx->CR, I2C_CR_TX_AUTO_EN); /* Set Clock Stretch Mode */ if (I2C_InitStruct->I2C_No_Stretch_Mode == NO_STRETCH_MODE_NOSTRETCH) SET_BIT(I2Cx->CR, I2C_CR_NOSTRETCH); else CLEAR_BIT(I2Cx->CR, I2C_CR_NOSTRETCH); /* Set Address 1 */ I2Cx->SLAVE_ADDR1 = I2C_InitStruct->I2C_Own_Address; }break; default: break; } } /************************************************************************ * function : I2C_DeInit * Description: Deinitializes the I2Cx peripheral registers to their default reset values. * input : I2Cx: where x can be 1 or 2 to select the I2C peripheral. * retval : None ************************************************************************/ void I2C_DeInit(I2C_TypeDef* I2Cx) { #if (USE_FULL_ASSERT == 1) /* Check the parameters */ assert_param(IS_I2C_ALL_PERIPH(I2Cx)); #endif if (I2Cx == I2C1) { /* Enable I2C1 reset state */ System_Module_Disable(EN_I2C1); } else { /* Enable I2C2 reset state */ System_Module_Disable(EN_I2C2); } } /************************************************************************ * function : I2C_Cmd * Description: Enables or disables the specified I2C peripheral. * input : I2Cx: where x can be 1 or 2 to select the I2C peripheral. * input : NewState: new state of the I2C START condition generation. * This parameter can be: ENABLE or DISABLE. * retval : None ************************************************************************/ void I2C_Cmd(I2C_TypeDef* I2Cx, FunctionalState NewState) { #if (USE_FULL_ASSERT == 1) /* Check the parameters */ assert_param(IS_I2C_ALL_PERIPH(I2Cx)); assert_param(IS_FUNCTIONAL_STATE(NewState)); #endif if (NewState != DISABLE) { /* Enable the selected I2C peripheral */ I2Cx->CR |= I2C_CR_MEN; } else { /* Disable the selected I2C peripheral */ I2Cx->CR &= ~I2C_CR_MEN; } } /************************************************************************ * function : I2C_DMACmd * Description: Enables or disables the specified I2C DMA requests. * input : I2Cx: where x can be 1 or 2 to select the I2C peripheral. * input : NewState: new state of the I2C START condition generation. * This parameter can be: ENABLE or DISABLE. * retval : None ************************************************************************/ void I2C_DMACmd(I2C_TypeDef* I2Cx, FunctionalState NewState) { #if (USE_FULL_ASSERT == 1) /* Check the parameters */ assert_param(IS_I2C_ALL_PERIPH(I2Cx)); assert_param(IS_FUNCTIONAL_STATE(NewState)); #endif if (NewState != DISABLE) { /* Enable the selected I2C DMA requests */ I2Cx->CR |= I2C_CR_DMA_EN; } else { /* Disable the selected I2C DMA requests */ I2Cx->CR &= ~I2C_CR_DMA_EN; } } /************************************************************************ * function : I2C_GetFlagStatus * Description: Checks whether the specified I2C flag is set or not. * input : I2Cx: where x can be 1 or 2 to select the I2C peripheral. * input : I2C_FLAG: specifies the flag to check. * This parameter can be: I2C_SR_TXE I2C_SR_MTF ... * retval : None ************************************************************************/ FlagStatus I2C_GetFlagStatus(I2C_TypeDef* I2Cx, uint32_t I2C_FLAG) { FlagStatus bitstatus = RESET; #if (USE_FULL_ASSERT == 1) /* Check the parameters */ assert_param(IS_I2C_ALL_PERIPH(I2Cx)); #endif if(READ_BIT(I2Cx->SR,I2C_FLAG)) { bitstatus =SET; } return bitstatus; } /************************************************************************ * function : I2C_ClearFlag * Description: Checks whether the specified I2C flag is set or not. * input : I2Cx: where x can be 1 or 2 to select the I2C peripheral. * input : I2C_FLAG: specifies the flag to clear. * This parameter can be: I2C_SR_TXE I2C_SR_MTF ... * retval : None ************************************************************************/ void I2C_ClearFlag(I2C_TypeDef* I2Cx, uint32_t I2C_FLAG) { uint32_t flagpos = 0; #if (USE_FULL_ASSERT == 1) /* Check the parameters */ assert_param(IS_I2C_ALL_PERIPH(I2Cx)); #endif /* Clear the selected I2C flag */ I2Cx->SR = READ_BIT(I2Cx->SR, I2C_FLAG); } /************************************************************************ * function : I2C_ClearFlag * Description: Checks whether the specified I2C flag is set or not. * input : I2Cx: where x can be 1 or 2 to select the I2C peripheral. * input :I2C_IT: specifies the I2C interrupts sources to be enabled or disabled. * This parameter can be:I2C_CR_TXE_INT_EN I2C_CR_TXE_INT_EN ... * input : NewState: new state of the I2C START condition generation. * This parameter can be: ENABLE or DISABLE. * retval : None ************************************************************************/ void I2C_ITConfig(I2C_TypeDef* I2Cx, uint16_t I2C_IT, FunctionalState NewState) { #if (USE_FULL_ASSERT == 1) /* Check the parameters */ assert_param(IS_I2C_ALL_PERIPH(I2Cx)); assert_param(IS_FUNCTIONAL_STATE(NewState)); #endif if (NewState != DISABLE) { /* Enable the selected I2C interrupts */ I2Cx->CR |= I2C_IT; } else { /* Disable the selected I2C interrupts */ I2Cx->CR &= (uint16_t)~I2C_IT; } } /************************************************************************ * function : I2C_GenerateSTART * Description: Generates I2Cx communication START condition. * input : I2Cx: where x can be 1 or 2 to select the I2C peripheral. * input : NewState: new state of the I2C START condition generation. * This parameter can be: ENABLE or DISABLE. * retval : None. ************************************************************************/ void I2C_GenerateSTART(I2C_TypeDef* I2Cx, FunctionalState NewState) { #if (USE_FULL_ASSERT == 1) /* Check the parameters */ assert_param(IS_I2C_ALL_PERIPH(I2Cx)); assert_param(IS_FUNCTIONAL_STATE(NewState)); #endif if (NewState != DISABLE) { /* Generate a START condition */ I2Cx->CR |= I2C_CR_START; } else { /* Disable the START condition generation */ I2Cx->CR &= ~I2C_CR_START; } } /************************************************************************ * function : I2C_GenerateSTOP * Description: Generates I2Cx communication STOP condition. * input : I2Cx: where x can be 1 or 2 to select the I2C peripheral. * input : NewState: new state of the I2C START condition generation. * This parameter can be: ENABLE or DISABLE. * retval : None. ************************************************************************/ void I2C_GenerateSTOP(I2C_TypeDef* I2Cx, FunctionalState NewState) { #if (USE_FULL_ASSERT == 1) /* Check the parameters */ assert_param(IS_I2C_ALL_PERIPH(I2Cx)); assert_param(IS_FUNCTIONAL_STATE(NewState)); #endif if (NewState != DISABLE) { /* Generate a STOP condition */ I2Cx->CR |= I2C_CR_STOP; } else { /* Disable the STOP condition generation */ I2Cx->CR &= ~I2C_CR_STOP; } } /************************************************************************ * function : I2C_Send7bitAddress * Description: Transmits the address byte to select the slave device. * input : I2Cx: where x can be 1 or 2 to select the I2C peripheral. * input : Address: specifies the slave address which will be transmitted * input : I2C_Direction: specifies whether the I2C device will be a * Transmitter or a Receiver. This parameter can be one of the following values * @arg I2C_Direction_Transmitter: Transmitter mode * @arg I2C_Direction_Receiver: Receiver mode * retval : None. ************************************************************************/ void I2C_Send7bitAddress(I2C_TypeDef* I2Cx, uint8_t Address, uint8_t I2C_Direction) { #if (USE_FULL_ASSERT == 1) /* Check the parameters */ assert_param(IS_I2C_ALL_PERIPH(I2Cx)); assert_param(IS_I2C_DIRECTION(I2C_Direction)); #endif /* Test on the direction to set/reset the read/write bit */ if (I2C_Direction != I2C_Direction_Transmitter) { /* Set the address bit0 for read */ Address |= 0x01; } else { /* Reset the address bit0 for write */ Address &= 0xFE; } /* Send the address */ I2Cx->DR = Address; } /********************************************************************************* * Function : I2C_StretchClockCmd * Description : Enables or disables the specified I2C Clock stretching. * Input : I2Cx: where x can be 1 or 2 to select the I2C peripheral. * Input : NewState: new state of the I2Cx Clock stretching. * This parameter can be: ENABLE or DISABLE. * Output : None **********************************************************************************/ void I2C_StretchClockCmd(I2C_TypeDef* I2Cx, FunctionalState NewState) { #if (USE_FULL_ASSERT == 1) /* Check the parameters */ assert_param(IS_I2C_ALL_PERIPH(I2Cx)); assert_param(IS_FUNCTIONAL_STATE(NewState)); #endif if (NewState == DISABLE) { /* Enable the selected I2C Clock stretching */ I2Cx->CR &= ~I2C_CR_NOSTRETCH; } else { /* Disable the selected I2C Clock stretching */ I2Cx->CR |= I2C_CR_NOSTRETCH; } } /********************************************************************************* * Function : I2C_ReadRegister * Description : Reads the specified I2C register and returns its value. * Input : I2Cx: where x can be 1 or 2 to select the I2C peripheral. * Input : I2C_Register: specifies the register to read. * This parameter can be: I2C_Register_ADDR1 I2C_Register_CR ... * retval : None **********************************************************************************/ uint32_t I2C_ReadRegister(I2C_TypeDef* I2Cx, uint8_t I2C_Register) { __IO uint32_t tmp = 0; #if (USE_FULL_ASSERT == 1) /* Check the parameters */ assert_param(IS_I2C_ALL_PERIPH(I2Cx)); assert_param(IS_I2C_REGISTER(I2C_Register)); #endif tmp = (uint32_t) I2Cx; tmp += I2C_Register; /* Return the selected register value */ return (*(__IO uint32_t *) tmp); } /********************************************************************************* * Function : I2C_SendData * Description : Sends a data byte through the I2Cx peripheral. * Input : I2Cx: where x can be 1 or 2 to select the I2C peripheral. * Input : Data: Byte to be transmitted.. * Output : None **********************************************************************************/ void I2C_SendData(I2C_TypeDef* I2Cx, uint8_t Data) { #if (USE_FULL_ASSERT == 1) /* Check the parameters */ assert_param(IS_I2C_ALL_PERIPH(I2Cx)); #endif /* Write in the DR register the data to be sent */ I2Cx->DR = Data; } /********************************************************************************* * Function : I2C_ReceiveData * Description : Returns the most recent received data by the I2Cx peripheral. * Input : I2Cx: where x can be 1 or 2 to select the I2C peripheral. * Input : Data: Byte to be transmitted.. * Output : None **********************************************************************************/ uint8_t I2C_ReceiveData(I2C_TypeDef* I2Cx) { #if (USE_FULL_ASSERT == 1) /* Check the parameters */ assert_param(IS_I2C_ALL_PERIPH(I2Cx)); #endif /* Return the data in the DR register */ return (uint8_t)I2Cx->DR; } /********************************************************************************* * Function : I2C_WaitOnFlagUntilTimeout * Description : This function handles I2C Communication Timeout. * Input : I2Cx: where x can be 1 or 2 to select the I2C peripheral. * Input : Flag: Flag specifies the I2C flag to check. * Input : Status: The new Flag status (SET or RESET). * Input : Timeout: Timeout duration. * Output : None **********************************************************************************/ static uint8_t I2C_WaitOnFlagUntilTimeout(I2C_TypeDef* I2Cx, uint32_t Flag, FlagStatus Status, uint32_t Timeout) { __IO uint32_t lu32_Timeout; /* have no timeout */ if (Timeout == 0) { while(_I2C_GET_FLAG(I2Cx, Flag)==Status); } else { lu32_Timeout = Timeout * 256; while(_I2C_GET_FLAG(I2Cx, Flag)==Status) { if (lu32_Timeout-- == 0) { return I2C_ERROR; } } } return I2C_OK; } /************************************************************************ * function : I2C_Master_Request_Write * Description: I2C Write Access Request * input : I2Cx: where x can be 1 or 2 to select the I2C peripheral. * DevAddress: Device address * Timeout: Timeout value ************************************************************************/ static uint8_t I2C_Master_Request_Write(I2C_TypeDef* I2Cx, uint8_t DevAddress, uint32_t Timeout) { /* Generate Start */ I2C_GenerateSTART(I2Cx,ENABLE); /* Clear MTF, To Prevent Errors */ I2C_ClearFlag(I2Cx,I2C_SR_MTF); /* Send Device Address */ I2C_Send7bitAddress(I2Cx,DevAddress,I2C_Direction_Transmitter); /* Wait for transmission End*/ if(I2C_WaitOnFlagUntilTimeout(I2Cx, I2C_SR_MTF, RESET, Timeout) != I2C_OK) return I2C_ERROR; /* Clear MTF */ I2C_ClearFlag(I2Cx,I2C_SR_MTF); /* Get NACK */ if (I2C_GetFlagStatus(I2Cx, I2C_SR_RACK)) { /* Generate Stop */ I2C_GenerateSTOP(I2Cx,ENABLE); /* Wait for the bus to idle */ if(I2C_WaitOnFlagUntilTimeout(I2Cx, I2C_SR_BUS_BUSY, SET, Timeout) != I2C_OK) return I2C_ERROR; return I2C_ERROR; } /* Get ACK */ else { return I2C_OK; } } /************************************************************************ * function : I2C_Master_Request_Read * Description: I2C Read Access Request * input : I2Cx: where x can be 1 or 2 to select the I2C peripheral. * DevAddress: Device address * Timeout: Timeout value ************************************************************************/ static uint8_t I2C_Master_Request_Read(I2C_TypeDef* I2Cx, uint8_t DevAddress, uint32_t Timeout) { /* Generate Start */ I2C_GenerateSTART(I2Cx,ENABLE); /* Clear MTF, To Prevent Errors */ I2C_ClearFlag(I2Cx,I2C_SR_MTF); /* Send Device Address */ I2C_Send7bitAddress(I2Cx,DevAddress,I2C_Direction_Receiver); /* Wait for transmission End */ if(I2C_WaitOnFlagUntilTimeout(I2Cx, I2C_SR_MTF, RESET, Timeout) != I2C_OK) return I2C_ERROR; /* Clear MTF */ I2C_ClearFlag(I2Cx,I2C_SR_MTF); /* Get NACK */ if (I2C_GetFlagStatus(I2Cx, I2C_SR_RACK)) { /* Generate Stop */ I2C_GenerateSTOP(I2Cx,ENABLE); /* Wait for the bus to idle */ if(I2C_WaitOnFlagUntilTimeout(I2Cx, I2C_SR_BUS_BUSY, SET, Timeout) != I2C_OK) return I2C_ERROR; return I2C_ERROR; } /* Get ACK */ else { return I2C_OK; } } /************************************************************************ * function : I2C_Check_Device_Ready * Description: Check Device Ready * input : I2Cx: where x can be 1 or 2 to select the I2C peripheral. * DevAddress: Device address * Timeout: Timeout value ************************************************************************/ static uint8_t I2C_Check_Device_Ready(I2C_TypeDef* I2Cx, uint8_t DevAddress, uint32_t Timeout) { /* Bus Busy */ if (I2C_GetFlagStatus(I2Cx, I2C_SR_BUS_BUSY)) return I2C_ERROR; /* Generate Start */ I2C_GenerateSTART(I2Cx,ENABLE); /* Send Device Address */ I2Cx->DR = DevAddress; /* Wait for transmission End */ if(I2C_WaitOnFlagUntilTimeout(I2Cx, I2C_SR_MTF, RESET, Timeout) != I2C_OK) return I2C_ERROR; /* Clear MTF */ I2C_ClearFlag(I2Cx,I2C_SR_MTF); /* Get NACK */ if (I2C_GetFlagStatus(I2Cx, I2C_SR_RACK)) { /* Generate Stop */ I2C_GenerateSTOP(I2Cx,ENABLE); /* Wait for the bus to idle */ if(I2C_WaitOnFlagUntilTimeout(I2Cx, I2C_SR_BUS_BUSY, SET, Timeout) != I2C_OK) return I2C_ERROR; return I2C_ERROR; } /* Get ACK */ else { /* Generate Stop */ I2C_GenerateSTOP(I2Cx,ENABLE); /* Wait for the bus to idle */ if(I2C_WaitOnFlagUntilTimeout(I2Cx, I2C_SR_BUS_BUSY, SET, Timeout) != I2C_OK) return I2C_ERROR; return I2C_OK; } } /************************************************************************ * function : I2C_Mem_Write * Description: Write an amount of data in blocking mode to a specific memory address * input : I2Cx: where x can be 1 or 2 to select the I2C peripheral. * DevAddress : Target device address * MemAddress : MemAddress Internal memory address * MemAddSize : MemAddSize Size of internal memory address * pData : Pointer to data buffer * Size : Amount of data to be sent * Timeout : Timeout value ************************************************************************/ uint8_t I2C_Mem_Write(I2C_TypeDef* I2Cx,uint8_t DevAddress, uint16_t MemAddress, uint16_t MemAddSize, uint8_t *pData, uint32_t Size, uint32_t Timeout) { uint32_t i; #if (USE_FULL_ASSERT == 1) /* Check the parameters */ assert_param(IS_I2C_ALL_PERIPH(I2Cx)); #endif /* Bus Busy */ if (I2C_GetFlagStatus(I2Cx, I2C_SR_BUS_BUSY)) return I2C_BUSY; /* Send Write Access Request */ if (I2C_Master_Request_Write(I2Cx, DevAddress,0) == I2C_OK) { /* If Memory address size is 8Bit */ if (MemAddSize == I2C_MEMADD_SIZE_8BIT) { /* Send Memory Address */ I2C_SendData(I2Cx,I2C_MEM_ADD_LSB(MemAddress)); } /* If Memory address size is 16Bit */ else { /* Send Memory Address MSB*/ I2C_SendData(I2Cx,I2C_MEM_ADD_MSB(MemAddress)); /* Wait for transmission End*/ if(I2C_WaitOnFlagUntilTimeout(I2Cx, I2C_SR_MTF, RESET, Timeout) != I2C_OK) return I2C_ERROR; /* Clear MTF */ I2C_ClearFlag(I2Cx,I2C_SR_MTF); /* Send Memory Address LSB*/ I2C_SendData(I2Cx,I2C_MEM_ADD_LSB(MemAddress)); } /* Wait for transmission End*/ if(I2C_WaitOnFlagUntilTimeout(I2Cx, I2C_SR_MTF, RESET, Timeout) != I2C_OK) return I2C_ERROR; /* Clear MTF */ I2C_ClearFlag(I2Cx,I2C_SR_MTF); /* Get NACK */ if (I2C_GetFlagStatus(I2Cx, I2C_SR_RACK)) { /* Generate Stop */ I2C_GenerateSTOP(I2Cx,ENABLE); /* Wait for the bus to idle */ if(I2C_WaitOnFlagUntilTimeout(I2Cx, I2C_SR_BUS_BUSY, SET, Timeout) != I2C_OK) return I2C_ERROR; return I2C_ERROR; } /* Get ACK */ else { for (i = 0; i < Size; i++) { /* Wait TXE Flag */ if(I2C_WaitOnFlagUntilTimeout(I2Cx, I2C_SR_TXE, RESET, Timeout)!= I2C_OK) return I2C_ERROR; /* Send Data */ I2C_SendData(I2Cx,pData[i]); /* Wait for transmission End*/ if(I2C_WaitOnFlagUntilTimeout(I2Cx, I2C_SR_MTF, RESET, Timeout) != I2C_OK) return I2C_ERROR; /* Clear MTF */ I2C_ClearFlag(I2Cx,I2C_SR_MTF); /* Get NACK */ if (I2C_GetFlagStatus(I2Cx, I2C_SR_RACK)) { /* Generate Stop */ I2C_GenerateSTOP(I2Cx,ENABLE); /* Wait for the bus to idle */ if(I2C_WaitOnFlagUntilTimeout(I2Cx, I2C_SR_BUS_BUSY, SET, Timeout) != I2C_OK) return I2C_ERROR; return I2C_ERROR; } } /* Generate Stop */ I2C_GenerateSTOP(I2Cx,ENABLE); /* Wait for the bus to idle */ if(I2C_WaitOnFlagUntilTimeout(I2Cx, I2C_SR_BUS_BUSY, SET, Timeout) != I2C_OK) return I2C_ERROR; /* Check Device Ready */ while(I2C_Check_Device_Ready(I2Cx, DevAddress, Timeout) != I2C_OK); } } else { return I2C_ERROR; } return I2C_OK; } /************************************************************************ * function : I2C_Mem_Read * Description: Read an amount of data in blocking mode to a specific memory address * input : I2Cx: where x can be 1 or 2 to select the I2C peripheral. * DevAddress : Target device address * MemAddress : MemAddress Internal memory address * MemAddSize : MemAddSize Size of internal memory address * pData : Pointer to data buffer * Size : Amount of data to be sent * Timeout : Timeout value ************************************************************************/ uint8_t I2C_Mem_Read(I2C_TypeDef* I2Cx, uint8_t DevAddress, uint16_t MemAddress, uint16_t MemAddSize, uint8_t *pData, uint16_t Size, uint32_t Timeout) { uint32_t i; #if (USE_FULL_ASSERT == 1) /* Check the parameters */ assert_param(IS_I2C_ALL_PERIPH(I2Cx)); #endif /* Bus Busy */ if (READ_BIT(I2Cx->SR, I2C_SR_BUS_BUSY)) return I2C_ERROR; /* Send Write Access Request */ if (I2C_Master_Request_Write(I2Cx, DevAddress,0) == I2C_OK) { /* If Memory address size is 8Bit */ if (MemAddSize == I2C_MEMADD_SIZE_8BIT) { /* Send Memory Address */ I2Cx->DR = I2C_MEM_ADD_LSB(MemAddress); } /* If Memory address size is 16Bit */ else { /* Send Memory Address MSB*/ I2Cx->DR = I2C_MEM_ADD_MSB(MemAddress); /* Wait for transmission End*/ if(I2C_WaitOnFlagUntilTimeout(I2Cx, I2C_SR_MTF, RESET, Timeout) != I2C_OK) return I2C_ERROR; /* Clear MTF */ I2Cx->SR = READ_BIT(I2Cx->SR, I2C_SR_MTF); /* Send Memory Address LSB*/ I2Cx->DR = I2C_MEM_ADD_LSB(MemAddress); } /* Wait for transmission End*/ if(I2C_WaitOnFlagUntilTimeout(I2Cx, I2C_SR_MTF, RESET, Timeout) != I2C_OK) return I2C_ERROR; /* Clear MTF */ I2Cx->SR = READ_BIT(I2Cx->SR, I2C_SR_MTF); /* Get NACK */ if (READ_BIT(I2Cx->SR, I2C_SR_RACK)) { /* Generate Stop */ SET_BIT(I2Cx->CR, I2C_CR_STOP); /* Wait for the bus to idle */ if(I2C_WaitOnFlagUntilTimeout(I2Cx, I2C_SR_BUS_BUSY, SET, Timeout) != I2C_OK) return I2C_ERROR; return I2C_ERROR; } /* Get ACK */ else { /* Send Write Read Request */ if (I2C_Master_Request_Read(I2Cx, DevAddress, Timeout) == I2C_OK) { /* Wait Master Transition receiving state */ if(I2C_WaitOnFlagUntilTimeout(I2Cx, I2C_SR_TX_RX_FLAG, RESET, Timeout) != I2C_OK) return I2C_ERROR; /* Clear TX_RX_FLAG */ I2Cx->SR = READ_BIT(I2Cx->SR, I2C_SR_TX_RX_FLAG); /* Generate ACK */ CLEAR_BIT(I2Cx->CR, I2C_CR_TACK); for (i = 0; i DR; /* Wait for transmission End*/ if(I2C_WaitOnFlagUntilTimeout(I2Cx, I2C_SR_MTF, RESET, Timeout) != I2C_OK) return I2C_ERROR; /* Clear MTF */ I2Cx->SR = READ_BIT(I2Cx->SR, I2C_SR_MTF); } /* Prepare for Generate NACK */ SET_BIT(I2Cx->CR, I2C_CR_TACK); /* Prepare for Generate STOP */ SET_BIT(I2Cx->CR, I2C_CR_STOP); /* Wait RXNE Flag */ if(I2C_WaitOnFlagUntilTimeout(I2Cx, I2C_SR_RXNE, RESET, Timeout) != I2C_OK) return I2C_ERROR; /* Read Data */ pData[i] = I2Cx->DR; /* Wait for transmission End*/ if(I2C_WaitOnFlagUntilTimeout(I2Cx, I2C_SR_MTF, RESET, Timeout) != I2C_OK) return I2C_ERROR; /* Clear MTF */ I2Cx->SR = READ_BIT(I2Cx->SR, I2C_SR_MTF); /* Wait for the bus to idle */ if(I2C_WaitOnFlagUntilTimeout(I2Cx, I2C_SR_BUS_BUSY, SET, Timeout) != I2C_OK) return I2C_ERROR; /* Generate ACK */ CLEAR_BIT(I2Cx->CR, I2C_CR_TACK); } else { /* Get NACK */ return I2C_ERROR; } } } else { return I2C_OK; } return I2C_OK; } /************************************************************************ * function : I2C_Master_Transmit * Description: Transmits in master mode an amount of data in blocking mode. * input : I2Cx: where x can be 1 or 2 to select the I2C peripheral. * DevAddress : Target device address * pData : Pointer to data buffer * Size : Amount of data to be sent * Timeout : Timeout value ************************************************************************/ uint8_t I2C_Master_Transmit(I2C_TypeDef* I2Cx, uint16_t DevAddress, uint8_t *pData, uint32_t Size, uint32_t Timeout) { uint32_t i; #if (USE_FULL_ASSERT == 1) /* Check the parameters */ assert_param(IS_I2C_ALL_PERIPH(I2Cx)); #endif /* Send Write Access Request */ if (I2C_Master_Request_Write(I2Cx, DevAddress, Timeout) == I2C_OK) { for (i = 0; i < Size; i++) { /* Wait TXE Flag */ if(I2C_WaitOnFlagUntilTimeout(I2Cx, I2C_SR_TXE, RESET, Timeout) != I2C_OK) return I2C_ERROR; /* Send Data */ I2C_SendData(I2Cx,pData[i]); /* Wait for transmission End*/ if(I2C_WaitOnFlagUntilTimeout(I2Cx, I2C_SR_MTF, RESET, Timeout) != I2C_OK) return I2C_ERROR; /* Clear MTF */ I2C_ClearFlag(I2Cx,I2C_SR_MTF); /* Get NACK */ if (I2C_GetFlagStatus(I2Cx, I2C_SR_RACK)) { /* Generate Stop */ I2C_GenerateSTOP(I2Cx,ENABLE); /* Wait for the bus to idle */ if(I2C_WaitOnFlagUntilTimeout(I2Cx, I2C_SR_BUS_BUSY, SET, Timeout) != I2C_OK) return I2C_ERROR; return I2C_ERROR; } } /* Generate Stop */ I2C_GenerateSTOP(I2Cx,ENABLE); /* Wait for the bus to idle */ if(I2C_WaitOnFlagUntilTimeout(I2Cx, I2C_SR_BUS_BUSY, SET, Timeout) != I2C_OK) return I2C_ERROR; } else { return I2C_ERROR; } return I2C_OK; } /************************************************************************ * function : I2C_Master_Receive * Description: Transmits in master mode an amount of data in blocking mode. * input : I2Cx: where x can be 1 or 2 to select the I2C peripheral. * DevAddress : Target device address * pData : Pointer to data buffer * Size : Amount of data to be Receive * Timeout : Timeout value ************************************************************************/ uint8_t I2C_Master_Receive(I2C_TypeDef* I2Cx, uint16_t DevAddress, uint8_t *pData, uint16_t Size, uint32_t Timeout) { uint32_t i; #if (USE_FULL_ASSERT == 1) /* Check the parameters */ assert_param(IS_I2C_ALL_PERIPH(I2Cx)); #endif /* Send Read Access Request */ if (I2C_Master_Request_Read(I2Cx, DevAddress, Timeout) == I2C_OK) { /* Wait Master Transition receiving state */ if(I2C_WaitOnFlagUntilTimeout(I2Cx, I2C_SR_TX_RX_FLAG, RESET, Timeout) != I2C_OK) return I2C_ERROR; /* Clear TX_RX_FLAG */ I2C_ClearFlag(I2Cx,I2C_SR_TX_RX_FLAG); /* Generate ACK */ CLEAR_BIT(I2Cx->CR, I2C_CR_TACK); for (i = 0; i < Size - 1; i++) { /* Wait RXNE Flag */ if(I2C_WaitOnFlagUntilTimeout(I2Cx, I2C_SR_RXNE, RESET, Timeout) != I2C_OK) return I2C_ERROR; /* Read Data */ pData[i] = I2C_ReceiveData(I2Cx); /* Wait for transmission End*/ if(I2C_WaitOnFlagUntilTimeout(I2Cx, I2C_SR_MTF, RESET, Timeout) != I2C_OK) return I2C_ERROR; /* Clear MTF */ I2Cx->SR = READ_BIT(I2Cx->SR, I2C_SR_MTF); } /* Prepare for Generate NACK */ SET_BIT(I2Cx->CR, I2C_CR_TACK); /* Prepare for Generate STOP */ SET_BIT(I2Cx->CR, I2C_CR_STOP); /* Wait RXNE Flag */ if(I2C_WaitOnFlagUntilTimeout(I2Cx, I2C_SR_RXNE, RESET, Timeout) != I2C_OK) return I2C_ERROR; /* Read Data */ pData[i] = I2C_ReceiveData(I2Cx); /* Wait for transmission End*/ if(I2C_WaitOnFlagUntilTimeout(I2Cx, I2C_SR_MTF, RESET, Timeout) != I2C_OK) return I2C_ERROR; /* Clear MTF */ I2C_ClearFlag(I2Cx,I2C_SR_MTF); /* Wait for the bus to idle */ if(I2C_WaitOnFlagUntilTimeout(I2Cx, I2C_SR_BUS_BUSY, SET, Timeout) != I2C_OK) return I2C_ERROR; /* Generate ACK */ CLEAR_BIT(I2Cx->CR, I2C_CR_TACK); } else { return I2C_ERROR; } return I2C_OK; } /************************************************************************ * function : I2C_Slave_Transmit * Description: Transmits in Slave mode an amount of data in blocking mode. * input : I2Cx: where x can be 1 or 2 to select the I2C peripheral. * pData : Pointer to data buffer * Size : Amount of data to be sent * Timeout : Timeout value ************************************************************************/ uint8_t I2C_Slave_Transmit(I2C_TypeDef* I2Cx, uint8_t *pData, uint32_t Size, uint32_t Timeout) { uint32_t i = 0; #if (USE_FULL_ASSERT == 1) /* Check the parameters */ assert_param(IS_I2C_ALL_PERIPH(I2Cx)); #endif /* Clear RX_ADDR1 Flag */ I2C_ClearFlag(I2Cx,I2C_SR_RX_ADDR1); /* Match the Address 1 */ if(I2C_WaitOnFlagUntilTimeout(I2Cx, I2C_SR_RX_ADDR1, RESET, Timeout) != I2C_OK) return I2C_ERROR; /* Clear RX_ADDR1 Flag */ I2C_ClearFlag(I2Cx,I2C_SR_RX_ADDR1); /* Slave Transmit */ if (I2C_GetFlagStatus(I2Cx, I2C_SR_SRW)) { /* BUS BUSY */ while(I2C_GetFlagStatus(I2Cx, I2C_SR_BUS_BUSY)) { if (I2C_GetFlagStatus(I2Cx, I2C_SR_MTF)) { /* Clear MTF */ I2C_ClearFlag(I2Cx,I2C_SR_MTF); } if (I2C_GetFlagStatus(I2Cx, I2C_SR_TXE)) { if (i < Size || Size == 0) { I2C_SendData(I2Cx,pData[i]); i++; } } } //Clear Flags I2Cx->SR = READ_REG(I2Cx->SR); } else { return I2C_ERROR; } return I2C_OK; } /************************************************************************ * function : I2C_Slave_Receive * Description: Receive in Slave mode an amount of data in blocking mode. * input : I2Cx: where x can be 1 or 2 to select the I2C peripheral. * pData : Pointer to data buffer * Size : Amount of data to be sent * Timeout : Timeout value * retval : I2C_OK or I2C_ERROR ************************************************************************/ uint8_t I2C_Slave_Receive(I2C_TypeDef* I2Cx, uint8_t *pData, uint32_t Size, uint32_t Timeout) { uint32_t Rx_Count =0; #if (USE_FULL_ASSERT == 1) /* Check the parameters */ assert_param(IS_I2C_ALL_PERIPH(I2Cx)); #endif /* Match the Address 1 */ if(I2C_WaitOnFlagUntilTimeout(I2Cx, I2C_SR_RX_ADDR1, RESET, Timeout) != I2C_OK) return I2C_ERROR; /* Clear RX_ADDR1 Flag */ I2C_ClearFlag(I2Cx,I2C_SR_RX_ADDR1); /* Slave Receive */ if (!I2C_GetFlagStatus(I2Cx, I2C_SR_SRW)) { /* Wait for transmission End*/ if(I2C_WaitOnFlagUntilTimeout(I2Cx, I2C_SR_MTF, RESET, Timeout) != I2C_OK) return I2C_ERROR; /* Clear MTF */ I2C_ClearFlag(I2Cx,I2C_SR_MTF); /* BUS BUSY */ while(I2C_GetFlagStatus(I2Cx, I2C_SR_BUS_BUSY)) { /* Receive Data */ if (I2C_GetFlagStatus(I2Cx, I2C_SR_RXNE)) { pData[Rx_Count++] = I2C_ReceiveData(I2Cx); /* Wait for transmission End*/ if(I2C_WaitOnFlagUntilTimeout(I2Cx, I2C_SR_MTF, RESET, Timeout) != I2C_OK) return I2C_ERROR; /* Clear MTF */ I2C_ClearFlag(I2Cx,I2C_SR_MTF); if (Size != 0) { if (Rx_Count >= Size) { break; } } } } /* Clear ACK */ CLEAR_BIT(I2Cx->CR, I2C_CR_TACK); I2Cx->SR = READ_REG(I2Cx->SR); } /* Slave Transmit */ else { return I2C_ERROR; } return I2C_OK; } /************************************************************************ * function : I2C_Slave_Transmit_IT * Description: Transmit in slave mode an amount of data in non-blocking mode with Interrupt * input : hi2c : pointer to a I2C_HandleTypeDef structure that contains * the configuration information for I2C module * pData : Pointer to data buffer * Size : Amount of data to be sent * return : HAL_StatusTypeDef ************************************************************************/ uint8_t I2C_Slave_Transmit_IT(I2C_TypeDef* I2Cx, Slave_Comm_TypeDef* Slave_Comm, uint8_t *pData, uint32_t Size) { #if (USE_FULL_ASSERT == 1) /* Check the parameters */ assert_param(IS_I2C_ALL_PERIPH(I2Cx)); #endif /* Slave machine is running */ if (Slave_Comm->Slave_TxState != SLAVE_TX_STATE_IDLE) return I2C_ERROR; /* Set Slave machine is sending */ Slave_Comm->Slave_TxState = SLAVE_TX_STATE_SENDING; Slave_Comm->Tx_Buffer = pData; Slave_Comm->Tx_Size = Size; Slave_Comm->Tx_Count = 0; CLEAR_BIT(I2Cx->CR, I2C_CR_TXE_SEL); I2Cx->DR = Slave_Comm->Tx_Buffer[0]; Slave_Comm->Tx_Count++; /* Clear RX ADDR1 Flag */ I2C_ClearFlag(I2Cx,I2C_SR_RX_ADDR1); /* RX ADDR1 Interrupt Enable */ I2C_ITConfig(I2Cx,I2C_CR_RX_ADDR1_INT_EN,ENABLE); return I2C_OK; } /************************************************************************ * function : I2C_Slave_Receive_IT * Description: Receive in slave mode an amount of data in non-blocking mode with Interrupt * input : hi2c : pointer to a I2C_HandleTypeDef structure that contains * the configuration information for I2C module * pData : Pointer to data buffer * Size : Amount of data to be sent ************************************************************************/ uint8_t I2C_Slave_Receive_IT(I2C_TypeDef* I2Cx, Slave_Comm_TypeDef* Slave_Comm,uint8_t *pData, uint32_t Size) { #if (USE_FULL_ASSERT == 1) /* Check the parameters */ assert_param(IS_I2C_ALL_PERIPH(I2Cx)); #endif /* Rx machine is running */ if (Slave_Comm->Slave_RxState != SLAVE_RX_STATE_IDLE) return I2C_ERROR; /* Set Slave machine is receiving */ Slave_Comm->Slave_RxState = SLAVE_RX_STATE_RECEIVING; Slave_Comm->Rx_Buffer = pData; Slave_Comm->Rx_Size = Size; Slave_Comm->Rx_Count = 0; /* Clear RX ADDR1 Flag */ I2C_ClearFlag(I2Cx,I2C_SR_RX_ADDR1); /* RX ADDR1 Interrupt Enable */ I2C_ITConfig(I2Cx,I2C_CR_RX_ADDR1_INT_EN,ENABLE); return I2C_OK; }