/*********************************************************************************
|
* Copyright: (C) 2014 Guo Wenxue<guowenxue@gmail.com>
|
* All rights reserved.
|
*
|
* Filename: gpio_i2c.c
|
* Description: STM8 GPIOÄ£ÄâI2C´úÂë
|
*
|
* Version: 1.0.0(09/28/2014)
|
* Author: Guo Wenxue <guowenxue@gmail.com>
|
* ChangeLog: 1, Release initial version on "09/28/2014 10:58:17 PM"
|
*
|
********************************************************************************/
|
|
#include "gpio_i2c.h"
|
#include "timing_delay.h"
|
|
/* ¿ªÊ¼ÐźţºSCLΪ¸ßµçƽʱ£¬SDAÓÉ¸ßµçÆ½ÏòµÍµçÆ½Ìø±ä£¬¿ªÊ¼´«ËÍÊý¾Ý. */
|
void gpio_i2c_start(void)
|
{
|
SDA_MODE_OUT;
|
|
SCL_LOW;
|
TIMDelay_N10us(1);
|
SDA_HIGH;
|
TIMDelay_N10us(1);
|
SCL_HIGH;
|
TIMDelay_N10us(1);
|
|
SDA_LOW;
|
TIMDelay_N10us(1);
|
|
SCL_LOW; /* StartÖ®ºóBUS×ÜÏßÒ»°ã±»ÈÏΪ´¦ÓÚÕ¼Ïß״̬ */
|
TIMDelay_N10us(1);
|
}
|
|
/* ½áÊøÐźţºSCLΪ¸ßµçƽʱ£¬SDAÓÉµÍµçÆ½Ïò¸ßµçÆ½Ìø±ä£¬½áÊø´«ËÍÊý¾Ý. */
|
void gpio_i2c_stop(void)
|
{
|
SDA_MODE_OUT;
|
|
SCL_LOW;
|
TIMDelay_N10us(1);
|
SDA_LOW;
|
TIMDelay_N10us(1);
|
|
SCL_HIGH;
|
TIMDelay_N10us(1);
|
|
SDA_HIGH;
|
TIMDelay_N10us(1);
|
}
|
|
/* ¶ÔÓÚ·´À¡ÓÐЧӦ´ðλACKµÄÒªÇóÊÇ£¬½ÓÊÕÆ÷ÔÚµÚ9¸öʱÖÓÂö³å֮ǰµÄ
|
*µÍµçƽÆÚ¼ä½«SDAÏßÀµÍ£¬²¢ÇÒÈ·±£ÔÚ¸ÃʱÖÓµÄ¸ßµçÆ½ÆÚ¼äΪÎȶ¨µÄµÍµçƽ
|
*/
|
void gpio_i2c_send_ack(void)
|
{
|
SDA_MODE_OUT;
|
|
/* ĬÈÏSCLÊÇµÍµçÆ½£¬ÏÖÔڸıäÊý¾Ý£¬µÍµçƽ±íʾACK */
|
SDA_LOW;
|
TIMDelay_N10us(1);
|
|
/* ʱÖÓÏßÀ¸ß²¢Î¬³ÖSDA״̬ */
|
SCL_HIGH;
|
TIMDelay_N10us(1);
|
|
/* »Ö¸´Ê±ÖÓÏßΪµÍµçƽ£¬×ÜÏßæ */
|
SCL_LOW;
|
TIMDelay_N10us(1);
|
}
|
|
/* NACK(°ÑÊý¾Ý×ÜÏßµÄµçÆ½ÀµÍ¸ß)À´±íʾÊý¾Ý³É¹¦Ê§°Ü */
|
void gpio_i2c_send_nak(void)
|
{
|
SDA_MODE_OUT;
|
|
/* ĬÈÏSCLÊÇµÍµçÆ½£¬ÏÖÔڸıäÊý¾Ý£¬¸ßµçƽ±íʾNAK */
|
SDA_HIGH;
|
TIMDelay_N10us(1);
|
|
/* ʱÖÓÏßÀ¸ß²¢Î¬³ÖSDA״̬ */
|
SCL_HIGH;
|
TIMDelay_N10us(1);
|
|
/* »Ö¸´Ê±ÖÓÏßΪµÍµçƽ£¬×ÜÏßæ */
|
SCL_LOW;
|
TIMDelay_N10us(1);
|
}
|
|
/* I2C ×ÜÏß¶ÁÒ»¸öACKÐźÅ
|
* ·µ»ØÖµ:0 ÊÕµ½ACK 1: ÊÕµ½NAK
|
*/
|
uint8_t gpio_i2c_wait_ack(void)
|
{
|
uint8_t rv;
|
uint8_t times = 200;
|
|
SDA_MODE_IN;
|
|
/* ʱÖÓÏßÀ¸ß */
|
SCL_HIGH;
|
TIMDelay_N10us(1);
|
|
do
|
{
|
times --;
|
} while ( (SDA_DAT==1) && (times!=0) );
|
|
if( !times )
|
{
|
/* µÈ´ý ACK ³¬Ê±£¬½ÓÊÕµ½NAK */
|
rv = I2C_NAK;
|
goto OUT;
|
}
|
|
/* µÈµ½ACK */
|
SCL_LOW;
|
TIMDelay_N10us(1);
|
|
rv = I2C_ACK;
|
|
OUT:
|
return rv;
|
}
|
|
/* I2C×ÜÏß·¢ËÍÒ»¸ö×Ö½ÚÊý¾Ý:
|
* ·µ»ØÖµ:0 ·¢Ëͳɹ¦£¬µÈµ½ACK 1: ·¢ËÍʧ°Ü,ÊÕµ½NAK
|
*/
|
uint8_t gpio_i2c_write_byte(uint8_t byte)
|
{
|
int i;
|
uint8_t rv = I2C_ACK;
|
|
SDA_MODE_OUT;
|
|
/* SCLΪµÍµçƽʱ,SDAÏß²ÅÄܸı䴫ÊäµÄbit; SCLΪ¸ßµçƽʱ,SDAÏß±£³ÖÎȶ¨ */
|
for(i=7; i>=0; i--) /* MSB */
|
{
|
/*MSB: Êä³öÏàӦλµÄµçƽÐźŠ*/
|
if( byte&(1<<i) )
|
SDA_HIGH;
|
else
|
SDA_LOW;
|
TIMDelay_N10us(1);
|
|
SCL_HIGH;
|
TIMDelay_N10us(1);
|
|
SCL_LOW;
|
TIMDelay_N10us(1);
|
}
|
|
rv = gpio_i2c_wait_ack();
|
return rv;
|
}
|
|
/* I2C×ÜÏß½ÓÊÕÒ»¸ö×Ö½ÚÊý¾Ý */
|
uint8_t gpio_i2c_read_byte(void)
|
{
|
uint8_t bit;
|
uint8_t byte = 0;
|
|
SDA_MODE_IN;
|
|
for(bit=0; bit<8; bit++)
|
{
|
byte <<= 1;
|
SCL_HIGH;
|
TIMDelay_N10us(2);
|
|
if(SDA_DAT)
|
byte |= 1;
|
|
SCL_LOW;
|
TIMDelay_N10us(2);
|
}
|
|
gpio_i2c_send_ack();
|
return byte;
|
}
|
|
uint8_t gpio_i2c_read(uint8_t addr, uint8_t reg_addr)
|
{
|
int rv;
|
uint8_t data = 0;
|
|
// Start condition
|
gpio_i2c_start();
|
|
// Send the slave address with write bit and check for ACK
|
if (I2C_ACK != gpio_i2c_write_byte(addr | I2C_DIR_WRITE))
|
{
|
rv = I2C_ERROR;
|
goto OUT;
|
}
|
|
// Send the register address and check for ACK
|
if (I2C_ACK != gpio_i2c_write_byte(reg_addr))
|
{
|
rv = I2C_ERROR;
|
goto OUT;
|
}
|
|
// Repeated start condition
|
gpio_i2c_start();
|
|
// Send the slave address with read bit and check for ACK
|
if (I2C_ACK != gpio_i2c_write_byte(addr | I2C_DIR_READ))
|
{
|
rv = I2C_ERROR;
|
goto OUT;
|
}
|
|
// Read the data byte
|
data = gpio_i2c_read_byte();
|
|
rv = data;
|
|
OUT:
|
gpio_i2c_stop();
|
if (rv == I2C_ERROR)
|
{
|
return -1;
|
}
|
return rv;
|
}
|
|
|
|
int gpio_i2c_write(uint8_t addr, uint8_t reg_addr, uint8_t data)
|
{
|
int rv = I2C_OK;
|
|
gpio_i2c_start();
|
|
// Send the slave device address with the write bit and check for ACK
|
if (I2C_ACK != gpio_i2c_write_byte(addr | I2C_DIR_WRITE))
|
{
|
rv = I2C_ERROR;
|
goto OUT;
|
}
|
|
// Send the register address and check for ACK
|
if (I2C_ACK != gpio_i2c_write_byte(reg_addr))
|
{
|
rv = I2C_ERROR;
|
goto OUT;
|
}
|
|
// Send the data byte and check for ACK
|
if (I2C_ACK != gpio_i2c_write_byte(data))
|
{
|
rv = I2C_ERROR;
|
}
|
|
OUT:
|
gpio_i2c_stop();
|
return rv;
|
}
|