4593 views|7 replies

931

Posts

3

Resources
The OP
 

【GD32F307E-START】+Software I2C driver DS1307 calendar module [Copy link]

 

After repeated debugging, I finally successfully drove the DS1307 calendar module today and can perform read and write operations on the calendar module.

The DS1307 module communicates via I2C. I initially planned to use the hardware I2C driver, but failed after many attempts. I had no choice but to use software driver, but the software driver was not smooth either. It took me more than a week to debug, and I even posted this thread for help.

The software I2C code is transplanted from other projects. The first step is to adjust the clock delay through the timing captured by the logic analyzer. This step is relatively easy. The clock flip is about microseconds:

The clock frequency is adjusted, but the device does not respond and no ACK is received:

Initial analysis showed that it might be a problem with the direction setting of the data pin SDA. After several days of repeatedly modifying the pin direction setting code, there was no effect. Changing other pins also did not help. So I paused the I2C communication test and first tested the button polling mode and interrupt mode. When I resumed the test today, I found that the device actually responded and was able to read data:

However, the data pins seem to be interfered with, and abnormal jumps occur, as shown in the yellow circle in the figure below. The reason is still unknown:

The regularity of these irregular jump phenomena has not yet been found and needs further debugging and resolution:

Transitions can sometimes cause misinterpretation, such as the following timing diagram, where a transition generates a STOP signal:

But no matter what, at least the data is basically read, and we need to continue debugging. The following are photos of the debugging process:

Here's a specific shot of the display:

Here is an animation of the test effect:

This post is from Domestic Chip Exchange

Latest reply

Thanks for sharing   Details Published on 2021-4-22 17:32

赞赏

1

查看全部赞赏

 
 

931

Posts

3

Resources
2
 

This is the header file of SI2C:


#ifndef I2C_H
#define I2C_H

#include "gd32f30x.h"

/*************************** 宏定义 *****************************/

#define SCL_PIN             GPIO_PIN_12
#define SCL_GPIO_PORT       GPIOD
#define SCL_GPIO_CLK        RCU_GPIOD
#define SDA_PIN             GPIO_PIN_14
#define SDA_GPIO_PORT       GPIOD
#define SDA_GPIO_CLK        RCU_GPIOD


#define SCL_1() {gpio_bit_set(SCL_GPIO_PORT, SCL_PIN);}   //写I2C时钟端口
#define SCL_0() {gpio_bit_reset(SCL_GPIO_PORT, SCL_PIN);}

#define SDA_1() {gpio_bit_set(SDA_GPIO_PORT, SDA_PIN);}   //写I2C数据端口
#define SDA_0() {gpio_bit_reset(SDA_GPIO_PORT, SDA_PIN);}
#define SDA_X() gpio_input_bit_get(SDA_GPIO_PORT, SDA_PIN)//读I2C数据端口状态

//#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);}
#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 delay_us(uint8_t us);
void SI2C_Init(void);

uint8_t SI2C_8bitByteWrite(uint8_t I2C_addr,uint8_t addr,uint8_t data);               //向指定的器件及地址写入1个字节
uint8_t SI2C_8bitByteRead(uint8_t I2C_addr,uint8_t addr);                             //从指定的器件及地址读取1个字节
uint8_t SI2C_8bitBuffWrite(uint8_t I2C_addr,uint8_t addr,uint8_t size,uint8_t *buf);  //向指定的器件及地址开始写入多个字节
uint8_t SI2C_8bitBuffRead(uint8_t I2C_addr,uint8_t addr,uint8_t size,uint8_t *buf);   //从指定的器件及地址开始读出多个字节
uint8_t SI2C_16bitBuffWrite(uint8_t I2C_addr,uint16_t addr,uint8_t size,uint8_t *buf);//写多个数据到16位地址的I2C设备
uint8_t SI2C_16bitBuffRead(uint8_t I2C_addr,uint16_t addr,uint8_t size,uint8_t *buf); //读取16位地址的多个数据


#endif  /* I2C_H */

Here is the C file, where reading and writing of double-byte addresses have not been tested:



#include "si2c.h"

extern uint8_t I2C_Buff[16];


void SI2C_Start(void);          //开始SI2C通讯
void SI2C_Stop(void);           //停止SI2C通讯
void SI2C_Send(uint8_t dat);    //向SI2C总线发送一个字节
uint8_t SI2C_Receive(void);     //从SI2C总结接收一个字节
void SI2CDoAck(void);           //发出应答信号
void SI2CNoAck(void);           //发出无应答信号
uint8_t SI2CIsAck(void);        //检测从机应答信号


/***************************************************
函数功能:微秒延时
入口参数:延时的微秒数
***************************************************/
void delay_us(uint8_t us)  
{
    uint8_t x,y;
    for(x=us;x>0;x--)    
    for(y=22;y>0;y--);  //120MHz=22,
}

/****************************************************************************************************************************************** 
* 函数名称: 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 | SDA_PIN); // SCL推挽输出模式

}


/****************************************************************************************************************************************** 
* 函数名称: I2C_Start()
* 功能说明:	产生I2C传输的Start信号
* 输    入: 无 
* 输    出: 无
******************************************************************************************************************************************/
void SI2C_Start(void)
{
    SDA_OUT();         //SDA输出
    SDA_1();
    SCL_1();           //scl = 1;
	delay_us(4);
	SDA_0();           //sda = 0;	scl为高时sda的下降沿表示“起始”
	delay_us(4);
	SCL_0();           //scl = 0;钳住I2C总线,准备发送或接收数据 START:when CLK is high,DATA change form high to low 
}


/****************************************************************************************************************************************** 
* 函数名称:	I2C_Stop()
* 功能说明:	产生I2C传输的Stop信号
* 输    入: 无 
* 输    出: 无
******************************************************************************************************************************************/
void SI2C_Stop(void)
{
    SDA_OUT();           // SDA写
    SCL_0();             // scl = 0;
    SDA_0();             // STOP:when CLK is high DATA change form low to high
    delay_us(4);
    SCL_1();             // scl = 1;
    delay_us(4);	
    SDA_1();             // sda = 1;   sclk为高时sdat的上升沿表示“停止”
}


/****************************************************************************************************************************************** 
* 函数名称: I2C_Send()
* 功能说明:	向IIC总线发送一个字节的数据
* 输    入: byte dat 	要发送的数据 
* 输    出: 无
******************************************************************************************************************************************/
void SI2C_Send(uint8_t dat)
{
    uint8_t i = 8;
    SDA_OUT();
    while(i--)
    {
        SCL_0();               //拉低时钟开始数据传输
        delay_us(2);
        if(dat&0x80){
            SDA_1();
        }else{
            SDA_0();
		}
        dat<<=1;
		delay_us(3);
        SCL_1();               //拉高时钟等待从设备读取数据
        delay_us(5);
    }
    SCL_0();
}


/****************************************************************************************************************************************** 
* 函数名称:	I2C_Receive()
* 功能说明:	从IIC总线接收一个字节的数据
* 输    入: 无
* 输    出: byte		从IIC总线上接收到得数据
* 注意事项: 无
******************************************************************************************************************************************/
uint8_t SI2C_Receive(void)
{
    uint8_t i = 8,dat;
    SDA_OUT();
    SDA_1();
    SDA_IN();               //设置为输入	
    while(i--)
    {
        dat<<=1;
        SCL_0();
        delay_us(5);
        SCL_1();
        delay_us(4);
        if(1 == SDA_X())
		    dat|=0x01;
    }
    SCL_0();
	return dat;
}


/****************************************************************************************************************************************** 
* 函数名称: I2CDoAck()
* 功能说明:	在应答位位置产生应答,从而继续连续传输
* 输    入: 无 
* 输    出: 无 
******************************************************************************************************************************************/
void SI2CDoAck(void)
{ 
    SCL_0();
    SDA_OUT();
    SDA_0();              //sda = 0;	/拉低数据线,即给于应答
    delay_us(3);
    SCL_1();              //scl = 1;
   	delay_us(6);
    SCL_0();              //scl = 0;
}


/****************************************************************************************************************************************** 
* 函数名称: I2CNoAck()
* 功能说明:	在应答位位置不产生应答,从而终止连续传输
* 输    入: 无 
* 输    出: 无 
******************************************************************************************************************************************/
void SI2CNoAck(void)
{ 
    SCL_0();
    SDA_OUT();
    SDA_1();              // sda = 1;	不拉低数据线,即不给于应答
    delay_us(3); 
    SCL_1();              // scl = 1;
    delay_us(6);
    SCL_0();              // scl = 0; 
}


/****************************************************************************************************************************************** 
* 函数名称: I2CIsAck()
* 功能说明:	检测从机应答位
* 输    入: 无 
* 输    出: uint8_t	0=ACK_OK 从机产生了应答;1=ACK_NO 从机没有产生应答
******************************************************************************************************************************************/
uint8_t SI2CIsAck(void)
{ 
    uint8_t i;
    SDA_OUT();
    SDA_1();              // sda = 1; 释放数据线
    delay_us(3);
    SDA_IN();
    SCL_1();              // scl = 1;
    delay_us(3);
	while(1 == SDA_X()){
		i++;
		if(i>250){
			SI2C_Stop(); //数据线未被拉低,即未收到应答
			return 1;
		}
	}
    SCL_0();
    return 0;
}


/********************************************************************************************** 
* 函数名称:	I2C_8bitByteWrite()
* 功能说明: 向I2C器件的地址addr开始写入一个字节的数据
* 输    入: uint8_t I2C_addr 器件地址
*           uint8_t addr     写入数据的地址
*			uint8_t data     要写入的数据
* 输    出: uint8_t	0=成功向器件写入数据  大于1=向器件写入数据过程中出现错误
**********************************************************************************************/
uint8_t SI2C_8bitByteWrite(uint8_t I2C_addr,uint8_t addr,uint8_t data)
{
    SI2C_Start();         //产生起始信号
    SI2C_Send(I2C_addr|0);//发送器件地址及读写位,0表示写
    if(SI2CIsAck())       //检测器件是否有响应
    {
        SI2C_Stop();      //产生停止信号
        return 1;
	}

    SI2C_Send(addr);      //发送数据要写入的地址
    if(SI2CIsAck())       //检测器件是否有响应
    {
        SI2C_Stop();      //产生停止信号
        return 2;
    }

    SI2C_Send(data);      //写入数据
    if(SI2CIsAck())       //检测器件是否有响应
    {
        SI2C_Stop();      //产生停止信号
        return 3;
    }

    SI2C_Stop();          //产生停止信号
    return 0;
}

/********************************************************************************************** 
* 函数名称:	I2C_8bitByteRead()
* 功能说明: 从I2C器件的地址addr读取1字节数据
* 输    入: uint8_t I2C_addr 器件地址
*           uint8_t addr     读取数据的地址
* 输    出: 读取的数据
**********************************************************************************************/
uint8_t SI2C_8bitByteRead(uint8_t I2C_addr,uint8_t addr)
{
    uint8_t data;

    SI2C_Start();         //产生起始信号
    SI2C_Send(I2C_addr);  //发送器件地址及读写位,0表示写
    if(SI2CIsAck())       //检测器件是否有响应
    {
        SI2C_Stop();      //产生停止信号
		return 2;
    }
    SI2C_Send(addr);      //发送读取数据的起始地址
    if(SI2CIsAck())       //检测器件是否有响应
    {
        SI2C_Stop();	  //产生停止信号
        return 3;
    }

    SI2C_Start();         //产生Repeated Start
    SI2C_Send(I2C_addr|1);//发送器件地址及读写位,1表示读
    if(SI2CIsAck())       //检测器件是否有响应
    {
        SI2C_Stop();      //产生停止信号
        return 4;
    }

    data = SI2C_Receive();//从addr处读取1个字节的数据
       
    SI2CNoAck();          //器件要求必须使用NOAck来结束数据读取
    SI2C_Stop();          //产生停止信号

	return data;
}

/********************************************************************************************** 
* 函数名称:	I2C_8bitBuffWrite()
* 功能说明: 向I2C器件的地址addr开始写入size个字节的数据,将要写入的数据存储在全局变量I2C_Buff中
* 输    入: uint8_t I2C_addr 器件地址
*           uint8_t addr     写入数据开始的地址
*			uint8_t size     要设置的数据个数(1~8)
* 输    出: uint8_t	0=成功向器件写入数据  大于1=向器件写入数据过程中出现错误
**********************************************************************************************/
uint8_t SI2C_8bitBuffWrite(uint8_t I2C_addr,uint8_t addr,uint8_t size,uint8_t *buf)
{
    uint8_t i = 0;

    SI2C_Start();         //产生起始信号
    SI2C_Send(I2C_addr|0);//发送器件地址及读写位,0表示写
    if(SI2CIsAck())       //检测器件是否有响应
    {
        SI2C_Stop();      //产生停止信号
        return 1;
	}

    SI2C_Send(addr);      //发送数据要写入的地址
    if(SI2CIsAck())       //检测器件是否有响应
    {
        SI2C_Stop();      //产生停止信号
        return 2;
    }

    for(i=0; i<size; i++)
    {
        SI2C_Send(buf[i]);
        if(SI2CIsAck())   //检测器件是否有响应
        {
            SI2C_Stop();  //产生停止信号
            return 3;
        }
    }

    SI2C_Stop();          //产生停止信号
	
    return 0;
}
 

/****************************************************************************************** 
* 函数名称: I2C_8bitBuffRead()
* 功能说明: 从指定的I2C器件地址addr开始获取size个字节的数据,获取的数据存储在全局变量I2C_Buff中
* 输    入: uint8_t I2C_addr I2C器件地址
*           uint8_t addr     获取数据从addr开始
*			uint8_t size     要获取的数据个数(1~8)
*           uint8_t *buff    数据缓存
* 输    出: 从器件获取数据(数组指针)
******************************************************************************************/
uint8_t SI2C_8bitBuffRead(uint8_t I2C_addr,uint8_t addr,uint8_t size,uint8_t *buf)
{
    uint8_t i = 0;

    SI2C_Start();         //产生起始信号
    SI2C_Send(I2C_addr);  //发送器件地址及读写位,0表示写
    if(SI2CIsAck())       //检测器件是否有响应
    {
        SI2C_Stop();      //产生停止信号
		return 2;
    }

    SI2C_Send(addr);      //发送读取数据的起始地址
    if(SI2CIsAck())       //检测器件是否有响应
    {
        SI2C_Stop();      //产生停止信号
        return 3;
    }

    SI2C_Start();         //产生Repeated Start
    SI2C_Send(I2C_addr|1);//发送器件地址及读写位,1表示读
    if(SI2CIsAck())       //检测器件是否有响应
    {
        SI2C_Stop();      //产生停止信号
        return 4;
    }

    for(i=0;i<size;i++)	  //从addr处开始读取size个字节的数据
    {
        buf[i] = SI2C_Receive();
        SI2CDoAck();
    }

    SI2CNoAck();          //器件要求必须使用NOAck来结束数据读取
    SI2C_Stop();          //产生停止信号

	return *buf;

}


/********************************************************************************************** 
* 函数名称:	I2C_16bitBuffWrite()
* 功能说明: 写多个数据到16位地址的I2C设备
* 输    入: uint8_t I2C_addr 器件地址
*           uint8_t addr     写入数据开始的地址
*			uint8_t size     要写入的数据个数(1~8)
*           uint8_t *buf     要写入的数据
* 输    出: uint8_t	0=成功向器件写入数据  大于1=向器件写入数据过程中出现错误
**********************************************************************************************/
uint8_t SI2C_16bitBuffWrite(uint8_t I2C_addr,uint16_t addr,uint8_t size,uint8_t *buf)
{
    uint8_t i = 0;

    SI2C_Start();         //产生起始信号
    SI2C_Send(I2C_addr|0);//发送器件地址及读写位,0表示写
    if(SI2CIsAck())       //检测器件是否有响应
    {
        SI2C_Stop();      //产生停止信号
        return 1;
	}
	
    SI2C_Send(addr>>8);   //发送读取数据的起始地址高8位
    SI2CIsAck();          //等待应答
    SI2C_Send(addr%256);  //发送低8位地址
    SI2CIsAck();          //等待应答

    for(i=0;i<size;i++)
    {
        SI2C_Send(buf[i]);
        if(SI2CIsAck())   //检测器件是否有响应
        {
            SI2C_Stop();  //产生停止信号
            return 3;
        }
    }

    SI2C_Stop();          //产生停止信号

    return 0;
}


/****************************************************************************************** 
* 函数名称: I2C_16bitBuffRead()
* 功能说明: 从指定的16位I2C器件地址addr开始获取size个字节的数据,返回数组变量指针
* 输    入: uint8_t I2C_addr I2C器件地址
*           uint8_t addr     获取数据从addr开始
*			uint8_t size     要获取的数据个数(1~8)
*           uint8_t *buff    数据缓存
* 输    出: 从器件获取数据(数组指针)
******************************************************************************************/
uint8_t SI2C_16bitBuffRead(uint8_t I2C_addr,uint16_t addr,uint8_t size,uint8_t *buf)
{
    uint8_t i = 0;

    SI2C_Start();         //产生起始信号
    SI2C_Send(I2C_addr);  //发送器件地址及读写位,0表示写
    if(SI2CIsAck())       //检测器件是否有响应
    {
        SI2C_Stop();      //产生停止信号
		return 2;
    }
	
    SI2C_Send(addr>>8);   //发送读取数据的起始地址高8位
    SI2CIsAck();          //等待应答
    SI2C_Send(addr%256);  //发送低8位地址
    SI2CIsAck();          //等待应答

    SI2C_Start();         //产生Repeated Start
    SI2C_Send(I2C_addr|1);//送器件地址及读写位,1表示读
    if(SI2CIsAck())       //检测器件是否有响应
    {
        SI2C_Stop();      //产生停止信号
        return 4;
    }

    for(i=0;i<size;i++)   //从addr处开始读取size个字节的数据
    {
        buf[i] = SI2C_Receive();
        SI2CDoAck();
    }

    SI2CNoAck();          //器件要求必须使用NOAck来结束数据读取
   
    SI2C_Stop();          //产生停止信号
	
	return *buf;

}




This post is from Domestic Chip Exchange
 
 
 

1942

Posts

2

Resources
3
 

The OP's IIC communication journey was really bumpy, but it shows the OP's perseverance!!!

This post is from Domestic Chip Exchange

Comments

The key issue is that the reason for the failure has not yet been found.  Details Published on 2020-11-21 08:49
 
 
 

7452

Posts

2

Resources
4
 

I2C seems a bit troublesome

This post is from Domestic Chip Exchange
Personal signature

默认摸鱼,再摸鱼。2022、9、28

 
 
 

931

Posts

3

Resources
5
 
w494143467 Published on 2020-11-20 19:41 The OP's IIC communication journey has been really bumpy, but we can see the OP's perseverance!!!

The key issue is that the reason for the failure has not yet been found.

This post is from Domestic Chip Exchange

Comments

It's a pity that you don't have two boards, otherwise you would know whether it is a problem with the board.  Details Published on 2020-11-21 08:57
 
 
 

1942

Posts

2

Resources
6
 
hujj posted on 2020-11-21 08:49 The key issue is that the reason for the failure has not yet been found.

It's a pity that you don't have two boards, otherwise you would know whether it is a problem with the board.

This post is from Domestic Chip Exchange
 
 
 

1w

Posts

204

Resources
7
 

GigaDevice GD32307E-START Review

Summary post: https://bbs.eeworld.com.cn/thread-1143008-1-1.html

This post is from Domestic Chip Exchange
Add and join groups EEWorld service account EEWorld subscription account Automotive development circle
Personal signature

玩板看这里:

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

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

 
 
 

661

Posts

0

Resources
8
 

Thanks for sharing

This post is from Domestic Chip Exchange
 
 
 

Just looking around
Find a datasheet?

EEWorld Datasheet Technical Support

EEWorld
subscription
account

EEWorld
service
account

Automotive
development
circle

Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号
快速回复 返回顶部 Return list