/**************************************************************************//** * @file i2c.c * @version V1.00 * $Revision: 2 $ * $Date: 16/02/2216:24 $ * @brief Panchip series I2C driver source file * * @note * Copyright (C) 2016 Panchip Technology Corp. All rights reserved. *****************************************************************************/ #include "PanSeries.h" #include "pan_i2c.h" #include "pan_clk.h" /** * @brief Initializes the I2Cx peripheral according to the specified * parameters in the I2C_InitStruct. * * @note To use the I2C at 400 KHz (in fast mode), the PCLK1 frequency * (I2C peripheral input clock) must be a multiple of 10 MHz. * * @param I2Cx: where x can be 1, 2 or 3 to select the I2C peripheral. * @param I2C_InitStruct: pointer to a I2C_InitTypeDef structure that contains * the configuration information for the specified I2C peripheral. * @note This function should be called before enabling the I2C Peripheral. * @retval None */ bool I2C_Init(I2C_T* I2Cx, I2C_InitTypeDef* I2C_InitStruct) { uint32_t tmpreg = 0; uint32_t result = 0; uint32_t pclk; /*get system clock frequency*/ pclk = CLK_GetPeripheralFreq(I2Cx); /*---------------------------- I2Cx CON Configuration ------------------------*/ /*Disable I2C */ tmpreg = I2Cx->CON; /*restart enable*/ tmpreg |= (I2C_CON_IC_RESTART_EN); /* slave address mode*/ if(I2C_AcknowledgedAddress_7bit == I2C_InitStruct->I2C_AcknowledgedAddress) { tmpreg &= ~I2C_CON_IC_10BITADDR_SLAVE; } else//10-bit addr { tmpreg |= I2C_CON_IC_10BITADDR_SLAVE; } tmpreg &= ~(I2C_CON_SPEED); /*---------------------------- I2Cx HCNT/LCNT Configuration ------------------------*/ /* Configure speed in standard mode */ result = pclk / I2C_InitStruct->I2C_ClockSpeed; if (I2C_InitStruct->I2C_ClockSpeed <= 100000) { /* Standart mode speed calculate: Tlow/Thigh = 1 */ result /= 2; if(result < I2Cx->FS_SPKLEN +7) return false; /*HCNT equals to LCNT*/ I2Cx->SS_SCL_HCNT = result - I2Cx->FS_SPKLEN - 7; I2Cx->SS_SCL_LCNT = result - 1; tmpreg |= I2C_SPEED_STANDARD_MODE; } /* Configure speed in fast mode */ else if (I2C_InitStruct->I2C_ClockSpeed <= 1000000) { I2C_InitStruct->I2C_DutyCycle = I2C_InitStruct->I2C_DutyCycle % 101; if(result* I2C_InitStruct->I2C_DutyCycle / 100 < I2Cx->FS_SPKLEN +7) return false; /* Set DUTY bit */ I2Cx->FS_SCL_HCNT = result * I2C_InitStruct->I2C_DutyCycle / 100 - I2Cx->FS_SPKLEN - 7; I2Cx->FS_SCL_LCNT = (result * (100 - I2C_InitStruct->I2C_DutyCycle) / 100) - 1; tmpreg |= I2C_SPEED_FAST_MODE; } /* To use the I2C at 1 MHz (in fast mode plus ) */ else { result /= 3; if(result < I2Cx->HS_SPKLEN +7) return false; /* Set DUTY bit */ I2Cx->HS_SCL_HCNT = result - I2Cx->HS_SPKLEN - 7; I2Cx->HS_SCL_LCNT = (result << 1) - 1; tmpreg |= I2C_SPEED_HIGH_MODE; } I2Cx->CON = tmpreg; /*data setup time: 250ns*/ I2Cx->SDA_SETUP = (pclk) / 4000000 + 1; /* Set I2Cx Own Address1 and acknowledged address */ I2Cx->SAR &= ~( I2C_TAR_TAR); /* Get 7-bit address from I2C_OwnAddress1*/ I2Cx->SAR |= ((I2C_InitStruct ->I2C_OwnAddress1 )) ; /* Disable all interrupts to avoid unexpected cases */ I2C_DisableAllIT(I2Cx); /*fifo threshold */ I2Cx->TX_TL = I2C_TX_TL_4; I2Cx->RX_TL = I2C_RX_TL_4; return true; } /** * @brief Configure the target address for any master transaction. * @param I2Cx: where x can be 1, 2 or 3 to select the I2C peripheral. * @param Address: specifies the slave 7-bit address which will be transmitted * @retval None. */ void I2C_Set7bitAddress(I2C_T* I2Cx, uint8_t Address) { uint32_t tmpreg; /* Check the parameters */ tmpreg = I2Cx->TAR; /*7-bits address mode*/ tmpreg &= ~(I2C_TAR_IC_10BITADDR_MASTER | I2C_TAR_SPECIAL | I2C_TAR_GC_OR_START | I2C_TAR_TAR); tmpreg |= (Address & 0x07F); /* Send the address */ I2Cx->TAR = tmpreg; } /** * @brief Configure the target address for any master transaction. * @param I2Cx: where x can be 1, 2 or 3 to select the I2C peripheral. * @param Address: specifies the slave 10-bit address which will be transmitted * @retval None. */ void I2C_Set10bitAddress(I2C_T* I2Cx, uint16_t Address) { uint32_t tmpreg; tmpreg = I2Cx->TAR; /*7-bits address mode*/ tmpreg &= ~(I2C_TAR_IC_10BITADDR_MASTER | I2C_TAR_SPECIAL | I2C_TAR_GC_OR_START | I2C_TAR_TAR); tmpreg |= (I2C_TAR_IC_10BITADDR_MASTER | (Address & 0x03ff)); /* Send the address */ I2Cx->TAR = tmpreg; } /** * @brief Checks whether the specified I2C flag is set or not. * @param I2Cx: where x can be 1, 2 or 3 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_SLV_ACTIVITY * @arg I2C_FLAG_MST_ACTIVITY * @arg I2C_FLAG_RFF * @arg I2C_FLAG_TFE * @arg I2C_FLAG_TFNF * @arg I2C_FLAG_ACTIVITY * @arg I2C_FLAG_MST_ACTIVITY * @retval The new state of I2C_FLAG (SET or RESET). */ FlagStatus I2C_GetFlagStatus(I2C_T* I2Cx, uint32_t I2C_FLAG) { FlagStatus bitstatus = RESET; __IO uint32_t i2cxbase = 0; /* Get the I2Cx peripheral base address */ i2cxbase = (uint32_t)I2Cx; /* Get bit[23:0] of the flag */ I2C_FLAG &= FLAG_MASK; i2cxbase += 0x70; 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; } /** * @brief Clears the I2Cx's interrupt pending bits. * @param I2Cx: where x can be 1, 2 or 3 to select the I2C peripheral. * @param I2C_IT: specifies the interrupt pending bit to clear. * @arg I2C_IT_RX_UNDER * @arg I2C_IT_RX_OVER * @arg I2C_IT_RX_FULL * @arg I2C_IT_TX_OVER * @arg I2C_IT_TX_EMPTY * @arg I2C_IT_RD_REQ * @arg I2C_IT_TX_ABRT * @arg I2C_IT_RX_DONE * @arg I2C_IT_ACTIVITY * @arg I2C_IT_STOP_DET * @arg I2C_IT_START_DET * @arg I2C_IT_GEN_CALL * @arg I2C_IT_MST_ON_HOLD * @retval None */ void I2C_ClearITPendingBit(I2C_T* I2Cx, uint16_t I2C_IT) { uint16_t flagpos = 0; /* Get the I2C flag position */ flagpos = (I2C_IT & IT_FLAG_MASK); /* Clear the selected I2C flag */ if(flagpos & I2C_IT_RX_UNDER) (void)(I2Cx->CLR_RX_UND); if(flagpos & I2C_IT_RX_OVER) (void)(I2Cx->CLR_RX_OVR); if(flagpos & I2C_IT_TX_OVER) (void)(I2Cx->CLR_TX_OVR); if(flagpos & I2C_IT_RD_REQ) (void)(I2Cx->CLR_RD_REQ); if(flagpos & I2C_IT_TX_ABORT) (void)(I2Cx->CLR_TX_ABRT); if(flagpos & I2C_IT_RX_DONE) (void)(I2Cx->CLR_RX_DONE); if(flagpos & I2C_IT_ACTIVITY) (void)(I2Cx->CLR_ACTIVITY); if(flagpos & I2C_IT_STOP_DET) (void)(I2Cx->CLR_STOP_DET); if(flagpos & I2C_IT_START_DET) (void)(I2Cx->CLR_START_DET); if(flagpos & I2C_IT_GEN_CALL) (void)(I2Cx->CLR_GEN_CALL); if(flagpos & I2C_IT_MST_ON_HOLD) (void)(I2Cx->CLR_RESTART_DET); if(flagpos & I2C_IT_ACTIVITY) (void)(I2Cx->CLR_ACTIVITY); } /** * @brief read data from the I2Cx peripheral. * @param I2Cx: where x can be 1, 2 or 3 to select the I2C peripheral. * @param ReadBuf: cache of stored readings. * @param Size: number of data read from I2C peripheral. * @retval none. */ void I2C_Read(I2C_T* I2Cx,uint8_t *ReadBuf,uint32_t Size) { // uint32_t timeout = SystemCoreClock / 10000; while(Size){ if(I2C_CON_MASTER_MODE & I2Cx->CON){ while(!I2C_GetFlagStatus(I2Cx,I2C_FLAG_TFNF)){} if(Size > 1){ I2C_SendCmd(I2Cx,I2C_CMD_RD); }else{ I2C_SendCmd(I2Cx,I2C_CMD_RD|I2C_CMD_STOP); } } while(!I2C_GetFlagStatus(I2Cx, I2C_FLAG_RFNE)){ // if (timeout == 0) // break; // timeout--; } *ReadBuf = (uint8_t)I2Cx->DATACMD; ReadBuf++; Size--; } // while(I2Cx->STATUS & I2C_STATUS_ACTIVITY); } /** * @brief write data to the I2Cx peripheral. * @param I2Cx: where x can be 1, 2 or 3 to select the I2C peripheral. * @param WriteBuf: cache of stored writings. * @param Size: number of data read from I2C peripheral. * @retval none. */ void I2C_Write(I2C_T* I2Cx,uint8_t *WriteBuf,uint32_t Size) { while(Size){ while(!I2C_GetFlagStatus(I2Cx,I2C_FLAG_TFNF)); if(Size > 1) I2Cx->DATACMD = ((I2C_CMD_WR << 8 ) | (*WriteBuf & 0xFF)); else{ if(I2C_CON_MASTER_MODE & I2Cx->CON) I2Cx->DATACMD = ((I2C_CMD_STOP << 8 ) | (*WriteBuf & 0xFF)); else I2Cx->DATACMD = ((I2C_CMD_WR << 8 ) | (*WriteBuf & 0xFF)); } WriteBuf++; Size--; } // while(I2Cx->STATUS & I2C_STATUS_ACTIVITY); } #ifndef __OS_SYSTEM_MODE__ void I2C_OsRead(I2C_T* I2Cx,uint8_t *ReadBuf,uint32_t Size) { } #endif