【STM32H7S78-DK】测评+SPI应用之驱动AD9833
[复制链接]
由于STM32H7S78是没有DAC外设的,因此要想产生模拟信号,通常有2种方法,一是PWM加输出滤波器,二是专用DDS芯片。
AD9833是一款低功耗、可编程波形发生器,能够产生正弦波、三角波和方波输出。各种类型的检测、信号激励和时域反射(TDR)应用都需要波形发生器。输出频率和相位可通过软件进行编程,调整简单。无需外部元件。频率寄存器为28位宽,时钟速率为25 MHz时,可以实现0.1 Hz的分辨率;时钟速率为1 MHz时,AD9833可以实现0.004 Hz的分辨率。
AD9833通过一个3线串行接口写入数据。该串行接口能够以最高40 MHz的时钟速率工作,并且与DSP和微控制器标准兼容。该器件采用2.3 V至5.5 V电源供电。主页特性:
特性
- 数字可编程频率和相位
- 当供电电压为3 V时,功耗为12.65 mW
- 输出频率范围:0 MHz至12.5 MHz
- 28位分辨率(25 MHz基准时钟时为0.1 Hz)
- 正弦波/三角波/方波输出
- 2.3 V至5.5 V电源供电
- 无需外部元件
- 三线式SPI接口
- 扩展温度范围: -40 ℃至+105 ℃
- 掉电选项
- 10引脚MSOP封装
- 通过汽车应用认证
AD9833-EP支持防务和航空航天应用(AQEC标准)
- 下载 AD9833-EP数据手册 (pdf)
- 温度范围: −55 ℃至+125 ℃
- 受控制造基线
- 一个装配/测试厂
- 一个制造厂
- 增强型产品变更通知
- 认证数据可应要求提供
- V62/14619-01XE DSCC图纸号
使用SPI接口即可与AD9833通信,通常可以使用GPIO模拟方式或者硬件SPI接口,本帖使用硬件SPI接口。查看原理图,得知arduino接口上的SPI接口是SPI4,片选使用的是PF8,不是硬件片选信号:
SPI接口配置如下:
PF8配置为GPIO作为片选:
然后在AD98333.h头文件定义相关寄存器:
#ifndef INC_AD9833_H_
#define INC_AD9833_H_
#include "main.h"
/*** Redefine if necessary ***/
#define AD9833_SPI_PORT hspi4
extern SPI_HandleTypeDef AD9833_SPI_PORT;
/*** Control Register Bits (DataSheet AD9833 p. 14, Table 6) ***/
#define B28_CFG (1 << 13)
#define HLB_CFG (1 << 12)
#define F_SELECT_CFG (1 << 11)
#define P_SELECT_CFG (1 << 10)
#define RESET_CFG (1 << 8)
#define SLEEP1_CFG (1 << 7)
#define SLEEP12_CFG (1 << 6)
#define OPBITEN_CFG (1 << 5)
#define DIV2_CFG (1 << 3)
#define MODE_CFG (1 << 1)
/*** Bitmask to register access ***/
#define FREQ0_REG 0x4000
#define PHASE0_REG 0xC000
//#define FREQ1_ACCESS 0x8000
//#define PHASE1_ACCESS 0xE000
/*** Waveform Types (DataSheet p. 16, Table 15) ***/
#define WAVEFORM_SINE 0
#define WAVEFORM_TRIANGLE MODE_CFG
#define WAVEFORM_SQUARE OPBITEN_CFG | DIV2_CFG
#define WAVEFORM_SQUARE_DIV2 OPBITEN_CFG
/*** Sleep Modes ***/
#define NO_POWERDOWN 0
#define DAC_POWERDOWN SLEEP12_CFG
#define CLOCK_POWERDOWN SLEEP1_CFG
#define FULL_POWERDOWN SLEEP12_CFG | SLEEP1_CFG
#define FMCLK 25000000
#define BITS_PER_DEG 11.3777777777778 // 4096 / 360
typedef enum {
wave_triangle,
wave_square,
wave_sine,
} WaveDef;
/*
* [url=home.php?mod=space&uid=159083]@brief[/url] Set signal generation frequency
* @param Frequency value in uint32_t format
*/
void AD9833_SetFrequency(uint32_t freq);
/*
* @brief Set signal generation waveform
* @param Waveform in WaveDef Type declared in .h file
*/
void AD9833_SetWaveform(WaveDef Wave);
/*
* @brief Set signal generation phase
* @param Phase in degrees in uint16_t format. Value can be large then 360
*/
void AD9833_SetPhase(uint16_t phase_deg);
/*
* @brief AD9833 Initial Configuration
* @param Type of Waveform, Frequency, Phase in degrees
*/
void AD9833_Init(WaveDef Wave, uint32_t freq, uint16_t phase_deg);
/*
* @brief Enable or disable the output of the AD9833
* @param Output state (ON/OFF)
*/
void AD9833_OutputEnable(uint8_t output_state);
/*
* @brief Set Sleep Mode Function (Explained in datasheet Table 14)
* @param Mode of sleep function defined in title
*/
void AD9833_SleepMode(uint8_t mode);
#endif /* INC_AD9833_H_ */
源码AD9833.c实现初始化、频率、相位设置:
//Setup Hardware SPI to POLATRITY HIGH, PHASE 1 EDGE
#include "AD9833.h"
uint8_t _waveform = WAVEFORM_SINE;
uint8_t _sleep_mode = NO_POWERDOWN;
uint8_t _freq_source = 0;
uint8_t _phase_source = 0;
uint8_t _reset_state = 0;
/*
* @brief Set Chip Select pin to LOW state
*/
static void AD9833_Select(void)
{
HAL_GPIO_WritePin(AD9833_FSYNC_GPIO_Port, AD9833_FSYNC_Pin, GPIO_PIN_RESET);
}
/*
* @brief Set Chip Select pin to HIGH state
*/
static void AD9833_Unselect(void)
{
HAL_GPIO_WritePin(AD9833_FSYNC_GPIO_Port, AD9833_FSYNC_Pin, GPIO_PIN_SET);
}
/*
* @brief Send data by SPI protocol
* @param Data variable in uint16_t format
*/
static void AD9833_WriteRegister(uint16_t data)
{
AD9833_Select();
uint8_t LByte = data & 0xff;
uint8_t HByte = (data >> 8) & 0xff;
HAL_SPI_Transmit(&AD9833_SPI_PORT, &HByte, 1, HAL_MAX_DELAY);
HAL_SPI_Transmit(&AD9833_SPI_PORT, &LByte, 1, HAL_MAX_DELAY);
AD9833_Unselect();
}
/*
* @brief Update Control Register Bits
*/
static void AD9833_WriteCfgReg(void)
{
uint16_t cfg = 0;
cfg |= _waveform;
cfg |= _sleep_mode;
cfg |= (_freq_source ? F_SELECT_CFG : 0); //it's unimportant because don't use FREQ1
cfg |= (_phase_source ? P_SELECT_CFG : 0); //it's unimportant because don't use PHASE1
cfg |= (_reset_state ? RESET_CFG : 0);
cfg |= B28_CFG;
AD9833_WriteRegister(cfg);
}
void AD9833_SetWaveform(WaveDef Wave)
{
if (Wave == wave_sine) _waveform = WAVEFORM_SINE;
else if (Wave == wave_square) _waveform = WAVEFORM_SQUARE;
else if (Wave == wave_triangle) _waveform = WAVEFORM_TRIANGLE;
AD9833_WriteCfgReg();
}
void AD9833_SetFrequency(uint32_t freq)
{
// TODO: calculate max frequency based on refFrequency.
// Use the calculations for sanity checks on numbers.
// Sanity check on frequency: Square - refFrequency / 2
// Sine/Triangle - refFrequency / 4
if (freq > (FMCLK >> 1)) //bitwise FMCLK / 2
freq = FMCLK >> 1;
else if (freq < 0) freq = 0;
uint32_t freq_reg = (float)freq * (float)((1 << 28) / FMCLK); // Tuning word
uint16_t LSB = FREQ0_REG | (freq_reg & 0x3FFF);
uint16_t MSB = FREQ0_REG | (freq_reg >> 14);
AD9833_WriteCfgReg(); // Update Config Register
AD9833_WriteRegister(LSB);
AD9833_WriteRegister(MSB);
}
void AD9833_SetPhase(uint16_t phase_deg)
{
if(phase_deg < 0) phase_deg = 0;
else if (phase_deg > 360) phase_deg %= 360;
uint16_t phase_val = ((uint16_t)(phase_deg * BITS_PER_DEG)) & 0xFFF;
AD9833_WriteRegister(PHASE0_REG | phase_val);
}
void AD9833_Init(WaveDef Wave, uint32_t freq, uint16_t phase_deg)
{
AD9833_OutputEnable(0);
AD9833_SetWaveform(Wave);
AD9833_WriteCfgReg();
AD9833_SetFrequency(freq);
AD9833_SetPhase(phase_deg);
AD9833_OutputEnable(1);
}
void AD9833_SleepMode(uint8_t mode)
{
_sleep_mode = mode;
AD9833_WriteCfgReg();
}
void AD9833_OutputEnable(uint8_t output_state)
{
_reset_state = !output_state;
AD9833_WriteCfgReg();
}
最后调用接口初始化:
AD9833_Init(wave_sine, 100, 0);
将输出频率100Hz的正弦波。
接线:
AD9833模块:
波形效果如下,可见正确驱动了芯片:
|