Синтезатор частоты AD9832 на базе SPI STM32F2xx

Синтезатор частоты на DDS AD9832 + STM32F217Синтезатор частоты AD9832 довольно таки избитая тема. И тем не менее время от времени приходится возвращаться к DDS для проведения тех или иных тестов. В данном посте описан один из возможных способов управления DDS AD9832 с помощью SPI нтерфейся микроконтроллера STM32F2xx. Такой вариант достаточно удобен, поскльку позволяет посылать команды на AD9832 в виде 16 битных слов с нужным расположением битов - старшими вперед.

Прежде чем привести простейший код инициализации SPI STM32F2xx для работы с синтезатором частоты AD9832 полезно пройтись по интерактивным программам позволяющим не только рассчитать и представить код соответствующий нужной частоте, который нужно загружать в регистры частоты DDS, но и представить предполагаемый спектр сформированного с помощью DDS сигнала.

Итак простейший вариант формирования синусоидального сигнала на базе DDS AD9832 это последовательное выполнение нескольких команд по сбросу, загрузке регистров частоты и пуску DDS. Для более полной информации ниже представлена картинка со стандартной схемой подключения AD9832.

Схема подключения синтезатора частоты AD9832

C14 - 100 nF, C23 - 100 nF, R8 - 50 Ohm (выход сигнала), R7 - 300 Ohm, R6 - 3,9 k, C18 - 10 nF, C17 - 10 nF
1 - Корпус. Аналоговое и цифровое питание на девайсик можно подавать от одного источника напряжения через резисторы 50...100 Ohm

Для примера, чтобы получить выходную частоту 1 КГц - при MCLK 12,5 мГц порядок загрузки Ad9832 будет следующий:

0xF800 - сброс
0x 3300 - загрузка регистра FREQ0 REG 8 H MSBs
0x2205 - загрузка регистра FREQ0 REG 8 L MSBs
0x313e - загрузка регистра FREQ0 REG 8 H LSBs
0x202d - загрузка регистра FREQ0 REG 8 L LSBs
0xc000 - пуск синтезатора

При этом загрузка каждого слова должна сопровождаться отрицательным сигналом на входе FSYNC. В дальнейшем перестройка DDS осуществляется только загрузкой нужных регистров частоты. Поскольку выходная частота рассчитывается как:
Fout = FREG0 * Fmclk / 2^32, где
Fout - частота на выходе dds, Hz;
FREG0 - значение регистра, определяющего частоту (32 бит);
Fmclk - тактовая частота dds, Hz;
2^32 = 4 294 967 296.

Решая это простое уровнение относительно FREG0, находим:
FREG0 = (Fout / Fmclk) * 2^32;
И для частоты 1 kHz
FREG0 = (1 000 /12 500 000) * 2^32 = 343597 = 0x00053e2d.

Итак функция инициализации SPI3


void SPI3_Init(void)
{
  GPIO_InitTypeDef  GPIO_InitStructure;
  SPI_InitTypeDef   SPI_InitStructure;

  // Output HSE clock (12.5 MHz) on MCO pin (PC9) to clock the AD9832 
  RCC_MCO2Config(RCC_MCO2Source_HSE, RCC_MCO2Div_2);

	// PC11 - NSS софтовый PС10 - SPI3 SCK	PС12 - SPI3 MOSI  
  RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOC, ENABLE);
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_SPI3, ENABLE);  

  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
  GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
  GPIO_Init(GPIOC, &GPIO_InitStructure);
  GPIO_PinAFConfig(GPIOC, GPIO_PinSource9, GPIO_AF_MCO);
   
	// NSS: выход push-pull 
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
	GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;   
	GPIO_Init(GPIOC, &GPIO_InitStructure);

	// SCK: выход push-pull 
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
	GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOC, &GPIO_InitStructure);
  GPIO_PinAFConfig(GPIOC, GPIO_PinSource10, GPIO_AF_SPI3);

	// MOSI: выход push-pull 
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
	GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOC, &GPIO_InitStructure);
  GPIO_PinAFConfig(GPIOC, GPIO_PinSource12, GPIO_AF_SPI3);
	
  // SPI Init
  SPI_InitStructure.SPI_Direction = SPI_Direction_1Line_Tx; 
  SPI_InitStructure.SPI_Mode = SPI_Mode_Master;
  SPI_InitStructure.SPI_DataSize = SPI_DataSize_16b;
	SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low;
	SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge;
  SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;   
  SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_256;
  SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB; 
   
  SPI_Init(SPI3, &SPI_InitStructure);
  SPI_Cmd(SPI3, ENABLE);
}

Ну и собственно функция загрузки AD9832


void SPI3_WriteWorld(int Data)
{
	Delay(10);
	// FSYNC в 0 
  GPIOC->ODR &= ~GPIO_OTYPER_ODR_11;
	// Отправка данных (16 бит)
  SPI_I2S_SendData(SPI3, Data);
  // Жду пока буфер TX будет пустой
  while (SPI_I2S_GetFlagStatus(SPI3, SPI_I2S_FLAG_TXE) == RESET)
	// Задержка подбирается  
	Delay(2500);
	// FSYNC в 1 
  GPIOC->ODR |= GPIO_OTYPER_ODR_11;
}

Данный код проверен на работоспособностьв демопроекте LwIp стека под платку SK-STM32F217

Top.Mail.Ru