我在一本书上读到这个:
如果系统中的 DMA 控制器以 5 MHz 的最大速率运行,而我们仍然使用 100 ns 内存,则最大传输速率为 5 MHz,因为 DMA 控制器比内存慢。在许多情况下,DMA 控制器会在发生 DMA 传输时降低系统速度。
我认为 DMA 控制器的全部原因是加快速度,而不是减慢速度。那么,如果它减慢了速度,它有什么帮助呢?为什么不让 DMA 控制器和内存一样快?
目前,我正在为 Linux 的 PCIe 驱动程序添加 DMA。当我阅读文档时,它通过使用 API 提到了一致或连贯的内存:
pci_set_consistent_dma_mask(...)
Run Code Online (Sandbox Code Playgroud)
但从来没有真正谈论过为什么要使用它或它的作用。似乎提到调用该函数以获得最佳实践和未来证明。我能收集到的最好结果是一致的 DMA 内存没有缓存效果,并且一旦正确设置(假设我正确读取),内存就会在设备(FPGA)和 CPU 之间写入,无需任何软件/驱动程序干预。所以我的问题是:
我想使用动态分配的数组来实现队列。这带来了一些我不确定如何处理的问题。如何检查队列是否为空?如何在一个时刻跟踪队列中的元素数量?
对于第二个问题,我想我可以创建一个变量来跟踪队列中随时更新的元素数量realloc()。不过,我欢迎其他建议。
如果您还有其他我应该考虑的考虑事项,请提出。
我有一个想要更新的循环 DMA。完成一半时是否可以中断(这样我可以更新前半部分)?
我想知道当设备的 DMA 控制器正在进行内存操作时,CPU 可以处理/执行什么类型的操作,以提高并发级别?如果 CPU 缓存/寄存器为空,如何在不交错 DMA 的情况下获取另一条指令
谢谢
我想知道如果 2 个 CPU 内核同时尝试访问内存(通过内存控制器),“一般情况下”如何处理内存访问?实际上,当内核和支持 DMA 的 IO 设备尝试以相同的方式访问时,这同样适用。
我认为,内存控制器足够智能,可以利用地址总线并同时处理这些请求,但是我不确定当它们尝试访问同一位置或 IO 操作垄断地址总线并且没有 CPU 空间时会发生什么继续前进。
谢谢
我正在使用 stm32f3 发现板和来自 CubeMX 的 HAL。我正在尝试在 ADC4 上使用 2 个 ADC 通道。我在循环模式下配置了 DMA。在 main 中的主循环之前,我调用:
HAL_ADC_Start_DMA(&hadc4, DMA_adc4_buffer, 16);
Run Code Online (Sandbox Code Playgroud)
我实现了功能HAL_ADC_ConvHalfCpltCallback和HAL_ADC_ConvCpltCallback. 现在奇怪的部分HAL_ADC_ConvHalfCpltCallback是:定期调用,HAL_ADC_ConvCpltCallback不是。
它告诉我,带有 DMA 传输的 ADC 运行良好。但是为什么不调用传输竞争回调?如果我用HAL_ADC_Start_IT中断函数启动ADC ,但那不是我想要的。
HAL_DMA_IRQHandler在 ST HAL 中放置断点也表明回调从未被调用。
为了完整起见,这里部分 ADC4_Init 函数:
/**Common config
*/
hadc4.Instance = ADC4;
hadc4.Init.ClockPrescaler = ADC_CLOCK_ASYNC_DIV1;
hadc4.Init.Resolution = ADC_RESOLUTION_12B;
hadc4.Init.ScanConvMode = ADC_SCAN_ENABLE;
hadc4.Init.ContinuousConvMode = ENABLE;
hadc4.Init.DiscontinuousConvMode = DISABLE;
hadc4.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE;
hadc4.Init.ExternalTrigConv = ADC_SOFTWARE_START;
hadc4.Init.DataAlign = ADC_DATAALIGN_RIGHT;
hadc4.Init.NbrOfConversion = 2;
hadc4.Init.DMAContinuousRequests = ENABLE; …Run Code Online (Sandbox Code Playgroud) 我有以下 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); …Run Code Online (Sandbox Code Playgroud) 我正在使用 STM32H743。我有一个外部时钟信号进入 GPIO 引脚,我想非常准确地测量外部时钟信号中每个上升(或下降)沿之间经过的时间。所以我进行了设置,使 TIM4 由外部时钟触发,TIM5 由内部振荡器触发。
我编写了一个 IRQ,以便每当 TIM4 触发时,都会运行一个中断来捕获 TIM5 的值。它似乎工作正常,但我想知道是否可以通过 DMA 来避免所有上下文切换并释放 CPU。基本上我想设置一个 DMA,以便每个 TIM4 事件启动一个 DMA 传输,将 TIM5 计数器值复制到某个地方的循环缓冲区。
我已经搜索了论坛和 DMA 文档,但我对定时器寄存器是否可以是有效的 DMA 源感到模糊。我在想也许我可以做这样的事情:
hDma->PAR = (uint32_t) &htim5.Instance->CNT;
hDma->M0AR = (uint32_t) myBufferPtr;
hDma->NDTR = myBufferSize;
hDma->CR |= (uint32_t)DMA_SxCR_EN;
Run Code Online (Sandbox Code Playgroud)
但我不确定这是否可行。
简短版本:我可以使用定时器的 CNT 寄存器作为 DMA 传输源吗?它会是外设到内存的传输吗?还是内存到内存的传输?我还需要其他标志来完成这项工作吗?或者不可能?或者是否有另一个 STM32 功能可以更轻松地计算脉冲之间的时间?
我正在尝试学习8237A-5 DMA控制器的细节.我一直在阅读它,现在我开始在软件的门级设计它.CS引脚为低电平有效.如果它在这里发出高信号,那么会发生什么?所有其他引脚是否都是高Z?当它获得低信号时会发生什么?