¿Cómo enviar correctamente la condición de parada cuando se usa DMA con I2C?

2

Estoy usando la transferencia DMA para obtener 1024 bytes del maestro (STM32F407VG) a la pantalla OLED esclava (SSD1306). La biblioteca que estoy usando hace esto:

extern void DMA1_Stream4_IRQHandler(void)
{
    // I2C3 DMA transmit completed
    if (DMA_GetFlagStatus(DMA1_Stream4, DMA_FLAG_TCIF4) != RESET)
    {
        // Stop DMA, clear interrupt
        DMA_Cmd(DMA1_Stream4, DISABLE);
        DMA_ClearFlag(DMA1_Stream4, DMA_FLAG_TCIF4);
        I2C_DMACmd(I2C3, DISABLE);
        TM_I2C_Stop(I2C3); // send i2c stop
    }
}

Pero leí que DMA normalmente termina antes de que I2C termine de transmitir el último byte y si lo detiene (TM_I2C_Stop (I2C3)), el último byte nunca se transmite. Así que leí en StackOvf que la forma correcta podría ser usar una interrupción separada para I2C y enviar la condición de parada allí. Así que lo intenté:

I2C_ITConfig(I2C3, I2C_IT_BTF, ENABLE);
I2C_ClearFlag(I2C3, I2C_FLAG_BTF);
// Set interupt controller for I2C
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_InitStructure.NVIC_IRQChannel = I2C3_EV_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);

y el controlador:

extern void I2C3_EV_IRQHandler(void)
{
    if (I2C_GetFlagStatus(I2C3, I2C_FLAG_BTF) != RESET)
    {
        TM_I2C_Stop(I2C3); // send i2c stop
        I2C_ClearFlag(I2C3, I2C_FLAG_BTF);
    }
}

pero el manejador nunca recibe una llamada y el programa se bloquea porque ya no puede enviar ningún dato a través de I2C porque dice que está ocupado. Ahora estoy empezando a pensar que BTF podría no ser el evento de interrupción correcto, aunque dice en la documentación:

  

Transmisor maestro: en la rutina de interrupción después de la interrupción EOT, desactive las solicitudes DMA y espere a que ocurra un evento BTF antes de programar la condición de parada.

Pero bloquear toda la CPU en la rutina de interrupción hasta que finalice I2C parece un poco tonto, especialmente cuando hay una interrupción de BTF disponible. ¿Cuál es la forma correcta de llamar al I2C e interrumpir para evitar truncar el último byte?

    
pregunta Terraviper-5

0 respuestas

Lea otras preguntas en las etiquetas