#include "api_rt_i2c.h" #include "api_rt_dbg.h" #include "board_config.h" #include "gd32f30x.h" #include ApiRtI2C_Handle I2Cs[1]; /* ========================================================================== */ /* ============================ Api RT Functions ============================ */ /* ========================================================================== */ void iRtI2C_Init() { I2Cs[0].I2CBase = I2C0; } int iRtI2C_BusReset(uint8_t devIndex) { i2c_deinit(I2Cs[devIndex].I2CBase); /* Configure SDA/SCL for GPIO */ GPIO_BC(GPIOB) |= GPIO_PIN_6; GPIO_BC(GPIOB) |= GPIO_PIN_7; gpio_init(GPIOB, GPIO_MODE_OUT_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_6); gpio_init(GPIOB, GPIO_MODE_OUT_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_7); __NOP(); __NOP(); __NOP(); __NOP(); __NOP(); GPIO_BOP(GPIOB) |= GPIO_PIN_6; __NOP(); __NOP(); __NOP(); __NOP(); __NOP(); GPIO_BOP(GPIOB) |= GPIO_PIN_7; /* Connect I2C_SCL_PIN to I2C_SCL */ /* Connect I2C_SDA_PIN to I2C_SDA */ gpio_init(GPIOB, GPIO_MODE_AF_OD, GPIO_OSPEED_50MHZ, GPIO_PIN_6); gpio_init(GPIOB, GPIO_MODE_AF_OD, GPIO_OSPEED_50MHZ, GPIO_PIN_7); /* configure I2Cs[devIndex].I2CBase clock */ i2c_clock_config(I2Cs[devIndex].I2CBase, 100000, I2C_DTCY_2); /* Configure I2C address */ i2c_mode_addr_config(I2Cs[devIndex].I2CBase, I2C_I2CMODE_ENABLE, I2C_ADDFORMAT_7BITS, HW_I2C_EE_ADDR_BLOCK1); /* Enable acknowledge */ i2c_ack_config(I2Cs[devIndex].I2CBase, I2C_ACK_ENABLE); /* Enable I2C_DMA */ // i2c_dma_config(I2Cs[devIndex].I2CBase, I2C_DMA_ON); /* Enable I2C */ i2c_enable(I2Cs[devIndex].I2CBase); return 1; } void iRtI2C_WaitEEReady() { uint16_t cnt1 = 0, cnt2 = 0; /* Wait at least 5ms after writing a page */ while (cnt2 < 2) { cnt1++; if (cnt1 == 10000) { cnt2++; cnt1 = 0; } } } int iRtI2C_PageWrite2EE(uint8_t devIndex, uint16_t devAddr, uint16_t memAddr, uint8_t *data, uint8_t count) { uint8_t state = (uint8_t)I2C_START; uint16_t timeoutCnt = 0; uint8_t i2c_timeout_flag = 0; uint8_t i2cBusResetCnt = 0; /* Write to EEPROM enable*/ GPIO_OCTL(GPIOC) &= ~0x1000; /* Enable acknowledge */ i2c_ack_config(I2Cs[devIndex].I2CBase , I2C_ACK_ENABLE); while(!(i2c_timeout_flag)) { /* I2C process */ switch(state) { case I2C_START: /* I2C master sends start signal only when the bus is idle */ while((i2c_flag_get(I2Cs[devIndex].I2CBase, I2C_FLAG_I2CBSY) != 0) && (timeoutCnt < I2C_TIME_OUT)) { timeoutCnt++; } if(timeoutCnt < I2C_TIME_OUT) { i2c_start_on_bus(I2Cs[devIndex].I2CBase); timeoutCnt = 0; state = I2C_SEND_ADDRESS; } else { i2cBusResetCnt += iRtI2C_BusReset(devIndex); timeoutCnt = 0; state = I2C_START; //printf("i2c bus is busy in WRITE!\n"); } break; case I2C_SEND_ADDRESS: /* I2C master sends START signal successfully */ while((i2c_flag_get(I2Cs[devIndex].I2CBase, I2C_FLAG_SBSEND) == 0) && (timeoutCnt < I2C_TIME_OUT)) { timeoutCnt++; } if(timeoutCnt < I2C_TIME_OUT) { i2c_master_addressing(I2Cs[devIndex].I2CBase, devAddr, I2C_TRANSMITTER); timeoutCnt = 0; state = I2C_CLEAR_ADDRESS_FLAG; } else { timeoutCnt = 0; state = I2C_START; printf("i2c master sends start signal timeoutCnt in WRITE!\n"); } break; case I2C_CLEAR_ADDRESS_FLAG: /* address flag set means i2c slave sends ACK */ while((i2c_flag_get(I2Cs[devIndex].I2CBase, I2C_FLAG_ADDSEND) == 0) && (timeoutCnt < I2C_TIME_OUT)) { timeoutCnt++; } if(timeoutCnt < I2C_TIME_OUT) { i2c_flag_clear(I2Cs[devIndex].I2CBase, I2C_FLAG_ADDSEND); timeoutCnt = 0; state = I2C_TRANSMIT_DATA; } else { timeoutCnt = 0; state = I2C_START; //printf("i2c master clears address flag timeoutCnt in WRITE!\n"); } break; case I2C_TRANSMIT_DATA: /* wait until the transmit data buffer is empty */ while((i2c_flag_get(I2Cs[devIndex].I2CBase, I2C_FLAG_TBE) == 0) && (timeoutCnt < I2C_TIME_OUT)) { timeoutCnt++; } if(timeoutCnt < I2C_TIME_OUT) { /* send the EEPROM's internal address to write to : only one byte address */ i2c_data_transmit(I2Cs[devIndex].I2CBase, memAddr); timeoutCnt = 0; } else { timeoutCnt = 0; state = I2C_START; //printf("i2c master sends EEPROM's internal address timeoutCnt in WRITE!\n"); } /* wait until BTC bit is set */ while((i2c_flag_get(I2Cs[devIndex].I2CBase, I2C_FLAG_BTC) == 0) && (timeoutCnt < I2C_TIME_OUT)){ timeoutCnt++; } if(timeoutCnt < I2C_TIME_OUT) { timeoutCnt = 0; } else { timeoutCnt = 0; state = I2C_START; //printf("i2c master sends data timeoutCnt in WRITE!\n"); } while(count != 0) { count --; i2c_data_transmit(I2Cs[devIndex].I2CBase, *data); /* Point to the next byte to be written */ data++; /* wait until BTC bit is set */ while((i2c_flag_get(I2Cs[devIndex].I2CBase, I2C_FLAG_BTC) == 0) && (timeoutCnt < I2C_TIME_OUT)) { timeoutCnt++; } if(timeoutCnt < I2C_TIME_OUT) { timeoutCnt = 0; } else { timeoutCnt = 0; state = I2C_START; //printf("i2c master sends data timeoutCnt in WRITE!\n"); } } timeoutCnt = 0; state = I2C_STOP; break; case I2C_STOP: /* send a stop condition to I2C bus */ i2c_stop_on_bus(I2Cs[devIndex].I2CBase); /* I2C master sends STOP signal successfully */ while((I2C_CTL0(I2Cs[devIndex].I2CBase) & I2C_CTL0_STOP) && (timeoutCnt < I2C_TIME_OUT)) { timeoutCnt++; } if(timeoutCnt < I2C_TIME_OUT) { timeoutCnt = 0; state = I2C_COMPLETE; i2c_timeout_flag = 1; } else { timeoutCnt = 0; state = I2C_START; //printf("i2c master sends stop signal timeoutCnt in WRITE!\n"); } break; default: state = I2C_START; i2c_timeout_flag = 1; timeoutCnt = 0; //printf("i2c master sends start signal in WRITE.\n"); break; } if(i2cBusResetCnt > 10) { break; } } /* Write to EEPROM disable */ GPIO_OCTL(GPIOC) |= 0x1000; if(state == I2C_COMPLETE) { return count; } else { return 0; } } /* ========================================================================== */ /* ============================== API Functions ============================= */ /* ========================================================================== */ int iI2C_Write(uint8_t devIndex, uint16_t devAddr, uint16_t memAddr, uint8_t memAddrSize, uint8_t* data, uint16_t count) { uint8_t addr = 0, misalignedDataCnt = 0, pageCnt = 0, singleDataCnt = 0; uint16_t writeCompCnt = 0; if(memAddrSize == 0x8) { memAddr = memAddr & 0xFF; } addr = memAddr % HW_I2C_EE_PAGESIZE_BYTE; misalignedDataCnt = HW_I2C_EE_PAGESIZE_BYTE - addr; pageCnt = count / HW_I2C_EE_PAGESIZE_BYTE; singleDataCnt = count % HW_I2C_EE_PAGESIZE_BYTE; /* If memAddr is HW_I2C_EE_PAGESIZE_BYTE aligned */ if (addr == 0) { while (pageCnt != 0) { pageCnt--; writeCompCnt += iRtI2C_PageWrite2EE(devIndex, devAddr, memAddr, data, HW_I2C_EE_PAGESIZE_BYTE); iRtI2C_WaitEEReady(); memAddr += HW_I2C_EE_PAGESIZE_BYTE; data += HW_I2C_EE_PAGESIZE_BYTE; } if (singleDataCnt != 0) { writeCompCnt += iRtI2C_PageWrite2EE(devIndex, devAddr, memAddr, data, singleDataCnt); iRtI2C_WaitEEReady(); } } else { /* If memAddr is not HW_I2C_EE_PAGESIZE_BYTE aligned */ if(count < misalignedDataCnt) { writeCompCnt += iRtI2C_PageWrite2EE(devIndex, devAddr, memAddr, data, count); iRtI2C_WaitEEReady(); } else { count -= misalignedDataCnt; pageCnt = count / HW_I2C_EE_PAGESIZE_BYTE; singleDataCnt = count % HW_I2C_EE_PAGESIZE_BYTE; /* Write misaligned data */ if(misalignedDataCnt != 0) { writeCompCnt += iRtI2C_PageWrite2EE(devIndex, devAddr, memAddr, data, misalignedDataCnt); iRtI2C_WaitEEReady(); memAddr += misalignedDataCnt; data += misalignedDataCnt; } /* Write page data */ while(pageCnt != 0) { pageCnt --; writeCompCnt += iRtI2C_PageWrite2EE(devIndex, devAddr, memAddr, data, HW_I2C_EE_PAGESIZE_BYTE); iRtI2C_WaitEEReady(); memAddr += HW_I2C_EE_PAGESIZE_BYTE; data += HW_I2C_EE_PAGESIZE_BYTE; } /* Write single data */ if (singleDataCnt != 0) { writeCompCnt += iRtI2C_PageWrite2EE(devIndex, devAddr, memAddr, data, singleDataCnt); iRtI2C_WaitEEReady(); } } } return writeCompCnt; } int iI2C_Read(uint8_t devIndex, uint16_t devAddr, uint16_t memAddr, uint8_t memAddrSize, uint8_t* data, uint16_t count) { uint8_t state = (uint8_t)I2C_START; uint8_t read_cycle = 0; uint16_t timeoutCnt = 0; uint8_t i2c_timeout_flag = 0; uint8_t i2cBusResetCnt = 0; /* enable acknowledge */ i2c_ack_config(I2Cs[devIndex].I2CBase, I2C_ACK_ENABLE); while(i2c_timeout_flag ==0) { switch(state) { case I2C_START: if(RESET == read_cycle) { /* Disable I2C0 */ i2c_disable(I2Cs[devIndex].I2CBase); /* Enable I2C0 */ i2c_enable(I2Cs[devIndex].I2CBase); /* Enable acknowledge */ i2c_ack_config(I2Cs[devIndex].I2CBase, I2C_ACK_ENABLE); /* I2C master sends start signal only when the bus is idle */ while((i2c_flag_get(I2Cs[devIndex].I2CBase, I2C_FLAG_I2CBSY) != 0) && (timeoutCnt < I2C_TIME_OUT)) { timeoutCnt++; } if(timeoutCnt < I2C_TIME_OUT) { /* Send the start signal */ i2c_start_on_bus(I2Cs[devIndex].I2CBase); timeoutCnt = 0; state = (uint8_t)I2C_SEND_ADDRESS; } else { i2cBusResetCnt += iRtI2C_BusReset(devIndex); timeoutCnt = 0; state = (uint8_t)I2C_START; } } else { i2c_start_on_bus(I2Cs[devIndex].I2CBase); timeoutCnt = 0; state = (uint8_t)I2C_SEND_ADDRESS; } break; case I2C_SEND_ADDRESS: /* I2C master sends START signal successfully */ while((i2c_flag_get(I2Cs[devIndex].I2CBase, I2C_FLAG_SBSEND) == 0) && (timeoutCnt < I2C_TIME_OUT)) { timeoutCnt++; } if(timeoutCnt < I2C_TIME_OUT) { if(RESET == read_cycle) { i2c_master_addressing(I2Cs[devIndex].I2CBase, devAddr, I2C_TRANSMITTER); state = (uint8_t)I2C_CLEAR_ADDRESS_FLAG; } else { i2c_master_addressing(I2Cs[devIndex].I2CBase, devAddr, I2C_RECEIVER); state = (uint8_t)I2C_CLEAR_ADDRESS_FLAG; } timeoutCnt = 0; } else { timeoutCnt = 0; state = (uint8_t)I2C_START; read_cycle = 0; } break; case I2C_CLEAR_ADDRESS_FLAG: /* Address flag set means i2c slave sends ACK */ while((i2c_flag_get(I2Cs[devIndex].I2CBase, I2C_FLAG_ADDSEND) == 0) && (timeoutCnt < I2C_TIME_OUT)) { timeoutCnt++; } if(timeoutCnt < I2C_TIME_OUT) { i2c_flag_clear(I2Cs[devIndex].I2CBase, I2C_FLAG_ADDSEND); timeoutCnt = 0; state = (uint8_t)I2C_TRANSMIT_DATA; } else { timeoutCnt = 0; state = (uint8_t)I2C_START; read_cycle = 0; } break; case I2C_TRANSMIT_DATA: if(RESET == read_cycle) { /* Wait until the transmit data buffer is empty */ while((i2c_flag_get(I2Cs[devIndex].I2CBase, I2C_FLAG_TBE) == 0) && (timeoutCnt < I2C_TIME_OUT)) { timeoutCnt++; } if(timeoutCnt < I2C_TIME_OUT) { /* Send the EEPROM's internal address to write to : only one byte address */ i2c_data_transmit(I2Cs[devIndex].I2CBase, memAddr); timeoutCnt = 0; } else { timeoutCnt = 0; state = (uint8_t)I2C_START; read_cycle = 0; } /* Wait until BTC bit is set */ while((i2c_flag_get(I2Cs[devIndex].I2CBase, I2C_FLAG_BTC) == 0) && (timeoutCnt < I2C_TIME_OUT)) { timeoutCnt++; } if(timeoutCnt < I2C_TIME_OUT) { timeoutCnt = 0; state = (uint8_t)I2C_START; read_cycle++; } else { timeoutCnt = 0; state = (uint8_t)I2C_START; read_cycle = 0; } } else { /* One byte master reception procedure (polling) */ if(count < 2) { /* Disable acknowledge */ i2c_ack_config(I2Cs[devIndex].I2CBase, I2C_ACK_DISABLE); /* Clear ADDSEND register by reading I2C_STAT0 then I2C_STAT1 register (I2C_STAT0 has already been read) */ i2c_flag_get(I2Cs[devIndex].I2CBase, I2C_FLAG_ADDSEND); /* Send a stop condition to I2C bus*/ i2c_stop_on_bus(I2Cs[devIndex].I2CBase); /* Wait for the byte to be received */ while(i2c_flag_get(I2Cs[devIndex].I2CBase, I2C_FLAG_RBNE) == 0) { // do nothing } /* Read the byte received from the EEPROM */ *data = i2c_data_receive(I2Cs[devIndex].I2CBase); /* Decrement the read bytes counter */ count--; timeoutCnt = 0; state = (uint8_t)I2C_STOP; } else { /* More than one byte master reception procedure (DMA) */ dma_transfer_number_config(DMA0, DMA_CH6, count); DMA_CH6MADDR(DMA0) = (uint32_t)data; i2c_dma_last_transfer_config(I2Cs[devIndex].I2CBase, I2C_DMALST_ON); /* Enable I2Cs[devIndex].I2CBase DMA */ i2c_dma_config(I2Cs[devIndex].I2CBase, I2C_DMA_ON); /* Enable DMA0 channel5 */ dma_channel_enable(DMA0, DMA_CH6); /* Wait until BTC bit is set */ while(dma_flag_get(DMA0, DMA_CH6, DMA_FLAG_FTF) == 0) {} state = (uint8_t)I2C_STOP; } } break; case I2C_STOP: /* Send a stop condition to I2C bus */ i2c_stop_on_bus(I2Cs[devIndex].I2CBase); /* I2C master sends STOP signal successfully */ while((I2C_CTL0(I2Cs[devIndex].I2CBase) & I2C_CTL0_STOP) && (timeoutCnt < I2C_TIME_OUT)) { timeoutCnt++; } if(timeoutCnt < I2C_TIME_OUT) { timeoutCnt = 0; i2c_timeout_flag = 1; state = (uint8_t)I2C_COMPLETE; read_cycle = 0; /* Disable DMA0 CH6 */ dma_channel_disable(DMA0, DMA_CH6); /* Disable I2Cs[devIndex].I2CBase DMA */ i2c_dma_config(I2Cs[devIndex].I2CBase, I2C_DMA_OFF); i2c_dma_last_transfer_config(I2Cs[devIndex].I2CBase, I2C_DMALST_OFF); } else { timeoutCnt = 0; state = (uint8_t)I2C_START; read_cycle = 0; } break; default: state = (uint8_t)I2C_START; read_cycle = 0; i2c_timeout_flag = 1; timeoutCnt = 0; break; } if(i2cBusResetCnt > 10) { break; } } if(state == I2C_COMPLETE) { return count; } else { return 0; } }