711|5

914

帖子

3

资源

纯净的硅(中级)

【GD32F307E-START】+I2C驱动的问题 [复制链接]

    我的测试计划需要开通I2C通讯,我首先试图启用硬件I2C通讯,参照厂家EEPROM读写的范例,写了I2C单字节和多字节的读和写函数,也许是对I2C通讯的基础函数理解不透彻,调试了几天都没有成功。下面是硬件I2C的初始化代码,这是直接从范例复制过来的,应该没有错误:

/*!
    \brief      configure the GPIO ports
    \param[in]  none
    \param[out] none
    \retval     none
*/
void i2c_gpio_config(void)
{
    /* enable GPIOB clock */
    rcu_periph_clock_enable(RCU_GPIOB);
    /* enable I2C0 clock */
    rcu_periph_clock_enable(RCU_I2C0);

    /* connect PB6 to I2C0_SCL */
    /* connect PB7 to I2C0_SDA */
    gpio_init(GPIOB, GPIO_MODE_AF_OD, GPIO_OSPEED_50MHZ, GPIO_PIN_6 | GPIO_PIN_7);
}

/*!
    \brief      configure the I2C0 interfaces
    \param[in]  none
    \param[out] none
    \retval     none
*/
void i2c_config(void)
{
    i2c_gpio_config();
	
	/* enable I2C clock */
    rcu_periph_clock_enable(RCU_I2C0);
    /* configure I2C clock */
    i2c_clock_config(I2C0,I2C0_SPEED,I2C_DTCY_2);
    /* configure I2C address */
    i2c_mode_addr_config(I2C0,I2C_I2CMODE_ENABLE,I2C_ADDFORMAT_7BITS,I2C0_SLAVE_ADDRESS7);
    /* enable I2C0 */
    i2c_enable(I2C0);
    /* enable acknowledge */
    i2c_ack_config(I2C0,I2C_ACK_ENABLE);
}

    下面是单字节读的代码,程序运行到发送从机地址的即死循环,不知是何原因:

/***********************************************************
* 函数名称:i2c_addr8_byte_read()
* 函数功能:从8位地址的从设备读入一个字节数据
* 输入参数:i2c_addr  器件地址
*           dat_addr  8位数据地址
* 返回参数:data      读入的数据
* 备    注:无
***********************************************************/
uint8_t i2c_addr8_byte_read(uint8_t i2c_addr, uint8_t dat_addr)
{
    uint8_t data;

    /* wait until I2C bus is idle 等待I2C总线空闲*/
    while(i2c_flag_get(I2C0, I2C_FLAG_I2CBSY));

    /* send a start condition to I2C bus 向I2C总线发送启动条件*/
    i2c_start_on_bus(I2C0);
    
    /* wait until SBSEND bit is set 等待SBSEND位设置完毕*/
    while(!i2c_flag_get(I2C0, I2C_FLAG_SBSEND));
    
    /* send slave address to I2C bus 发送从机地址到I2C总线(标准模式) */
    i2c_master_addressing(I2C0, i2c_addr, I2C_TRANSMITTER);            //程序运行至此停止
    
    /* wait until ADDSEND bit is set 等待ADDREND位设置完毕*/
    while(!i2c_flag_get(I2C0, I2C_FLAG_ADDSEND));

    
    /* clear the ADDSEND bit 清除ADDRSEND位*/
    i2c_flag_clear(I2C0,I2C_FLAG_ADDSEND);
    
    /* wait until the transmit data buffer is empty 等待传输数据缓冲区为空*/
    while(SET != i2c_flag_get(I2C0, I2C_FLAG_TBE));

    /* enable I2C0*/
    i2c_enable(I2C0);  //??

    /* send slave internal address to write (one byte address) 发送从机的写入地址(单字节地址)*/
    i2c_data_transmit(I2C0, dat_addr);
      
    /* wait until BTC bit is set 等待BTC位设置完毕*/
    while(!i2c_flag_get(I2C0, I2C_FLAG_BTC));

    /* send a start condition to I2C bus 向I2C总线发送启动条件 */
    i2c_start_on_bus(I2C0);
    
    /* wait until SBSEND bit is set */
    while(!i2c_flag_get(I2C0, I2C_FLAG_SBSEND));
	
	/* send slave address to I2C bus 发送从机地址到I2C总线(标准模式) */
    i2c_master_addressing(I2C0, i2c_addr, I2C_RECEIVER);
    
    /* wait until ADDSEND bit is set 等待ADDREND位设置完毕*/
    while(!i2c_flag_get(I2C0, I2C_FLAG_ADDSEND));
    
    /* clear the ADDSEND bit 清除ADDRSEND位*/
    i2c_flag_clear(I2C0,I2C_FLAG_ADDSEND);

    /* wait until the transmit data buffer is empty 等待传输数据缓冲区为空*/
    while(SET != i2c_flag_get(I2C0, I2C_FLAG_TBE));

    /* read a byte from slave 接收1个字节数据*/
    data = i2c_data_receive(I2C0); 

    /* wait until the stop condition is finished 等待停止条件完成*/
    while(I2C_CTL0(I2C0)&0x0200);

    /* enable acknowledge */
    i2c_ack_config(I2C0,I2C_ACK_ENABLE);

    i2c_ackpos_config(I2C0,I2C_ACKPOS_CURRENT);
	
    /* send a stop condition to I2C bus 发送停止信息*/
    i2c_stop_on_bus(I2C0);	

    return data;

}

    通过逻辑分析仪抓取的时序如下图(首行是SCL,第二行是SDA),从图上看不到正常的时钟时序:

I2C_01.jpg

 

    硬件I2C调不通,于是我转而使用软件I2C通讯,下面是初始化和设置SDA引脚数据方向的代码,也许问题就出在设置SDA引脚方向的代码上:

/****************************************************************************************************************************************** 
* 函数名称: I2C_Init()
* 功能说明:	I2C_Init
* 输    入: 无
* 输    出: 无
******************************************************************************************************************************************/
void SI2C_Init(void)
{
    rcu_periph_clock_enable(SCL_GPIO_CLK);
    gpio_init(SCL_GPIO_PORT, GPIO_MODE_OUT_PP, GPIO_OSPEED_50MHZ, SCL_PIN);     // SCL推挽输出模式
	gpio_init(SDA_GPIO_PORT, GPIO_MODE_IN_FLOATING, GPIO_OSPEED_50MHZ, SDA_PIN);// SDA浮空输入模式 
}


/****************************************************************************************************************************************** 
* 函数名称: I2C_DAT_Dir()
* 功能说明:	设置I2C_SDA引脚的读或写
* 输    入: 0=读入,1=写 
* 输    出: 无
******************************************************************************************************************************************/
void SDA_Dir(uint8_t dir)
{
	if(dir)
        gpio_init(SDA_GPIO_PORT, GPIO_MODE_OUT_PP, GPIO_OSPEED_50MHZ, SDA_PIN);  // SDA推挽输出模式
	else
        gpio_init(SDA_GPIO_PORT, GPIO_MODE_IN_FLOATING, GPIO_OSPEED_50MHZ, SDA_PIN);// SDA浮空输入模式 
}

 

    这些代码是我在沁恒CH579M开发板上正常使用的,移植过来之后首先是调整时钟的延时时间,尽管延时已经调整的符合要求,但读不到从设备发出的SDA数据,就象没有设置好SDA引脚为输入模式一样,下面是截取的时序图,从图上可以看出地址数据发出之后,没有收到从设备的ACK回应:

I2C_S03.jpg

    下图是程序两次对从设备发出地址信息,但没有回应:

I2C_S02.jpg

    我测试用的I2C设备是DS1307日历模块,模块不会有问题,在其他开发板上调换测试仪过的:

I2C_S00.jpg

    下面是模块近景:

I2C_S01.jpg

    从成功驱动LCD之后我就开始尝试开通I2C,弄了几天,反复调试软件I2C和硬件I2C,均没有成功,至今仍未找到解决办法。

 


回复

424

帖子

0

资源

版主

你可以看看之前调IIC的测评帖子,说不定有帮助,也有可能是开发板有点问题。

http://bbs.eeworld.com.cn/thread-1145598-1-1.html


回复

2867

帖子

1

资源

五彩晶圆(初级)

不至于啊,硬件i2c好像挺简单的.

点评

    我参照对EEPROM读写操作的范例,写了对DS1307操作的代码,测试时发现死循环在等待器件回应的语句上,今天对照trucy老师的帖子,写操作的代码没有差别。也许问题出在配置I2C上,我发现范例中在配置I2C  详情 回复 发表于 2020-11-18 16:21
个人签名人已离开,无事别找,找也找不到。

回复

914

帖子

3

资源

纯净的硅(中级)

    我的软件I2C一直读不到数据,从逻辑分析仪抓取的时序看是器件一直不应答,很可能是SDA引脚转换输入方向时不起作用,我原来转换方向的宏定义是:

#define SDA_OUT() gpio_init(SDA_GPIO_PORT, GPIO_MODE_OUT_PP, GPIO_OSPEED_50MHZ, SDA_PIN) //SDA推挽输出模式 
#define SDA_IN()  gpio_init(SDA_GPIO_PORT, GPIO_MODE_IN_FLOATING, GPIO_OSPEED_50MHZ, SDA_PIN); //SDA浮空输入模式
    后来改为用函数方式也不行,代码如下:

void SDA_Dir(uint8_t dir)
{
    if(dir)
        gpio_init(SDA_GPIO_PORT, GPIO_MODE_OUT_PP, GPIO_OSPEED_50MHZ, SDA_PIN);  // SDA推挽输出模式
    else
        gpio_init(SDA_GPIO_PORT, GPIO_MODE_IN_FLOATING, GPIO_OSPEED_50MHZ, SDA_PIN);// SDA浮空输入模式 
}
    今天下载了trucy老师的项目文件学习,参照他的代码改为如下,测试仍然是没有回应:

#define SDA_OUT()  {gpio_init(SDA_GPIO_PORT, GPIO_MODE_OUT_PP,  GPIO_OSPEED_50MHZ,  SDA_PIN);}
#define SDA_IN()   {gpio_init(SDA_GPIO_PORT, GPIO_MODE_IPU, GPIO_OSPEED_50MHZ, SDA_PIN);}
 


回复

914

帖子

3

资源

纯净的硅(中级)

freebsder 发表于 2020-11-17 21:26 不至于啊,硬件i2c好像挺简单的.

    我参照对EEPROM读写操作的范例,写了对DS1307操作的代码,测试时发现死循环在等待器件回应的语句上,今天对照trucy老师的帖子,写操作的代码没有差别。也许问题出在配置I2C上,我发现范例中在配置I2C的同时,还设置了从器件的地址:

void i2c_config(void)
{
    i2c_gpio_config();
    
    /* enable I2C clock */
    rcu_periph_clock_enable(RCU_I2C0);
    /* configure I2C clock  supports standard mode*/
    i2c_clock_config(I2C0,I2C0_SPEED,I2C_DTCY_2);
    /* configure I2C address */
    i2c_mode_addr_config(I2C0,I2C_I2CMODE_ENABLE,I2C_ADDFORMAT_7BITS,I2C0_SLAVE_ADDRESS7);
    /* enable I2C0 */
    i2c_enable(I2C0);
    /* enable acknowledge */
    i2c_ack_config(I2C0,I2C_ACK_ENABLE);
}

     我将其中的地址宏定义修改为0xD0,测试仍然不行。下载了trucy老师的代码,但没有找到硬件I2C配置方法。看来还需要进一步分析硬件I2C的基础函数,弄清楚其如何配置。

 


回复

1万

帖子

133

资源

管理员

个人签名

玩板看这里:

http://bbs.eeworld.com.cn/elecplay.html

EEWorld测评频道众多好板等你来玩,还可以来频道许愿树许愿说说你想要玩的板子,我们都在努力为大家实现!


回复
您需要登录后才可以回帖 登录 | 注册

最新文章 更多>>
    关闭
    站长推荐上一条 1/6 下一条

    About Us 关于我们 客户服务 联系方式 器件索引 网站地图 最新更新 手机版

    站点相关: 安防电子 汽车电子 手机便携 工业控制 家用电子 医疗电子 测试测量 网络通信 物联网

    北京市海淀区知春路23号集成电路设计园量子银座1305 电话:(010)82350740 邮编:100191

    电子工程世界版权所有 京ICP证060456号 京ICP备10001474号 电信业务审批[2006]字第258号函 京公海网安备110108001534 Copyright © 2005-2020 EEWORLD.com.cn, Inc. All rights reserved
    快速回复 返回顶部 返回列表