zoukankan      html  css  js  c++  java
  • STM32硬件I2C调试

    调试情况1

    现象:主I2C发送数据而没有收到应答,则下一次不能正常发送数据

    背景:主I2C每次应该都能正常发送数据

    硬件:野火STM32-MINI,1主0从,SCL和SDA直接上拉

    软件:按键触发中断,主I2C发送一次数据,中断优先级,按键最低,I2C最高,且主I2C中有TIMEOUT计时

    void PB_K2_IRQ_HANDLER(void)
    {
        if(EXTI_GetITStatus(PB_K2_EXTILINE) != RESET)
        {
            EXTI_ClearITPendingBit(PB_K2_EXTILINE);
            
            mini_i2c_write(0x22, 0x47);
            LED_D5_TOGGLE;
    //        printf("Push button K2 clicked!
    ");
        }
    }
    #define PB_PREPRIO                        3
    #define PB_SUBPRIO                        3
    #define SLAVER_I2C_PRIPRIO                0
    #define SLAVER_I2C_SUBPRIO                0

    优先级分组均为2

    void mini_uart_config(void)
    {
        // structure define
        USART_InitTypeDef usart_struct;
        GPIO_InitTypeDef gpio_struct;
        NVIC_InitTypeDef nvic_struct;
        
        // clock enable
        DEBUG_UART_RCC_CMD(DEBUG_UART_RCC, ENABLE);
        GPIO_RCC_CMD(DEBUG_UART_GPIO_RCC, ENABLE);
        
        // GPIO initialization
        gpio_struct.GPIO_Mode = GPIO_Mode_AF_PP;
        gpio_struct.GPIO_Speed = GPIO_Speed_50MHz;
        gpio_struct.GPIO_Pin = DEBUG_UART_TX;
        GPIO_Init(DEBUG_UART_GPIO, &gpio_struct);
        
        gpio_struct.GPIO_Mode = GPIO_Mode_IN_FLOATING;
        gpio_struct.GPIO_Pin = DEBUG_UART_RX;
        GPIO_Init(DEBUG_UART_GPIO, &gpio_struct);
        
        // NVIC    initialization
        NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
        nvic_struct.NVIC_IRQChannel = DEBUG_UART_IRQ;
        nvic_struct.NVIC_IRQChannelPreemptionPriority = DEBUG_UART_PRIPRIO;
        nvic_struct.NVIC_IRQChannelSubPriority = DEBUG_UART_SUBPRIO;
        nvic_struct.NVIC_IRQChannelCmd = ENABLE;
        NVIC_Init(&nvic_struct);
        
        // USART initialization
        usart_struct.USART_Mode = USART_Mode_Tx | USART_Mode_Rx;
        usart_struct.USART_Parity = USART_Parity_No;
        usart_struct.USART_StopBits = USART_StopBits_1;
        usart_struct.USART_WordLength = USART_WordLength_8b;
        usart_struct.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
        usart_struct.USART_BaudRate = DEBUG_UART_BAUDRATE;
        USART_Init(DEBUG_UART, &usart_struct);
        
        USART_Cmd(DEBUG_UART, ENABLE);
        
        USART_ITConfig(DEBUG_UART, USART_IT_RXNE, ENABLE);
    }
    void mini_i2c_write(uint8_t reg_addr, uint8_t wdata)
    {
        uint32_t timeout;
        
        I2C_GenerateSTART(MASTER_I2C, ENABLE);
        timeout = I2C_TIMEOUT;
        while(I2C_CheckEvent(MASTER_I2C, I2C_EVENT_MASTER_MODE_SELECT) == RESET)
        {
            if(timeout-- == 0)
            {
                I2C_GenerateSTOP(MASTER_I2C, ENABLE);
                break;
            }
        }
        
        // device address
        I2C_Send7bitAddress(MASTER_I2C, SLAVER_I2C_OWN_ADDR, I2C_Direction_Transmitter);
        timeout = I2C_TIMEOUT;
        while(I2C_CheckEvent(MASTER_I2C, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED) == RESET)
        {
            if(timeout-- == 0)
            {
                I2C_GenerateSTOP(MASTER_I2C, ENABLE);
                break;
            }
        }
        
        I2C_SendData(MASTER_I2C, reg_addr);
        timeout = I2C_TIMEOUT;
        while(I2C_CheckEvent(MASTER_I2C, I2C_EVENT_MASTER_BYTE_TRANSMITTED) == RESET)
        {
            if(timeout-- == 0)
            {
                I2C_GenerateSTOP(MASTER_I2C, ENABLE);
                break;
            }
        }
        
        I2C_SendData(MASTER_I2C, wdata);
        timeout = I2C_TIMEOUT;
        while(I2C_CheckEvent(MASTER_I2C, I2C_EVENT_MASTER_BYTE_TRANSMITTED) == RESET)
        {
            if(timeout-- == 0)
            {
                I2C_GenerateSTOP(MASTER_I2C, ENABLE);
                break;
            }
        }
        
        I2C_GenerateSTOP(MASTER_I2C, ENABLE);
    }

    问题所在:主I2C在未收到ACK应答,会产生应答错误,SR1的AF位置1,在TIMEOUT时间后,上面的用户代码会调用I2C_GenerateSTOP(MASTER_I2C, ENABLE)函数,CR1的STOP为会被置位,导致出错

    调试代码,用串口打印状态寄存器及控制寄存器的值

    void mini_i2c_write(uint8_t reg_addr, uint8_t wdata)
    {
        if((MASTER_I2C->SR1 != 0) || (MASTER_I2C->SR2 != 0))
        {
            printf("Master I2C SR1 is %x and SR2 is %x
    ", MASTER_I2C->SR1, MASTER_I2C->SR2);
            printf("Master I2C CR1 is %x and CR2 is %x
    ", MASTER_I2C->CR1, MASTER_I2C->CR2);
    //        mini_i2c_config();
            MASTER_I2C->CR1 ^= 0x0200;
            printf("Master I2C SR1 is %x and SR2 is %x
    ", MASTER_I2C->SR1, MASTER_I2C->SR2);
            printf("Master I2C CR1 is %x and CR2 is %x
    ", MASTER_I2C->CR1, MASTER_I2C->CR2);
        }
        
        uint32_t timeout;
        
        I2C_GenerateSTART(MASTER_I2C, ENABLE);
        timeout = I2C_TIMEOUT;
        while(I2C_CheckEvent(MASTER_I2C, I2C_EVENT_MASTER_MODE_SELECT) == RESET)
        {
            if(timeout-- == 0)
            {
                I2C_GenerateSTOP(MASTER_I2C, ENABLE);
                break;
            }
        }
        
        // device address
        I2C_Send7bitAddress(MASTER_I2C, SLAVER_I2C_OWN_ADDR, I2C_Direction_Transmitter);
        timeout = I2C_TIMEOUT;
        while(I2C_CheckEvent(MASTER_I2C, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED) == RESET)
        {
            if(timeout-- == 0)
            {
                I2C_GenerateSTOP(MASTER_I2C, ENABLE);
                break;
            }
        }

    经验证,重新初始化I2C或复位CR1的STOP可以排除对下次发送数据的干扰,串口打印消息如下

    // Using mini_i2c_config()
    Program started! Master I2C SR1 is 400 and SR2 is 0 Master I2C CR1 is 601 and CR2 is 24 Master I2C SR1 is 0 and SR2 is 0 Master I2C CR1 is 401 and CR2 is 24
    // Using MASTER_I2C->CR1 ^= 0x0200 Program started! Master I2C SR1 is 400 and SR2 is 0 Master I2C CR1 is 601 and CR2 is 24 Master I2C SR1 is 400 and SR2 is 0 Master I2C CR1 is 401 and CR2 is 24

    解决方案:使能主I2C错误中断,在中断中重新初始化I2C,并设置一个变量使主I2C发送函数提前终止

        nvic_struct.NVIC_IRQChannel = MASTER_I2C_ER_IRQ;
        NVIC_Init(&nvic_struct);
        I2C_ITConfig(MASTER_I2C, I2C_IT_ERR, ENABLE);
    void MASTER_I2C_ER_IRQ_HANDLER(void)
    {
        if(I2C_GetITStatus(MASTER_I2C, I2C_IT_AF) != RESET)
        {
            I2C_ClearITPendingBit(MASTER_I2C, I2C_IT_AF);
            
            mini_i2c_config();
            master_i2c_af = 1;
        }
    }
    void mini_i2c_write(uint8_t reg_addr, uint8_t wdata)
    {
        master_i2c_af = 0;
        
        I2C_GenerateSTART(MASTER_I2C, ENABLE);
        while(I2C_CheckEvent(MASTER_I2C, I2C_EVENT_MASTER_MODE_SELECT) == RESET);
        
        // device address
        I2C_Send7bitAddress(MASTER_I2C, SLAVER_I2C_OWN_ADDR, I2C_Direction_Transmitter);
        while(I2C_CheckEvent(MASTER_I2C, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED) == RESET)
        {
            if(master_i2c_af)
            {
                master_i2c_af = 0;
                return;    // maybe there is a solution here
            }
        }
        
        I2C_SendData(MASTER_I2C, reg_addr);
        while(I2C_CheckEvent(MASTER_I2C, I2C_EVENT_MASTER_BYTE_TRANSMITTED) == RESET);
        
        I2C_SendData(MASTER_I2C, wdata);
        while(I2C_CheckEvent(MASTER_I2C, I2C_EVENT_MASTER_BYTE_TRANSMITTED) == RESET);
        
        I2C_GenerateSTOP(MASTER_I2C, ENABLE);
    }
  • 相关阅读:
    spl_autoload_register()和__autoload()区别
    编程语言相关科目
    类继承和重写的区别
    心理扭曲和心理变态含义分别是什么?
    java中的静态方法
    《深入理解JavaScript》—— JSON
    《深入理解JavaScript》—— Date
    《深入理解JavaScript》—— 正则表达式
    《深入理解JavaScript》—— 数组
    《深入理解JavaScript》—— 对象与继承(第2层)
  • 原文地址:https://www.cnblogs.com/qingkai/p/9939903.html
Copyright © 2011-2022 走看看