uint32_t I2C_WrBuf(uint8_t DevAddr, uint8_t *buf, uint32_t cnt) { //Generate a Start condition I2C_Start(); //Send I2C device Address I2C_Addr(DevAddr, I2C_Direction_Transmitter); //Unstretch the clock by just reading SR2 (Physically the clock is continued to be strectehed because we have not written anything to the DR yet.) (void) I2Cx->SR2; //Start Writing Data while (cnt--) { I2C_Write(*buf++); } //Wait for the data on the shift register to be transmitted completely WaitSR1FlagsSet(I2C_SR1_BTF); //Here TXE=BTF=1. Therefore the clock stretches again. //Order a stop condition at the end of the current tranmission (or if the clock is being streched, generate stop immediatelly) I2Cx->CR1 |= I2C_CR1_STOP; //Stop condition resets the TXE and BTF automatically. //Wait to be sure that line is iddle WaitLineIdle(); return 0; }
/*----------------------------------------------------------------------------- * I2C_RdData: * * Parameters: addr - 7-bit device address * secByte - byte to send after address, before switching to read mode * buf - data buffer * cnt - number of bytes to read * * Return: 0 on success, nonzero on error *----------------------------------------------------------------------------*/ uint32_t I2C_RdData (uint8_t addr, uint8_t secByte, uint8_t *buf, uint32_t cnt) { uint8_t *dp = buf; uint32_t num = cnt; uint32_t err = 0; uint32_t st = 0; uint32_t br = 0; do { switch (st++) { case 0: err = I2C_Start (); break; case 1: err |= I2C_Addr (addr, A_WR); break; case 2: err |= I2C_Write (secByte); break; case 3: err |= I2C_Start (); break; case 4: err |= I2C_Addr (addr, A_RD); break; case 5: while (!err && num--) { err |= I2C_Read ((num != 0), dp++); } break; case 6: err |= I2C_Stop (); break; } if (err) { br++; /* Attempt recovery for 10 times, break otherwise */ if (br < 10) { if (I2C_Recovery (err) == 0) { /* Recovery succedded, retry */ dp = buf; num = cnt; err = 0; st = 0; } } else break; } } while (err == 0 && st < 7); return (err); }
uint32_t I2C_RdData(uint8_t DevAddr, uint8_t RegAddr, uint8_t *buf, uint32_t cnt) { //Reads "cnt" number of data starting from RegAddr //Send the Register Addres I2C_Start(); I2C_Addr(DevAddr, I2C_Direction_Transmitter); (void) I2Cx->SR2; I2Cx->DR = RegAddr; WaitSR1FlagsSet(I2C_SR1_BTF); //Start Reading I2C_RdBuf(DevAddr, buf, cnt); return 0; }
uint32_t I2C_WrData(uint8_t DevAddr, uint8_t RegAddr, uint8_t data) { //Write a single byte data to the given register address //Generate a Start condition I2C_Start(); //Send I2C device Address and clear ADDR I2C_Addr(DevAddr, I2C_Direction_Transmitter); (void) I2Cx->SR2; //Send Data I2Cx->DR = data; WaitSR1FlagsSet(I2C_SR1_BTF); //wait till the data is actually written. //Generate Stop I2Cx->CR1 |= I2C_CR1_STOP; //Wait to be sure that line is iddle WaitLineIdle(); return 0; }
uint32_t I2C_RdBufEasy (uint8_t DevAddr, uint8_t *buf, uint32_t cnt) { //The easy read. //We assume that we will reset ACK and order a stop condition while the last byte is being received by the shift register. //If this can't be done on time (during last byte reception), the slave will continue to send at least 1 more byte than cnt. //In most cases, such a condition does not hurt at all. Therefore people uses this method exclusively. //Note that it is impossible to guarantee the timig requirement only for single byte reception. //For N>=2, the timing is almost always satisfied. (if there is no interrupt, it will definetely be satisfied) //Generate Start I2C_Start(); //Send I2C Device Address and clear ADDR I2C_Addr(DevAddr, I2C_Direction_Receiver); (void)I2Cx->SR2; while ((cnt--)>1) { I2C_Read(buf++); } //At this point we assume last byte is being received by the shift register. (reception has not been completed yet) //Reset ack I2Cx->CR1 &= (uint16_t)~((uint16_t)I2C_CR1_ACK); //Order a stop condition I2Cx->CR1 |= I2C_CR1_STOP; //Now read the final byte I2C_Read(buf); //Make Sure Stop bit is cleared and Line is now Iddle WaitLineIdle(); //Enable the Acknowledgement I2Cx->CR1 |= ((uint16_t)I2C_CR1_ACK); return 0; }
uint32_t I2C_RdBuf (uint8_t DevAddr, uint8_t *buf, uint32_t cnt) { //Generate Start I2C_Start(); //Send I2C Device Address I2C_Addr(DevAddr, I2C_Direction_Receiver); if (cnt==1) {//We are going to read only 1 byte //Before Clearing Addr bit by reading SR2, we have to cancel ack. I2Cx->CR1 &= (uint16_t)~((uint16_t)I2C_CR1_ACK); //Now Read the SR2 to clear ADDR (void)I2Cx->SR2; //Order a STOP condition //Note: Spec_p583 says this should be done just after clearing ADDR //If it is done before ADDR is set, a STOP is generated immediately as the clock is being streched I2Cx->CR1 |= I2C_CR1_STOP; //Be carefull that till the stop condition is actually transmitted the clock will stay active even if a NACK is generated after the next received byte. //Read the next byte I2C_Read(buf); //Make Sure Stop bit is cleared and Line is now Iddle WaitLineIdle(); //Enable the Acknowledgement again I2Cx->CR1 |= ((uint16_t)I2C_CR1_ACK); } else if (cnt==2) { //We are going to read 2 bytes (See: Spec_p584) //Before Clearing Addr, reset ACK, set POS I2Cx->CR1 &= (uint16_t)~((uint16_t)I2C_CR1_ACK); I2Cx->CR1 |= I2C_CR1_POS; //Read the SR2 to clear ADDR (void)I2Cx->SR2; //Wait for the next 2 bytes to be received (1st in the DR, 2nd in the shift register) WaitSR1FlagsSet(I2C_SR1_BTF); //As we don't read anything from the DR, the clock is now being strecthed. //Order a stop condition (as the clock is being strecthed, the stop condition is generated immediately) I2Cx->CR1 |= I2C_CR1_STOP; //Read the next two bytes I2C_Read(buf++); I2C_Read(buf); //Make Sure Stop bit is cleared and Line is now Iddle WaitLineIdle(); //Enable the ack and reset Pos I2Cx->CR1 |= ((uint16_t)I2C_CR1_ACK); I2Cx->CR1 &= (uint16_t)~((uint16_t)I2C_CR1_POS); } else { //We have more than 2 bytes. See spec_p585 //Read the SR2 to clear ADDR (void)I2Cx->SR2; while((cnt--)>3) {//Read till the last 3 bytes I2C_Read(buf++); } //3 more bytes to read. Wait till the next to is actually received WaitSR1FlagsSet(I2C_SR1_BTF); //Here the clock is strecthed. One more to read. //Reset Ack I2Cx->CR1 &= (uint16_t)~((uint16_t)I2C_CR1_ACK); //Read N-2 I2C_Read(buf++); //Once we read this, N is going to be read to the shift register and NACK is generated //Wait for the BTF WaitSR1FlagsSet(I2C_SR1_BTF); //N-1 is in DR, N is in shift register //Here the clock is stretched //Generate a stop condition I2Cx->CR1 |= I2C_CR1_STOP; //Read the last two bytes (N-1 and N) //Read the next two bytes I2C_Read(buf++); I2C_Read(buf); //Make Sure Stop bit is cleared and Line is now Iddle WaitLineIdle(); //Enable the ack I2Cx->CR1 |= ((uint16_t)I2C_CR1_ACK); } return 0; }