STM32-ЦАП+ПДП формируем несколько частот
Не давно в комментариях к статье о работе с ЦАП и ПДП, был вопрос о формировании нескольких частот, точнее о смене частот при использовании ЦАП+ПДП в качестве генератора (читать). Решений может быть несколько, я воспользовался самым простым.
Контроллер ПДП может работать в двух режимах: нормальном и цикличном.
В нормальном режиме после передачи установленного количества данных, контроллер “говорит” об окончании передачи и останавливается, соответственно в циклическом режиме по окончании передачи он автообновляется и начинает передачу данных заново. Так же в циклическом режиме нельзя обновить количество передаваемых данных, можно только менять адреса источника данных.
Приведенный ниже пример основан на коде описанном в статье STM32–ЦАП + ПДП.
Нормальный режим работы ПДП
Допустим нам необходимо сформировать последовательно несколько частот: 500Гц, 2000Гц и 2200Гц, с определенным интервалом обновления (формируемый сигнал синус).
Зададимся частотой дискретизации: 100 кГц.
Рассчитаем для каждой частоты один период данных:
// 200 points per period
const uint16_t sinus_500hz[] =
{ 2048, 2112, 2177, 2241, 2305, 2368, 2432, 2495, 2557, 2619, 2681, 2742, 2802,
2861, 2920, 2978, 3035, 3091, 3145, 3199, 3252, 3303, 3353, 3402, 3450,
3496, 3541, 3584, 3626, 3666, 3705, 3742, 3777, 3811, 3843, 3873, 3901,
3928, 3952, 3975, 3996, 4015, 4032, 4047, 4060, 4071, 4080, 4087, 4092,
4095, 4095, 4095, 4092, 4087, 4080, 4071, 4060, 4047, 4032, 4015, 3996,
3975, 3952, 3928, 3901, 3873, 3843, 3811, 3777, 3742, 3705, 3666, 3626,
3584, 3541, 3496, 3450, 3402, 3353, 3303, 3252, 3199, 3145, 3091, 3035,
2978, 2920, 2861, 2802, 2742, 2681, 2619, 2557, 2495, 2432, 2368, 2305,
2241, 2177, 2112, 2048, 1984, 1919, 1855, 1791, 1728, 1664, 1601, 1539,
1477, 1415, 1354, 1294, 1235, 1176, 1118, 1061, 1005, 951, 897, 844,
793, 743, 694, 646, 600, 555, 512, 470, 430, 391, 354, 319, 285, 253,
223, 195, 168, 144, 121, 100, 81, 64, 49, 36, 25, 16, 9, 4, 1, 0, 1, 4,
9, 16, 25, 36, 49, 64, 81, 100, 121, 144, 168, 195, 223, 253, 285, 319,
354, 391, 430, 470, 512, 555, 600, 646, 694, 743, 793, 844, 897, 951,
1005, 1061, 1118, 1176, 1235, 1294, 1354, 1415, 1477, 1539, 1601, 1664,
1728, 1791, 1855, 1919, 1984 };
// 50 points per period
const uint16_t sinus_2000hz[] =
{ 2048, 2305, 2557, 2802, 3035, 3252, 3450, 3626, 3777, 3901, 3996, 4060, 4092,
4092, 4060, 3996, 3901, 3777, 3626, 3450, 3252, 3035, 2802, 2557, 2305,
2048, 1791, 1539, 1294, 1061, 844, 646, 470, 319, 195, 100, 36, 4, 4,
36, 100, 195, 319, 470, 646, 844, 1061, 1294, 1539, 1791 };
// ~14 points per period
const uint16_t sinus_2200hz[] =
{ 2048, 2333, 2613, 2881, 3133, 3364, 3570, 3746, 3889, 3996, 4065, 4095, 4085,
4035, 3947, 3822, 3662, 3471, 3252, 3009, 2748, 2474, 2191, 1905, 1622,
1348, 1087, 844, 625, 434, 274, 149, 61, 11, 1, 31, 100, 207, 350, 526,
732, 963, 1215, 1483, 1763 };
Сконфигурируем ПДП на генерацию в начальный момент частоты 500Гц:
// конфигурируем ПДП1 канал 3
DMA_DeInit(DMA1_Channel3);
DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t) & DAC->DHR12R1;
DMA_InitStructure.DMA_MemoryBaseAddr = (u32) &sinus_500hz;
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;
DMA_InitStructure.DMA_BufferSize = ARRAY_LENGHT(sinus_500hz);
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;
DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;
DMA_InitStructure.DMA_Priority = DMA_Priority_High;
DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
DMA_Init(DMA1_Channel3, &DMA_InitStructure);
Смену частот (данных) будем производить по окончании передачи одного периода, для этого необходимо настроить прерывания по окончанию передачи:
DMA_ITConfig(DMA1_Channel3, DMA_IT_TC, ENABLE);
и настроить контроллер прерываний:
void interrupt_init(void)
{
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_SetVectorTable(NVIC_VectTab_FLASH, 0x0);
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0);
NVIC_InitStructure.NVIC_IRQChannel = DMA1_Channel3_IRQn;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
}
ну вот, теперь осталось только в обработчике менять частоты:
#define period_sinus_500hz 1
#define period_sinus_2000hz 2
#define period_sinus_2200hz 1
//------------------------------------------------------------------------------
void change_sinus(void)
{
DMA_Cmd(DMA1_Channel3, DISABLE);
if (count > period_sinus_500hz)
{
DMA_InitStructure.DMA_MemoryBaseAddr = (u32) &sinus_500hz;
DMA_InitStructure.DMA_BufferSize = ARRAY_LENGHT(sinus_500hz);
}
else if (count > period_sinus_500hz+ period_sinus_2000hz)
{
DMA_InitStructure.DMA_MemoryBaseAddr = (u32) &sinus_2000hz;
DMA_InitStructure.DMA_BufferSize = ARRAY_LENGHT(sinus_2000hz);
}
else
{
DMA_InitStructure.DMA_MemoryBaseAddr = (u32) &sinus_2200hz;
DMA_InitStructure.DMA_BufferSize = ARRAY_LENGHT(sinus_2200hz);
}
if (++count >= (period_sinus_500hz + period_sinus_2000hz
+ period_sinus_2200hz))
{
count = 0;
}
DMA_Init(DMA1_Channel3, &DMA_InitStructure);
DMA_Cmd(DMA1_Channel3, ENABLE);
}
Ну вот и все.
Попробуем собрать мысли.
Сразу после “включения” мк у нас начинает формироваться первый период частоты 500Гц, по окончании передачи в обработчике прерываний настраиваем ПДП на новые данные, и далее по кругу…
Количество периодов каждой частоты можно менять:
#define period_sinus_500hz 1
#define period_sinus_2000hz 2
#define period_sinus_2200hz 1
Фотография сигнала (сори за качество)
Циклический режим работы ПДП
Примера для данного режима пока нет, но скоро будет в виде DDS генератора с плавной перестройкой частоты.
Проект целиком:
comments powered by Disqus