Как Микроконтроллер Может Читать Данные Со Скоростью 1,6 Гбит/С

Добрый день всем! Такого еще никогда не было, и вот оно снова.

С моим последняя статья Прошло достаточно времени, но оно ставит новые задачи.

И если раньше я передавал данные со скоростью 100 Мбит/с, то теперь мне пришлось стремиться к 1600 Мбит/с.

На КДПВ – герое нашего романа – он умел читать данные с такой скоростью!

Как микроконтроллер может читать данные со скоростью 1,6 Гбит/с

Итак, мой следующий проект требовал чтения 32-битного потока данных на скорости 50 МГц (это, кстати, будут те же 1,6 Гбит/с) в известном заранее количестве — пусть это будет 10 000. Было бы просто здорово читать сразу по DMA с одного порта - но, к сожалению, подходящих процессоров не нашлось (надеюсь, кто-то поправит этот вопрос в комментариях), почему-то все подходящие по скорости порты 16-битные.

Но такая мелочь нас не остановит — мы будем читать сразу с двух портов! Правда, в общем случае не всегда получится сделать это с необходимой степенью контроля и синхронизации, но в нашем случае все не так печально — есть сигнал, после которого данные будут оставаться на порту в течение 20 нс.

.

А поскольку процессор у нас stm32h750 на 400 МГц, а шина и таймеры на 200 МГц, то всё должно получиться.

Казалось бы, простой случай запустить одну передачу DMA по сигналу.

Но у DMA такой возможности нет — порт может выдать прерывание, но не может управлять DMA. Но у нашего процессора есть хорошая штука - DMAMUX, у которого есть генератор событий для канала DMA, но у этого генератора есть два подходящих варианта - либо использовать прерывание EXTIT0, либо сигнал от таймера TIM12 (это была странная фантазия разработчиков чипа ).

Прерывание мы не успеем вовремя — даже пустая обработка требует около 47 тактов, а наш такт составляет 2,5 нс… Но мы успеем вовремя.

Остается только тактировать таймер от внешнего сигнала 100 МГц, установить длину таймера в 1 и на его выходе TRGO сработает генератор DMAMUX, а затем он выдаст команду на передачу DMA и прочитает порт и отправить данные в память.

Но стоп! Порт 16-битный, а у нас 32. Ну можно попробовать прочитать второй порт. Но для этого нужен второй канал DMA, и он тоже будет занимать ту же шину - т.е.

прочитать мы не успеем, а записать данные в память можем не успеть.

Ну теоретически у этого процессора разные типы памяти, и на большой картинке структуры процессора видно, что и память DMA, и RAM_D1 сидят на одной шине с частотой 200 МГц.

Остается только проверить практически.

  
  
  
   

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

Для проверки ну как первый вариант было реализовано просто тупое копирование с помощью Процессор (все еще 400 МГц):

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 были помещены в другую память; самой быстрой (ну ее всего 64К) стала сверхбыстрая память (тоже 400 МГц) DTCMRAM.

Полученные результаты

В ходе тестирования выяснилось, что с помощью ЦП можно читать на скорости 12,5 МГц с двух портов.

И 25 МГц с одного.

Так что этот вариант не работает. С помощью DMA и такой-то матери TIM12 смог успешно читать на скорости 50 МГц, и за несколько часов тестирования ошибок не было.

Оба порта были читабельны, но замерить, насколько лагает чтение по второму DMA, пока не удалось.

Вот и в моем (немного вырожденном) случае мне удалось добиться скорости передачи данных на процессор stm32h750 на скорости 32х50=1600 Мбит/с.

Теги: #Программирование микроконтроллеров #Сделай сам или Сделай сам #микроконтроллер

Вместе с данным постом часто просматривают:

Автор Статьи


Зарегистрирован: 2019-12-10 15:07:06
Баллов опыта: 0
Всего постов на сайте: 0
Всего комментарий на сайте: 0
Dima Manisha

Dima Manisha

Эксперт Wmlog. Профессиональный веб-мастер, SEO-специалист, дизайнер, маркетолог и интернет-предприниматель.