/* * I2C_Comm.c * * Created on: Jun 12, 2018 * Author: avi */ #include #include #include "include.h" #include "inc/hw_memmap.h" #include "inc/hw_types.h" #include "inc/tm4c1294ncpdt.h" #include "driverlib/gpio.h" #include "driverlib/pin_map.h" #include "driverlib/rom.h" #include "driverlib/rom_map.h" #include "driverlib/sysctl.h" #include "driverlib/i2c.h" #include "inc/hw_i2c.h" #include "i2c_fifo.h" #include "i2c.h" uint32_t LastReadI2C_BASE; unsigned char LastReadaddr; unsigned char* LastReaddata; unsigned int LastReadlen; uint32_t LastWriteI2C_BASE; unsigned char LastWriteaddr; unsigned char *LastWritedata; unsigned int LastWritelen; Task_Handle TaskId; uint32_t Arb_Loss_Count = 0; //***************************************************************************** //! Indicates whether or not the I2C bus has timed out. //! //! \param ui32Base is the base address of the I2C module. //! //! This function returns an indication of whether or not the I2C bus has time //! out. The I2C Master Timeout Value must be set. //! //! \return Returns \b true if the I2C bus has timed out; otherwise, returns //! \b false. //***************************************************************************** char I2CErrMsg[181]; uint32_t I2C_WriteBuff(uint32_t I2C_BASE, unsigned char addr, unsigned char* data, unsigned int len) { uint32_t status = OK; uint32_t I2C_BUSY_DELAY; if(I2C_BASE == I2C4_BASE) { I2C_BUSY_DELAY = I2C_4_BUSY_DELAY; } else { I2C_BUSY_DELAY = I2C_2_3_BUSY_DELAY; } if (I2CMasterBusy(I2C_BASE)) { ReportWithPackageFilter(CommFilter,"I2C_WriteBuff busy", __FILE__,__LINE__,status, RpMessage, Task_self(), 0); return 0xFF; } I2CMasterSlaveAddrSet(I2C_BASE, addr, false); I2CMasterDataPut(I2C_BASE, *data); if (len == 1) { I2CMasterControl(I2C_BASE, I2C_MASTER_CMD_SINGLE_SEND); SysCtlDelay(I2C_BUSY_DELAY);//The CPU waits for the Command processing to begin before it goes to check if the command is processed status |= I2CMasterErr(I2C_BASE); while(I2CMasterBusy(I2C_BASE)); } else { // Start sending consecutive data I2CMasterControl(I2C_BASE, I2C_MASTER_CMD_BURST_SEND_START); SysCtlDelay(I2C_BUSY_DELAY);//The CPU waits for the Command processing to begin before it goes to check if the command is processed status |= I2CMasterErr(I2C_BASE); while(I2CMasterBusy(I2C_BASE)); len--; data++; // Continue sending consecutive data while(len > 1){ I2CMasterDataPut(I2C_BASE, *data); I2CMasterControl(I2C_BASE, I2C_MASTER_CMD_BURST_SEND_CONT); SysCtlDelay(I2C_BUSY_DELAY);//The CPU waits for the Command processing to begin before it goes to check if the command is processed status |= I2CMasterErr(I2C_BASE); while(I2CMasterBusy(I2C_BASE)); len--; data++; } // Send last piece of data I2CMasterDataPut(I2C_BASE, *data); I2CMasterControl(I2C_BASE, I2C_MASTER_CMD_BURST_SEND_FINISH); SysCtlDelay(I2C_BUSY_DELAY);//The CPU waits for the Command processing to begin before it goes to check if the command is processed status |= I2CMasterErr(I2C_BASE); while(I2CMasterBusy(I2C_BASE)); } return status; } uint32_t I2C_ReadBuff(uint32_t I2C_BASE, unsigned char addr, unsigned char* data, unsigned int len) { uint32_t status = OK; uint32_t I2C_BUSY_DELAY; if(I2C_BASE == I2C4_BASE) { I2C_BUSY_DELAY = I2C_4_BUSY_DELAY; } else { I2C_BUSY_DELAY = I2C_2_3_BUSY_DELAY; } if (I2CMasterBusy(I2C_BASE)) { ReportWithPackageFilter(CommFilter,"I2C_ReadBuff busy", __FILE__,__LINE__, status, RpMessage, Task_self(), 0); return 0xFF; } /*if (Task_self()!= I2C_Task_Handle) { status = ERROR; } status = OK;*/ I2CMasterSlaveAddrSet(I2C_BASE, addr, true); if (len == 1) { I2CMasterControl(I2C_BASE, I2C_MASTER_CMD_SINGLE_RECEIVE); //On the TM4C129 we discovered a design behavior that due to higher system clock frequency and lower I2C baud rate, //the CPU when it starts a I2C Transaction or writes a new I2C Command, for the I2C to respond to it takes time. //So in effect the I2CMasterBusy statement gets skipped which causes The I2C controller to lose data. //see: https://e2e.ti.com/support/microcontrollers/other/f/908/t/368493?Why-is-a-delay-needed-before-writing-the-first-byte-from-I2C-Master- //therefore we need delay before waiting until bus is not busy - it doesn't work as expected without it or with while(!(I2CMasterBusy(I2C0_BASE) SysCtlDelay(I2C_BUSY_DELAY);//The CPU waits for the Command processing to begin before it goes to check if the command is processed status |= I2CMasterErr(I2C_BASE); while(I2CMasterBusy(I2C_BASE)); *data = I2CMasterDataGet(I2C_BASE); } else { // Start receiving consecutive data I2CMasterControl(I2C_BASE, I2C_MASTER_CMD_BURST_RECEIVE_START); SysCtlDelay(I2C_BUSY_DELAY);//The CPU waits for the Command processing to begin before it goes to check if the command is processed status |= I2CMasterErr(I2C_BASE); while(I2CMasterBusy(I2C_BASE)); *data = I2CMasterDataGet(I2C_BASE); len--; data++; // Continue receiving consecutive data while(len > 1){ I2CMasterControl(I2C_BASE, I2C_MASTER_CMD_BURST_RECEIVE_CONT); SysCtlDelay(I2C_BUSY_DELAY);//The CPU waits for the Command processing to begin before it goes to check if the command is processed status |= I2CMasterErr(I2C_BASE); while(I2CMasterBusy(I2C_BASE)); *data = I2CMasterDataGet(I2C_BASE); len--; data++; } // Receive last piece of data I2CMasterControl(I2C_BASE, I2C_MASTER_CMD_BURST_RECEIVE_FINISH); SysCtlDelay(I2C_BUSY_DELAY);//The CPU waits for the Command processing to begin before it goes to check if the command is processed status |= I2CMasterErr(I2C_BASE); while(I2CMasterBusy(I2C_BASE)); *data = I2CMasterDataGet(I2C_BASE); } return status; } uint32_t I2C_Write(uint32_t I2C_ID, uint32_t Slave_Add, uint8_t *I2C_Write_buf, uint32_t No_BytesToWrite ) { uint32_t status = OK; uint32_t I2C_BASE; if (I2C_ID == 4) I2C_BASE = I2C4_BASE; else if (I2C_ID == 3) I2C_BASE = I2C3_BASE; else if (I2C_ID == 2) I2C_BASE = I2C2_BASE; else return ERROR; /* if (Task_self()!=I2C_Task_Handle) { ReportWithPackageFilter(CommFilter,"I2C_Write called from different task", __FILE__,__LINE__, I2C_Task_Handle, RpMessage, Task_self(), 0); }*/ /* if ( (Slave_Add != 0xE0) && (Slave_Add != 0xE4) && (Slave_Add != 0xE3) & (Slave_Add != 0x40) && (Slave_Add != 0x44) && (Slave_Add != 0x46) & (Slave_Add != 0x98) && (Slave_Add != 0xA0) ) return ERROR;*/ Slave_Add = Slave_Add>>1; //Byte2Write = Byte2Write & 0xFF; status = I2C_WriteBuff(I2C_BASE, Slave_Add, I2C_Write_buf, No_BytesToWrite); //status = I2C_WriteFifo(I2C_BASE, Slave_Add, buff, No_BytesToWrite); /*if(No_BytesToWrite <= 2) { status = I2C_WriteBuff(I2C_BASE, Slave_Add, I2C_Write_buf, No_BytesToWrite); } else { status = I2C_WriteFifo(I2C_BASE, Slave_Add, buff, No_BytesToWrite); }*/ if (status == OK) { //LastWriteI2C_BASE = I2C_BASE; LastWriteaddr = Slave_Add; LastWritedata = I2C_Write_buf; LastWritelen = No_BytesToWrite; TaskId = Task_self(); } else { usnprintf(I2CErrMsg, 180, "I2C Err write 0x%x 0x%x, last good read 0x%x, %d, write 0x%x, %d, T 0x%x 0x%x",status,Slave_Add, LastReadaddr, LastReadlen, LastWriteaddr, LastWritelen, Task_self(),TaskId); Report(I2CErrMsg, __FILE__, __LINE__, status, RpWarning, Slave_Add, 0); } //uint32_t I2C_W_buf[256] = {0},i; // for(i = 0; i < request->n_bytestwrite;i++) // { // I2C_W_buf[i] = request->bytestwrite[i]; // } if (status) { if (Arb_Loss_Count++ >= 5) { Arb_Loss_Count= 0; Init_All_I2C(); ReportWithPackageFilter(CommFilter,"Reinitializing I2C master", __FILE__,__LINE__, status, RpMessage, Task_self(), 0); } } /*else { if (Arb_Loss_Count) ReportWithPackageFilter(CommFilter,"Resetting count", __FILE__, Arb_Loss_Count, status, RpMessage, Task_self(), 0); //Arb_Loss_Count = 0; }*/ return status; } uint32_t I2C_Read(uint32_t I2C_ID, uint32_t Slave_Add, uint8_t *I2C_Read_buf, uint32_t No_BytesToRead ) { uint32_t status = OK; uint32_t I2C_BASE; if (I2C_ID == 4) I2C_BASE = I2C4_BASE; else if (I2C_ID == 3) I2C_BASE = I2C3_BASE; else if (I2C_ID == 2) I2C_BASE = I2C2_BASE; else return ERROR; /* if ( (Slave_Add != 0xE0) && (Slave_Add != 0xE4) && (Slave_Add != 0xE3) & (Slave_Add != 0x40) && (Slave_Add != 0x44) && (Slave_Add != 0x46) & (Slave_Add != 0x98) && (Slave_Add != 0xA0) ) return ERROR;*/ /*if (Task_self()!=I2C_Task_Handle) { ReportWithPackageFilter(CommFilter,"I2C_Write called from different task", __FILE__,__LINE__, I2C_Task_Handle, RpMessage, Task_self(), 0); }*/ Slave_Add = Slave_Add>>1; //Byte2Write = Byte2Write & 0xFF; status = I2C_ReadBuff(I2C_BASE, Slave_Add, I2C_Read_buf, No_BytesToRead); if (status) { if (Arb_Loss_Count++ >= 5) { Arb_Loss_Count= 0; Init_All_I2C(); ReportWithPackageFilter(CommFilter,"Reinitializing I2C master", __FILE__,__LINE__, status, RpMessage, Task_self(), 0); } } if (status == OK) { //LastReadI2C_BASE = I2C_BASE; LastReadaddr = Slave_Add; LastReaddata = I2C_Read_buf; LastReadlen = No_BytesToRead; TaskId = Task_self(); } else { usnprintf(I2CErrMsg, 180, "I2C Err read 0x%x 0x%x, last good read 0x%x, %d, write 0x%x, %d, T 0x%x 0x%x",status,Slave_Add, LastReadaddr, LastReadlen, LastWriteaddr, LastWritelen, Task_self(),TaskId); Report(I2CErrMsg, __FILE__, __LINE__, status, RpWarning, Slave_Add, 0); } /*else { if (Arb_Loss_Count) ReportWithPackageFilter(CommFilter,"Resetting count", __FILE__, Arb_Loss_Count, status, RpMessage, Task_self(), 0); //Arb_Loss_Count = 0; }*/ return status; }