DAC в STM32, аппаратный генератор

По сути эта статья продолжение статьи DAC в STM32
ЦАП stm32 может аппаратно генерировать сигналы. Это может быть либо треугольный сигнал, либо шум.

Генерация возможно только при запуске преобразования ЦАП от события. При возникновении события данные суммируются с DHRx и переносятся в выходной регистр DORx, затем вычисляется следующее значение на протяжении 3 тактов. Можно выбирать амплитуду и смещение сигнала относительно 0. Смещение определяется значением в DHRx, амплитуда битами MAMPx в регистре DAC->CR.

Генератор белого шума

Генератор сделан по такой схеме:


В сдвиговом регистре по умолчанию загружено 0xAAA, сдвигается после каждого события запуска ЦАП за 3 тактовых импульса. Если регистр станет равным нулю, в него автоматически загрузиться 1. Включается путем установки битов WAVEx[1:0] в “01”. Также можно изменять амплитуду (или разрядность) путем установки битов MAMPx[3:0]



По событию ЦАП данные из LFSR (linear feedback shift register) регистра суммируется с DHRx и результат загружаются в DORx.

Инициализации выглядит так:
void DAC_init(void)
{

	RCC->APB1ENR |= RCC_APB1ENR_DACEN; 	// вкл. тактирование ЦАП

	DAC->CR |= DAC_CR_MAMP1;	// амплитуда на максимум
	DAC->CR |= DAC_CR_WAVE1_0;	// вкл. генератор шума

	DAC->CR |= DAC_CR_TEN1;	// включение запуска от события, по умолчанию таймер 6

	DAC->CR |= DAC_CR_EN1;		// вкл. ЦАП 1
}

На выходе ЦАП получаем такой сигнал


Интересная штука, если не включать ЦАП
//DAC->CR |= DAC_CR_EN1;
то генератор все-равно будет работать, только выход будет отключен. Поскольку чтение с выходного регистра дозволено то мы получаем аппаратный генератор псевдослучайных чисел.
#define STM32F10X_LD_VL
#include "stm32f10x.h"

void SystemInit (void)
{
	return;
}

void DAC_init(void);
void TIM6_init(void);
void UART_init(void);

int main (void)
{
	int i;

	DAC_init();	
	TIM6_init();
	UART_init();

	for (;;)
	{
		USART1->DR = DAC->DOR1;
		for (i=200000; i>0; i--)
			;
	}
}

void DAC_init(void)
{
	RCC->APB1ENR |= RCC_APB1ENR_DACEN; 	// вкл. тактирование ЦАП

	DAC->CR |= DAC_CR_TEN1;	// включение запуска от события, по умолчанию таймер 6
	DAC->CR |= DAC_CR_MAMP1;	// амплитуда на максимум		
	DAC->CR |= DAC_CR_WAVE1_0;	// вкл. генератор шума

	//DAC->CR |= DAC_CR_EN1;		// вкл. ЦАП 1
}

void TIM6_init(void)
{
	RCC->APB1ENR |= RCC_APB1ENR_TIM6EN;		// тактирование таймера

	TIM6->PSC = 0x000F;				// предделитель
	TIM6->ARR = 0xFF;	

	TIM6->CR2 |= TIM_CR2_MMS_1; 	// ЦАП будет запускаться по переполнению
	TIM6->CR1 |= TIM_CR1_CEN;		// запуск счета			
}							

void UART_init(void)
{
	// включаю тактирование ЮАРТ1 и порта на которам он висит
	RCC->APB2ENR |= RCC_APB2ENR_USART1EN;
	RCC->APB2ENR|= RCC_APB2ENR_AFIOEN;
	RCC->APB2ENR |= RCC_APB2ENR_IOPAEN;
		
	// настраиваю соответсв. порты на вход и выход от расшир. функций
	GPIOA->CRH &= ~GPIO_CRH_MODE9;
	GPIOA->CRH &= ~GPIO_CRH_CNF9;
	GPIOA->CRH &= ~GPIO_CRH_MODE10;
	GPIOA->CRH &= ~GPIO_CRH_CNF10;

	GPIOA->CRH |= GPIO_CRH_MODE9_1;	// выход на 2 МГц
	GPIOA->CRH |= GPIO_CRH_CNF9_1;

	GPIOA->CRH |= GPIO_CRH_CNF10_0;

	// 8 МГц/16*115200 = 4.34
	USART1->BRR = (4 << 4) + 5;
	// включаю ЮАРТ
	USART1->CR1 |= USART_CR1_UE;
	USART1->CR1 |= USART_CR1_TE;	// включил передатчик
	//USART1->CR1 |= USART_CR1_RE;	// включил приемник
}

Младшие 8 бит отправляются по ЮАРТу, после ресета видим такие данные
E8 D8 CB 3A 98 5C 2F 35 BF B0 98 86 0A EA 31 D7 31 0A ED C8 CA 98 3D B3 6F 7F 76 DF 5C 49 50 F8 D9 69 9F 77
К сожалению после следующего ресета приходит то же самое.

Генератор треугольного сигнала

Там все просто, стоит счетчик который считает до значения определенного битами MAMPx[3:0] (те же что и для генератора шума), и вниз до нуля, и так по кругу.


Включается установкой битов WAVEx[1:0] в “10”, амплитуду надо выбрать до включения ЦАП.
void DAC_init(void)
{
	RCC->APB1ENR |= RCC_APB1ENR_DACEN; 	// вкл. тактирование ЦАП

	DAC->CR |= DAC_CR_TEN1;	// включение запуска от события, по умолчанию таймер 6
	DAC->CR |= DAC_CR_MAMP1;// амплитуда на максимум							 
	DAC->CR |= DAC_CR_WAVE1_1;	// вкл. генератор треуг. сигн.

	DAC->CR |= DAC_CR_EN1;		// вкл. ЦАП 1
}




Выходной буфер

Я упоминал о выходном буфере, который по умолчанию включен и нужен чтобы к ЦАП можно было подключать хоть какую-то нагрузку без внешнего повторителя, также я говорил что он ухудшает динамические характеристики.

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

Вместо такого (то же, но с выключенным буфером)


Выключается установкой бита DAC_CR_BOFFx в регистре DAC->CR
DAC->CR |= DAC_CR_BOFF1;


P.S.
Зачем там понадобились эти генераторы трудно сказать, пишут что для создания электронной музыки и тестирования усилителей.

Комментарии (15)

RSS свернуть / развернуть
Кхм. Есть пара идеек использования как раз таки в электронной (в некотором смысле) музыке. Спасибо за информацию!
0
А на какой частоте буфер начинает гадить?
0
Забыл замерять, по расчетам то что на фотке 3.9 кГц, завтра проведу нормальные измерения.
0
У ST есть AN где улучшается разрешение АЦП путем подмешивания шума или треугольного сигнала с DAC на вход ADC. Думаю, что это основное применение встроенного генератора. Если бы для тестирования усилителей — то вшили бы встроенный синус. А так — шум и треугольник — как раз те сигналы, что нужны для увеличения разрешения АЦП.
0
  • avatar
  • OlegG
  • 05 октября 2011, 10:08
Забавно. А линк на этот апнот есть?
0
AN2668 Application note
Improving STM32F101xx and STM32F103xx ADC resolution by oversampling
0
Это было написано в аппноуте к ЦАП, про улучшение расширения АЦП тоже упоминается, но решил не писать поскольку не знаю как это работает.
0
Еще тут интересный момент то, что при установки внешнего тактирования никакой EXTI9 включать ненадо, хватает просто DAC enable. Синхроимпульсы пихаются в pin А9 и по ним уже можно менять DAC->DHR12R1.
0
  • avatar
  • basil
  • 07 октября 2011, 20:55
На семинаре по STM32L кто то ВНЕЗАПНО, когда докладчик рассказывал про ЦАП, выдал такую гипотезу:
Интересная штука, если не включать ЦАП
//DAC->CR |= DAC_CR_EN1;
то генератор все-равно будет работать, только выход будет отключен. 
Поскольку чтение с выходного регистра дозволено то мы получаем 
аппаратный генератор псевдослучайных чисел. 
Слабо верится, что он допер до этого самостоятельно прямо во время семинара, а не прочитал заранее, скорее всего здесь))
0
А больше нигде он этого не мог прочитать, приятно :)
0
Cудя по рисункам могу предположить, что скорость буфера к искажениям сигнала имеет слабое отношение. Скорее всего это буфер просто не может дотянуть выходной сигнал до минуса. В моих экспериментах по моему 0,2 вольта не дотягивал с буфером.
0
да, действительно до нуля не дотягивает, только у меня меньше напряжение было
0
а как на основе stm32 (конкретно f4 дискавери) сделать генератор тональных сигналов? про это в интернете вообще почти нет конкретных листингов, да и в целом задача не слишком ясна, особенно если только начала с этим работать. может быть, есть какие-то примеры? если знаете, конечно :)
0
Поищите информацию по DDS генераторам.
Если просто, то у вас есть таблица (или функция) синуса. Есть какая-то переменная, которая содержит фазу. Есть таймер и прерывание по таймеру. В прерывании рассчитываете значение синуса основываясь на значении фазы, выдаете значение на ЦАП. Тут же увеличиваете значение фазы. В зависимости от приращения фазы вы получаете различные частоты.
Вместо синуса можете взять косинус :)
0
Добавлю, что для синуса достаточно иметь в таблице четверть волны, остальное получается из той же таблицы элементарными преобразованиями.
0
Только зарегистрированные и авторизованные пользователи могут оставлять комментарии.