找回密码
 立即注册

使用微信账号登录

只需一步,快速开始

CSR环境中的GPIO模拟I2C

2021-2-7 17:20| 发布者: csdn| 查看: 7391| 评论: 5|来自: CSDN

摘要: 碰到个客户,就是不用官方库中的i2c引脚,非要用普通PIO模拟的,没办法,只能自己写了。原理很简单,其实就是GPIO的拉高拉而已。先准备好头文件,将基本的拉高拉低封装一下。#define DELAY 10 /* pin definition */ ...
碰到个客户,就是不用官方库中的i2c引脚,非要用普通PIO模拟的,没办法,只能自己写了。

原理很简单,其实就是GPIO的拉高拉而已。

先准备好头文件,将基本的拉高拉低封装一下。

#define DELAY	10
 
/* pin definition */
#define SDA_PIN (1 << 12)
#define SCL_PIN (1 << 14)
#define RST_PIN (0x10000)
 
/* SDA input */
#define SET_SDA_IN() do \
{ \
  PioSetDir32(SDA_PIN, 0); \
  PioSet32(SDA_PIN, SDA_PIN); \
  PioSetStrongBias32(SDA_PIN, 0); \
}while(0)
#define GET_SDA() (PioGet32() & SDA_PIN) 
/* SDA output */
#define SET_SDA_OUT()   PioSetDir32(SDA_PIN, SDA_PIN)
#define SDA_HIGH()  PioSet32(SDA_PIN, SDA_PIN)
#define SDA_LOW()   PioSet32(SDA_PIN, 0)
 
 
/* SCL input */
#define SET_SCL_IN() do \
{ \
  PioSetDir32(SCL_PIN, 0); \
  PioSet32(SCL_PIN, SCL_PIN); \
  PioSetStrongBias32(SCL_PIN, 0); \
}while(0)
/* SCL output */
#define SET_SCL_OUT()   PioSetDir32(SCL_PIN, SCL_PIN)
#define SCL_HIGH()  PioSet32(SCL_PIN, SCL_PIN)
#define SCL_LOW()   PioSet32(SCL_PIN, 0)
 
/* RST output */
#define SET_RST_OUT()   PioSetDir32(RST_PIN, RST_PIN)
#define RST_HIGH()  PioSet32(RST_PIN, RST_PIN)
#define RST_LOW()   PioSet32(RST_PIN, 0)
 
/* function procotype */
void mysleep(int sec);
void msdelay(int ms);
void udelay(int us);
void i2c_start(void);
void i2c_stop(void);
void i2c_send_ack(uint8 ack);
uint8 i2c_receive_ack(void);
uint8 i2c_send_byte(uint8 send_byte);
void i2c_read_byte(uint8 *buffer, uint8 ack);
 
/*!
     @brief Allows transfer of data across the Bwave PIO simulated i2c interface.
     @param address The target address of the slave for this transfer.
     @param tx      A pointer to the data we wish to transmit. One octet per word.
     @param tx_len  The length of the data we wish to transmit.
     @param rx      A pointer to the memory we wish to read received data into. One octet per word.
     @param rx_len  The length of the data we wish to receive.
     @return The number of bytes acknowledged including the address bytes and the final data byte (which isn't strictly acknowledged).
     Perform a composite transfer consisting of a sequence of writes followed by a sequence of reads. These will be separated by a repeated start condition (Sr) and slave address if both reads and writes are performed.
     The general sequence of operations performed is:
     - Start condition (S).
     - Write slave address and direction byte (address | 0).
     - Write \e tx_len data bytes from the buffer at \e tx.
     - Repeated start condition (Sr) if \e tx_len and \e rx_len are non-zero.
     - Write slave address and direction byte (address | 1) if \e tx_len and \e rx_len are non-zero.
     - Read \e rx_len data bytes into the buffer at \e rx, acknowledging all but the final byte.
     - Stop condition (P).
     If \e tx_len is non-zero and \e rx_len is zero then the sequence reduces to:
     - Start condition (S).
     - Write slave address and direction byte (address | 0).
     - Write \e tx_len data bytes from the buffer at \e tx.
     - Stop condition (P).
     Alternatively, if \e tx_len is zero and \e rx_len is non-zero then the sequence reduces to:
     - Start condition (S).
     - Write slave address and direction byte (address | 1).
     - Read \e rx_len data bytes, acknowledging all but the final byte.
     - Stop condition (P).
     Finally, if both \e tx_len and \e rx_len are zero then the following minimal sequence is used:
     - Start condition (S).
     - Write slave address and direction byte (address | 1).
     - Stop condition (P).
     The transfer will be aborted if either the slave address or a byte being written is not acknowledged. The stop condition (P) will still be driven to reset the bus.
     Note also that the address is not shifted before being combined with the direction bit, i.e. the slave address should occupy bits 7 to 1 of address. This allows the R/W bit to be foerred to 1 for composite write/read transfers without a repeated start condition (Sr).
     If either \e tx_len or \e rx_len exceeds 64, failure may be returned or performance may be impaired; for instance, audio streaming may be disrupted.
*/
uint16 I2cTransfer(uint16 address, const uint8 *tx, uint16 tx_len, uint8 *rx, uint16 rx_len);
然后就是自己实现一下了。
/*
  2.0C is ok
  */
#include <stdlib.h>
#include <string.h>
#include <pio.h>
#include <print.h>
#include " _i2c.h"
 
uint16  I2cTransfer(uint16 address, const uint8 *tx, uint16 tx_len, uint8 *rx, uint16 rx_len)
{
    uint16 ack_num = 0;
    uint16 i;
 
    uint8 dev_address = (uint8)(address); /* 7-bit address supported */
    
    i2c_start();
    
    if( 0 != tx_len)
    {
        if(0 == i2c_send_byte(dev_address & 0xfe))
        {
            ack_num ++;
        }
        for(i = 0; i < tx_len; i++)
        {
            if(0 == i2c_send_byte(tx[i]))
            {
                ack_num ++;
            }
        }
    }
 
    if( (0 != tx_len) && (0 != rx_len))
    {
        i2c_stop();
        i2c_start();
    }
    
    if( 0 != rx_len)
    {
        if(0 == i2c_send_byte(dev_address | 0x01))
        {
            ack_num ++;
        }
        for(i=0; i < rx_len; i++)
        {
            /*  !(len-i-1)  这个用来保证在读到每个字节后发送一个ACK并能在最后一个字节读完后发送一个NACK*/
            i2c_read_byte((uint8*)&(rx[i]), !(rx_len-i-1));
        }
    }
    
    if( 0 == tx_len && 0 == rx_len)
    {
        if(0 == i2c_send_byte(dev_address))
        {
            ack_num ++;
        }
    }
    i2c_stop();
    
    return ack_num;
}
/******************************************************************************/
#if 1
int main(void)
{
 
    uint8 data[128]={0xff, 0x02, 0x04, 0xff};
    uint8 retry = 0;
 
 
    SET_SDA_OUT();    
    SET_SCL_OUT();
 
    SDA_HIGH();    
    SCL_HIGH();
 
    msdelay(40);
 
    SET_RST_OUT();
    RST_LOW();
    msdelay(40);
 #if 0
    RST_HIGH();
    msdelay(40);
 
#endif    
  
    while(1)
    {
 
#if 1
        /* case 1 */
        for(retry = 3; retry > 0; retry --)
        {
            if( I2cTransfer(0x20, NULL, 0, NULL, 0))
            {
                /* check whether salve alive */
                PRINT(("0x20 alive\n"));
                break;
            }
            else
            {
                PRINT(("\t\t\t0x20 dead\n"));
            }
        }
        data[0] = data[0];/* let gcc happy */
        mysleep(1);
        PRINT(("#########\n"));
#endif
#if 1
        /* case 2 write only */
        for(retry = 3; retry > 0; retry --)
        {
            memset((void*)data, 0x55, sizeof(data)/sizeof(data[0]));
            data[0] = 0x20; /* register address */
            if( 4 ==  I2cTransfer(0x20, (uint8 *)&data[0], 3, NULL, 0))
            {
                PRINT(("write bytes OK\n"));
                break;
            }
            else
            {
                PRINT(("\t\t\twrite bytes fail\n"));
            }
        }   
        
        mysleep(1);
        PRINT(("#########\n"));
 
#endif
#if 1
        /* case 3 write read */
        for(retry = 3; retry > 0; retry --)
        {
            memset((void*)data, 0xff, sizeof(data)/sizeof(data[0]));
            data[0] = 0x04; /* register address */
            if( 2 ==  I2cTransfer(0x20, (uint8 *)&data[0], 1, NULL, 0))
            {
                PRINT(("write OK\n"));
                break;
            }
            else
            {
                PRINT(("\t\t\twrite refore read fail\n"));
            }
        }
        for(retry = 3; retry > 0; retry --)
        {
            if(1 ==  I2cTransfer(0x20, NULL, 0, (uint8 *)&data[1], 4))
            {
                PRINT(("data: %x %x %x %x\n", data[1], data[2], data[3], data[4]));
                break;
            }
            else
            {
                PRINT(("\t\t\tread error""\n"));
            }
        }
        mysleep(1);
        PRINT(("#########\n"));
    #endif     
 
    }
}
#endif
/******************************************************************************/
/* START */
void i2c_start(void)
{	  
	SDA_HIGH();
	SCL_HIGH();
	udelay(DELAY);
    
	SDA_LOW();
    
	udelay(DELAY);
    
	SCL_LOW();
	udelay(DELAY);
}
/* STOP */
void i2c_stop(void)
{ 
	SCL_LOW();
	SDA_LOW();
    
	udelay(DELAY);
    
	SCL_HIGH();
	udelay(DELAY);
    
	SDA_HIGH();
	udelay(DELAY);
}
 
/* when ack 0 Send ack bit
   when ack 1 Don't send ack bit */
void i2c_send_ack(uint8 ack)
{
    SCL_LOW();
	if(ack)
		SDA_HIGH(); 
	else 
		SDA_LOW();
	udelay(DELAY);
	
	SCL_HIGH();
   	udelay(DELAY);
   	
	SCL_LOW();
	udelay(DELAY);	
}
/* try to get ack bit */
uint8 i2c_receive_ack(void)
{
	uint8 rc = 0;	
 
    SET_SDA_IN();
    udelay(DELAY);
	SCL_HIGH();
	udelay(DELAY);
    
	if(0 != GET_SDA())
    {
        /* nobody ack */
		rc = 1;
	}
 
    SCL_LOW();
    udelay(DELAY);
    
    SET_SDA_OUT();
	/*SDA_HIGH();*/
	return rc;
}
uint8 i2c_send_byte(uint8 send_byte)
{
	uint8 rc = 0;
	uint8 out_mask = 0x80;
	uint8 value;
	uint8 count = 8;
	
    for(count = 8; count > 0; count--, out_mask >>= 1)
    {
		value = ((send_byte & out_mask) ? 1 : 0);   
		if (1 == value)
		{    					      		
			SDA_HIGH();     
		}    
		else
		{      					     	
			SDA_LOW();
		}    
		udelay(DELAY);
		                          
		SCL_HIGH();   				    
		udelay(DELAY);
		             
		SCL_LOW();     
		udelay(DELAY);
	}
	
	/* SDA_HIGH();*/
	rc = i2c_receive_ack();
	return rc;
}
void i2c_read_byte(uint8 *buffer, uint8 ack)
{
	uint8 count = 0x08;
	uint8 data = 0x00;
	uint8 temp = 0;
	
    SET_SDA_IN();
	for(count = 8; count > 0; count--)
	{
		SCL_HIGH();
		udelay(DELAY);
		temp = GET_SDA();    	
		data <<= 1;
		if (temp)
		{
			data |= 0x01;
		}
		SCL_LOW();
		udelay(DELAY);
    }
    SET_SDA_OUT();
    /*SDA_HIGH();*/
	i2c_send_ack(ack);/*0 = ACK    1 = NACK */
	*buffer = data;
}
/******************************************************************************/
void mysleep(int sec)
{
    int i;
    uint32 a;
    for(i=0; i< sec; i++)
        for(a=0; a < 0xBC3C3B; a++)
            ;
    return; 
}
 
void msdelay(int ms)
{
    int i;
    uint32 a;
    for(i=0; i< ms; i++)
        for(a=0; a < 7273; a++)
            ;
    return; 
}
 
void udelay(int us)
{
    uint32 a;
        for(a=0; a < 100; a++)
            ;
    return; 
}
思路很简单,就是用封装好的拉高拉低组成序列,比如开始位停止位,然后再次封装读写byte的函数即可。

来源:https://blog.csdn.net/yilonglucky/article/details/52527907
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
4

路过

雷人

握手

鲜花

鸡蛋

刚表态过的朋友 (4 人)

相关阅读

发表评论

最新评论

引用 not30 2024-2-9 04:40
感谢分享,学习
引用 moyanming2013 2022-3-26 15:21
这个学习了
引用 音魅蓝牙测试仪 2021-6-3 16:17
不错
引用 Zcbh本土 2021-3-22 16:03
楼主威武,软件模拟IIC,其实挺好用的。

查看全部评论(5)

小黑屋|手机版|我爱蓝牙网 - 52Bluetooth

GMT+8, 2024-3-29 15:37 , Processed in 0.087139 second(s), 16 queries , Gzip On, MemCached On.

Powered by Discuz! X3.5

© 2001-2024 Discuz! Team.

返回顶部