|
@@ -0,0 +1,236 @@
|
|
|
+/**
|
|
|
+ \file i2c.h
|
|
|
+
|
|
|
+ \author G. Icking-Konert
|
|
|
+ \date 2013-11-22
|
|
|
+ \version 0.1
|
|
|
+
|
|
|
+ \brief implementation of I2C functions/macros
|
|
|
+
|
|
|
+ implementation of functions for I2C bus communication
|
|
|
+ For I2C bus, see http://en.wikipedia.org/wiki/I2C
|
|
|
+*/
|
|
|
+
|
|
|
+/*-----------------------------------------------------------------------------
|
|
|
+ INCLUDE FILES
|
|
|
+-----------------------------------------------------------------------------*/
|
|
|
+#include "stm8s.h"
|
|
|
+
|
|
|
+/*-----------------------------------------------------------------------------
|
|
|
+ DEFINITION OF GLOBAL MACROS/#DEFINES
|
|
|
+-----------------------------------------------------------------------------*/
|
|
|
+#define I2C_FAST 1
|
|
|
+#define F_MASTER_MHZ 16UL
|
|
|
+#define F_MASTER_HZ 16000000UL
|
|
|
+#ifdef I2C_FAST
|
|
|
+//400 kHz
|
|
|
+#define F_I2C_HZ 400000UL
|
|
|
+#else
|
|
|
+//100 kHz
|
|
|
+#define F_I2C_HZ 100000UL
|
|
|
+#endif // I2C_FAST
|
|
|
+
|
|
|
+//CCR = Fmaster/2*Fiic = 16MHz/2*100kHz = 80
|
|
|
+#define CCR (uint16_t)(F_MASTER_HZ / (2 * F_I2C_HZ))
|
|
|
+
|
|
|
+/* Таймаут ожидания события I2C */
|
|
|
+extern __IO uint8_t I2C_timeout;
|
|
|
+
|
|
|
+/*----------------------------------------------------------
|
|
|
+ FUNCTIONS
|
|
|
+----------------------------------------------------------*/
|
|
|
+static uint8_t i2c_read(void);
|
|
|
+
|
|
|
+/**
|
|
|
+ \fn void i2c_init(void)
|
|
|
+ \brief configure I2C bus
|
|
|
+ configure I2C bus as master in standard mode, BR=100kHz, 7bit address, 250ns rise time
|
|
|
+*/
|
|
|
+void i2c_init() {
|
|
|
+ //Частота тактирования периферии MHz
|
|
|
+ I2C->FREQR = (uint8_t)(F_MASTER_MHZ);
|
|
|
+
|
|
|
+ //Отключаем I2C
|
|
|
+ I2C->CR1 &= (uint8_t)(~I2C_CR1_PE);
|
|
|
+
|
|
|
+ //Выбираем режим
|
|
|
+#ifdef I2C_FAST
|
|
|
+ I2C->CCRH = I2C_CCRH_FS; // | I2C_CCRH_DUTY;
|
|
|
+#else
|
|
|
+ I2C->CCRH = 0;
|
|
|
+#endif
|
|
|
+
|
|
|
+ //Set Maximum Rise Time: 1000ns max in Standard Mode
|
|
|
+ //= [1000ns/(1/InputClockFrequencyMHz.10e6)]+1
|
|
|
+ //= InputClockFrequencyMHz+1
|
|
|
+ I2C->TRISER = (uint8_t)(F_MASTER_MHZ + 1);
|
|
|
+ I2C->CCRL = (uint8_t)CCR;
|
|
|
+ I2C->CCRH |= (uint8_t)((uint8_t)(CCR >> 8) & I2C_CCRH_CCR);
|
|
|
+
|
|
|
+ //Включаем I2C
|
|
|
+ I2C->CR1 |= I2C_CR1_PE;
|
|
|
+
|
|
|
+ //Разрешаем подтверждение в конце посылки
|
|
|
+ I2C->CR2 |= I2C_CR2_ACK;
|
|
|
+} // i2c_init
|
|
|
+
|
|
|
+/**
|
|
|
+ \fn uint8_t i2c_waitFree(void)
|
|
|
+ \brief wait until bus is free
|
|
|
+ \return error code (0=ok; 1=timeout)
|
|
|
+ wait until bus is free with timeout
|
|
|
+*/
|
|
|
+uint8_t i2c_waitFree() {
|
|
|
+ // wait until bus free with timeout
|
|
|
+ I2C_timeout = 10;
|
|
|
+ while (((I2C->SR3 & I2C_SR3_BUSY)) && I2C_timeout);
|
|
|
+
|
|
|
+ // on I2C timeout return error
|
|
|
+ if ((I2C->SR3 & I2C_SR3_BUSY)) {
|
|
|
+ i2c_init();
|
|
|
+ return(1);
|
|
|
+ }
|
|
|
+
|
|
|
+ // return success
|
|
|
+ return(0);
|
|
|
+} // i2c_waitFree
|
|
|
+
|
|
|
+/**
|
|
|
+ \fn uint8_t i2c_start(void)
|
|
|
+ \brief generate I2C start condition
|
|
|
+ \return error code (0=ok; 1=timeout)
|
|
|
+ generate I2C start condition with timeout
|
|
|
+*/
|
|
|
+uint8_t i2c_start() {
|
|
|
+ // wait until bus free with timeout
|
|
|
+ I2C_timeout = 10;
|
|
|
+ while (((I2C->SR3 & I2C_SR3_BUSY)) && I2C_timeout);
|
|
|
+
|
|
|
+ // on I2C timeout return error
|
|
|
+ if ((I2C->SR3 & I2C_SR3_BUSY)) {
|
|
|
+ i2c_init();
|
|
|
+ return(2);
|
|
|
+ }
|
|
|
+
|
|
|
+ // generate start condition with timeout
|
|
|
+ I2C->CR2 |= I2C_CR2_START;
|
|
|
+ I2C_timeout = 10;
|
|
|
+ while (!(I2C->SR1 & I2C_SR1_SB) && I2C_timeout);
|
|
|
+
|
|
|
+ // on I2C timeout return error
|
|
|
+ if (!(I2C->SR1 & I2C_SR1_SB)) {
|
|
|
+ i2c_init();
|
|
|
+ return(1);
|
|
|
+ }
|
|
|
+
|
|
|
+ // return success
|
|
|
+ return(0);
|
|
|
+} // i2c_start
|
|
|
+
|
|
|
+/**
|
|
|
+ \fn uint8_t i2c_stop(void)
|
|
|
+ \brief generate I2C stop condition
|
|
|
+ \return error code (0=ok; 1=timeout)
|
|
|
+ generate I2C stop condition with timeout
|
|
|
+*/
|
|
|
+uint8_t i2c_stop() {
|
|
|
+ // generate stop condition with timeout
|
|
|
+ I2C->CR2 |= I2C_CR2_STOP;
|
|
|
+ I2C_timeout = 10;
|
|
|
+ while ((I2C->SR3 & I2C_SR3_MSL) && I2C_timeout);
|
|
|
+
|
|
|
+ // on I2C timeout set error flag
|
|
|
+ if (I2C->SR3 & I2C_SR3_MSL) {
|
|
|
+ i2c_init();
|
|
|
+ return(1);
|
|
|
+ }
|
|
|
+
|
|
|
+ // return success
|
|
|
+ return(0);
|
|
|
+} // i2c_stop
|
|
|
+
|
|
|
+/**
|
|
|
+ \fn uint8_t i2c_send(uint8_t addr, uint8_t numTx, uint8_t *bufTx)
|
|
|
+ \brief write data via I2C
|
|
|
+ \param[in] addr 7b address [6:0] of I2C slave
|
|
|
+ \param[in] numTx number of bytes to send
|
|
|
+ \param[in] bufTx send buffer
|
|
|
+ \return error code (0=ok; 1=timeout)
|
|
|
+ write data to I2C slave with frame timeout. Note that no start or
|
|
|
+ stop condition is generated.
|
|
|
+*/
|
|
|
+uint8_t i2c_send(uint8_t addr, uint8_t numTx, uint8_t *bufTx) {
|
|
|
+ uint8_t i;
|
|
|
+
|
|
|
+ // send 7b slave adress [7:1] + write flag (LSB=0)
|
|
|
+ I2C->DR = (uint8_t) ((addr << 1) & ~0x01); // shift left and set LSB (write=0, read=1)
|
|
|
+ I2C_timeout = 10;
|
|
|
+ while ((!(I2C->SR1 & I2C_SR1_ADDR)) && I2C_timeout); // wait until address sent or timeout
|
|
|
+ I2C_timeout = 10;
|
|
|
+ while ((!(I2C->SR3 & I2C_SR3_BUSY)) && I2C_timeout); // seems to be required...???
|
|
|
+
|
|
|
+ // no I2C timeout -> send data
|
|
|
+ if (I2C_timeout) {
|
|
|
+ for (i=0; i<numTx; i++) {
|
|
|
+ I2C->DR = bufTx[i];
|
|
|
+ I2C_timeout = 2;
|
|
|
+ while ((!(I2C->SR1 & I2C_SR1_TXE)) && I2C_timeout); // wait until DR buffer empty or timeout
|
|
|
+ }
|
|
|
+ }
|
|
|
+ // on I2C timeout return error
|
|
|
+ else {
|
|
|
+ i2c_init();
|
|
|
+ return(1);
|
|
|
+ }
|
|
|
+
|
|
|
+ // return success
|
|
|
+ return(0);
|
|
|
+} // i2c_send
|
|
|
+
|
|
|
+static uint8_t i2c_read(void) {
|
|
|
+ I2C->CR2 &= ~I2C_CR2_ACK;
|
|
|
+ i2c_stop();
|
|
|
+ while (!(I2C->SR1 & I2C_SR1_RXNE));
|
|
|
+ return I2C->DR;
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ \fn uint8_t i2c_request(uint8_t slaveAddr, uint8_t numRx, uint8_t *bufRx)
|
|
|
+ \brief request data via I2C as master with i2c_stop()
|
|
|
+ \param[in] slaveAddr 7b address [6:0] of I2C slave
|
|
|
+ \param[in] numRx number of bytes to receive
|
|
|
+ \param[out] bufRx receive buffer
|
|
|
+ \return error code (0=ok; 1=timeout)
|
|
|
+ request data from I2C slave with frame timeout. Note that no start or
|
|
|
+ stop condition is generated.
|
|
|
+*/
|
|
|
+uint8_t i2c_request(const uint8_t slaveAddr, const uint8_t numRx, uint8_t *bufRx) {
|
|
|
+ uint8_t i = numRx;
|
|
|
+
|
|
|
+ // send 7b slave adress [7:1] + read flag (LSB=1)
|
|
|
+ I2C->DR = (uint8_t) ((slaveAddr << 1) | 0x01); // shift left and set LSB (write=0, read=1)
|
|
|
+ I2C_timeout = 10;
|
|
|
+ while ((!(I2C->SR1 & I2C_SR1_ADDR)) && I2C_timeout); // wait until adress sent or timeout
|
|
|
+ I2C_timeout = 2;
|
|
|
+ while ((!(I2C->SR3 & I2C_SR3_BUSY)) && I2C_timeout); // seems to be required...???
|
|
|
+
|
|
|
+ while (i-- > 1) {
|
|
|
+ I2C_timeout = 2;
|
|
|
+ while ((!(I2C->SR1 & I2C_SR1_RXNE)) && I2C_timeout); // wait until DR buffer not empty or timeout
|
|
|
+ *(bufRx++) = I2C->DR;
|
|
|
+ }
|
|
|
+ *bufRx = i2c_read();
|
|
|
+
|
|
|
+ // on I2C timeout return error
|
|
|
+ if (I2C_timeout == 0) {
|
|
|
+ i2c_init();
|
|
|
+ return(1);
|
|
|
+ }
|
|
|
+
|
|
|
+ // return success
|
|
|
+ return(0);
|
|
|
+} // i2c_request
|
|
|
+
|
|
|
+/*-----------------------------------------------------------------------------
|
|
|
+ END OF MODULE
|
|
|
+-----------------------------------------------------------------------------*/
|