如何以100 Mbps在微控制器之间传输数据

我遇到了这样的问题:我需要在两个微控制器STM32F407之间至少以100 Mbps的速度传输数据。 可能会使用以太网(MAC-to-MAC),但是麻烦的是它很忙,正是从这些数据中获取它们的...
从空闲外设来看,可能只有SPI-但只有42 Mbps。

奇怪的是,网络上没有任何准备就绪。 于是我决定实现一个并行的8位时钟寄存器。 而且-频率可以设置为10 MHz(当然,时钟本身快一倍,但是20 MHz并不复杂)-因此,在如此低的频率下,您不必担心电路板的布线。 速度将是100 Mbps。

言归正传。 通常,系统看起来像这样。 我们在发送端使用计时器,比较信号之一输出到引脚-这将是时钟信号,第二个将用于启动DMA的一个突发。

我有一条82 MHz的总线(由于较高频率下的电流消耗:),一个计时器处于相同的频率:因此,在ARR = 8的周期内,它的结果约为10 MHz(所以大约80 Mbps,好吧)。

DMA会将一个字节从存储器(当然是自动递增)直接传输到寄存器输出端口-在我的情况下,PORTE出现了-它的前8位正好适合DMA接收器地址。

在接收端,我们将在两个边沿上使用时钟信号为定时器提供时钟,周期为1,并且将使用更新信号开始DMA的转发,DMA从端口读取数据(再次进入PORTE端口)并以自动递增的方式写入内存。

现在,仍然可以正确配置所有内容(下面的代码)并运行。 两端的终止取决于DMA的中断。

但是,为了完整起见,您当然需要在代码中包括检查传输延迟和错误处理,但是我忽略了这一点。

在下面的代码中,TIM8计时器使用CC2通道输出信号-看看会发生什么。

volatile int transmit_done; volatile int receive_done; void DMA2_Stream1_IRQHandler(void) { TIM8->CR1 &= ~TIM_CR1_CEN; DMA2->LIFCR |= 0b1111 << 8; receive_done = 1; } void DMA2_Stream4_IRQHandler(void) { TIM1->CR1 &= ~TIM_CR1_CEN; TIM1->EGR |= TIM_EGR_BG; DMA2->HIFCR |= 0b1111101; transmit_done = 1; } void ii_receive(uint8_t *data, int len) { GPIOE->MODER = (GPIOE->MODER & 0xFFFF0000) | 0x0000; DMA2_Stream1->PAR = (uint32_t) &(GPIOE->IDR); DMA2_Stream1->M0AR = (uint32_t) data; DMA2_Stream1->NDTR = len; TIM8->CNT = 0; TIM8->BDTR |= TIM_BDTR_MOE; receive_done = 0; DMA2_Stream1->CR |= DMA_SxCR_EN; TIM8->CR1 |= TIM_CR1_CEN; } void ii_transmit(uint8_t *data, int len) { GPIOE->MODER = (GPIOE->MODER & 0xFFFF0000) | 0x5555; DMA2_Stream4->PAR = (uint32_t) &(GPIOE->ODR); DMA2_Stream4->M0AR = (uint32_t) data; DMA2_Stream4->NDTR = len; TIM1->CNT = 6; transmit_done = 0; DMA2_Stream4->CR |= DMA_SxCR_EN; TIM1->SR |= TIM_SR_BIF; TIM1->BDTR |= TIM_BDTR_MOE; TIM1->CR1 |= TIM_CR1_CEN; } // tx: TIM1 CH4 on DMA2/stream4/channel6, CH1 on output clock in PE9 // rx: TIM8 CH2 on DMA2/stream3/channel7, CH1 on input clock in PC6 void ii_init() { __HAL_RCC_GPIOC_CLK_ENABLE(); __HAL_RCC_GPIOE_CLK_ENABLE(); __HAL_RCC_TIM1_CLK_ENABLE(); __HAL_RCC_TIM8_CLK_ENABLE(); __HAL_RCC_TIM2_CLK_ENABLE(); __HAL_RCC_DMA2_CLK_ENABLE(); GPIOC->MODER |= (0b10 << GPIO_MODER_MODE6_Pos) | (0b10 << GPIO_MODER_MODE7_Pos); GPIOC->PUPDR |= (0b10 << GPIO_PUPDR_PUPD7_Pos); GPIOC->AFR[0] |= (GPIO_AF3_TIM8 << 24) | (GPIO_AF3_TIM8 << 28); GPIOE->MODER |= (0b10 << GPIO_MODER_MODE9_Pos); GPIOE->OSPEEDR |= GPIO_OSPEEDER_OSPEEDR9 | 0xFFFF; GPIOE->AFR[1] |= GPIO_AF1_TIM1 << 4; GPIOE->PUPDR |= (0b10 << GPIO_PUPDR_PUPD9_Pos); TIM1->ARR = 8; TIM1->CCR1 = 5; TIM1->CCR4 = 1; TIM1->EGR |= TIM_EGR_CC4G; TIM1->DIER |= TIM_DIER_CC4DE; TIM1->CCMR1 |= (0b110 << TIM_CCMR1_OC1M_Pos); TIM1->CCER |= TIM_CCER_CC1E; TIM1->EGR |= TIM_EGR_BG; TIM8->ARR = 1; TIM8->CCR2 = 1; TIM8->EGR |= TIM_EGR_UG; TIM8->DIER |= TIM_DIER_UDE; TIM8->SMCR |= (0b100 << TIM_SMCR_TS_Pos) | (0b111 << TIM_SMCR_SMS_Pos); TIM8->CCMR1 = (0b01 << TIM_CCMR1_CC1S_Pos) | (0b110 << TIM_CCMR1_OC2M_Pos); TIM8->CCER |= (0b11 << TIM_CCER_CC1P_Pos) | TIM_CCER_CC2E; DMA2_Stream1->CR = DMA_CHANNEL_7 | DMA_PRIORITY_VERY_HIGH | DMA_MINC_ENABLE | (0b00 << DMA_SxCR_DIR_Pos) | DMA_SxCR_TCIE | DMA_SxCR_TEIE | DMA_SxCR_DMEIE; DMA2_Stream1->FCR |= DMA_FIFOMODE_ENABLE; DMA2_Stream4->CR = DMA_CHANNEL_6 | DMA_PRIORITY_VERY_HIGH | DMA_MINC_ENABLE | (0b01 << DMA_SxCR_DIR_Pos) | DMA_SxCR_TCIE | DMA_SxCR_TEIE | DMA_SxCR_DMEIE; DMA2_Stream4->FCR |= DMA_FIFOMODE_ENABLE; HAL_NVIC_SetPriority(DMA2_Stream1_IRQn, 0, 0); HAL_NVIC_EnableIRQ(DMA2_Stream1_IRQn); HAL_NVIC_SetPriority(DMA2_Stream4_IRQn, 0, 0); HAL_NVIC_EnableIRQ(DMA2_Stream4_IRQn); } 

对于测试,使用了同一块板,只是将PE9时钟输出连接到PC6输入。 主循环如下所示:

  ii_receive(rdata, 256); ii_transmit(tdata, 256); while (!transmit_done); while (!receive_done); 

根据结果​​:数据完美发送30-31微秒而没有丢失。 信号看起来像这样:


这里,白色是TIM8定时器的输出,红色是时钟信号(TIM1),橙色是数据的最低有效位(0-1-0-1 -...)。

我对此不满意的是,您无法通过GPIO输入的中断来启动DMA,而您必须使用计时器。 也许有人会告诉你另一种方式?

PS作为最新实验的结果,事实证明,将频率提高到168 MHz可以自然地使速度提高2倍,并且数据在14微秒(即150 Mbps)中传输,但是当主计时器降低到7以下时,接收端开始出现毛刺-计时器没有时间TIM8。 在7时它仍然可以工作,但是在6时它已经消失了,毕竟是200 Mbps ...

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


All Articles