CH32v307V_R1 开发板使用硬件IIC,一直报busy

CH32v307V_R1 开发板使用CH32V307EVT 中的IIC例程I2C_EEPROM,用硬件IIC,一直报busy,测量示波器波形PB10和PB11都是低电平

代码如下

/*

 * bsp_i2c.c

 *

 *  Created on: May 13, 2024

 *      Author: mx

 */



/********************************** (C) COPYRIGHT *******************************

* File Name          : main.c

* Author             : WCH

* Version            : V1.0.0

* Date               : 2024/03/05

* Description        : Main program body.

*********************************************************************************

* Copyright (c) 2021 Nanjing Qinheng Microelectronics Co., Ltd.

* Attention: This software (modified or not) and binary are used for

* microcontroller manufactured by Nanjing Qinheng Microelectronics.

*******************************************************************************/


/*

 *@Note

 I2C interface routine to operate EEPROM peripheral.

 I2C1_SCL(PB10)\I2C1_SDA(PB11).

 This example uses EEPROM for AT24Cxx series.

 Steps:

 READ EEPROM:Start + 0xA0 + 8bit Data Address + Start + 0xA1 + Read Data + Stop.

 WRITE EERPOM:Start + 0xA0 + 8bit Data Address + Write Data + Stop.


*/

#include "bsp_i2c.h"

#include "debug.h"

#include "FreeRTOS.h"

#include "task.h"

/**********************************************************************

*@Note:

AT24Cxx


READ EEPROM:Start + 0xA0 + 8bit Data Address + Start + 0xA1 + Read Data + Stop.

WRITE EERPOM:Start + 0xA0 + 8bit Data Address + Write Data + Stop.

*******************************************************************************/

/* EERPOM DATA ADDRESS Length Definition */

#define Address_8bit     0

#define Address_16bit    1


/* EERPOM DATA ADDRESS Length Selection */

#define Address_Lenth    Address_8bit

//#define Address_Lenth   Address_16bit


/* Global define */

#define SIZE             sizeof(TEXT_Buffer)


/* Global Variable */

const u8 TEXT_Buffer[] = {"CH32F10x I2C TEST"};



/**

 * @brief IIC初始化

 * 

 * @param bound 速率

 * @param address 地址

 */

void IIC_Init(u32 bound, u16 address)

{

    GPIO_InitTypeDef GPIO_InitStructure = {0};

    I2C_InitTypeDef  I2C_InitTSturcture = {0};


    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);

    RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C2, ENABLE);


    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;

    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_OD;

    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

    GPIO_Init(GPIOB, &GPIO_InitStructure);


    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11;

    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_OD;

    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

    GPIO_Init(GPIOB, &GPIO_InitStructure);


    I2C_InitTSturcture.I2C_ClockSpeed = bound;

    I2C_InitTSturcture.I2C_Mode = I2C_Mode_I2C;

    I2C_InitTSturcture.I2C_DutyCycle = I2C_DutyCycle_2;

    I2C_InitTSturcture.I2C_OwnAddress1 = address;

    I2C_InitTSturcture.I2C_Ack = I2C_Ack_Enable;

    I2C_InitTSturcture.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;

    I2C_Init(I2C2, &I2C_InitTSturcture);


    I2C_Cmd(I2C2, ENABLE);

}

u8 iic_err_count(void)

{

    static u8 err_count = 0;

    err_count++;

    vTaskDelay(1);

    

    if (err_count > 10)

    {

err_count = 0;

        return 1;

    }

    return 0;

}

/**

 * @brief 读取数据

 * 

 * @param addr 设备地址

 * @param reg 寄存器地址

 * @return u8 

 */

u8 IIC_ReadBuffer(u8 addr, u8 reg, u8 *buf, size_t len)

{

    static u8 ret = 1;


    if (len == 0 || ret != 1)

    {

        if (ret == 0)

        {

            printf("len error\r\n");

            ret = 2;

        }

        return 1;

    }

    if (I2C_GetFlagStatus(I2C2, I2C_FLAG_BUSY) != RESET)

    {

        printf("bus busy\r\n");

        ret = 0;

        return 1;

    }


    I2C_GenerateSTART(I2C2, ENABLE); // 开始信号


    while(!I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_MODE_SELECT))

    {

        if (iic_err_count())

        {

            printf("not com\r\n");

            return 1;

        }

    }

    I2C_Send7bitAddress(I2C2, addr<<1, I2C_Direction_Transmitter); // 发送设备地址


    while(!I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED))

    {

        if (iic_err_count())

        {

            printf("not com1\r\n");

            return 1;

        }

    }


    I2C_SendData(I2C2, (u8)(reg & 0x00FF));  // 发送要读取的寄存器地址

    while(!I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_BYTE_TRANSMITTED))

    {

        if (iic_err_count())

        {

            printf("not com2\r\n");

            return 1;

        }

    }

    I2C_GenerateSTART(I2C2, ENABLE); // 开始信号


    while(!I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_MODE_SELECT))

    {

        if (iic_err_count())

        {

            printf("not com3\r\n");

            return 1;

        }

    }

    I2C_Send7bitAddress(I2C2, addr<<1, I2C_Direction_Receiver); // 发送设备地址


    while(!I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED))

    {

        if (iic_err_count())

        {

            printf("not com4\r\n");

            return 1;

        }

    

    }

    for (size_t i = 0; i < len; i++)

    {

        while(I2C_GetFlagStatus(I2C2, I2C_FLAG_RXNE) == RESET)

        {

            I2C_AcknowledgeConfig(I2C2, DISABLE); // 关闭应答

        }

        buf[i] = I2C_ReceiveData(I2C2); // 读取数据

    }


    I2C_GenerateSTOP(I2C2, ENABLE); // 停止信号

    return 0;

}


image.pnglog如图


使用gpio翻转实验过,PB10和PB11是可以正常翻转的


把外设去掉只接示波器发现也没时钟和数据信号


先确定硬件是否加上拉电阻。然后能抓到主机发送的START信号吧,数据线在时钟线高电平时拉低,然后抓到了主机发送的地址信息了吗。这种情况往往是从设备没有ack信号导致总线卡死,出现卡死时,加上超时检测,然后停止STOP IIC,重现开始一次START。


没有开始信号,时钟和数据都是低电平,我找硬件确认下有没有上拉电阻,如果没有的话可以配置成内部上拉吗


引脚必须配置成服用开漏输出,不能再配置内部上拉了,所以必须外部加上拉电阻,4.7K左右就行。


只有登录才能回复,可以选择微信账号登录