打印

GD32 F4硬件I2C总是锁死

[复制链接]
5870|9
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
jacket123|  楼主 | 2022-10-22 22:42 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
1.问题描述买了一个磁力计模块,用杜邦线连接到427start开发板,参考网上各种例程一直失败,要么是ADSEND不置1 ,要么是I2C总线一直忙,反复置位或者上电重启能读到一次,今天尝试了参考官方EEPROM的延时检测程序,还是没办法实现,求解求解!!
2.代码
代码1:未加延时检测代码
         while(i2c_flag_get(I2C1, I2C_FLAG_I2CBSY));
    printf("I2C bus is idle\r\n");
    i2c_start_on_bus(I2C1);   
    while(!i2c_flag_get(I2C1, I2C_FLAG_SBSEND));
    printf("SBSEND bit is set\r\n");
    i2c_master_addressing(I2C1, QMC5883L_DEFAULT_ADDRESS, I2C_RECEIVER);       
    while(!i2c_flag_get(I2C1, I2C_FLAG_ADDSEND));
    printf("ADDSEND bit is set\r\n");
    i2c_flag_clear(I2C1, I2C_FLAG_ADDSEND);
    i2c_ack_config(I2C1,I2C_ACK_DISABLE);
    i2c_stop_on_bus(I2C1);
    while(!i2c_flag_get(I2C1, I2C_FLAG_RBNE));
    printf("I2C_FLAG_RBNE bit is set\r\n");
    chipID = i2c_data_receive(I2C1);
        printf("0x %u \r\n",chipID);


++++++++++++++++++++++++++++++++++++++++++++++++
代码2延时检测
/*!
    \file    main.c
    \brief   GPIO running led demo

    \version 2022-04-26, V2.0.0, demo for GD32F4xx
*/

/*
    Copyright (c) 2022, GigaDevice Semiconductor Inc.

    Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:

    1. Redistributions of source code must retain the above copyright notice, this
       list of conditions and the following disclaimer.
    2. Redistributions in binary form must reproduce the above copyright notice,
       this list of conditions and the following disclaimer in the documentation
       and/or other materials provided with the distribution.
    3. Neither the name of the copyright holder nor the names of its contributors
       may be used to endorse or promote products derived from this software without
       specific prior written permission.

    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
OF SUCH DAMAGE.
*/

#include "gd32f4xx.h"
#include "gd32f4xx_timer.h"
#include "gd32f4xx_rcu.h"
#include "systick.h"
#include <stdio.h>
#include "gpio.h"
#include "usart.h"
#include "time.h"
#include "QMC5883L.h"
#include <stdbool.h>
#include "i2c.h"
/* Private variables ---------------------------------------------------------*/

/* USER CODE BEGIN PV */
volatile uint32_t time =0;
uint8_t u_buf[256];
uint8_t USART1_RX_BUF[USART1_REC_LEN];
uint16_t USART1_RX_STA = 0;
bool ConnectionRsult;
uint8_t chipID=0x01;
uint8_t i2c_receiver[16];
uint8_t  i;

#define I2C_TIME_OUT    (uint16_t)(5000)
#define I2C_OK          1
#define I2C_FAIL        0
#define I2C_END         1



/* USER CODE END PV */
/*!
    \brief      main function
    \param[in]  none
    \param[out] none
    \retval     none
*/
uint8_t buffer_read_timeout(uint8_t *p_bufer,uint8_t read_address,uint16_t number_of_byte);

int main(void)
{
    /* configure systick */
    systick_config();
    /* configure GPIO */
    GD_GPIO_Init();
    /* configure         Timer1 */
    // GD_TIMER1_Init();
    /* configure GPIO */
    GD_USART1_UART_Init();
    //printf("====USART CONFIGURED====\r\n ");
    /* configure QMC5883L I2C */
    printf("====I2C START====\r\n ");
    gpio_config();
    i2c_config();
                buffer_read_timeout(i2c_receiver,0x0D,16);
    printf("0x%02X\r\n",chipID);
    /* System initialisation */
    //  rcu_periph_clock_enable(RCU_TIMER1);
    while(1)
    {

                }
}


uint8_t buffer_read_timeout(uint8_t *p_buffer,uint8_t read_address,uint16_t number_of_byte)
{
    uint8_t state=I2C_START;
    uint8_t read_cycle=0;
    uint16_t timeout=0;
    uint8_t i2c_timeout_flag=0;

    /* enable acknowledge */
    i2c_ack_config(I2C0, I2C_ACK_ENABLE);
    while(!(i2c_timeout_flag)){
        switch(state){
            case I2C_START:
                if(RESET==read_cycle){
                    /* i2c master sends start signal only when the bus is idle */
                    while(i2c_flag_get(I2C0, I2C_FLAG_I2CBSY) && (timeout < I2C_TIME_OUT)){
                        timeout++;
                    }
                    if(timeout<I2C_TIME_OUT){
                        if(2==number_of_byte){
                            /* whether to send ACK or not for the next byte */
                            i2c_ackpos_config(I2C0,I2C_ACKPOS_NEXT);
                        }
                    }else{
                        i2c_bus_reset();
                        timeout=0;
                        state=I2C_START;
                       // printf("i2c bus is busy in READ\r\n");
                    }
                }
                /* send the start signal */
                i2c_start_on_bus(I2C0);
                timeout=0;
                state=I2C_SEND_ADDRESS;
                break;
            case I2C_SEND_ADDRESS:
                /* i2c master sends START signal successfully */
                while((!i2c_flag_get(I2C0, I2C_FLAG_SBSEND)) && (timeout < I2C_TIME_OUT)){
                    timeout++;
                }
                if(timeout<I2C_TIME_OUT)
                {
                    if(RESET==read_cycle)
                    {   
                        /*If it is the first time to execute here,
                        it should be the sending host address*/
                        i2c_master_addressing(I2C0,QMC5883L_DEFAULT_ADDRESS,I2C_TRANSMITTER);
                        state=I2C_CLEAR_ADDRESS_FLAG;
                    }else{
                        i2c_master_addressing(I2C0,QMC5883L_I2C_OWN_ADDRESS,I2C_RECEIVER);
                        if(number_of_byte<3){
                            /* disable acknowledge */
                            i2c_ack_config(I2C0, I2C_ACK_DISABLE);
                        }
                        state=I2C_CLEAR_ADDRESS_FLAG;
                    }
                    timeout=0;
                }else{
                    timeout=0;
                    state=I2C_START;
                    read_cycle = 0;
                   // printf("i2c master sends start signal timeout in READ!\r\n");
                }
                break;
            case I2C_CLEAR_ADDRESS_FLAG:
                /* address flag set means i2c slave sends ACK */
                 while((!i2c_flag_get(I2C0, I2C_FLAG_ADDSEND)) && (timeout < I2C_TIME_OUT)){
                    timeout++;
                 }
                 if(timeout<I2C_TIME_OUT)
                 {
                    i2c_flag_clear(I2C0,I2C_FLAG_ADDSEND);
                    if((SET==read_cycle)&&(1==number_of_byte))
                    {
                        /* send a stop condition to I2C bus */
                        i2c_stop_on_bus(I2C0);
                    }
                    timeout=0;
                    state=I2C_TRANSMIT_DATA;
                 }else{
                    timeout=0;
                    state=I2C_START;
                    read_cycle=0;
                   // printf("i2c master clears address flag timeout in READ!\r\n");
                 }
                 break;
            case I2C_TRANSMIT_DATA:
                if(RESET==read_cycle)
                {
                    /* wait until the transmit data buffer is empty */
                    while((! i2c_flag_get(I2C0, I2C_FLAG_TBE)) && (timeout < I2C_TIME_OUT)){
                         timeout++;
                    }
                    if(timeout<I2C_TIME_OUT)
                    {
                        /* send the EEPROM's internal address to write to : only one byte address */
                        i2c_data_transmit(I2C0, read_address);
                        timeout=0;
                    }else{
                        timeout=0;
                        state=I2C_START;
                        read_cycle=0;
                      //  printf("i2c master wait data buffer is empty timeout in READ!\r\n");
                    }

                    while((!i2c_flag_get(I2C0, I2C_FLAG_BTC)) && (timeout < I2C_TIME_OUT)){
                        timeout++;
                    }
                    if(timeout < I2C_TIME_OUT){
                        timeout = 0;
                        state = I2C_START;
                        read_cycle++;
                    }else{
                        timeout = 0;
                        state = I2C_START;
                        read_cycle = 0;
                      //  printf("i2c master sends EEPROM's internal address timeout in READ!\r\n");
                    }
                }else{
                    while(number_of_byte){
                        timeout++;
                        if(3 == number_of_byte){
                            /* wait until BTC bit is set */
                            while(!i2c_flag_get(I2C0, I2C_FLAG_BTC));
                            /* disable acknowledge */
                            i2c_ack_config(I2C0, I2C_ACK_DISABLE);
                        }
                        if(2 == number_of_byte){
                            /* wait until BTC bit is set */
                            while(!i2c_flag_get(I2C0, I2C_FLAG_BTC));
                            /* send a stop condition to I2C bus */
                            i2c_stop_on_bus(I2C0);
                        }
                        /* wait until RBNE bit is set */
                        if(i2c_flag_get(I2C0, I2C_FLAG_RBNE)){
                            /* read a byte from the EEPROM */
                            *p_buffer = i2c_data_receive(I2C0);
                            p_buffer++;
                            number_of_byte--;
                            timeout = 0;
                        }
                        if(timeout>I2C_TIME_OUT){
                            timeout=0;
                            state=I2C_START;
                            read_cycle=0;
                        //    printf("i2c master sends data timeout in READ!\r\n");
                        }
                    }
                    timeout=0;
                    state=I2C_STOP;
                }
                break;
            case I2C_STOP:
                /* i2c master sends STOP signal successfully */
                while((I2C_CTL0(I2C0) & I2C_CTL0_STOP) && (timeout < I2C_TIME_OUT)){
                    timeout++;
                }
                if(timeout < I2C_TIME_OUT){
                    timeout = 0;
                    state = I2C_END;
                    i2c_timeout_flag = I2C_OK;
                }else{
                    timeout = 0;
                    state=I2C_START;
                    read_cycle=0;
                 //   printf("i2c master sends stop signal timeout in READ!\r\n");
                }
                break;
            default:
                state = I2C_START;
                read_cycle = 0;
                i2c_timeout_flag = I2C_OK;
                timeout = 0;
             //   printf("i2c master sends start signal in READ.\r\n");
                break;

        }
    }
    return I2C_END;
}

+++++++++++++++++++++++++++++++++++++++++++++

使用特权

评论回复
沙发
tpgf| | 2022-11-4 11:34 | 只看该作者
如果iic可以正常初始化的话 说明晶振问题不大 检查一下时钟配置吧

使用特权

评论回复
板凳
qcliu| | 2022-11-4 11:45 | 只看该作者
楼主前期调试iic模块的时候使用的是什么模式呢

使用特权

评论回复
地板
drer| | 2022-11-4 12:08 | 只看该作者
我看了一个很多行代码的函数是用来处理超时的吗

使用特权

评论回复
5
coshi| | 2022-11-4 13:08 | 只看该作者
这个代码风格不够好  在超时的函数里边分支太多了

使用特权

评论回复
6
sonicll| | 2022-11-4 13:39 | 只看该作者
有上拉电阻吗

使用特权

评论回复
7
kxsi| | 2022-11-4 13:39 | 只看该作者
一般死锁发生于主机与从机通信之间,出现意外的通信错误(可能是SCL、SDA与3V3 GND意外短路,或者通信速率太高,而总线电容太大,导致丢失某些bit),或者丢失ack

使用特权

评论回复
8
wiba| | 2022-11-4 14:00 | 只看该作者
硬件上可以为所有I2C设备设置一个统一的复位电路,一旦陷入死锁,断开I2C设备的电源,重新上电(较为麻烦,且重新上电后需要重新初始化I2C设备)

使用特权

评论回复
9
jf101| | 2022-11-23 13:21 | 只看该作者
是不硬件本身的问题呀,冬天静电多很容易就设备坏了

使用特权

评论回复
10
星辰大海不退缩| | 2022-11-23 21:07 | 只看该作者
I2C这个还是时序问题,建议先简单编写程序进行通讯吧设计框架后期再说

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

2

主题

5

帖子

0

粉丝