STM32 I2C cuelga la comunicación

0

Actualmente estoy intentando usar el sensor de presión MS5611 (sentado en un CJMCU-117) sobre I²C con libopencm3 en un STM32F103C8.

Desde el i2c_transfer7() of libopencmic / ícono de la coyuntura href="https://electronics.stackexchange.com/questions/405540/ms5611-sends-additional-byte-after-nack"> pregunta anterior: MS5611 envía un byte adicional después de NACK ), implementé un envío de sondeo y recibir en un nivel de registro (aún utilizando las definiciones de registro de libopencm3).

Mientras que una lectura de presión en un bucle principal infinito funciona, deja de funcionar después de una sola lectura, tan pronto como hay más (más tiempo) código en el bucle después. Como si esto no fuera suficiente, funciona de nuevo como hago una compilación de depuración (heisenbug). Al utilizar el método printf sobre UART, revela que el código se cuelga en una verificación del bit de modo maestro después de configurar el bit de inicio en la función de envío (impresión 3, pero no 4).

Parece ser algo relacionado con el tiempo. ¿O podría estar relacionado con el cableado? Si lo veo correctamente, el CJMCU-117 tiene una resistencia de 10 kΩ tanto en SCL como en SDA, por eso no he agregado ninguna otra resistencia al bus. He probado el modo estándar (100 kHz) y el modo rápido (400 kHz).

Enviar :

template <class T>
void send(const uint32_t& i2cUnit, const uint32_t i2cAddress, T& data)
{
    usart_send_blocking(USART1, '1');
    while (I2C_SR2(i2cUnit) & I2C_SR2_BUSY);

    usart_send_blocking(USART1, '2');
    i2c_send_start(i2cUnit);

    usart_send_blocking(USART1, '3');
    // Setting the START bit causes the interface [...] to switch to Master mode (MSL bit set) when the BUSY bit is cleared.
    while (!(I2C_SR2(i2cUnit) & I2C_SR2_MSL));

    usart_send_blocking(USART1, '4');
    // EV5: SB=1, cleared by reading SR1 register followed by writing DR register with Address
    while (!(I2C_SR1(i2cUnit) & I2C_SR1_SB));

    usart_send_blocking(USART1, '5');
    i2c_send_7bit_address(i2cUnit, i2cAddress, I2C_WRITE);

    usart_send_blocking(USART1, '6');
    // EV6: ADDR=1, cleared by reading SR1 register followed by reading SR2
    while (!(I2C_SR1(i2cUnit) & I2C_SR1_ADDR));
    (void)I2C_SR2(i2cUnit);

    // EV8_1: TxE=1, shift register empty, data register empty, write Data1 in DR.
    while (!(I2C_SR1(i2cUnit) & I2C_SR1_TxE));

    i2c_send_data(i2cUnit, static_cast<uint8_t *>(&data)[0]);

    for (size_t i = 1; i < sizeof(data); i++)
    {
        // EV8: TxE=1, shift register not empty, data  register empty, cleared  by writing DR register
        // The EV8 software sequence must complete before the end of the current byte transfer. In case EV8 software sequence can not be managed before the current byte end of transfer, it is recommended to use BTF instead of TXE with the drawback of slowing the communication.

        while (!(I2C_SR1(i2cUnit) & I2C_SR1_BTF));//I2C_SR1_TxE));

        i2c_send_data(i2cUnit, static_cast<uint8_t *>(&data)[i]);
    }

    // EV8_2: TxE=1, BTF=1, Program Stop request. TxE and BTF are cleared by hardware by the Stop condition
    // Note: Stop condition should be programmed during EV8_2 event, when either TxE or BTF is set.
    while (!(I2C_SR1(i2cUnit) & I2C_SR1_TxE) && !(I2C_SR1(i2cUnit) & I2C_SR1_BTF));

    i2c_send_stop(i2cUnit);

    // The interface automatically goes back to slave mode (MSL bit cleared).
    while (I2C_SR2(i2cUnit) & I2C_SR2_MSL);
}

Recibir :

template <size_t bytesToRead>
void receive(const uint32_t& i2cUnit, const uint32_t i2cAddress, std::array<uint8_t, bytesToRead>& buffer)
{
    // Method 2

    while (I2C_SR2(i2cUnit) & I2C_SR2_BUSY);

    // Restore ACK and POS
    i2c_enable_ack(i2cUnit);
    i2c_nack_current(i2cUnit);

    i2c_send_start(i2cUnit);

    // Setting the START bit causes the interface [...] to switch to Master mode (MSL bit set) when the BUSY bit is cleared.
    while (!(I2C_SR2(i2cUnit) & I2C_SR2_MSL));

    // EV5: SB=1, cleared by reading SR1 register followed by writing DR register
    while (!(I2C_SR1(i2cUnit) & I2C_SR1_SB));

    i2c_send_7bit_address(i2cUnit, i2cAddress, I2C_READ);

    // EV6: ADDR=1, cleared by reading SR1 register ...
    while (!(I2C_SR1(i2cUnit) & I2C_SR1_ADDR));

    if constexpr (bytesToRead == 1)
    {
        // EV6_3: ADDR = 1, program ACK = 0 ...
        i2c_disable_ack(i2cUnit);

        // Note: The EV6_3 software sequence must complete before the current byte end of transfer.
        cm_disable_interrupts();

            // EV6: ... followed by reading SR2
            (void)I2C_SR2(i2cUnit);

            // EV6_3: ... program STOP =1 just after ADDR is cleared
            i2c_send_stop(i2cUnit);

        cm_enable_interrupts();

        // EV7: RxNE =1, cleared by reading DR register.
        while (!(I2C_SR1(i2cUnit) & I2C_SR1_RxNE));

        buffer[0] = i2c_get_data(i2cUnit);
    }

    if constexpr (bytesToRead == 2)
    {
        // Set POS
        i2c_nack_next(i2cUnit);

        cm_disable_interrupts();

            // EV6: ... followed by reading SR2
            (void)I2C_SR2(i2cUnit);

            // EV6_1: No associated flag event. The acknowledge disable should be done just after EV6, that is after ADDR is cleared
            i2c_disable_ack(i2cUnit);

        cm_enable_interrupts();

        // EV7_3: BTF = 1, program STOP = 1, read DR twice (Read Data1 and Data2) just after programming the STOP
        while (!(I2C_SR1(i2cUnit) & I2C_SR1_BTF));

        cm_disable_interrupts();

            i2c_send_stop(i2cUnit);

            buffer[0] = i2c_get_data(i2cUnit);
            buffer[1] = i2c_get_data(i2cUnit);

        cm_enable_interrupts();
    }

    if constexpr (bytesToRead >= 3)
    {
        // EV6: ... followed by reading SR2
        (void)I2C_SR2(i2cUnit);

        for (size_t i = 0; i < bytesToRead - 3; ++i)
        {
            // EV7: RxNE=1, cleared by reading DR register
            while (!(I2C_SR1(i2cUnit) & I2C_SR1_RxNE));

            buffer[i] = i2c_get_data(i2cUnit);
        }

        // RxNE = 1 => Nothing (DataN-2 not read).
        while (!(I2C_SR1(i2cUnit) & I2C_SR1_RxNE));
        // EV7_2: BTF = 1, DataN-2 in DR and DataN-1 in shift register, program ACK = 0, Read DataN-2 in DR both RxNE and BTF are set
        while (!(I2C_SR1(i2cUnit) & I2C_SR1_BTF));
        i2c_disable_ack(i2cUnit);
        buffer[bytesToRead - 3] = i2c_get_data(i2cUnit);

        // Program STOP = 1, read DataN-1
        i2c_send_stop(i2cUnit);
        buffer[bytesToRead - 2] = i2c_get_data(i2cUnit);

        // After RxNE is set, read DataN
        while (!(I2C_SR1(i2cUnit) & I2C_SR1_RxNE));
        buffer[bytesToRead - 1] = i2c_get_data(i2cUnit);
    }

    // The interface automatically goes back to slave mode (MSL bit cleared).
    while (I2C_SR2(i2cUnit) & I2C_SR2_MSL);
}

Setup:

void setupI2C()
{
    rcc_periph_clock_enable(RCC_GPIOB);
    rcc_periph_clock_enable(RCC_I2C2);

    gpio_set_mode(GPIOB, GPIO_MODE_OUTPUT_50_MHZ, GPIO_CNF_OUTPUT_ALTFN_OPENDRAIN,
        GPIO_I2C2_SCL | GPIO_I2C2_SDA);

    i2c_reset(I2C2);

    i2c_peripheral_disable(I2C2);
    i2c_set_speed(I2C2, i2c_speed_fm_400k, I2C_CR2_FREQ_36MHZ);
    i2c_peripheral_enable(I2C2);
}
    
pregunta Tonke

0 respuestas

Lea otras preguntas en las etiquetas