123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329 |
- /**
- ******************************************************************************
- * @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.
- *
- * <h2><center>© COPYRIGHT 2009 STMicroelectronics</center></h2>
- */
- #include "i2c_master_poll.h"
- /* Таймаут ожидания события I2C */
- extern __IO uint8_t I2C_timeout;
- /* flag clearing sequence - uncoment next for peripheral clock under 2MHz */
- #define dead_time() { /* _asm("nop"); _asm("nop"); */ }
- #define tout() (I2C_timeout)
- #define set_tout_ms(a) { I2C_timeout = a; }
- /******************************************************************************
- * Function name : I2C_Init
- * Description : Initialize I2C peripheral
- * Input param : None
- * Return : None
- * See also : None
- *******************************************************************************/
- void I2C_Init(void) {
- //define SDA, SCL outputs, HiZ, Open drain, Fast
- GPIOB->ODR |= (GPIO_PIN_4 | GPIO_PIN_5);
- GPIOB->DDR |= (GPIO_PIN_4 | GPIO_PIN_5);
- GPIOB->CR2 |= (GPIO_PIN_4 | GPIO_PIN_5);
- #ifdef FAST_I2C_MODE
- I2C->FREQR = 16; // input clock to I2C - 16MHz
- I2C->CCRL = 15; // 900/62.5= 15, (SCLhi must be at least 600+300=900ns!)
- I2C->CCRH = 0x80; // fast mode, duty 2/1 (bus speed 62.5*3*15~356kHz)
- I2C->TRISER = 5; // 300/62.5 + 1= 5 (maximum 300ns)
- #else
- I2C->FREQR = 8; // input clock to I2C - 8MHz
- I2C->CCRL = 40; // CCR= 40 - (SCLhi must be at least 4000+1000=5000ns!)
- I2C->CCRH = 0; // standard mode, duty 1/1 bus speed 100kHz
- I2C->TRISER = 9; // 1000ns/(125ns) + 1 (maximum 1000ns)
- #endif
- I2C->OARL = 0xA0; // own address A0;
- I2C->OARH |= 0x40;
- //I2C->ITR = 1; // enable error interrupts
- I2C->CR2 |= 0x04; // ACK=1, Ack enable
- I2C->CR1 |= 0x01; // PE=1
- }
- /******************************************************************************
- * 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 *ReadBuffer)
- {
- /*--------------- BUSY? -> STOP request ---------------------*/
- while(I2C->SR3 & I2C_SR3_BUSY && tout()) // Wait while the bus is busy
- {
- I2C->CR2 |= I2C_CR2_STOP; // Generate stop here (STOP=1)
- while(I2C->CR2 & I2C_CR2_STOP && tout()); // Wait until stop is performed
- }
- I2C->CR2 |= I2C_CR2_ACK; // ACK=1, Ack enable
- /*--------------- Start communication -----------------------*/
- I2C->CR2 |= I2C_CR2_START; // START=1, generate start
- while((I2C->SR1 & I2C_SR1_SB)==0 && tout()); // Wait for start bit detection (SB)
- /*------------------ Address send ---------------------------*/
- if(tout())
- {
- I2C->DR = (u8)(SLAVE_ADDRESS << 1); // Send 7-bit device address & Write (R/W = 0)
- }
- while(!(I2C->SR1 & I2C_SR1_ADDR) && tout()); // test EV6 - wait for address ack (ADDR)
- dead_time(); // ADDR clearing sequence
- I2C->SR3;
- /*--------------- Register/Command send ----------------------*/
- while(!(I2C->SR1 & I2C_SR1_TXE) && tout()); // Wait for TxE
- if(tout())
- {
- I2C->DR = u8_regAddr; // Send register address
- } // Wait for TxE & BTF
- while((I2C->SR1 & (I2C_SR1_TXE | I2C_SR1_BTF)) != (I2C_SR1_TXE | I2C_SR1_BTF) && tout());
- dead_time(); // clearing sequence
- /*-------------- Stop/Restart communication -------------------*/
- #ifdef NO_RESTART // if 7bit address and NO_RESTART setted
- I2C->CR2 |= I2C_CR2_STOP; // STOP=1, generate stop
- while(I2C->CR2 & I2C_CR2_STOP && tout()); // wait until stop is performed
- #endif // NO_RESTART
- /*--------------- Restart communication ---------------------*/
- I2C->CR2 |= I2C_CR2_START; // START=1, generate re-start
- while((I2C->SR1 & I2C_SR1_SB)==0 && tout()); // Wait for start bit detection (SB)
- /*------------------ Address send ---------------------------*/
- if(tout())
- {
- I2C->DR = (u8)(SLAVE_ADDRESS << 1) | 1; // Send 7-bit device address & Write (R/W = 1)
- }
- while(!(I2C->SR1 & I2C_SR1_ADDR) && tout()); // Wait for address ack (ADDR)
- /*------------------- Data Receive --------------------------*/
- if (u8_NumByteToRead > 2) // *** more than 2 bytes are received? ***
- {
- I2C->SR3; // ADDR clearing sequence
- while(u8_NumByteToRead > 3 && tout()) // not last three bytes?
- {
- while(!(I2C->SR1 & I2C_SR1_BTF) && tout()); // Wait for BTF
- *ReadBuffer++ = I2C->DR; // Reading next data byte
- --u8_NumByteToRead; // Decrease Numbyte to reade by 1
- }
- //last three bytes should be read
- while(!(I2C->SR1 & I2C_SR1_BTF) && tout()); // Wait for BTF
- I2C->CR2 &=~I2C_CR2_ACK; // Clear ACK
- disableInterrupts(); // Errata workaround (Disable interrupt)
- *ReadBuffer++ = I2C->DR; // Read 1st byte
- I2C->CR2 |= I2C_CR2_STOP; // Generate stop here (STOP=1)
- *ReadBuffer++ = I2C->DR; // Read 2nd byte
- enableInterrupts(); // Errata workaround (Enable interrupt)
- while(!(I2C->SR1 & I2C_SR1_RXNE) && tout()); // Wait for RXNE
- *ReadBuffer++ = I2C->DR; // Read 3rd Data byte
- }
- else
- {
- if(u8_NumByteToRead == 2) // *** just two bytes are received? ***
- {
- I2C->CR2 |= I2C_CR2_POS; // Set POS bit (NACK at next received byte)
- disableInterrupts(); // Errata workaround (Disable interrupt)
- I2C->SR3; // Clear ADDR Flag
- I2C->CR2 &=~I2C_CR2_ACK; // Clear ACK
- enableInterrupts(); // Errata workaround (Enable interrupt)
- while(!(I2C->SR1 & I2C_SR1_BTF) && tout()); // Wait for BTF
- disableInterrupts(); // Errata workaround (Disable interrupt)
- I2C->CR2 |= I2C_CR2_STOP; // Generate stop here (STOP=1)
- *ReadBuffer++ = I2C->DR; // Read 1st Data byte
- enableInterrupts(); // Errata workaround (Enable interrupt)
- *ReadBuffer = I2C->DR; // Read 2nd Data byte
- }
- else // *** only one byte is received ***
- {
- I2C->CR2 &=~I2C_CR2_ACK;; // Clear ACK
- disableInterrupts(); // Errata workaround (Disable interrupt)
- I2C->SR3; // Clear ADDR Flag
- I2C->CR2 |= I2C_CR2_STOP; // generate stop here (STOP=1)
- enableInterrupts(); // Errata workaround (Enable interrupt)
- while(!(I2C->SR1 & I2C_SR1_RXNE) && tout()); // test EV7, wait for RxNE
- *ReadBuffer = I2C->DR; // Read Data byte
- }
- }
- /*--------------- All Data Received -----------------------*/
- while((I2C->CR2 & I2C_CR2_STOP) && tout()); // Wait until stop is performed (STOPF = 1)
- I2C->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 *ReadBuffer)
- {
- while((I2C->SR3 & 2) && tout()) // Wait while the bus is busy
- {
- I2C->CR2 |= 2; // STOP=1, generate stop
- while((I2C->CR2 & 2) && tout()); // wait until stop is performed
- }
-
- I2C->CR2 |= 1; // START=1, generate start
- while(((I2C->SR1 & 1)==0) && tout()); // Wait for start bit detection (SB)
- dead_time(); // SB clearing sequence
- if(tout())
- {
- I2C->DR = (u8)(SLAVE_ADDRESS << 1); // Send 7-bit device address & Write (R/W = 0)
- }
- while(!(I2C->SR1 & 2) && tout()); // Wait for address ack (ADDR)
- dead_time(); // ADDR clearing sequence
- I2C->SR3;
- while(!(I2C->SR1 & 0x80) && tout()); // Wait for TxE
- if(tout())
- {
- I2C->DR = u8_regAddr; // send Offset command
- }
- if(u8_NumByteToWrite)
- {
- while(u8_NumByteToWrite--)
- { // write data loop start
- while(!(I2C->SR1 & 0x80) && tout()); // test EV8 - wait for TxE
- I2C->DR = *ReadBuffer++; // send next data byte
- } // write data loop end
- }
- while(((I2C->SR1 & 0x84) != 0x84) && tout()); // Wait for TxE & BTF
- dead_time(); // clearing sequence
-
- I2C->CR2 |= 2; // generate stop here (STOP=1)
- while((I2C->CR2 & 2) && tout()); // wait until stop is performed
- }
- /**
- * @brief
- *
- * @param NumByteToRead
- * @param ReadBuffer
- */
- void I2C_ReadBytes(const u8 Addr, const u8 NumByteToRead, u8 *ReadBuffer) {
- u8 adr = Addr << 1;
- u8 n = NumByteToRead;
- set_tout_ms(10);
- /*--------------- BUSY? -> STOP request ---------------------*/
- while(I2C->SR3 & I2C_SR3_BUSY && tout()) // Wait while the bus is busy
- {
- I2C->CR2 |= I2C_CR2_STOP; // Generate stop here (STOP=1)
- while(I2C->CR2 & I2C_CR2_STOP && tout()); // Wait until stop is performed
- }
- I2C->CR2 |= I2C_CR2_ACK; // ACK=1, Ack enable
- /*--------------- Start communication -----------------------*/
- I2C->CR2 |= I2C_CR2_START; // START=1, generate start
- while((I2C->SR1 & I2C_SR1_SB)==0 && tout()); // Wait for start bit detection (SB)
- /*------------------ Address send ---------------------------*/
- if(tout())
- {
- I2C->DR = (adr | 1); // Send 7-bit device address & Write (R/W = 1)
- }
- while(!(I2C->SR1 & I2C_SR1_ADDR) && tout()); // Wait for address ack (ADDR)
- /*------------------- Data Receive --------------------------*/
- if (n > 2) // *** more than 2 bytes are received? ***
- {
- I2C->SR3; // ADDR clearing sequence
- while(n > 3 && tout()) // not last three bytes?
- {
- while(!(I2C->SR1 & I2C_SR1_BTF) && tout()); // Wait for BTF
- *ReadBuffer++ = I2C->DR; // Reading next data byte
- --n; // Decrease Numbyte to reade by 1
- }
- //last three bytes should be read
- while(!(I2C->SR1 & I2C_SR1_BTF) && tout()); // Wait for BTF
- I2C->CR2 &=~I2C_CR2_ACK; // Clear ACK
- disableInterrupts(); // Errata workaround (Disable interrupt)
- *ReadBuffer++ = I2C->DR; // Read 1st byte
- I2C->CR2 |= I2C_CR2_STOP; // Generate stop here (STOP=1)
- *ReadBuffer++ = I2C->DR; // Read 2nd byte
- enableInterrupts(); // Errata workaround (Enable interrupt)
- while(!(I2C->SR1 & I2C_SR1_RXNE) && tout()); // Wait for RXNE
- *ReadBuffer++ = I2C->DR; // Read 3rd Data byte
- }
- else
- {
- if(n == 2) // *** just two bytes are received? ***
- {
- I2C->CR2 |= I2C_CR2_POS; // Set POS bit (NACK at next received byte)
- disableInterrupts(); // Errata workaround (Disable interrupt)
- I2C->SR3; // Clear ADDR Flag
- I2C->CR2 &=~I2C_CR2_ACK; // Clear ACK
- enableInterrupts(); // Errata workaround (Enable interrupt)
- while(!(I2C->SR1 & I2C_SR1_BTF) && tout()); // Wait for BTF
- disableInterrupts(); // Errata workaround (Disable interrupt)
- I2C->CR2 |= I2C_CR2_STOP; // Generate stop here (STOP=1)
- *ReadBuffer++ = I2C->DR; // Read 1st Data byte
- enableInterrupts(); // Errata workaround (Enable interrupt)
- *ReadBuffer = I2C->DR; // Read 2nd Data byte
- }
- else // *** only one byte is received ***
- {
- I2C->CR2 &=~I2C_CR2_ACK;; // Clear ACK
- disableInterrupts(); // Errata workaround (Disable interrupt)
- I2C->SR3; // Clear ADDR Flag
- I2C->CR2 |= I2C_CR2_STOP; // generate stop here (STOP=1)
- enableInterrupts(); // Errata workaround (Enable interrupt)
- while(!(I2C->SR1 & I2C_SR1_RXNE) && tout()); // test EV7, wait for RxNE
- *ReadBuffer = I2C->DR; // Read Data byte
- }
- }
- /*--------------- All Data Received -----------------------*/
- while((I2C->CR2 & I2C_CR2_STOP) && tout()); // Wait until stop is performed (STOPF = 1)
- I2C->CR2 &= ~I2C_CR2_POS; // return POS to default state (POS=0)
- }
- /**
- * @brief write defined number bytes to slave device
- *
- * @param Addr
- * @param NumByteToWrite
- * @param DataBuffer
- */
- void I2C_WriteBytes(const u8 Addr, const u8 NumByteToWrite, u8 *DataBuffer) {
- u8 adr = Addr << 1;
- u8 n = NumByteToWrite;
- set_tout_ms(10);
- while((I2C->SR3 & 2) && tout()) // Wait while the bus is busy
- {
- I2C->CR2 |= 2; // STOP=1, generate stop
- while((I2C->CR2 & 2) && tout()); // wait until stop is performed
- }
-
- I2C->CR2 |= 1; // START=1, generate start
- while(((I2C->SR1 & 1)==0) && tout()); // Wait for start bit detection (SB)
- dead_time(); // SB clearing sequence
- if(tout())
- {
- I2C->DR = adr; // Send 7-bit device address & Write (R/W = 0)
- }
- while(!(I2C->SR1 & 2) && tout()); // Wait for address ack (ADDR)
- dead_time(); // ADDR clearing sequence
- I2C->SR3;
- if(n)
- {
- while(n--)
- { // write data loop start
- while(!(I2C->SR1 & 0x80) && tout()); // test EV8 - wait for TxE
- I2C->DR = *DataBuffer++; // send next data byte
- } // write data loop end
- }
- while(((I2C->SR1 & 0x84) != 0x84) && tout()); // Wait for TxE & BTF
- dead_time(); // clearing sequence
-
- I2C->CR2 |= 2; // generate stop here (STOP=1)
- while((I2C->CR2 & 2) && tout()); // wait until stop is performed
- }
|