Кто любит RISC в жизни, заходим, не стесняемся.
Ответить

EFM32 / EFR32 вопросы про LDMA

Ср окт 27, 2021 22:10:15

Не будет ли многоуважаемое сообщество дать мне пинка в нужном направлении, чтобы разобраться, как им пользоваться.

Простенький трансфер я делать научился: из памяти в регистр и обратно байтики пересылаю без проблем по запросу устройства.
А теперь хочу пересылать данные по таймеру. Но у меня ничего не получается.

Т.е. приходит сигнал от таймера по переполнению, и мне надо послать одно 16-битное слово.


И ничего не происходит. Если я включаю прерывание от таймера по переполнению и делаю посылку в прерывании - всё работает (т.е. предполагаю USART и TIMER сконфигурированы правильно. А вот подключая LDMA - ничего нет

Re: EFM32 / EFR32 вопросы про LDMA

Пт окт 29, 2021 09:52:37

Итак, после недельного слепого тыканья по даташитам и тырнету задачка решена.

Проблемы были следующие:
Как пересылать 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 сделает только один трансфер и следующий будет только в следующем цикле таймера.
Ответить