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