I2C函数之中断处理函数(四)

 函数来源于来源于Linux设备驱动开发详解.pdf。

// 1. 定义中断处理函数`s3c24xx_i2c_irq`,该函数用于处理S3C2410 I2C适配器的中断。
//   参数包括:
//   - `irq`: 中断号。
//   - `void *dev_id`: 传递给请求中断处理函数的设备标识符。
//   - `struct pt_regs *regs`: 指向程序状态寄存器的指针,包含中断发生时的上下文信息。
static irqreturn_t s3c24xx_i2c_irq(int irq, void *dev_id, struct pt_regs *regs)

{
    // 3. 声明一个指向`s3c24xx_i2c`结构的指针`i2c`,用于访问I2C设备的私有数据。
    struct s3c24xx_i2c *i2c = (struct s3c24xx_i2c *)dev_id;

    // 5-7. 声明两个无符号长整型变量`status`和`tmp`,用于存储从寄存器读取的状态信息。
    unsigned long status;
    unsigned long tmp;

    // 8-9. 读取I2C状态寄存器的值,并存储到`status`变量中。
    //       `S3C2410_IICSCON`是I2C状态寄存器的偏移。
    status = readl(i2c->regs + S3C2410_IICSCON);

    // 10-11. 检查状态寄存器中的仲裁丢失位。
    //         `S3C24XX_I2CSTAT_ARBITR`是仲裁丢失的状态位掩码。
    if (status & S3C24XX_I2CSTAT_ARBITR)

    // 12-13. 如果发生仲裁丢失,处理相关逻辑。
        // `STATE_TX_RX`可能是用于标识I2C总线状态的一个宏。
        if (i2c->state == STATE_TX_RX)

    // 14-16. 清除I2C控制寄存器中的低功耗模式和中断挂起位。
    //         `S3C2410_IICCON`是I2C控制寄存器的偏移。
        // `tmp`变量用于临时存储控制寄存器的值。
        tmp = readl(i2c->regs + S3C2410_IICCON);
        tmp &= ~S3C2410_TICCON_LPENPEND;
        writel(tmp, i2c->regs + S3C2410_IICCON);

    // 17. 跳转到标签`out`,结束中断处理。
        goto out;

    // 18-24. 这部分代码似乎是一个条件执行块,用于在特定条件下调用`s3c_i2c_nextbyte`函数
    //         以推进传输工作。但代码不完整,无法提供准确的注释。

    // 23. 如果满足某个条件,则返回`IRQ_HANDLED`,表示中断已被处理。
    //       `IRQ_HANDLED`是一个宏,用于标识中断处理成功。
    return IRQ_HANDLED;

    // 24. 标签`out`,用于结束中断处理函数。
out:
    return 0;
}
// 26. 定义一个名为`i2s_s3c_irq_nextbyte`的静态函数,用于处理I2C中断并推进数据传输。
// 参数包括:
// - `struct s3c24xx_i2c *i2c`: 指向I2C控制器私有数据的指针。
// - `unsigned long cstat`: 当前I2C的状态。
static int i2s_s3c_irq_nextbyte(struct s3c24xx_i2c *i2c, unsigned long cstat)

{
    // 28-29. 声明局部变量`tmp`(无符号长整型),`byte`(无符号字符型),`ret`(整型)。
    unsigned long tmp;
    unsigned char byte;
    int ret = 0;

    // 32. 使用`switch`语句根据`i2c`结构中的`state`成员来处理不同的I2C状态。
    switch (i2c->state)
    {
        // 33-35. 如果状态是`STATE_IDLE`(空闲状态),直接跳到函数末尾结束。
        case STATE_IDLE:
            goto out;
            break;

        // 37-39. 如果状态是`STATE_STOP`(停止状态),禁用I2C中断,然后跳到末尾。
        case STATE_STOP:
            s3c24xx_i2c_disable_irq(i2c);
            goto out_ack;
            break;

        // 40-42. 如果状态是`STATE_START`(开始状态),检查是否需要启动新的消息。
        // 如果收到的最后一个位是开始位,并且没有收到ACK,则发送停止条件。
        case STATE_START:
            if (cstat & S3C2410_IICSTAT_LASTBIT &
                i2c->flags & I2C_M_RD)
            {
                // 没有收到ACK,发送远程I/O错误并停止。
                s3c24xx_i2c_stop(i2c, -EREMOTEIO);
                goto out_ack;
            }

            // 48-53. 根据消息的读取/写入标志设置状态为读或写。
            if (i2c->msg->flags & I2C_M_RD)
                i2c->state = STATE_READ;
            else
                i2c->state = STATE_WRITE;

            // 54-56. 如果是最后一条消息,发送停止条件。
            if (is_lastmsg(i2c))
                s3c24xx_i2c_stop(i2c, 0);
            break;

        // 59-85. 处理读和写状态,包括发送数据、接收数据、处理ACK等。
        case STATE_WRITE:
            // 64-66. 发送当前消息缓冲区的第一个字节。
            byte = i2c->msg->buf[i2c->msg_ptr++];
            writeb(byte, i2c->regs + S3C2410_IICDS);

            // 68-85. 如果是当前消息的最后,检查是否需要发送停止条件或继续。
            if (is_lastmsg(i2c))
            {
                // 处理停止条件或继续到下一条消息的逻辑。
            }
            break;

        case STATE_READ:
            // 90-123. 处理读取一个字节的情况,包括检查ACK、读取数据、处理消息结束等。
            if (/* 条件 */)
            {
                // 处理读取的逻辑。
            }
            break;

        // 其他状态和默认情况的处理...
    }

    // 125-128. 在退出前,清除中断挂起位并写回控制寄存器。
    tmp = readl(i2c->regs + S3C2410_IICCON);
    tmp &= ~S3C2410_IICCON_IROPEND;
    writel(tmp, i2c->regs + S3C2410_IICCON);

    // 129. 返回函数的返回值。
out:
    return ret;

    // 其他标签用于不同退出点...
out_ack:
    // 处理ACK的退出逻辑。
}

stm8si2c程序,调试通过 INTERRUPT_HANDLER(I2C_IRQHandler, 19) { /* In order to detect unexpected events during development, it is recommended to set a breakpoint on the following instruction. */ struct SCB_T *system=&system_process; unsigned char i,i2c_sr1,i2c_sr2,i2c_event,i2c__status=0,temp,sr1_analysis_int_resource[8],sr2_analysis_int_resource[8]; char i2c_interrupt_type=0,p;//在一次I2中断中,I2C中断中的中断标志位个数; disableInterrupts();//关总中断 i2c_sr1=I2C->SR1; p=I2C->SR3; i2c_sr2=I2C->SR2; //temp=I2C->SR3; //analysis interrupt resource in i2c->sr1 register sr1_analysis_int_resource[0]=i2c_sr1&I2C_SR1_SB; sr1_analysis_int_resource[1]=i2c_sr1&I2C_SR1_ADDR; sr1_analysis_int_resource[2]=i2c_sr1&I2C_SR1_BTF; sr1_analysis_int_resource[3]=i2c_sr1&I2C_SR1_ADD10; sr1_analysis_int_resource[4]=i2c_sr1&I2C_SR1_STOPF; // sr1_i2c__state[5]=i2c_state&((u8)I2C_SR1_BIT6); sr1_analysis_int_resource[6]=i2c_sr1&I2C_SR1_RXNE; sr1_analysis_int_resource[7]=i2c_sr1&I2C_SR1_TXE; //analysis interrupt resource in i2c->sr2 register sr2_analysis_int_resource[0]=i2c_sr2&I2C_SR2_BERR; sr2_analysis_int_resource[1]=i2c_sr2&I2C_SR2_ARLO; sr2_analysis_int_resource[2]=i2c_sr2&I2C_SR2_AF; sr2_analysis_int_resource[3]=i2c_sr2&I2C_SR2_OVR; sr2_analysis_int_resource[5]=i2c_sr2&I2C_SR2_WUFH; if(sr1_analysis_int_resource[0]==I2C_SR1_SB) {i2c__status=0x01;i2c_interrupt_type++;} if(sr1_analysis_int_resource[1]==I2C_SR1_ADDR) {i2c__status=0x02;i2c_interrupt_type++;} if(sr1_analysis_int_resource[2]==I2C_SR1_BTF) {i2c__status=0x03;i2c_interrupt_type++;} if(sr1_analysis_int_resource[3]==I2C_SR1_ADD10) {i2c__status=0x04;i2c_interrupt_type++;} if(sr1_analysis_int_resource[4]==I2C_SR1_STOPF) {i2c__status=0x05;i2c_interrupt_type++;} if(sr1_analysis_int_resource[6]==I2C_SR1_RXNE) {i2c__status=0x06;i2c_interrupt_type++;} if(sr1_analysis_int_resource[7]==I2C_SR1_TXE) {i2c__status=0x07;i2c_interrupt_type++;} if(sr2_analysis_int_resource[0]==I2C_SR2_BERR) {i2c__status=0x08;i2c_interrupt_type++;} if(sr2_analysis_int_resource[1]==I2C_SR2_ARLO) {i2c__status=0x09;i2c_interrupt_type++;} if(sr2_analysis_int_resource[2]==I2C_SR2_AF) {i2c__status=0x0a;i2c_interrupt_type++;} if(sr2_analysis_int_resource[3]==I2C_SR2_OVR) {i2c__status=0x0b;i2c_interrupt_type++;} if(sr2_analysis_int_resource[5]==I2C_SR2_WUFH) {i2c__status=0x0c;i2c_interrupt_type++;} if(i2c_interrupt_type>=2) /*there are more than one interrupt resource in the time*/ { if(i2c_interrupt_type==2) { if((sr1_analysis_int_resource[1]==I2C_SR1_ADDR)&&(sr1_analysis_int_resource[7]==I2C_SR1_TXE)) { I2C->DR=system->i2c.send_frame.data[system->i2c.send_frame.proc]; system->i2c.send_frame.proc++; system->i2c.debug.reserve[system->i2c.int_debug_count].type=0x62; } else if((sr1_analysis_int_resource[7]==I2C_SR1_TXE)&&(sr1_analysis_int_resource[2]==I2C_SR1_BTF)) { system->i2c.send_frame.terminate=0; //set I2C transfer terminate bit; system->i2c.send_frame.mod=0; system->i2c.send_frame.write=0; system->i2c.debug.reserve[system->i2c.int_debug_count].type=0x64; } else if((sr1_analysis_int_resource[7]==I2C_SR1_TXE)&&(sr2_analysis_int_resource[2]==I2C_SR2_AF)) { I2C->CR2|=I2C_CR2_STOP; I2C->SR2&=(~I2C_SR2_AF);//clear AF bit; system->i2c.error=1; system->i2c.debug.reserve[system->i2c.int_debug_count].type=0x64; } else { system->i2c.error=1; I2C_ITConfig(I2C_IT_EVT, DISABLE); system->i2c.debug.reserve[system->i2c.int_debug_count].type=0x37; } } else { system->i2c.error=1; I2C_ITConfig(I2C_IT_EVT, DISABLE); system->i2c.debug.reserve[system->i2c.int_debug_count].type=0x37; } } else { switch(i2c__status) { case I2C_SR1_SB_proc: //如果是发送模式 if(system->i2c.send_frame.mod==1)//说明本次中断之前是从模式,说明这是在从模式下发的起始位; { //EV5 p=I2C->SR1; I2C->DR=system->i2c.send_frame.add__L; //自动清除I2C_SR1_SB标志 system->i2c.debug.reserve[system->i2c.int_debug_count].type=0x38; } else { if(system->i2c.rev_frame.mod==1) //说明本次中断之间是主模式,这次发的是重复起始位; { //EV6如果是接收模式 p=I2C->SR1; I2C->DR=system->i2c.rev_frame.add__L;//自动清除I2C_SR1_SB标志; system->i2c.debug.reserve[system->i2c.int_debug_count].type=0x51; } else { system->i2c.error=1; system->i2c.debug.reserve[system->i2c.int_debug_count].type=0x36; } } break; case I2C_SR1_ADDR_proc: p=I2C->SR1; temp=I2C->SR3;//软件读取SR1寄存器后,对SR3寄存器的读操作将清除该位 temp&=(u8)I2C_SR3_TRA; I2C->CR2|=(u8)I2C_CR2_ACK;// 使能应答位 I2C->CR2&=(u8)(~I2C_CR2_POS);//设置接受到当字节应答 //如果是发送模式 if(system->i2c.send_frame.mod==1) { if(temp==(u8)I2C_SR3_TRA) {; } else { system->i2c.error=1; } } else { if(system->i2c.rev_frame.mod==1) { if(temp==0)//machine at a master-receive mod { system->i2c.rev_frame.proc=0; } else { system->i2c.error=1; } } else { system->i2c.error=1; } } system->i2c.debug.reserve[system->i2c.int_debug_count].type=0x52; break; case I2C_SR1_RXNE_proc: if(system->i2c.rev_frame.proci2c.rev_frame.num-3)) { system->i2c.rev_frame.data[system->i2c.rev_frame.proc]=I2C->DR; system->i2c.rev_frame.proc++; system->i2c.debug.reserve[system->i2c.int_debug_count].type=0x57; } else if(system->i2c.rev_frame.proc==(u8)(system->i2c.rev_frame.num-2)) { system->i2c.rev_frame.data[system->i2c.rev_frame.proc]=I2C->DR; system->i2c.rev_frame.proc++; system->i2c.debug.reserve[system->i2c.int_debug_count].type=0x58; I2C->CR2&=(u8)(~I2C_CR2_ACK);//不返回应答 I2C->CR2|=I2C_CR2_STOP; //发停止位结束这次数据接收; } else if(system->i2c.rev_frame.proc>=(u8)(system->i2c.rev_frame.num-1)) { system->i2c.rev_frame.data[system->i2c.rev_frame.proc]=I2C->DR; system->i2c.rev_frame.proc++; system->i2c.debug.reserve[system->i2c.int_debug_count].type=0x59; system->i2c.rev_frame.terminate=0; //set I2C transfer terminate bit; system->i2c.rev_frame.mod=0; system->i2c.rev_frame.read=0; } else { system->i2c.error=1; system->i2c.debug.reserve[system->i2c.int_debug_count].type=0xfb; } break; case I2C_SR1_TXE_proc: if(system->i2c.send_frame.proci2c.send_frame.num-1)) { I2C->DR=system->i2c.send_frame.data[system->i2c.send_frame.proc]; system->i2c.send_frame.proc++; system->i2c.debug.reserve[system->i2c.int_debug_count].type=0x61; } else if(system->i2c.send_frame.proc=(u8)(system->i2c.send_frame.num)) { I2C->CR2|=I2C_CR2_STOP; // 发停止位结束 这次数据接收; I2C_ITConfig(I2C_IT_BUF, DISABLE); system->i2c.debug.reserve[system->i2c.int_debug_count].type=0x60; } else { system->i2c.error=1; system->i2c.debug.reserve[system->i2c.int_debug_count].type=0xfc; } break; case I2C_SR2_AF_proc: I2C->CR2|=I2C_CR2_STOP; I2C->SR2&=(~I2C_SR2_AF);//clear AF bit; system->i2c.error=1; system->i2c.debug.reserve[system->i2c.int_debug_count].type=0x63; break; default: system->i2c.error=1; system->i2c.debug.reserve[system->i2c.int_debug_count].type=0xfd; break; } } system->i2c.int_debug_count++; enableInterrupts();//开总中断 }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值