微控制器如何以1.6 Gbps读取数据

祝大家有美好的一天! 它从未发生过,再次在这里 。 自从我上一篇文章以来,时间已经过去了,它提出了新的挑战。 如果我以前以100 Mbps的速度传输数据,现在我不得不以1600 Mbps的速度摆动...

在KDPV(我们小说的英雄)上,他能够以这种速度读取数据!



因此,我的下一个项目要求以预先知道的数量以50 MHz的速度读取32位数据流(顺便说,这将是相同的1.6 Gbps)-设为10000。立即从一个端口使用DMA读取就好了-但是,不幸的是,没有合适的处理器(我希望有人在注释中纠正此问题),由于某种原因,所有适合速度的端口出于某种原因都是16位的。

但是,这样的琐事不会阻止我们-我们将一次从两个端口读取! 没错,在一般情况下,这不一定能达到必要的控制和同步程度,但是在我们的情况下,一切并不那么糟糕-有一个信号将在此之后将20 ns的数据保留在端口上。

而且由于我们拥有的处理器是400 MHz的stm32h750,而总线和计时器的频率是200 MHz,那么一切都应该可以解决。

看起来很简单-在信号上触发单个DMA转发。 但是只有DMA没有这种机会-端口可以发出中断,但不能控制DMA。 但是我们的处理器有一个好东西-DMAMUX,其中有一个DMA通道的事件生成器,但是该生成器有两种合适的可能性-使用EXTIT0中断或TIM12定时器的信号(对于芯片开发人员来说这是一个奇怪的幻想)。

我们没有时间进行中断-我们甚至需要大约47个时钟周期来计算为空,而我们的时钟周期为2.5 ns ...

但是要赶时间。 剩下的只是从100 MHz的外部信号上设置定时器,并将定时器的长度设置为1,然后TRGO输出将触发DMAMUX生成器,然后它将发出命令发送DMA,并且它将读取端口并将数据发送到内存。

但是停下来! 端口是16位的,但我们有32位。。。您可以尝试读取另一个第二个端口。。。为此,我们需要第二个DMA通道,它将占用相同的总线-也就是说,我们将有时间读取,但是我们可以没有时间将数据写入内存。 嗯,从理论上讲,该处理器具有不同类型的内存,在处理器结构的大图中,您可以看到DMA和RAM_D1内存都位于频率为200 MHz的同一条总线上。 在实践中还有待验证。

DMA1->LIFCR |= ~0; DMA1_Stream0->CR = (0b11 << DMA_SxCR_PL_Pos) | (0b01 << DMA_SxCR_MSIZE_Pos) | (0b01 << DMA_SxCR_PSIZE_Pos) | DMA_SxCR_MINC; DMA1_Stream0->M0AR = (uint32_t) data; DMA1_Stream0->PAR = (uint32_t) &(GPIOE->IDR); DMA1_Stream0->NDTR = 10000; DMA1_Stream1->CR = (0b11 << DMA_SxCR_PL_Pos) | (0b01 << DMA_SxCR_MSIZE_Pos) | (0b01 << DMA_SxCR_PSIZE_Pos) | DMA_SxCR_MINC; DMA1_Stream1->M0AR = (uint32_t) data2; DMA1_Stream1->PAR = (uint32_t) &(GPIOD->IDR); DMA1_Stream1->NDTR = 10000; DMAMUX1_Channel0->CCR = DMAMUX_CxCR_EGE | (1); DMAMUX1_Channel1->CCR = DMAMUX_CxCR_EGE | (2); DMAMUX1_RequestGenerator0->RGCR = DMAMUX_RGxCR_GE | (0b01 << DMAMUX_RGxCR_GPOL_Pos) | (7); DMAMUX1_RequestGenerator1->RGCR = DMAMUX_RGxCR_GE | (0b01 << DMAMUX_RGxCR_GPOL_Pos) | (7); DMA1_Stream0->CR |= DMA_SxCR_EN; DMA1_Stream1->CR |= DMA_SxCR_EN; TIM12->CNT = 0; TIM12->CCMR1 |= TIM_CCMR1_CC2S_0; TIM12->CR2 = (0b010 << TIM_CR2_MMS_Pos); TIM12->CR1 |= TIM_CR1_CEN; while (DMA1_Stream0->NDTR) i++; TIM12->CR1 &= ~TIM_CR1_CEN; 

当然,您需要将data和data2数组放置在所需的内存段中,方法如下:

 __attribute__((section(".dma_buffer"))) uint16_t data[10240],data2[10240]; 

并在链接器文件中指示:

 .dma_buffer : { *(.dma_buffer) } >RAM_D1 

首先要检查的是愚蠢的复制
CPU(仍为400 MHz):

  uint16_t * ptr = cpudata; volatile uint16_t * src = &(GPIOE->IDR); volatile uint16_t * src2 = &(GPIOD->IDR); for (register int i = 0; i < 10000; i++) { *ptr++ = *src; *ptr++ = *src2; } 

为了进行验证,cpudata数据位于不同的内存中,最快的内存(当然,只有64K)是最快的内存(也是400 MHz)DTCMRAM。

结果


在测试期间,事实证明,借助CPU,可以从两个端口以12.5 MHz的速度读取。 并从一个25 MHz。 因此,该选项不起作用...

在DMA和这样的母亲的帮助下 TIM12能够以50 MHz的速度成功读取,并且在几个小时内没有进行任何错误测试。 读取了两个端口,但尚无法测量第二个DMA滞后的读数...

因此,在我的情况(略微退化)中,我设法以32x50 = 1600 Mbps的速度实现了信息传输到stm32h750处理器的速度。

Source: https://habr.com/ru/post/zh-CN467459/


All Articles