stm32f401 I2C no envía byte después de un inicio repetido

0

Estoy programando un maestro I2C en una placa de núcleo STM32F401. Lo programo sin HAL, solo usando registros.

Estoy interconectando un periférico, que debe leerse como el siguiente:

  1. Iniciar
  2. escriba la dirección con R / W 0
  3. escriba la dirección de registro
  4. Enviar condición de inicio repetido
  5. escriba la dirección con R / W 1
  6. Leer datos desde el periférico

Los primeros 3 pasos funcionan totalmente bien, pero no puedo enviar la dirección con R / W 1 después de la condición de reinicio.

Aquí puede ver el diagrama de tiempo utilizando un analizador lógico. Se envía la condición de reinicio, pero luego SCL y SDA son bajos.

Aquí está mi código

    i2c_start();
    if (i2c_sendAddr(TLC2991_ADDR)) { //returns != 0 if NACK
        fault = true;
        i2c_end();
        I2C1->SR1 &= ~I2C_SR1_AF;
        return -1;
    }
    i2c_sendByte(VOLTAGE_REG_OFFS + 2 * ch);
    i2c_wfw();
    i2c_start();
    i2c_sendByte(TLC2991_ADDR | 1); //tried i2c_sendAddr too
    u8 msb = i2c_recvByte(1);
    u8 lsb = i2c_recvByte(0);

Y las funciones llamadas

void i2c_start() {
    I2C1->CR1 |= I2C_CR1_START;
    while (!I2C1->SR1 & I2C_SR1_SB);
}

int i2c_sendAddr(u8 addr) {
    I2C1->DR = addr;
    while (!(I2C1->SR1 & I2C_SR1_ADDR))
        if (I2C1->SR1 & I2C_SR1_AF)
            return -1;
    I2C1->SR2; //generates a read, clears ADDR
    return 0;
}

int i2c_sendByte(u8 data) {
    while (!(I2C1->SR1 & (I2C_SR1_TXE | I2C_SR1_AF)));
    I2C1->DR = data;
    return I2C1->SR1 & I2C_SR1_AF ? -1 : 0;
}

//wait for byte transfer
void i2c_wfw() {
    while (!(I2C1->SR1 & (I2C_SR1_BTF | I2C_SR1_AF)));
}

El bit TXE es alto antes de configurar el DR después del reinicio, luego es bajo, pero el I2C no transmite nada. Por favor, señale lo que me perdí.

También he comprobado la línea SDA con un osciloscopio y no hay problemas técnicos o similares.

    
pregunta Alexander Daum

1 respuesta

1

Sugiero intentar lo siguiente:

i2c_start: while (!I2C1->SR1 & I2C_SR1_SB); - > while (!(I2C1->SR1 & I2C_SR1_SB));

i2c_sendByte: Mueve I2C1->DR = data; a la primera línea. Reemplace el cheque para TXE con el cheque para BTF.

no llame a i2c_wfw después de i2c_sendByte(VOLTAGE_REG_OFFS + 2 * ch); , se hará en i2c_sendByte como se indicó anteriormente.

use i2c_sendAddr en lugar de i2c_sendByte después de un inicio repetido.

También verifica la AF en i2c_sendByte y i2c_wfw () pero no maneja los errores correctamente. Es mejor no comprobarlo en absoluto que tener un flujo de código impredecible. Recomiendo mirar los diagramas de flujo en AN2824 y muy bien código de ejemplo en GitHub.

    
respondido por el Maple

Lea otras preguntas en las etiquetas