STM32 SRAM 到 DMA GPIO 引脚

电器工程 stm32 DMA
2022-01-08 10:15:02

我希望将大量数据传输到同一个端口上的 8 个输出引脚。例如,一个 500 元素的 8 位数组,其中每个元素的每一位代表引脚状态。因此需要 500 次独立转移到港口。

我一直在查看 ST 的示例,但似乎没有一个这样做。似乎有很多“DMA 到 PWM”示例,它们传输到连接有定时器的引脚,但这对我没有用,因为我想传输到整个端口。我该怎么做?有没有类似的例子可以根据我的需要进行修改?

谢谢

1个回答

简短的介绍:

定时器以所需速度触发 DMA,DMA 将数据写入 GPIO 输出寄存器。

详细描述:

  1. 将选定的 GPIO 端口输出状态准备为默认状态低/高
  2. 配置选定的GPIO端口PX输出推挽/开漏
  3. 将任何定时器配置为所需的 GPIO 端口更新周期
  4. 配置选定的 DMA 并将其链接到选定的 TIM
  5. 为 DMA IRQ 配置回调:HT、TC、ERR
  6. 启用 DMA 以将数据缓冲区、缓冲区长度写入选定的 PX->ODR
  7. 启用 TIM 以生成 DMA 事件
  8. 运行 TIM
  9. 在回调中处理 DMA 状态并根据需要控制 TIM

代码空白:

所有代码都在此处编写且未经测试,它可能包含简单的错误,例如在 HAL 宏或函数调用中使用变量而不是指针。

GPIO_InitTypeDef GPIO_InitStruct;
TIM_HandleTypeDef htim1;
DMA_HandleTypeDef hdma_tim1_uev;

/* 1 (Port GPIOA) */
__HAL_RCC_GPIOA_CLK_ENABLE();
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_All, GPIO_PIN_RESET);

/* 2 (Port GPIOA) */
GPIO_InitStruct.Pin = GPIO_PIN_All;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

/* 3 (Timer TIM1) */
__HAL_RCC_TIM1_CLK_ENABLE();
htim1.Instance = TIM1;
htim1.Init.Prescaler = DESIRED_PRESCALER;
htim1.Init.CounterMode = TIM_COUNTERMODE_UP;
htim1.Init.Period = DESIRED_PERIOD;
htim1.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
htim1.Init.RepetitionCounter = 0;
HAL_TIM_Base_Init(&htim1)

/* 4 (DMA1 Channel2) */
__HAL_RCC_DMA1_CLK_ENABLE();
hdma_tim1_uev.Instance = DMA1_Channel2;
hdma_tim1_uev.Init.Direction = DMA_MEMORY_TO_PERIF;
hdma_tim1_uev.Init.PeriphInc = DMA_PINC_DISABLE;
hdma_tim1_uev.Init.MemInc = DMA_MINC_ENABLE;
hdma_tim1_uev.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD; // 16 bits
hdma_tim1_uev.Init.MemDataAlignment = DMA_PDATAALIGN_HALFWORD;
hdma_tim1_uev.Init.Mode = DMA_NORMAL;
hdma_tim1_uev.Init.Priority = DMA_PRIORITY_LOW;
HAL_DMA_Init(&hdma_tim1_uev);
__HAL_DMA1_REMAP(HAL_DMA1_CH2_TIM1_UP);
__HAL_LINKDMA(&htim1,hdma[TIM_DMA_ID_UPDATE],hdma_tim1_uev);
HAL_NVIC_SetPriority(DMA1_Ch2_3_DMA2_Ch1_2_IRQn, 0, 0); // enable DMA IRQ
HAL_NVIC_EnableIRQ(DMA1_Ch2_3_DMA2_Ch1_2_IRQn);

/* 5 (Callbacks for DMA IRQs) */
htim->hdma[TIM_DMA_ID_UPDATE]->XferCpltCallback = data_tramsmitted_handler;
htim->hdma[TIM_DMA_ID_UPDATE]->XferErrorCallback = transmit_error_handler;

/* 6 (Enable DMA) */
HAL_DMA_Start_IT(htim1.hdma[TIM_DMA_ID_UPDATE],(uint32_t)&my_data_buf, 
    (uint32_t)&GPIOA->ODR, my_data_buf_length);

/* 7 (Enable TIM for DMA events) */
__HAL_TIM_ENABLE_DMA(&htim1, TIM_DMA_UPDATE);

/* 8 (Run TIM) */
__HAL_TIM_ENABLE(&htim1);

/* 9 (DMA IRQ callbacks) */
void data_tramsmitted_handler(DMA_HandleTypeDef *hdma)
{
    /* Stop timer */
    __HAL_TIM_DISABLE(&htim1);
    /* Reconfigure DMA */
    HAL_DMA_Start_IT(htim1.hdma[TIM_DMA_ID_UPDATE],(uint32_t)&my_data_buf, 
        (uint32_t)&GPIOA, my_data_buf_length);
    /* Start timer for new data transmit */
    __HAL_TIM_ENABLE(&htim1);
}

void transmit_error_handler(DMA_HandleTypeDef *hdma)
{
    /* Stop timer */
    __HAL_TIM_DISABLE(&htim1);
    /* Some error handle ? */
}