问答

汇集网友智慧,解决技术难题

21ic问答首页 - ch32v103 c8t6 如何支持中断发送

I2c CH32V103 从机

ch32v103 c8t6 如何支持中断发送

lhsls012022-06-22
hi,    我根据https://bbs.21ic.com/icview-3141094-1-1.html sample代码,可以实现从机接收。(主机为RK3566, 从机CH32V103)
即主机可以i2c_write成功。
但如果调用 i2c_read, 则ch32v103会 一直拉低I2C CLK线,CH32只产生了三个中断,最后一个中断报ACK FAILED。
int R1:2 R2:2, TxCount:0
int R1:82 R2:6, TxCount:0
error int :480 6
I2C_IT_AF

出现以上问题后,必须复位CH32V103才会使I2C CLK线重新拉高。

请问是否有中断从机发的sample code.
目前代码如下:

//下述中断程序中,当主机读取和写入数据时,都会引起地址位被置位,即发生EV1事件(即本中断处理程序中将发送和接收的EV1合并了);
//当主机写入数据时,中断的执行顺序是EV1―>EV2―>EV4,其中有多个数据EV2会多次执行;
//当主机读取数据时,中断的执行顺序是EV1―>EV3―>EV3-2,本中断程序中将EV3和EV3-1合并了,若有多个数据,EV3将多次执行。
//本程序只进行从机中断接收
//事件中断处理函数
void I2C1_EV_IRQHandler( void )
{
        uint16_t STAR1Register,STAR2Register;
        int i = 0;
        u8 rcv = 0;

        //状态寄存器1和状态寄存器2对应值
        STAR1Register = I2C1->STAR1;
        STAR2Register = I2C1->STAR2;

        printf("int R1:%x R2:%x, TxCount:%d\r\n", STAR1Register, STAR2Register, TxCount);
        //I2C从机 (MSL = 0)
        //若状态寄存器2的位0不为1,即为0,则代表从模式(1代表主模式)
        if( ( STAR2Register & 0x0001 ) == 0x0000 )
        {

                //从机发送数据   发送数据(TxE = 1: EV3、EV3-1)
                //从模式下,若状态寄存器1 位7 TxE位为1,则数据寄存器空
                if( (STAR1Register & 0x0080) == 0x0080)
                {
                        I2C1->DATAR = TxData[ TxCount ];
                        //printf("Tx:W reg:%x\r\n", TxData[ TxCount ]);
                        TxCount++;
                        STAR1Register = 0;
                        STAR2Register = 0;
                        //RxData[ RxCount ] = I2C1->DATAR;

                }

                //从模式下,若状态寄存器1 位1 ADDR的位为1,收到的地址匹配,即 主机已发送地址,地址为被置位・(ADDR = 1: EV1(包括发送和接收))
                if( STAR1Register & 0x0002 )
                {
                        //清除相应值
                        STAR1Register = 0;
                        STAR2Register = 0;
                        RxCount = 0x00;
                        TxCount = 0x00;
                }

                //从机接收到数据 (RXNE = 1: EV2)
                //从模式下,若状态寄存器1 位6 RxNE位为1,则数据寄存器非空
                if( STAR1Register & 0x0040 )
                {
                        RxData[ RxCount ] = I2C1->DATAR;
                        printf("40 rx reg:%x\r\n", RxData[RxCount]);
                        RxCount++;
                        STAR1Register = 0;
                        STAR2Register = 0;
                }

                //从机接收到停止信号,检测到停止条件(STOPF =1: EV4)
                //从模式下,若状态寄存器1 位4 STOPF位为1,则检测到停止条件
                if( STAR1Register & 0x0010 )
                {
                        //控制寄存器1 位0设置为1,启用IIC模块
                        I2C1->CTLR1 |= 0x0001;
                        STAR1Register = 0;
                        STAR2Register = 0;
                        Rec_Finish_Flag = 0x01;
                }


                //从机发送数据   发送数据(TxE = 1: EV3、EV3-1)
                //从模式下,若状态寄存器1 位7 TxE位为1,则数据寄存器空
                if( (STAR1Register & 0x0080) == 0x0080)
                {
                        I2C1->DATAR = TxData[ TxCount ];
                        TxCount++;
                        STAR1Register = 0;
                        STAR2Register = 0;
                        RxData[ RxCount ] = I2C1->DATAR;
                        printf("rx reg:%x\r\n", RxData[RxCount]);
                }

                //从机接收非应答信号  检测到非应答(AF =1: EV3-2)
                //从模式下,若状态寄存器1 位10 AF位为1,则应答失败(当没有返回应答时,硬件将置该位为’1’)
                if( STAR1Register & 0x0400 )
                {

                        printf("event AF ERROR\r\n");
                        I2C1->STAR1 &= ~( 0x0400 );  //该位由软件写’0’清除,或在PE=0时由硬件清除。
                        I2C1->STAR1 &= ( 0xFDFF );
                        STAR1Register = 0;
                        STAR2Register = 0;
                }
        }

        //printf("out int :%x %x, TxCount:%d\r\n", STAR1Register, STAR2Register, TxCount);
}


//错误中断处理函数
//下述程序中,发送各种错误进行错误中断不做对应的处理,最后只进行清除寄存器(STAR1和STAR2)操作。
void I2C1_ER_IRQHandler(void)
{

        uint16_t STAR1Register,STAR2Register;

        //状态寄存器1和状态寄存器2对应值
        STAR1Register = I2C1->STAR1;
        STAR2Register = I2C1->STAR2;
        printf("error int :%x %x\r\n", STAR1Register, STAR2Register);

        if(I2C_GetITStatus(I2C1, I2C_IT_SMBALERT))
        {
                printf("I2C_IT_SMBALERT\r\n");
        }
        else if(I2C_GetITStatus(I2C1, I2C_IT_TIMEOUT))
        {
                printf("I2C_IT_TIMEOUT\r\n");
        }
        else if(I2C_GetITStatus(I2C1, I2C_IT_PECERR))
        {
                printf("I2C_IT_PECERR\r\n");
        }
        else if(I2C_GetITStatus(I2C1, I2C_IT_OVR))
        {
                printf("I2C_IT_OVR\r\n");
        }
        else if(I2C_GetITStatus(I2C1, I2C_IT_AF))
        {
                I2C_ClearITPendingBit(I2C1, I2C_IT_AF);
                I2C1->STAR1 &= ~( 0x0400 );  //该位由软件写’0’清除,或在PE=0时由硬件清除。
                I2C1->STAR1 &= ( 0xFDFF );
                STAR1Register = 0;
                STAR2Register = 0;
                printf("I2C_IT_AF\r\n");
                //IIC_Init(g_bound,  g_address);
        }
        else if(I2C_GetITStatus(I2C1, I2C_IT_ARLO))
        {
                printf("I2C_IT_ARLO\r\n");
        }
        else if(I2C_GetITStatus(I2C1, I2C_IT_BERR))
        {
                printf("I2C_IT_BERR\r\n");

        }
        //控制寄存器1 位0设置为1,启用IIC模块
        I2C1->CTLR1 |= 0x0001;
        STAR1Register = 0;
        STAR2Register = 0;
}


回答 +关注 15
1655人浏览 0人回答问题 分享 举报
0 个回答

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