/* This function transmits one byte to the slave device * Parameters: * I2Cx --> the I2C peripheral e.g. i2c_dev * data --> the data byte to be transmitted */ void I2C_write(I2C_TypeDef* I2Cx, uint8_t data) { I2C_SendData(I2Cx, data); // wait for i2c_dev EV8_2 --> byte has been transmitted while(!I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_BYTE_TRANSMITTED)); }
/** * @brief Reads a buffer of 2 bytes from the device registers. * @param DeviceAddr: The address of the device, could be : IOE_1_ADDR. * @param RegisterAddr: The target register adress (between 00x and 0x24) * @retval A pointer to the buffer containing the two returned bytes (in halfword). */ uint16_t I2C_ReadDataBuffer(uint8_t DeviceAddr, uint32_t RegisterAddr) { uint8_t tmp= 0; uint8_t IOE_BufferRX[2] = {0x00, 0x00}; /* Configure DMA Peripheral */ IOE_DMA_Config(IOE_DMA_RX, (uint8_t*)IOE_BufferRX); /* Enable DMA NACK automatic generation */ I2C_DMALastTransferCmd(IOE_I2C, ENABLE); /* Enable the I2C peripheral */ I2C_GenerateSTART(IOE_I2C, ENABLE); /* Test on SB Flag */ IOE_TimeOut = TIMEOUT_MAX; while (!I2C_GetFlagStatus(IOE_I2C,I2C_FLAG_SB)) { if (IOE_TimeOut-- == 0) return(IOE_TimeoutUserCallback()); } /* Send device address for write */ I2C_Send7bitAddress(IOE_I2C, DeviceAddr, I2C_Direction_Transmitter); /* Test on ADDR Flag */ IOE_TimeOut = TIMEOUT_MAX; while (!I2C_CheckEvent(IOE_I2C, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED)) { if (IOE_TimeOut-- == 0) return(IOE_TimeoutUserCallback()); } /* Send the device's internal address to write to */ I2C_SendData(IOE_I2C, RegisterAddr); /* Test on TXE FLag (data dent) */ IOE_TimeOut = TIMEOUT_MAX; while ((!I2C_GetFlagStatus(IOE_I2C,I2C_FLAG_TXE)) && (!I2C_GetFlagStatus(IOE_I2C,I2C_FLAG_BTF))) { if (IOE_TimeOut-- == 0) return(IOE_TimeoutUserCallback()); } /* Send START condition a second time */ I2C_GenerateSTART(IOE_I2C, ENABLE); /* Test on SB Flag */ IOE_TimeOut = TIMEOUT_MAX; while (!I2C_GetFlagStatus(IOE_I2C,I2C_FLAG_SB)) { if (IOE_TimeOut-- == 0) return(IOE_TimeoutUserCallback()); } /* Send IOExpander address for read */ I2C_Send7bitAddress(IOE_I2C, DeviceAddr, I2C_Direction_Receiver); /* Test on ADDR Flag */ IOE_TimeOut = TIMEOUT_MAX; while (!I2C_CheckEvent(IOE_I2C, I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED)) { if (IOE_TimeOut-- == 0) return(IOE_TimeoutUserCallback()); } /* Enable I2C DMA request */ I2C_DMACmd(IOE_I2C,ENABLE); /* Enable DMA RX Channel */ DMA_Cmd(IOE_DMA_RX_CHANNEL, ENABLE); /* Wait until DMA Transfer Complete */ IOE_TimeOut = 2 * TIMEOUT_MAX; while (!DMA_GetFlagStatus(IOE_DMA_RX_TCFLAG)) { if (IOE_TimeOut-- == 0) return(IOE_TimeoutUserCallback()); } /* Send STOP Condition */ I2C_GenerateSTOP(IOE_I2C, ENABLE); /* Disable DMA RX Channel */ DMA_Cmd(IOE_DMA_RX_CHANNEL, DISABLE); /* Disable I2C DMA request */ I2C_DMACmd(IOE_I2C,DISABLE); /* Clear DMA RX Transfer Complete Flag */ DMA_ClearFlag(IOE_DMA_RX_TCFLAG); /* Reorganize received data */ tmp = IOE_BufferRX[0]; IOE_BufferRX[0] = IOE_BufferRX[1]; IOE_BufferRX[1] = tmp; /* return a pointer to the IOE_Buffer */ return *(uint16_t *)IOE_BufferRX; }
void i2c_ev_handler(void) { static uint8_t subaddress_sent, final_stop; //flag to indicate if subaddess sent, flag to indicate final bus condition static int8_t index; //index is signed -1==send the subaddress uint8_t SReg_1 = I2Cx->SR1; //read the status register here if (SReg_1 & 0x0001) { //we just sent a start - EV5 in ref manual I2Cx->CR1 &= ~0x0800; //reset the POS bit so ACK/NACK applied to the current byte I2C_AcknowledgeConfig(I2Cx, ENABLE); //make sure ACK is on index = 0; //reset the index if (reading && (subaddress_sent || 0xFF == reg)) { //we have sent the subaddr subaddress_sent = 1; //make sure this is set in case of no subaddress, so following code runs correctly if (bytes == 2) I2Cx->CR1 |= 0x0800; //set the POS bit so NACK applied to the final byte in the two byte read I2C_Send7bitAddress(I2Cx, addr, I2C_Direction_Receiver); //send the address and set hardware mode } else { //direction is Tx, or we havent sent the sub and rep start I2C_Send7bitAddress(I2Cx, addr, I2C_Direction_Transmitter); //send the address and set hardware mode if (reg != 0xFF) //0xFF as subaddress means it will be ignored, in Tx or Rx mode index = -1; //send a subaddress } } else if (SReg_1 & 0x0002) { //we just sent the address - EV6 in ref manual // Read SR1,2 to clear ADDR __DMB(); // memory fence to control hardware if (bytes == 1 && reading && subaddress_sent) { // we are receiving 1 byte - EV6_3 I2C_AcknowledgeConfig(I2Cx, DISABLE); // turn off ACK __DMB(); (void)I2Cx->SR2; // clear ADDR after ACK is turned off I2C_GenerateSTOP(I2Cx, ENABLE); // program the stop final_stop = 1; I2C_ITConfig(I2Cx, I2C_IT_BUF, ENABLE); // allow us to have an EV7 } else { // EV6 and EV6_1 (void)I2Cx->SR2; // clear the ADDR here __DMB(); if (bytes == 2 && reading && subaddress_sent) { //rx 2 bytes - EV6_1 I2C_AcknowledgeConfig(I2Cx, DISABLE); //turn off ACK I2C_ITConfig(I2Cx, I2C_IT_BUF, DISABLE); //disable TXE to allow the buffer to fill } else if (bytes == 3 && reading && subaddress_sent) //rx 3 bytes I2C_ITConfig(I2Cx, I2C_IT_BUF, DISABLE); //make sure RXNE disabled so we get a BTF in two bytes time else //receiving greater than three bytes, sending subaddress, or transmitting I2C_ITConfig(I2Cx, I2C_IT_BUF, ENABLE); } } else if (SReg_1 & 0x004) { //Byte transfer finished - EV7_2, EV7_3 or EV8_2 final_stop = 1; if (reading && subaddress_sent) { //EV7_2, EV7_3 if (bytes > 2) { //EV7_2 I2C_AcknowledgeConfig(I2Cx, DISABLE); //turn off ACK read_p[index++] = I2C_ReceiveData(I2Cx); //read data N-2 I2C_GenerateSTOP(I2Cx, ENABLE); //program the Stop final_stop = 1; //reuired to fix hardware read_p[index++] = I2C_ReceiveData(I2Cx); //read data N-1 I2C_ITConfig(I2Cx, I2C_IT_BUF, ENABLE); //enable TXE to allow the final EV7 } else { //EV7_3 if (final_stop) I2C_GenerateSTOP(I2Cx, ENABLE); //program the Stop else I2C_GenerateSTART(I2Cx, ENABLE); //program a rep start read_p[index++] = I2C_ReceiveData(I2Cx); //read data N-1 read_p[index++] = I2C_ReceiveData(I2Cx); //read data N index++; //to show job completed } } else { //EV8_2, which may be due to a subaddress sent or a write completion if (subaddress_sent || (writing)) { if (final_stop) I2C_GenerateSTOP(I2Cx, ENABLE); //program the Stop else I2C_GenerateSTART(I2Cx, ENABLE); //program a rep start index++; //to show that the job is complete } else { //We need to send a subaddress I2C_GenerateSTART(I2Cx, ENABLE); //program the repeated Start subaddress_sent = 1; //this is set back to zero upon completion of the current task } } //we must wait for the start to clear, otherwise we get constant BTF while (I2Cx->CR1 & 0x0100) { ; } } else if (SReg_1 & 0x0040) { //Byte received - EV7 read_p[index++] = I2C_ReceiveData(I2Cx); if (bytes == (index + 3)) I2C_ITConfig(I2Cx, I2C_IT_BUF, DISABLE); //disable TXE to allow the buffer to flush so we can get an EV7_2 if (bytes == index) //We have completed a final EV7 index++; //to show job is complete } else if (SReg_1 & 0x0080) { //Byte transmitted -EV8/EV8_1 if (index != -1) { //we dont have a subaddress to send I2C_SendData(I2Cx, write_p[index++]); if (bytes == index) //we have sent all the data I2C_ITConfig(I2Cx, I2C_IT_BUF, DISABLE); //disable TXE to allow the buffer to flush } else { index++; I2C_SendData(I2Cx, reg); //send the subaddress if (reading || !bytes) //if receiving or sending 0 bytes, flush now I2C_ITConfig(I2Cx, I2C_IT_BUF, DISABLE); //disable TXE to allow the buffer to flush } } if (index == bytes + 1) { //we have completed the current job //Completion Tasks go here //End of completion tasks subaddress_sent = 0; //reset this here // I2Cx->CR1 &= ~0x0800; //reset the POS bit so NACK applied to the current byte if (final_stop) //If there is a final stop and no more jobs, bus is inactive, disable interrupts to prevent BTF I2C_ITConfig(I2Cx, I2C_IT_EVT | I2C_IT_ERR, DISABLE); //Disable EVT and ERR interrupts while bus inactive busy = 0; } }
/** \brief Envia um byte ao escravo. * * @param I2Cx I2C a ser utilizada. * @param data Byte a ser enviado. */ void c_common_i2c_write(I2C_TypeDef* I2Cx, uint8_t data) { I2C_SendData(I2Cx, data); // wait for I2C1 EV8_2 --> byte has been transmitted timeoutCounter = c_common_utils_millis(); while(while_timeout(!I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_BYTE_TRANSMITTED), timeoutCounter)); }
/** * @brief Reads a buffer of 4 bytes from IO_Expander registers. * @param DeviceAddr: The address of the IOExpander, could be : IOE_1_ADDR * or IOE_2_ADDR. * @param RegisterAddr: The target register adress (between 00x and 0x24) * @retval : The value of the read register (0xAA if Timout occured) */ uint32_t I2C_ReadDataBuffer(u8 DeviceAddr, uint32_t RegisterAddr) { u8 Buffer[4] , idx = 2; /* Initialize the buffer */ Buffer[0] = 0; Buffer[1] = 0; Buffer[2] = 0; Buffer[3] = 0; /* Disable the I2C1 peripheral */ I2C_Cmd(I2C1, DISABLE); /* Reset all I2C2 registers */ I2C_SoftwareResetCmd(I2C1, ENABLE); I2C_SoftwareResetCmd(I2C1, DISABLE); /* Configure the I2C peripheral */ IOE_I2C_Config(); /* Enable the I2C peripheral */ I2C_GenerateSTART(I2C1, ENABLE); TimeOut = TIMEOUT_MAX; /* Test on EV5 and clear it */ while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT)) { if (TimeOut-- == 0) return IOE_TIEMOUT; } /* Send device address for write */ I2C_Send7bitAddress(I2C1, DeviceAddr, I2C_Direction_Transmitter); /* Test on EV6 and clear it */ while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED)) { if (TimeOut-- == 0) return IOE_TIEMOUT; } /* Clear EV6 by setting again the PE bit */ I2C_Cmd(I2C1, ENABLE); /* Send the device's internal address to write to */ I2C_SendData(I2C1, RegisterAddr); /* Test on EV8 and clear it */ while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTED)) { if (TimeOut-- == 0) return IOE_TIEMOUT; } /* Send STRAT condition a second time */ I2C_GenerateSTART(I2C1, ENABLE); /* Test on EV5 and clear it */ while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT)) { if (TimeOut-- == 0) return IOE_TIEMOUT; } /* Send EEPROM address for read */ I2C_Send7bitAddress(I2C1, DeviceAddr, I2C_Direction_Receiver); /* Test on EV6 and clear it */ while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED)) { if (TimeOut-- == 0) return IOE_TIEMOUT; } /* While there is data to be read */ while(idx) { if(idx == 1) { /* Disable Acknowledgement */ I2C_AcknowledgeConfig(I2C1, DISABLE); /* Send STOP Condition */ I2C_GenerateSTOP(I2C1, ENABLE); } /* Test on EV7 and clear it */ if(I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_RECEIVED)) { /* Read a byte from the EEPROM */ Buffer[idx-1] = I2C_ReceiveData(I2C1); /* Decrement the read bytes counter */ idx--; } } /* Enable Acknowledgement to be ready for another reception */ I2C_AcknowledgeConfig(I2C1, ENABLE); /* return a pointer to the buffer */ return *(uint32_t *)Buffer; }
/** * @brief Reads a register of the audio Codec through I2C. * @param DeviceAddr: The address of the IOExpander, could be : IOE_1_ADDR * or IOE_2_ADDR. * @param RegisterAddr: The target register adress (between 00x and 0x24) * @retval The value of the read register (0xAA if Timout occured) */ uint8_t I2C_ReadDeviceRegister(uint8_t DeviceAddr, uint8_t RegisterAddr) { uint32_t tmp = 0; /* Disable the IOE_I2C peripheral */ I2C_Cmd(IOE_I2C, DISABLE); /* Reset all I2C2 registers */ I2C_SoftwareResetCmd(IOE_I2C, ENABLE); I2C_SoftwareResetCmd(IOE_I2C, DISABLE); /* Configure the I2C peripheral */ IOE_I2C_Config(); /* Enable the I2C peripheral */ I2C_GenerateSTART(IOE_I2C, ENABLE); TimeOut = TIMEOUT_MAX; /* Test on EV5 and clear it */ while (!I2C_CheckEvent(IOE_I2C, I2C_EVENT_MASTER_MODE_SELECT)) { if (TimeOut-- == 0) return IOE_TIEMOUT; } /* Disable Acknowledgement */ I2C_AcknowledgeConfig(IOE_I2C, DISABLE); /* Transmit the slave address and enable writing operation */ I2C_Send7bitAddress(IOE_I2C, DeviceAddr, I2C_Direction_Transmitter); TimeOut = TIMEOUT_MAX; /* Test on EV6 and clear it */ while (!I2C_CheckEvent(IOE_I2C, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED)) { if (TimeOut-- == 0) return IOE_TIEMOUT; } /* Transmit the first address for r/w operations */ I2C_SendData(IOE_I2C, RegisterAddr); /* Test on EV8 and clear it */ while (!I2C_CheckEvent(IOE_I2C, I2C_EVENT_MASTER_BYTE_TRANSMITTED)) { if (TimeOut-- == 0) return IOE_TIEMOUT; } /* Regenerate a start condition */ I2C_GenerateSTART(IOE_I2C, ENABLE); /* Test on EV5 and clear it */ while (!I2C_CheckEvent(IOE_I2C, I2C_EVENT_MASTER_MODE_SELECT)) { if (TimeOut-- == 0) return IOE_TIEMOUT; } /* Transmit the slave address and enable writing operation */ I2C_Send7bitAddress(IOE_I2C, DeviceAddr, I2C_Direction_Receiver); /* Test on EV6 and clear it */ while (!I2C_CheckEvent(IOE_I2C, I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED)) { if (TimeOut-- == 0) return IOE_TIEMOUT; } /* Test on EV7 and clear it */ while (!I2C_CheckEvent(IOE_I2C, I2C_EVENT_MASTER_BYTE_RECEIVED)) { if (TimeOut-- == 0) return IOE_TIEMOUT; } /* End the configuration sequence */ I2C_GenerateSTOP(IOE_I2C, ENABLE); /* Load the register value */ tmp = I2C_ReceiveData(IOE_I2C); /* Enable Acknowledgement */ I2C_AcknowledgeConfig(IOE_I2C, ENABLE); /* Return the read value */ return tmp; }
/** * @brief Writes a value in a register of the IOE through I2C. * @param DeviceAddr: The address of the IOExpander, could be : IOE_1_ADDR * or IOE_2_ADDR. * @param RegisterAddr: The target register adress * @param RegisterValue: The target register value to be written * @retval IOE_OK: if all operations are OK. Other value if error. */ uint8_t I2C_WriteDeviceRegister(uint8_t DeviceAddr, uint8_t RegisterAddr, uint8_t RegisterValue) { uint32_t read_verif = 0; /* Reset all I2C2 registers */ I2C_SoftwareResetCmd(IOE_I2C, ENABLE); I2C_SoftwareResetCmd(IOE_I2C, DISABLE); TimeOut = TIMEOUT_MAX; /* Enable the IOE_I2C peripheral */ I2C_Cmd(IOE_I2C, ENABLE); /* Configure the I2C peripheral */ IOE_I2C_Config(); /* Begin the config sequence */ I2C_GenerateSTART(IOE_I2C, ENABLE); /* Test on EV5 and clear it */ while (!I2C_CheckEvent(IOE_I2C, I2C_EVENT_MASTER_MODE_SELECT)) { if (TimeOut-- == 0) return IOE_TIEMOUT; } /* Transmit the slave address and enable writing operation */ I2C_Send7bitAddress(IOE_I2C, DeviceAddr, I2C_Direction_Transmitter); /* Test on EV6 and clear it */ while (!I2C_CheckEvent(IOE_I2C, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED)) { if (TimeOut-- == 0) return IOE_TIEMOUT; } /* Transmit the first address for r/w operations */ I2C_SendData(IOE_I2C, RegisterAddr); TimeOut = TIMEOUT_MAX; /* Test on EV8 and clear it */ while (!I2C_CheckEvent(IOE_I2C, I2C_EVENT_MASTER_BYTE_TRANSMITTED)) { if (TimeOut-- == 0) return IOE_TIEMOUT; } /* Prepare the register value to be sent */ I2C_SendData(IOE_I2C, RegisterValue); /* Test on EV8 and clear it */ while (!I2C_CheckEvent(IOE_I2C, I2C_EVENT_MASTER_BYTE_TRANSMITTED)) { if (TimeOut-- == 0) return IOE_TIEMOUT; } /* End the configuration sequence */ I2C_GenerateSTOP(IOE_I2C, ENABLE); #ifdef VERIFY_WRITTENDATA /* Verify (if needed) that the loaded data is correct */ /* Read the just written register*/ read_verif = I2C_ReadDeviceRegister(DeviceAddr, RegisterAddr); /* Load the register and verify its value */ if (read_verif != RegisterValue) { /* Control data wrongly tranfered */ read_verif = IOE_FAILURE; } else { /* Control data correctly transfered */ read_verif = 0; } #endif /* Return the verifying value: 0 (Passed) or 1 (Failed) */ return read_verif; }