/** ****************************************************************************** * @file i2c_master_poll.c * @author MCD Application Team * @version V0.0.3 * @date Oct 2010 * @brief This file contains optimized drivers for I2C master ****************************************************************************** * @copy * * THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS * WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE * TIME. AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY * DIRECT, INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING * FROM THE CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE * CODING INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS. * *

© COPYRIGHT 2009 STMicroelectronics

*/ #include "i2c_master_poll.h" volatile u8 err_save; volatile u16 TIM4_tout; volatile u8 DataReg_Value = 0; /****************************************************************************** * Function name : I2C_Init * Description : Initialize I2C peripheral * Input param : None * Return : None * See also : None *******************************************************************************/ void I2C_Init(void) { GPIOC->ODR |= 3; //define SDA, SCL outputs, HiZ, Open drain, Fast GPIOC->DDR |= 3; GPIOC->CR2 |= 3; CLK->PCKENR1 |= 8; // I2C clock enable #ifdef FAST_I2C_MODE I2C1->FREQR = 16; // input clock to I2C - 16MHz I2C1->CCRL = 15; // 900/62.5= 15, (SCLhi must be at least 600+300=900ns!) I2C1->CCRH = 0x80; // fast mode, duty 2/1 (bus speed 62.5*3*15~356kHz) I2C1->TRISER = 5; // 300/62.5 + 1= 5 (maximum 300ns) #else I2C1->FREQR = 8; // input clock to I2C - 8MHz I2C1->CCRL = 40; // CCR= 40 - (SCLhi must be at least 4000+1000=5000ns!) I2C1->CCRH = 0; // standard mode, duty 1/1 bus speed 100kHz I2C1->TRISER = 9; // 1000ns/(125ns) + 1 (maximum 1000ns) #endif I2C1->OARL = 0xA0; // own address A0; I2C1->OARH |= 0x40; //I2C1->ITR = 1; // enable error interrupts I2C1->CR2 |= 0x04; // ACK=1, Ack enable I2C1->CR1 |= 0x01; // PE=1 } /****************************************************************************** * Function name : I2C_RandomRead * Description : Read defined number bytes from slave memory starting with curret offset * Input param : number of bytes to read, starting address to store received data * Return : None * See also : None *******************************************************************************/ void I2C_RandomRead(u8 u8_NumByteToRead, u8 *u8_DataBuffer) { /*--------------- BUSY? -> STOP request ---------------------*/ while(I2C1->SR3 & I2C_SR3_BUSY && tout()) // Wait while the bus is busy { I2C1->CR2 |= I2C_CR2_STOP; // STOP=1, generate stop while(I2C1->CR2 & I2C_CR2_STOP && tout()); // wait until stop is performed } I2C1->CR2 |= I2C_CR2_ACK; // ACK=1, Ack enable /*--------------- Start communication -----------------------*/ I2C1->CR2 |= I2C_CR2_START; // START=1, generate start while((I2C1->SR1 & I2C_SR1_SB)==0 && tout()); // wait for start bit detection (SB) /*------------------ Address send ---------------------------*/ #ifdef TEN_BITS_ADDRESS I2C1->DR = (u8)(((SLAVE_ADDRESS >> 7) & 6) | 0xF0); // Send header of 10-bit device address (R/W = 0) while(!(I2C1->SR1 & I2C_SR1_ADD10) && tout()); // Wait for header ack (ADD10) I2C1->DR = (u8)(SLAVE_ADDRESS); // Send lower 8-bit device address while(!(I2C1->SR1 & I2C_SR1_ADDR) && tout()); // Wait for address ack (ADDR) I2C1->CR2 |= I2C_CR2_START; // START=1, generate start while((I2C1->SR1 & I2C_SR1_SB)==0 && tout()); // Wait for start bit detection (SB) I2C1->DR = (u8)(((SLAVE_ADDRESS >> 7) & 6) | 0xF1); // Send header of 10-bit device address (R/W = 1) #else I2C1->DR = (u8)(SLAVE_ADDRESS << 1) | 1; // Send 7-bit device address & Write (R/W = 1) #endif // TEN_BITS_ADDRESS while(!(I2C1->SR1 & I2C_SR1_ADDR) && tout()); // Wait for address ack (ADDR) /*------------------- Data Receive --------------------------*/ if (u8_NumByteToRead > 2) // *** more than 2 bytes are received? *** { I2C1->SR3; // ADDR clearing sequence while(u8_NumByteToRead > 3 && tout()) // not last three bytes? { while(!(I2C1->SR1 & I2C_SR1_BTF) && tout()); // Wait for BTF *u8_DataBuffer++ = I2C1->DR; // Reading next data byte --u8_NumByteToRead; // Decrease Numbyte to reade by 1 } //last three bytes should be read while(!(I2C1->SR1 & I2C_SR1_BTF) && tout()); // Wait for BTF I2C1->CR2 &=~I2C_CR2_ACK; // Clear ACK disableInterrupts(); // Errata workaround (Disable interrupt) *u8_DataBuffer++ = I2C1->DR; // Read 1st byte I2C1->CR2 |= I2C_CR2_STOP; // Generate stop here (STOP=1) *u8_DataBuffer++ = I2C1->DR; // Read 2nd byte enableInterrupts(); // Errata workaround (Enable interrupt) while(!(I2C1->SR1 & I2C_SR1_RXNE) && tout()); // Wait for RXNE *u8_DataBuffer++ = I2C1->DR; // Read 3rd Data byte } else { if(u8_NumByteToRead == 2) // *** just two bytes are received? *** { I2C1->CR2 |= I2C_CR2_POS; // Set POS bit (NACK at next received byte) disableInterrupts(); // Errata workaround (Disable interrupt) I2C1->SR3; // Clear ADDR Flag I2C1->CR2 &=~I2C_CR2_ACK; // Clear ACK enableInterrupts(); // Errata workaround (Enable interrupt) while(!(I2C1->SR1 & I2C_SR1_BTF) && tout()); // Wait for BTF disableInterrupts(); // Errata workaround (Disable interrupt) I2C1->CR2 |= I2C_CR2_STOP; // Generate stop here (STOP=1) *u8_DataBuffer++ = I2C1->DR; // Read 1st Data byte enableInterrupts(); // Errata workaround (Enable interrupt) *u8_DataBuffer = I2C1->DR; // Read 2nd Data byte } else // *** only one byte is received *** { I2C1->CR2 &=~I2C_CR2_ACK;; // Clear ACK disableInterrupts(); // Errata workaround (Disable interrupt) I2C1->SR3; // Clear ADDR Flag I2C1->CR2 |= I2C_CR2_STOP; // generate stop here (STOP=1) enableInterrupts(); // Errata workaround (Enable interrupt) while(!(I2C1->SR1 & I2C_SR1_RXNE) && tout()); // test EV7, wait for RxNE *u8_DataBuffer = I2C1->DR; // Read Data byte } } /*--------------- All Data Received -----------------------*/ while((I2C1->CR2 & I2C_CR2_STOP) && tout()); // Wait until stop is performed (STOPF = 1) I2C1->CR2 &=~I2C_CR2_POS; // return POS to default state (POS=0) } /****************************************************************************** * Function name : I2C_ReadRegister * Description : Read defined number bytes from slave memory starting with defined offset * Input param : offset in slave memory, number of bytes to read, starting address to store received data * Return : None * See also : None *******************************************************************************/ void I2C_ReadRegister(u8 u8_regAddr, u8 u8_NumByteToRead, u8 *u8_DataBuffer) { /*--------------- BUSY? -> STOP request ---------------------*/ while(I2C1->SR3 & I2C_SR3_BUSY && tout()) // Wait while the bus is busy { I2C1->CR2 |= I2C_CR2_STOP; // Generate stop here (STOP=1) while(I2C1->CR2 & I2C_CR2_STOP && tout()); // Wait until stop is performed } I2C1->CR2 |= I2C_CR2_ACK; // ACK=1, Ack enable /*--------------- Start communication -----------------------*/ I2C1->CR2 |= I2C_CR2_START; // START=1, generate start while((I2C1->SR1 & I2C_SR1_SB)==0 && tout()); // Wait for start bit detection (SB) /*------------------ Address send ---------------------------*/ if(tout()) { #ifdef TEN_BITS_ADDRESS I2C1->DR = (u8)(((SLAVE_ADDRESS >> 7) & 6) | 0xF0);// Send header of 10-bit device address (R/W = 0) while(!(I2C1->SR1 & I2C_SR1_ADD10) && tout()); // Wait for header ack (ADD10) if(tout()) { I2C1->DR = (u8)(SLAVE_ADDRESS); // Send lower 8-bit device address & Write } #else I2C1->DR = (u8)(SLAVE_ADDRESS);// << 1); // Send 7-bit device address & Write (R/W = 0) DataReg_Value = I2C1->DR; #endif // TEN_BITS_ADDRESS } while((I2C1->SR1 & I2C_SR1_ADDR) == 0 && tout()); // test EV6 - wait for address ack (ADDR) dead_time(); // ADDR clearing sequence I2C1->SR3; /*--------------- Register/Command send ----------------------*/ while(!(I2C1->SR1 & I2C_SR1_TXE) && tout()); // Wait for TxE if(tout()) { I2C1->DR = u8_regAddr; // Send register address } // Wait for TxE & BTF while((I2C1->SR1 & (I2C_SR1_TXE | I2C_SR1_BTF)) != (I2C_SR1_TXE | I2C_SR1_BTF) && tout()); dead_time(); // clearing sequence /*-------------- Stop/Restart communication -------------------*/ #ifndef TEN_BITS_ADDRESS #ifdef NO_RESTART // if 7bit address and NO_RESTART setted I2C1->CR2 |= I2C_CR2_STOP; // STOP=1, generate stop while(I2C1->CR2 & I2C_CR2_STOP && tout()); // wait until stop is performed #endif // NO_RESTART #endif // TEN_BITS_ADDRESS /*--------------- Restart communication ---------------------*/ I2C1->CR2 |= I2C_CR2_START; // START=1, generate re-start while((I2C1->SR1 & I2C_SR1_SB)==0 && tout()); // Wait for start bit detection (SB) /*------------------ Address send ---------------------------*/ if(tout()) { #ifdef TEN_BITS_ADDRESS I2C1->DR = (u8)(((SLAVE_ADDRESS >> 7) & 6) | 0xF1);// send header of 10-bit device address (R/W = 1) #ifdef NO_RESTART while(!(I2C1->SR1 & I2C_SR1_ADD10) && tout()); // Wait for header ack (ADD10) if(tout()) { I2C1->DR = (u8)(SLAVE_ADDRESS); // Send lower 8-bit device address & Write } #endif // NO_RESTART #else I2C1->DR = (u8)(SLAVE_ADDRESS << 1) | 1; // Send 7-bit device address & Write (R/W = 1) #endif // TEN_BITS_ADDRESS } while(!(I2C1->SR1 & I2C_SR1_ADDR) && tout()); // Wait for address ack (ADDR) /*------------------- Data Receive --------------------------*/ if (u8_NumByteToRead > 2) // *** more than 2 bytes are received? *** { I2C1->SR3; // ADDR clearing sequence while(u8_NumByteToRead > 3 && tout()) // not last three bytes? { while(!(I2C1->SR1 & I2C_SR1_BTF) && tout()); // Wait for BTF *u8_DataBuffer++ = I2C1->DR; // Reading next data byte --u8_NumByteToRead; // Decrease Numbyte to reade by 1 } //last three bytes should be read while(!(I2C1->SR1 & I2C_SR1_BTF) && tout()); // Wait for BTF I2C1->CR2 &=~I2C_CR2_ACK; // Clear ACK disableInterrupts(); // Errata workaround (Disable interrupt) *u8_DataBuffer++ = I2C1->DR; // Read 1st byte I2C1->CR2 |= I2C_CR2_STOP; // Generate stop here (STOP=1) *u8_DataBuffer++ = I2C1->DR; // Read 2nd byte enableInterrupts(); // Errata workaround (Enable interrupt) while(!(I2C1->SR1 & I2C_SR1_RXNE) && tout()); // Wait for RXNE *u8_DataBuffer++ = I2C1->DR; // Read 3rd Data byte } else { if(u8_NumByteToRead == 2) // *** just two bytes are received? *** { I2C1->CR2 |= I2C_CR2_POS; // Set POS bit (NACK at next received byte) disableInterrupts(); // Errata workaround (Disable interrupt) I2C1->SR3; // Clear ADDR Flag I2C1->CR2 &=~I2C_CR2_ACK; // Clear ACK enableInterrupts(); // Errata workaround (Enable interrupt) while(!(I2C1->SR1 & I2C_SR1_BTF) && tout()); // Wait for BTF disableInterrupts(); // Errata workaround (Disable interrupt) I2C1->CR2 |= I2C_CR2_STOP; // Generate stop here (STOP=1) *u8_DataBuffer++ = I2C1->DR; // Read 1st Data byte enableInterrupts(); // Errata workaround (Enable interrupt) *u8_DataBuffer = I2C1->DR; // Read 2nd Data byte } else // *** only one byte is received *** { I2C1->CR2 &=~I2C_CR2_ACK;; // Clear ACK disableInterrupts(); // Errata workaround (Disable interrupt) I2C1->SR3; // Clear ADDR Flag I2C1->CR2 |= I2C_CR2_STOP; // generate stop here (STOP=1) enableInterrupts(); // Errata workaround (Enable interrupt) while(!(I2C1->SR1 & I2C_SR1_RXNE) && tout()); // test EV7, wait for RxNE *u8_DataBuffer = I2C1->DR; // Read Data byte } } /*--------------- All Data Received -----------------------*/ while((I2C1->CR2 & I2C_CR2_STOP) && tout()); // Wait until stop is performed (STOPF = 1) I2C1->CR2 &=~I2C_CR2_POS; // return POS to default state (POS=0) } /****************************************************************************** * Function name : I2C_WriteRegister * Description : write defined number bytes to slave memory starting with defined offset * Input param : offset in slave memory, number of bytes to write, starting address to send * Return : None. * See also : None. *******************************************************************************/ void I2C_WriteRegister(u8 u8_regAddr, u8 u8_NumByteToWrite, u8 *u8_DataBuffer) { while((I2C1->SR3 & 2) && tout()) // Wait while the bus is busy { I2C1->CR2 |= 2; // STOP=1, generate stop while((I2C1->CR2 & 2) && tout()); // wait until stop is performed } I2C1->CR2 |= 1; // START=1, generate start while(((I2C1->SR1 & 1)==0) && tout()); // Wait for start bit detection (SB) dead_time(); // SB clearing sequence if(tout()) { #ifdef TEN_BITS_ADDRESS // TEN_BIT_ADDRESS decalred in I2c_master_poll.h I2C1->DR = (u8)(((SLAVE_ADDRESS >> 7) & 6) | 0xF0); // Send header of 10-bit device address (R/W = 0) while(!(I2C1->SR1 & 8) && tout()); // Wait for header ack (ADD10) if(tout()) { I2C1->DR = (u8)(SLAVE_ADDRESS); // Send lower 8-bit device address & Write } #else I2C1->DR = (u8)(SLAVE_ADDRESS << 1); // Send 7-bit device address & Write (R/W = 0) #endif } while(!(I2C1->SR1 & 2) && tout()); // Wait for address ack (ADDR) dead_time(); // ADDR clearing sequence I2C1->SR3; while(!(I2C1->SR1 & 0x80) && tout()); // Wait for TxE if(tout()) { I2C1->DR = u8_regAddr; // send Offset command } if(u8_NumByteToWrite) { while(u8_NumByteToWrite--) { // write data loop start while(!(I2C1->SR1 & 0x80) && tout()); // test EV8 - wait for TxE I2C1->DR = *u8_DataBuffer++; // send next data byte } // write data loop end } while(((I2C1->SR1 & 0x84) != 0x84) && tout()); // Wait for TxE & BTF dead_time(); // clearing sequence I2C1->CR2 |= 2; // generate stop here (STOP=1) while((I2C1->CR2 & 2) && tout()); // wait until stop is performed } /****************************************************************************** * Function name : ErrProc * Description : Manage all I2C error detected by interrupt handler * Input param : None * Return : None * See also : None *******************************************************************************/ void ErrProc(void) { // Clear Error Falg I2C1->SR2= 0; // STOP=1, generate stop I2C1->CR2 |= 2; // Disable Timout TIM4_tout= 0; // Switch on LED3 for I2C Error detection switch_on(LED3); } /****************************************************************************** * Function name : I2C_error_Interrupt_Handler * Description : Manage all I2C error inetrrupts * Input param : None * Return : None * See also : None *******************************************************************************/ #ifdef _COSMIC_ @far @interrupt void I2C_error_Interrupt_Handler (void) { #else void I2CInterruptHandle (void) interrupt 29 { #endif ErrProc(); } /****************************************************************************** * Function name : TIM4_Init * Description : Initialize TIM4 peripheral * Input param : None * Return : None * See also : None *******************************************************************************/ void TIM4_Init (void) { CLK->PCKENR1 |= 0x4; // TIM4 clock enable TIM4->ARR = 0x80; // init timer 4 1ms inetrrupts TIM4->PSCR= 7; TIM4->IER = 1; TIM4->CR1 |= 1; } /****************************************************************************** * Function name : TIM4InterruptHandle * Description : Testing load for Main * Input param : None * Return : None * See also : None *******************************************************************************/ /*#ifdef _COSMIC_ @far @interrupt void TIM4InterruptHandle (void) { #else void TIM4InterruptHandle (void) interrupt 25 { #endif u8 dly= 10; TIM4->SR1= 0; if(TIM4_tout) //if(--TIM4_tout == 0) #ifdef _COSMIC_ _asm("nop"); #else _nop_(); #endif while(dly--); }*/