Как стать автором
Обновить

Комментарии 8

Что то очень заумное использование DMA.
Я бы сделал запрос одиночных передач по DMA от Таймера 1.
В данном случае Таймер только генерирует запросы, а передачи идут из ОЗУ в DAC.

Запрос по переполнению Таймера, один отсчет ушел в DAC
Следующий запрос, еще один отсчет ушел в DAC и так далее по таблице 1024 раза (ну или 100 как вы любите).
После обнуления таблицы процессор ее регенерит за время между запросами от Таймера.
Изменяя частоту переполнения таймера можно легко выставлять битрейт.

Кстати, подобный пример уже делали для кого-то, и в службе тех поддержки он должен быть.
Обратитесь в support@mi....dr.ru

Для меня, видимо… Ссылку указал. То, что вы описали, будет представлено в следующей статье. Хочется показать сначала реализацию от «что первое приходит на ум» до «как надо».
Для того, чтобы сделать то, что вы описали — нужно уметь работать с таймером. А пока что у меня не было такого урока. Следующим будет именно он.
Тоже что-то подобное делал, только на PIC24. Там еще были отдельные векторы прерываний для случая, когда DMA прошел половину буфера, и случая, когда DMA закончил передачу. Можно было, получив INT, что половина пройдена, посчитать амплитуду\фазу для следующего периода синуса (DMA при этом продолжает выдавать вторую часть синуса), а получив сигнал об окончании текущего периода, перезарядить DMA на новую выдачу. Тут такого нет?
ЗЫ: а почему один из хабов статьи — Objective C?
Тут такое есть (сказали ниже).
ЗЫ: а почему один из хабов статьи — Objective C?

Я вроде бы на C пишу… Значит и этот тег тоже выбрать следовало. Разве нет?
Это чисто Эппловское расширение Си. Между С и C# куда больше общего, чем между С и Objective C…
Спасибо, изменю.
В структуре DMA этого процессора есть возможность работы с «половинками» синусоиды (режим пинг-понг).
Ниже инициализация DMA-ЦАП для такого подхода с использованием библиотек Миландр.
За основу взят код примера из этой библиотеки.

DMA_ChannelInitTypeDef DMA_InitStr_TIM1;
DMA_CtrlDataInitTypeDef DMA_PriCtrlStr_TIM1;
DMA_CtrlDataInitTypeDef DMA_AltCtrlStr_TIM1;
........

// ФОРМИРОВАНИЕ СИНУСОИДЫ - ДМА И ЦАП
DMA_DeInit_();
DMA_StructInit(&DMA_InitStr_TIM1);
/* Set Primary Control Data */
DMA_PriCtrlStr_TIM1.DMA_SourceBaseAddr = (uint32_t)Sine12bit1;
DMA_PriCtrlStr_TIM1.DMA_DestBaseAddr = (uint32_t)(&(MDR_DAC->DAC2_DATA));
DMA_PriCtrlStr_TIM1.DMA_SourceIncSize = DMA_SourceIncHalfword;
DMA_PriCtrlStr_TIM1.DMA_DestIncSize = DMA_DestIncNo;
DMA_PriCtrlStr_TIM1.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;
DMA_PriCtrlStr_TIM1.DMA_Mode = DMA_Mode_PingPong;
DMA_PriCtrlStr_TIM1.DMA_CycleSize = TABLE_SIN_SIZE/2;
DMA_PriCtrlStr_TIM1.DMA_NumContinuous = DMA_Transfers_1;
DMA_PriCtrlStr_TIM1.DMA_SourceProtCtrl = DMA_SourcePrivileged;
DMA_PriCtrlStr_TIM1.DMA_DestProtCtrl = DMA_DestPrivileged;

/* Set Alternate Control Data */
DMA_AltCtrlStr_TIM1.DMA_SourceBaseAddr = (uint32_t)Sine12bit2;

DMA_AltCtrlStr_TIM1.DMA_DestBaseAddr   = (uint32_t)(&(MDR_DAC->DAC2_DATA));

DMA_AltCtrlStr_TIM1.DMA_SourceIncSize = DMA_SourceIncHalfword;
DMA_AltCtrlStr_TIM1.DMA_DestIncSize = DMA_DestIncNo;
DMA_AltCtrlStr_TIM1.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;
DMA_AltCtrlStr_TIM1.DMA_Mode = DMA_Mode_PingPong;
DMA_AltCtrlStr_TIM1.DMA_CycleSize = TABLE_SIN_SIZE/2;
DMA_AltCtrlStr_TIM1.DMA_NumContinuous = DMA_Transfers_1;
DMA_AltCtrlStr_TIM1.DMA_SourceProtCtrl = DMA_SourcePrivileged;
DMA_AltCtrlStr_TIM1.DMA_DestProtCtrl = DMA_DestPrivileged;

/* Set Channel Structure */
DMA_InitStr_TIM1.DMA_PriCtrlData = &DMA_PriCtrlStr_TIM1;
DMA_InitStr_TIM1.DMA_AltCtrlData = &DMA_AltCtrlStr_TIM1;
DMA_InitStr_TIM1.DMA_Priority = DMA_Priority_High;
DMA_InitStr_TIM1.DMA_UseBurst = DMA_BurstClear;
DMA_InitStr_TIM1.DMA_SelectDataStructure = DMA_CTRL_DATA_PRIMARY;

/* Init DMA channel TIM2*/
DMA_Init(DMA_Channel_TIM1, &DMA_InitStr_TIM1);

/* Enable dma_req or dma_sreq to generate DMA request */
MDR_DMA->CHNL_REQ_MASK_CLR = DMA_SELECT(DMA_Channel_TIM1);
MDR_DMA->CHNL_USEBURST_CLR = DMA_SELECT(DMA_Channel_TIM1);

/* Enable DMA_Channel_TIM2 */
DMA_Cmd(DMA_Channel_TIM1, ENABLE);


В прерывании по таймеру заполняем размеры половинок:

   DMA_AltCtrlStr_TIM1.DMA_CycleSize = TABLE_SIN_SIZE/2;
   DMA_PriCtrlStr_TIM1.DMA_CycleSize = TABLE_SIN_SIZE/2;
   DMA_Init(DMA_Channel_TIM1, &DMA_InitStr_TIM1);


Хотелось бы использовать прерывание не таймера, а самого DMA — но там у этого кристалла оказалось много подводных камней, особенно когда DMA используется не только для канала ЦАП.
Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации

Изменить настройки темы

Истории