动态 DMA 传输

Dav*_*vis 3 c stm32 dma

我有以下 snipper 来生成声音,在 while 循环中,我想动态更改它,以便在声音生成过程中创建不同频率的声音。

for(uint16_t i = 0; i < sample_N; i++)
{
    dataI2S[i*2] = i*5000; 
    dataI2S[i*2 + 1] =i*5000; 
} 

HAL_I2S_Transmit_DMA(&hi2s3, (uint16_t *)dataI2S, sample_N*2);

while (1)
{
    ps = HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_0);
    HAL_I2S_Transmit_DMA(&hi2s3, (uint16_t *)dataI2S, sample_N*b);

    b++;
    if (b == 5)
        b = 1;

    if(ps){
        generate();
        HAL_GPIO_WritePin(GPIOD, GPIO_PIN_12, ps);
    } else {
        stop();
        HAL_GPIO_WritePin(GPIOD, GPIO_PIN_12, 0);   
    }
}
Run Code Online (Sandbox Code Playgroud)

它仅使用第一个 sample_N*b 值生成声音。它不会动态更改。

如何HAL_I2S_Transmit_DMA(&hi2s3, (uint16_t *)dataI2S, sample_N*b);动态更改?

void DMA1_Stream5_IRQHandler(void) {
if(x % 2 == 1)
    HAL_I2S_Transmit_DMA(&hi2s3, (uint16_t *)dataI2S, sample_N*2);
else 
    HAL_I2S_Transmit_DMA(&hi2s3, (uint16_t *)dataI2S2, sample_N2*2);
    x++;
HAL_DMA_IRQHandler(&hdma_spi3_tx);
Run Code Online (Sandbox Code Playgroud)

}

Max*_*hny 6

当您告诉控制器通过 DMA 传输数据时,它只会注册您的愿望(指令),并且在 HAL_I2S_Transmit_DMA 函数内部时不传输任何内容。

您的循环将进行多次迭代,同时控制器传输单个缓冲区(与您的代码执行并行)。

因此,在传输时告诉控制器传输新数据可能会导致副作用。

您需要注册中断处理程序,它会告诉您传输已完成。

然后您需要再次注册您的后续“愿望”以维持不间断的数据流。

通常在控制器传输数据时更改缓冲区中的数据是没有意义的。通常我们使用两个缓冲区来传输真实数据:

  • 在 buffer1 中准备数据
  • 将缓冲区 1 移交给控制器进行传输
  • 在缓冲区 2 中准备数据,而控制器从缓冲区 1 传输数据
  • 当中断告诉您 buffer1 的传输完成时,您告诉控制器使用 buffer2
  • 当它从 bugger2 传输数据时,您再次在 buffer1 中准备数据
  • 等等

您可以从中断处理程序设置全局标志并在循环中检查它(并从您的循环启动后续 tx)或使用消息队列将消息从中断处理程序传递到您的循环中。

static void MX_I2S3_Init(void) {
    ...some code
    hdma_spi3_tx.Instance = DMA1_Stream0;
    HAL_NVIC_EnableIRQ(DMA1_Stream0_IRQn);
}

void DMA1_Stream0_IRQHandler(void) {
    HAL_GPIO_WritePin(GPIOD, GPIO_PIN_14, 1);
}
Run Code Online (Sandbox Code Playgroud)