硬件IIC主从机中断代码注释解析
阅读原文时间:2023年07月09日阅读:2

目录

硬件IIC的主从中断在582的最新EVT中已支持。

对于IIC从机中断,例程中已封装好中断处理过程,用户调用app_i2c时,初始化中需要配置回调函数。

初始化的配置如下。

struct i2c\_slave\_cb slave\_user = {          //配置回调结构体  
    .on\_receive = i2c\_on\_slave\_receive\_user,  
    .on\_transmit = i2c\_on\_slave\_transmit\_user,  
};  
i2c\_app\_init(RxAdderss);                //IIC硬件模块的初始化及软件标志的初始化

i2c\_slave\_cb\_register(&slave\_user);     //注册回调

默认回调函数如下。

static void i2c_on_slave_transmit_user(uint8_t *data, uint8_t *len)
{
*len = sizeof(TxData);
memcpy(data, TxData, sizeof(TxData));
}

static void i2c_on_slave_receive_user(uint8_t *data, uint8_t len)
{
PRINT("I2C slave receiver callback: received (");
for(int i = 0; i < len; i++) {
PRINT(" %#x", data[i]);
}
PRINT(" )\n");
}

若需要串口打印日志,可以在工程预编译中增加宏CONFIG_I2C_DEBUG。

接下来以注释的方式解析一下中断服务函数中做了哪些处理。

__INTERRUPT
__HIGH_CODE
void I2C_IRQHandler(void)
{
uint32_t event = I2C_GetLastEvent();
print_i2c_irq_sta(event);

/\* I2C Master \*/  
if (event & (RB\_I2C\_MSL << 16)) {       //判断为主机模式  
    if (event & RB\_I2C\_SB) {            //判断主机模式已发送起始信号  
        /\* Start condition sent, send address \*/  
        I2C\_SendData(i2c\_slave\_addr\_rw);    //写从地址到数据寄存器后,SB位会自动清除  
        I2C\_DBG("Master selected, send address\\n");  
    }

    /\* I2C Master transmitter \*/  
    if (event & (RB\_I2C\_TRA << 16)) {   //判断是主机的发送模式  
        I2C\_DBG("Master transmitter:\\n");  
        /\* Slave receiver acked address or sent bit \*/  
        if (event & (RB\_I2C\_ADDR | RB\_I2C\_BTF | RB\_I2C\_TxE | (RB\_I2C\_TRA << 16))) {  
            /\* if there is data to send, send it, otherwise stop \*/  
            if (i2c\_master\_buffer\_index < i2c\_master\_buffer\_length) {       //判断待发送数据还没发完  
                I2C\_SendData(i2c\_master\_buffer\[i2c\_master\_buffer\_index++\]);  
                I2C\_DBG("  send (%#x)\\n",  
                        i2c\_master\_buffer\[i2c\_master\_buffer\_index - 1\]);  
            } else {  
                if (i2c\_send\_stop) {    //判断数据发完了,如果允许产生停止位则产生停止位  
                    i2c\_state = I2C\_READY;  
                    I2C\_GenerateSTOP(ENABLE);   //产生停止位  
                    I2C\_DBG("  send STOP\\n");  
                } else {  
                    i2c\_in\_repstart = true;     //置标志表示即将重起始  
                    /\* we're gonna send the START, don't enable the interrupt. \*/  
                    I2C\_ITConfig(I2C\_IT\_BUF, DISABLE);  
                    I2C\_ITConfig(I2C\_IT\_EVT, DISABLE);  
                    I2C\_ITConfig(I2C\_IT\_ERR, DISABLE);  
                    I2C\_GenerateSTART(ENABLE);  
                    i2c\_state = I2C\_READY;  
                    I2C\_DBG("  restart\\n");  
                }  
            }  
        }

        /\* Address or data sent, nack received \*/  
        if (event & RB\_I2C\_AF) {        //地址/数据发送后应答失败  
            I2C\_ClearFlag(I2C\_FLAG\_AF);     //清标志

            i2c\_error = I2C\_MT\_NACK;    //置主机发送接收错误标志  
            i2c\_state = I2C\_READY;      //发送停止信号停止帧传输  
            I2C\_GenerateSTOP(ENABLE);   //产生停止信号  
            I2C\_DBG("  NACK received, sent stop\\n");  
        }  
    } else {                //判断为主机的接收模式  
    /\* I2C Master reveiver \*/  
        I2C\_DBG("Master receiver:\\n");

        /\* address sent, ack received \*/  
        if(event & RB\_I2C\_ADDR) {       //主机成功设置了从机的地址  
            /\* ack if more bytes are expected, otherwise nack \*/  
            if (i2c\_master\_buffer\_length) {   //判断接下来需要接收多少字节,如果需要接收多个字节,就置自动回ACK  

              //注意这里判断条件,在1.8的583EVT与之前的EVT不同,以这里的为准。
I2C_AcknowledgeConfig(ENABLE);
I2C_DBG(" address sent\n");
I2C_DBG(" ACK next\n");
} else { //判断接下来只接收一个字节,关闭自动回ACK即自动回NACK
//XXX: Should not delay too match before NACK
I2C_AcknowledgeConfig(DISABLE);
is_nack_sent = true; //置标志,数据接收时做具体处理
I2C_DBG(" address sent\n");
I2C_DBG(" NACK next\n");
}
}

        /\* data reveived \*/  
        if (event & (RB\_I2C\_RxNE)) {        //接收数据寄存器内非空,即收到数据  
            /\* put byte into buffer \*/  
            i2c\_master\_buffer\[i2c\_master\_buffer\_index++\] = I2C\_ReceiveData();   //接收数据到buffer中

            if (i2c\_master\_buffer\_index < i2c\_master\_buffer\_length) {   //判断接下来是否为期望接收的最后一个字节  
                I2C\_AcknowledgeConfig(ENABLE);      //接下来不是最后一个字节,接收应答设置为自动回ACK  
                I2C\_DBG("  ACK next\\n");  
            } else {  
                //XXX: Should not delay too match before NACK  
                I2C\_AcknowledgeConfig(DISABLE);     //连续读倒数最后一个字节前将接收应答ACK关闭,即最后一个字节后自动回NACK  
                I2C\_DBG("  NACK next\\n");

                if (is\_nack\_sent) {             //如果已设置最后一个字节前置了接收应答NACK  
                    is\_nack\_sent = false;       //清标志  
                    if (i2c\_send\_stop) {  
                        I2C\_GenerateSTOP(ENABLE);  
                        i2c\_state = I2C\_READY;  
                        I2C\_DBG("  send STOP\\n");  
                    } else {  
                        i2c\_in\_repstart = true; //写完了从机内的目标寄存器,发重起始信号  
                        /\* we're gonna send the START, don't enable the interrupt. \*/  
                        I2C\_ITConfig(I2C\_IT\_BUF, DISABLE);  
                        I2C\_ITConfig(I2C\_IT\_EVT, DISABLE);  
                        I2C\_ITConfig(I2C\_IT\_ERR, DISABLE);  
                        I2C\_GenerateSTART(ENABLE);  
                        i2c\_state = I2C\_READY;  
                        I2C\_DBG("  restart\\n");  
                    }  
                } else {  
                    is\_nack\_sent = true;        //没有要求  
                }  
            }

            I2C\_DBG("  received data (%#x)\\n",  
                    i2c\_master\_buffer\[i2c\_master\_buffer\_index - 1\]);  
        }

        /\* nack received \*/  
        if (event & RB\_I2C\_AF) {                //主机接收模式最后一个字节后为NACK  
            I2C\_ClearFlag(I2C\_FLAG\_AF);  
            /\* put final byte into buffer \*/  
            i2c\_master\_buffer\[i2c\_master\_buffer\_index++\] = I2C\_ReceiveData();       //收下最后一个字节的数据

            if (i2c\_send\_stop) {            //判断读完之后是停止信号还是重起始信号  
                i2c\_state = I2C\_READY;  
                I2C\_GenerateSTOP(ENABLE);  
                I2C\_DBG("  NACK received, send STOP\\n");  
            } else {  
                i2c\_in\_repstart = true;     //读完后不停止,会产生重起始信号以衔接后续操作  
                /\* we're gonna send the START, don't enable the interrupt. \*/  
                I2C\_ITConfig(I2C\_IT\_BUF, DISABLE);  
                I2C\_ITConfig(I2C\_IT\_EVT, DISABLE);  
                I2C\_ITConfig(I2C\_IT\_ERR, DISABLE);  
                I2C\_GenerateSTART(ENABLE);  
                i2c\_state = I2C\_READY;  
                I2C\_DBG("  restart\\n");  
            }  
        }  
    }

} else {        //判断为从机模式  
/\* I2C slave \*/  
    /\* addressed, returned ack \*/  
    if (event & RB\_I2C\_ADDR) {      //地址匹配,接下来判断方向

        if (event & ((RB\_I2C\_TRA << 16) | RB\_I2C\_TxE)) {    //判断从机发送方向匹配或者发送方向寄存器空,那么接下来需要发送数据      //发送方向寄存器空需要判断吗?  
            I2C\_DBG("Slave transmitter address matched\\n");

            i2c\_state = I2C\_STX;  
            i2c\_slave\_txbuffer\_index = 0;  
            i2c\_slave\_txbuffer\_length = 0;

            if (slave\_cb && slave\_cb->on\_transmit) {        //如果注册了回调,就按照回调函数,将数据拷贝到i2c\_slave\_txbuffer中  
                slave\_cb->on\_transmit(i2c\_slave\_txbuffer, &i2c\_slave\_txbuffer\_length);  
            }  
        } else {                //判断从机接收方向地址匹配,那么接下来需要接收数据  
            I2C\_DBG("Slave reveiver address matched\\n");

            i2c\_state = I2C\_SRX;  
            i2c\_slave\_rxbuffer\_index = 0;  
        }  
    }

    if (event & (RB\_I2C\_TRA << 16)) {       //从机发送  
        /\* Slave transmintter \*/  
        I2C\_AcknowledgeConfig(ENABLE);      //预设自动回复ACK  
        I2C\_DBG("Slave transmitter:\\n");

        if (event & RB\_I2C\_AF) {        //收到了NACK,发送失败  
            /\* Nack received \*/  
            I2C\_ClearFlag(I2C\_FLAG\_AF);     //清除应答失败标志  
            I2C\_AcknowledgeConfig(ENABLE);  //预设自动回复ACK  
            I2C\_DBG("  Nack received\\n");

            /\* leave slave receiver state \*/  
            i2c\_state = I2C\_READY;  
            /\* clear status \*/  
            event = 0;  
        }

        if(event & (RB\_I2C\_BTF | RB\_I2C\_TxE)) {     //字节发送结束或者发送方向寄存器空  
            /\* copy data to output register \*/

            I2C\_SendData(i2c\_slave\_txbuffer\[i2c\_slave\_txbuffer\_index++\]);   //逐字节发送数据

            /\* if there is more to send, ack, otherwise nack \*/  
            if (i2c\_slave\_txbuffer\_index < i2c\_slave\_txbuffer\_length) {  
                I2C\_AcknowledgeConfig(ENABLE);      //预设自动回复ACK  
            }else{  
                I2C\_AcknowledgeConfig(DISABLE);     //预设自动回复NACK  
            }  
            I2C\_DBG("  send (%#x)\\n",  
                    i2c\_slave\_txbuffer\[i2c\_slave\_txbuffer\_index - 1\]);  
        }  
    } else {                    //从机接收  
        /\* Slave receiver \*/  
        I2C\_DBG("Slave receiver:\\n");

        if (event & RB\_I2C\_RxNE) {      //判断非空即收到了数据  
            /\* if there is still room in the rx buffer \*/  
            //判断还有没有缓存空间,如果仍有空间就接收数据并回ACK,没有更多空间了就回NACK  
            if (i2c\_slave\_rxbuffer\_index < I2C\_BUFFER\_LENGTH) {  
                /\* put byte in buffer and ack \*/  
                i2c\_slave\_rxbuffer\[i2c\_slave\_rxbuffer\_index++\] = I2C\_ReceiveData();  
                I2C\_AcknowledgeConfig(ENABLE);  
                I2C\_DBG("  received (%#x)\\n",  
                        i2c\_slave\_rxbuffer\[i2c\_slave\_rxbuffer\_index - 1\]);  
            } else {  
                // otherwise nack  
                I2C\_AcknowledgeConfig(DISABLE);  
            }  
        }

        if (event & RB\_I2C\_STOPF) {     //从机接收模式下收到停止位,清标志,清数组下标索引  
            /\* ack future responses and leave slave receiver state \*/

            R16\_I2C\_CTRL1 |= RB\_I2C\_PE; //clear flag

            I2C\_DBG("  reveive stop\\n");

            /\* callback to user defined callback \*/  
            if (slave\_cb && slave\_cb->on\_receive) {  
                slave\_cb->on\_receive(i2c\_slave\_rxbuffer, i2c\_slave\_rxbuffer\_index);  
            }  
            /\* since we submit rx buffer , we can reset it \*/  
            i2c\_slave\_rxbuffer\_index = 0;  
        }

        if (event & RB\_I2C\_AF) {        //如果接收模式中接收到了NACK,清标志,预设自动回复ACK  
            I2C\_ClearFlag(I2C\_FLAG\_AF);

            /\* ack future responses \*/  
            I2C\_AcknowledgeConfig(ENABLE);  
        }  
    }  
}

if(event & RB\_I2C\_BERR){            //总线错误  
    I2C\_ClearFlag(RB\_I2C\_BERR);  
    I2C\_GenerateSTOP(ENABLE);

    i2c\_error = I2C\_BUS\_ERROR;  
    I2C\_DBG("RB\_I2C\_BERR\\n");  
}

if(event & RB\_I2C\_ARLO){            //仲裁丢失错误  
    I2C\_ClearFlag(RB\_I2C\_ARLO);

    i2c\_error = I2C\_ARB\_LOST;  
    I2C\_DBG("RB\_I2C\_ARLO\\n");  
}

I2C\_DBG("\\n");  

}