¿Está restringida la dirección de destino DMA del STM32?

1

Estoy usando stm32f446 y me gustaría usar la solicitud TIM4_CH2 con el modo DMA1 en Memory-to-peripheral para transferir datos de una matriz al ODR (registro de datos de salida) de un GPIO puerto.

Por alguna razón, solo funciona con algunas direcciones de destino (y no con la dirección &GPIOx->ODR ), incluso a través de el manual de referencia indica en 9.3.6 Origen, Destino y modos de transferencia :

  

Tanto las transferencias de origen como de destino pueden direccionar periféricos y memorias en el área completa de 4 GB, en direcciones comprendidas entre 0x0000 0000 y 0xFFFF FFFF

¿Hay alguna otra restricción que deba tener en cuenta?

HAL_TIM_OC_Start(&htim4, TIM_CHANNEL_2);


uint16_t buffer[] = {1,2,3,4,5};
uint32_t dataLength = sizeof(buffer)/sizeof(buffer[0]);
uint32_t srcAddress = (uint32_t) buffer;
//uint32_t dstAddress = (uint32_t) &(TIM4->CCR2); // Works
//uint32_t dstAddress = (uint32_t) &(TIM4->CCR4); // Works
//uint32_t dstAddress = (uint32_t) &(TIM5->CCR4); // Doesn't work
uint32_t dstAddress = (uint32_t) &(GPIOC->ODR); // Doesn't work


HAL_DMA_Start_IT(&hdma_tim4_ch2, srcAddress, dstAddress, dataLength);
__HAL_TIM_ENABLE_DMA(&htim4, TIM_DMA_CC2);

El código de inicialización DMA:

hdma_tim4_ch2.Instance = DMA1_Stream3;
hdma_tim4_ch2.Init.Channel = DMA_CHANNEL_2;
hdma_tim4_ch2.Init.Direction = DMA_MEMORY_TO_PERIPH;
hdma_tim4_ch2.Init.PeriphInc = DMA_PINC_DISABLE;
hdma_tim4_ch2.Init.MemInc = DMA_MINC_ENABLE;
hdma_tim4_ch2.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD;
hdma_tim4_ch2.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD;
hdma_tim4_ch2.Init.Mode = DMA_NORMAL;
hdma_tim4_ch2.Init.Priority = DMA_PRIORITY_LOW;
hdma_tim4_ch2.Init.FIFOMode = DMA_FIFOMODE_DISABLE;
HAL_DMA_Init(&hdma_tim4_ch2);

__HAL_LINKDMA(htim_base,hdma[TIM_DMA_ID_CC2],hdma_tim4_ch2);

Configuración del temporizador:

TIM_ClockConfigTypeDef sClockSourceConfig;
TIM_MasterConfigTypeDef sMasterConfig;
TIM_OC_InitTypeDef sConfigOC;

htim4.Instance = TIM4;
htim4.Init.Prescaler = 0;
htim4.Init.CounterMode = TIM_COUNTERMODE_UP;
htim4.Init.Period = 72;
htim4.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
HAL_TIM_Base_Init(&htim4);

sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
HAL_TIM_ConfigClockSource(&htim4, &sClockSourceConfig);

HAL_TIM_OC_Init(&htim4);

sMasterConfig.MasterOutputTrigger = TIM_TRGO_OC2REF;
sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
HAL_TIMEx_MasterConfigSynchronization(&htim4, &sMasterConfig);

sConfigOC.OCMode = TIM_OCMODE_TOGGLE;
sConfigOC.Pulse = 0;
sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH;
sConfigOC.OCFastMode = TIM_OCFAST_DISABLE;
HAL_TIM_OC_ConfigChannel(&htim4, &sConfigOC, TIM_CHANNEL_2);
    
pregunta someonr

1 respuesta

4

Las direcciones DMA están restringidas por la arquitectura de memoria (consulte el Capítulo 2, Arquitectura de bus y memoria en reference manual ). La siguiente figura del manual de referencia ilustra el problema del uso de DMA1:

El problema se puede resolver simplemente utilizando DMA2 (y otra solicitud de acuerdo con la tabla de asignación de solicitudes DMA2). P.ej. DMA2 con la solicitud del canal 1 del temporizador solo funcionará bien:

HAL_TIM_OC_Start(&htim1, TIM_CHANNEL_1);

uint16_t buffer[] = {0,1,2,4,8,16,32,64,128,256,512,1024,2048};
uint32_t dataLength = sizeof(buffer)/sizeof(buffer[0]);
uint32_t srcAddress = (uint32_t) buffer;
uint32_t dstAddress = (uint32_t) &(GPIOC->ODR);

HAL_DMA_Start_IT(&hdma_tim1_ch1, srcAddress, dstAddress, dataLength);
__HAL_TIM_ENABLE_DMA(&htim1, TIM_DMA_CC1);
    
respondido por el someonr

Lea otras preguntas en las etiquetas