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

Фотография сигнала (сори за качество)

img008


Циклический режим работы ПДП

Примера для данного режима пока нет, но скоро будет в виде DDS генератора с плавной перестройкой частоты.


Проект целиком:

2011-05-27-STM32-StdLib-DAC-Demo



comments powered by Disqus