STM32F3 Circular DMA

3

Tengo algunos problemas para que mi memoria con la configuración circular GPIO DMA sea correcta. El código de inicialización pegado a continuación tiene algunos problemas.

Estoy intentando mover los datos de una matriz uint16_t al registro GPIO- > ODR. Tengo la fuente y el destino configurados como media palabra ya que ambos son registros de 16 bits. Mi matriz tiene una longitud de 48 bytes, y quiero transferir 96 bytes (la matriz de 48 bytes 2 veces). Así que quiero que el DMA desplace los 48 bytes, luego regrese al inicio de la matriz y vuelva a hacerlo con la misma matriz.

Sin embargo, no tengo claro cómo decirle a la DMA después de cuántos bytes hay que devolver el círculo. Si configuro el tamaño de búfer en 96, simplemente sigue leyendo 48 bytes más allá de mi matriz.

void WS2812_Basic_DMA_Init2(void)
{
    DMA_InitTypeDef DMA_InitStructure;
    NVIC_InitTypeDef NVIC_InitStructure;

    RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);      // Enable DMA1 clock

    DMA_DeInit(DMA1_Channel2);                              // Reset DMA1 channe1 to default values;

    DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;            // M2M Disabled- Peripheral mode (requires timer trigger)
    DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;         // Circular mode
    DMA_InitStructure.DMA_Priority = DMA_Priority_VeryHigh; // High priority
    DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;      // Memory to Peripheral

    DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord; // 16-bit Register
    DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;            // Always write to same register
    DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&GPIOC->ODR;           // Output data for GPIO

    DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;         // 16-bit array
    DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;                     // Increment through array
    DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)&source16;                 // 16-bit Source data

    DMA_InitStructure.DMA_BufferSize = ARRAYSIZE;           // Size of source array x 2

    DMA_Init(DMA1_Channel2, &DMA_InitStructure);            // Initialize DMA

    //Enable DMA1 channel IRQ Channel */
    NVIC_InitStructure.NVIC_IRQChannel = DMA1_Channel2_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_InitStructure);

    // Enable DMA1 Channel Transfer Complete interrupt
    DMA_ITConfig(DMA1_Channel2, DMA_IT_TC, ENABLE);
}
    
pregunta spizzak

2 respuestas

3

El DMA se configuró correctamente pero lo estaba deshabilitando en el evento TC. Si no lo inhabilito, seguirá moviendo el número especificado de bytes de forma indefinida.

El tamaño del búfer es lo que le dice al DMA cuántos bytes se deben transferir antes de envolverlos, y continuará recorriendo esas direcciones hasta que se deshabilite explícitamente.

    
respondido por el spizzak
2
  

Mi matriz tiene una longitud de 48 bytes, y quiero transferir 96 bytes (la matriz de 48 bytes 2 veces).

     

Si configuro el tamaño de buffers a 96, simplemente sigue leyendo 48 bytes más allá de mi matriz.

Esto se debe a que el registro de "número de datos" ( DMA1_Channel2->CNTDR ) debe ser el número de transferencias en cada pase ( 24 ), no el número de bytes en cada pase ( 24 * sizeof (uint16_t) ) o el número en todos pasa El DMA normalmente se detendría después de tantas transferencias, pero como tienes habilitado el modo circular, comenzará una nueva pasada cada vez que termine.

Las funciones de envoltura dan una falsa impresión de que puedes usar estos periféricos correctamente sin leer el manual de referencia, pero los detalles siguen siendo importantes.

    
respondido por el Ben Voigt

Lea otras preguntas en las etiquetas