Добрый день всем! Такого еще никогда не было, и вот оно снова.
С моим последняя статья Прошло достаточно времени, но оно ставит новые задачи.
И если раньше я передавал данные со скоростью 100 Мбит/с, то теперь мне пришлось стремиться к 1600 Мбит/с.
На КДПВ – герое нашего романа – он умел читать данные с такой скоростью!
Итак, мой следующий проект требовал чтения 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 МГц.
Остается только проверить практически.
И конечно же нужно разместить массивы data и data2 в необходимый сегмент памяти, делается это так: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;
__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 Мбит/с.
Теги: #Программирование микроконтроллеров #Сделай сам или Сделай сам #микроконтроллер
-
Плесснер, Хельмут
19 Oct, 24 -
Hotspot — Примечания На Полях
19 Oct, 24 -
Сохранение Реестра Своими Руками
19 Oct, 24 -
Удобный Для Пальцев Интерфейс
19 Oct, 24 -
Снижаем Битрейт Подкастов Онлайн
19 Oct, 24 -
Псевдо 3D Эффект
19 Oct, 24