¿Por qué se rompen los últimos datos de la transferencia DMA de I2C?

1

Usé DMA para transferir datos I2C, pero siempre pierdo los últimos datos. La configuración del hardware se muestra a continuación:

  DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)I2C1_DR_Address;
  DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)I2C1_Buffer_Tx;
  DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;
  DMA_InitStructure.DMA_BufferSize = 2;
  DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
  DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
  DMA_InitStructure.DMA_PeripheralDataSize = DMA_MemoryDataSize_Byte;
  DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
  DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;
  DMA_InitStructure.DMA_Priority = DMA_Priority_VeryHigh;
  DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
  DMA_Init(DMA1_Channel6, &DMA_InitStructure);
  DMA_ITConfig(DMA1_Channel6, DMA_IT_TC, ENABLE); 

Los datos a transferir son:

  I2C1_Buffer_Tx[0] = 0xF0;
  I2C1_Buffer_Tx[1] = 0x55;

Cuando se envía un marco de datos, se genera una interrupción de DMA:

void DMA1_Channel6_IRQHandler(void)
{
  if (DMA_GetFlagStatus(DMA1_IT_TC6) != RESET)
  {
    DMA_Cmd(DMA1_Channel6, DISABLE);
    DMA1_Channel6->CNDTR = 2;
    DMA_ClearFlag(DMA1_IT_TC6);
    switch (mode)
    {
      case 1:
        I2C_GenerateSTART(I2C1, ENABLE);
        mode = 2;
        break;
      case 2:
        I2C_GenerateSTOP(I2C1, ENABLE);
        mode = 3;
        break;......

Cuando establezco un punto de interrupción en I2C_GenerateSTART(I2C1, ENABLE) :

RecibolaseñalSDAdelosciloscopioenestepatrón:

Muestra que se han enviado dos datos a través de SDA: 0xF0 y 0x55, sin embargo, cuando establezco un punto de interrupción después de ese código:

yobtuvelossiguientesdatos:

muestra que solo se ha enviado un dato a través de SDA: 0xF0 y luego una condición de reinicio. así, perderé los últimos datos si dejo que todo el programa se ejecute como de costumbre.

Solo puedo explicar el fenómeno de esta manera: DMA ya ha enviado dos datos (0xF0 0x55), y luego genera una interrupción. Sin embargo, esos dos datos todavía están en el búfer de I2C, luego, en la interrupción de DMA, se genera una condición de inicio. Por alguna razón, rompe los datos finales.

¿Alguien puede dar alguna sugerencia para solucionar este problema o solo puedo configurar el tamaño de DMA n + 1 si quiero enviar n datos?

    
pregunta oilpig

1 respuesta

5

Llaman a su controlador DMA antes , se envía el último byte, ya que este es el momento en el que el búfer DMA se vacía. Se acaba de escribir en el registro periférico.

Debe esperar a que este byte esté fuera del bus, por ejemplo, con el controlador de interrupciones I2C.

    
respondido por el Turbo J

Lea otras preguntas en las etiquetas