为什么I2C发送错误数据?

问题描述 投票:0回答:1

我正在尝试使用STM32G474RE的I2C与MCP4728 DAC芯片进行通信。我要发送到芯片的字节是

{0xFF, 0x58, 0x04, 0x56}
并且调试同意TX寄存器接收上述字节。然而,当我实际传输字节时,示波器上显示的是
{0xFF, 0x58, 0xFF, 0xFF}
,每当我修改第一个字节时,第三个和第四个字节也会改变。

int main(void){
    SystemClock_Config();   //16MHz HSI16 Clock
    I2C2_Init();
    while (1){
        MCP4728_Transmit(SINGLE_WRITE, CHANNEL_A, 0x456);
    }
}

void MCP4728_Transmit(uint8_t tx_mode, uint8_t channel, uint16_t data){
    /*If data larger than 12 bits (0xFFF) return*/
    if (data > 0xFFF)
        return;
    
    int tx_buffer_index = 0;
    uint8_t tx_buffer[4];
    tx_buffer[0] = 0xFF;
    tx_buffer[1] = tx_mode | (channel << 1); 
    tx_buffer[2] = (uint8_t) (data >> 8) & 0x0F;
    tx_buffer[3] = (uint8_t) data & 0xFF;
    
    I2C2->CR2 |= 0x04 << I2C_CR2_NBYTES_Pos;
    I2C2->CR2 &= ~I2C_CR2_AUTOEND;
    I2C2->CR2 |= ((0x60<<1)<< I2C_CR2_SADD_Pos);
    I2C2->CR2 |= I2C_CR2_START;
    
    
    
    while(!(I2C2->ISR & I2C_ISR_TC)){
        if (I2C2->ISR & I2C_ISR_NACKF)
            return;
        if (!(I2C2->ISR & I2C_ISR_TXIS))
            return;
        else{
            I2C2->TXDR = tx_buffer[tx_buffer_index];
            tx_buffer_index++;
        }
    }
    I2C2->CR2 |= I2C_CR2_STOP;
}

void I2C2_Init(void){
    /*Enable I2C and GPIOA clock*/
    RCC->APB1ENR1 |= RCC_APB1ENR1_I2C2EN;
    RCC->AHB2ENR |= RCC_AHB2ENR_GPIOAEN;
    
    
    /*Config PA8 and PA9*/
    //PA8 and PA9 Alternate Function (AF4)
    GPIOA->MODER &= ~(GPIO_MODER_MODE8 | GPIO_MODER_MODE9);
    GPIOA->MODER |= (0x02 << GPIO_MODER_MODE8_Pos | 0x02 << GPIO_MODER_MODE9_Pos);
    GPIOA->AFR[1] |= (0x04 << GPIO_AFRH_AFSEL8_Pos | 0x04 <<GPIO_AFRH_AFSEL9_Pos);
    //Output type Open Drain
    GPIOA->OTYPER |= (GPIO_OTYPER_OT8 | GPIO_OTYPER_OT9);
    //High Speed
    GPIOA->OSPEEDR &= ~(GPIO_OSPEEDR_OSPEED8 | GPIO_OSPEEDR_OSPEED9);
    GPIOA->OSPEEDR |= (0x02 << GPIO_OSPEEDR_OSPEED8_Pos | 0x02 << GPIO_OSPEEDR_OSPEED9_Pos);
    //Enable Pull Up
    GPIOA->PUPDR &= ~(GPIO_PUPDR_PUPD8 | GPIO_PUPDR_PUPD9);
    GPIOA->PUPDR |= (0x01 << GPIO_PUPDR_PUPD8_Pos | 0x01 << GPIO_PUPDR_PUPD9_Pos);
    
    
    /*Configure I2C2*/
    //Disable I2C
    I2C2->CR1 &= ~I2C_CR1_PE;
    //Default filter
    I2C2->CR1 &= ~I2C_CR1_ANFOFF;
    I2C2->CR1 &= ~I2C_CR1_DNF;
    //TIMINGR value for 16MHz taken from table in Reference Manual (page xxx)
    I2C2->TIMINGR |= (0x03 << I2C_TIMINGR_PRESC_Pos  | 0x04 << I2C_TIMINGR_SCLDEL_Pos | \
                      0x02 << I2C_TIMINGR_SDADEL_Pos | 0x0F << I2C_TIMINGR_SCLH_Pos   | \
                      0x13 << I2C_TIMINGR_SCLL_Pos);
    //Enable stretching
    I2C2->CR1 &= ~I2C_CR1_NOSTRETCH;
    //Enable I2C
    I2C2->CR1 |= I2C_CR1_PE;
}
c stm32 bare-metal
1个回答
0
投票

I2C_ISR.TXIS 表示发送缓冲区为空,即数据已移至移位寄存器。当移位寄存器仍为空时,第一个字节可能会立即发生这种情况,但在写入第二个字节后,需要传输整个前一个字节才能使 TXIS 再次变为 1。然而,你不会等待:

if (!(I2C2->ISR & I2C_ISR_TXIS))
            return;

这意味着,在第二个字节之后您立即返回。就像在主循环中一样,您无条件地重复调用此函数,一旦第一个字节被发送,第二个字节被发送到移位寄存器,并且 TXIS 再次变为 1,此函数再次存储第一个字节,并且不会成功存储第二个字节,依此类推。为什么你看到模式第一个字节 - 第二个字节 - 第一个字节 - 第一个字节。

循环等待I2C_ISR.TXIS。

© www.soinside.com 2019 - 2024. All rights reserved.