| Форум РадиоКот https://radiokot.ru/forum/ |
|
| EFM32 / EFR32 вопросы про LDMA https://radiokot.ru/forum/viewtopic.php?f=59&t=179346 |
Страница 1 из 1 |
| Автор: | uldemir [ Ср окт 27, 2021 22:10:15 ] |
| Заголовок сообщения: | EFM32 / EFR32 вопросы про LDMA |
Не будет ли многоуважаемое сообщество дать мне пинка в нужном направлении, чтобы разобраться, как им пользоваться. Простенький трансфер я делать научился: из памяти в регистр и обратно байтики пересылаю без проблем по запросу устройства. А теперь хочу пересылать данные по таймеру. Но у меня ничего не получается. Т.е. приходит сигнал от таймера по переполнению, и мне надо послать одно 16-битное слово. СпойлерКод: volatile uint16_t videobuff[4]; LDMA_TransferCfg_t dispXferCfg = LDMA_TRANSFER_CFG_PERIPHERAL(ldmaPeripheralSignal_TIMER0_UFOF); LDMA_Descriptor_t disp_descriptor = LDMA_DESCRIPTOR_SINGLE_M2P_BYTE(videobuff, &(USART0->TXDOUBLE), sizeof(videobuff)/sizeof(videobuff[0]) ); void InitTransfer(void) { // USART0 сконфигурирован... TIMER0->CFG = TIMER_CFG_MODE_UP | TIMER_CFG_PRESC_DIV2 | TIMER_CFG_SYNC_DISABLE | TIMER_CFG_DISSYNCOUT_EN ; TIMER_DEVICE->EN = TIMER_EN_EN; timer_freq = CMU_ClockFreqGet(cmuCLOCK_TIMER0); divider = (usart_freq/(2 * 4* 125)) - 1; // 500us TIMER0->TOP = divider; // Enable LDMA clock CMU_ClockEnable(cmuClock_LDMA, true); LDMA_Init_t init = LDMA_INIT_DEFAULT; // Initialize LDMA LDMA_Init(&init); // Enable LDMA Interrupt NVIC_ClearPendingIRQ(LDMA_IRQn); NVIC_SetPriority(LDMA_IRQn, 3); NVIC_EnableIRQ(LDMA_IRQn); disp_descriptor.xfer.size = ldmaCtrlSizeHalf; disp_descriptor.xfer.blockSize = 1; LDMA_StartTransfer(DYNAMIC_DISPLAY_LDMA_CH, &dispXferCfg, &disp_descriptor); TIMER_DEVICE->CMD = TIMER_CMD_START; } И ничего не происходит. Если я включаю прерывание от таймера по переполнению и делаю посылку в прерывании - всё работает (т.е. предполагаю USART и TIMER сконфигурированы правильно. А вот подключая LDMA - ничего нет |
|
| Автор: | uldemir [ Пт окт 29, 2021 09:52:37 ] |
| Заголовок сообщения: | Re: EFM32 / EFR32 вопросы про LDMA |
Итак, после недельного слепого тыканья по даташитам и тырнету задачка решена. Проблемы были следующие: Как пересылать 16 бит слова, если нет темплейта дескриптора для Half, а есть только для Byte? Надо не стесняться менять поля. Т.е. берется темплейт LDMA_Descriptor_t disp_descriptor = LDMA_DESCRIPTOR_SINGLE_M2P_BYTE() и потом делаем его модификацию Код: disp_descriptor.xfer.size = ldmaCtrlSizeHalf; Теперь обмен будет не байтами, а 16 битными словами.Как зациклить трансфер? Есть, конечно, в темплейте поле loopCount, но это даёт только конечное число повторов. это не то. Во втором воркшопе в прерывании по окончании трансфера просто всё переинициализировалось по новой - можно, но не изящно. Правильное решение - использовать букву "L" в слове LDMA - Linked. Этот DMA можно связать с другим трансфером, т.е. по окончании этого трансфера начинается другой, который может быть либо следующий в списке, либо еще где. Тут же оказалось, можно указать следующим самого себя используя Relative Link и этот Relative указать как 0. Код: LDMA_Descriptor_t disp_descriptor = LDMA_DESCRIPTOR_LINKREL_M2P_BYTE(videobuff, // откуда передавать данные &(USART_DEVICE->TXDOUBLE), // куда передавать данные sizeof(videobuff)/sizeof(videobuff[0]), // сколько передавать данных 0); // относительный указатель на следующий дескриптор И кстати, если не нужно, чтобы по окончании каждого трансфера в данном случае вызывалось прерывание, в дескрипторе поле doneIfs можно обнулить. Как передать один трансфер за один запрос? С этим я долго боролся, но решение оказалось простым. То что у меня запрос DMA делал таймер - это правильно. Но, если таймер делает запрос, то он не будет снят, пока не будет прочитан какой-нибудь регистр того же таймера! А так как передача идёт из памяти в USART - таймер, в данном случае не читается и запрос не снимается и передача продолжается и продолжается. Оказывается, запрос можно снять автоматически, установив в конфиге таймера бит DMACLRACT. Тогда по событию возникнет запрос и он сразу же снимется. Таким образом LDMA сделает только один трансфер и следующий будет только в следующем цикле таймера. |
|
| Страница 1 из 1 | Часовой пояс: UTC + 3 часа |
| Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group http://www.phpbb.com/ |
|


