AD9854 串行驱动(stm32)

说明

AD9854是一款频率合成芯片,由于电赛的需要需要写串行驱动。在网上找了很多资料,都是并行的。就算有串行的也是430芯片,于是自己阅读技术手册,并在电赛小伙伴的共同帮助下,完成了串口的驱动编写。

注意

  • AD9854串行口用的是标准的SPI协议,用stm32自带的就行,也可以用IO口自己模拟。官方手册上说速率可达到10M,但是速率能太低,原因之后会说到。
  • AD9854写入数据时候并不是直接,而是会将数据放入一个缓存区,当更新时钟更新后才将数据锁存到对应的寄存器中。
  • AD9854有一个更新时钟问题,默认是内部时钟。相当于个定时器,当定时器满时,就会锁存数据。如果写入速度太慢的话,当数据还没完全写到缓存去里,内部时钟就更新了,就会造成芯片没法正常工作。至于这个内部时钟是多长时间一次,官方似乎没有说明,官方手册也建议最好换成外部时钟。
  • 如果换成外部时钟的话,每一个数据就需要手动更新时钟,即拉高一段时间再拉低,好像是10个系统周期,这个系统周期指的是外部晶振的周期。
  • 最重要的来了,外部update引脚在写入第一组48位控制字的时候不能进行初始化操作!!!否则会造成芯片没法正常工作,正常工作应该至少300ma,这是个坑,我在这里就卡了几天,后来发现在开单片机之前,把updata的引脚的导线拔了再插上就可以正常工作了,才发现这个问题,其中的原因是因为:当内部计数器计数到0的时候,会在外部更新时钟引脚(20)产生一个时间长达8个时钟长度的高电平,如果在第一组控制字写进去的时候对20引脚进行初始化可能会对其电平产生干扰,从而无法使数据正常写入。

程序

c文件:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
#include "ad9854.h"
SPI_InitTypeDef SPI_InitStructure;
/*
AD9854驱动
Update_clock---PC5
~CS---PIN22---PC6
RESET---PIN17---PC7
MOSI: PIN19---PB15
MISO: PIN18---PB14
SCK: PIN21---PB13
SPI2:
PB 13 14 15
SCK MISO MOSI
*/
void AD9854_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOB|RCC_APB2Periph_GPIOC, ENABLE );
RCC_APB1PeriphClockCmd(RCC_APB1Periph_SPI2,ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7; //PB5:UPDATE LOCK PB6:CS PB7:RESET
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //推挽输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOC, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13 | GPIO_Pin_14 | GPIO_Pin_15; //PA5:SCK PA6:MISO PA7:MOSI
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //复用推挽输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &GPIO_InitStructure);
GPIO_SetBits(GPIOB,GPIO_Pin_13|GPIO_Pin_14|GPIO_Pin_15);
GPIO_SetBits(GPIOC,GPIO_Pin_6|GPIO_Pin_7);
SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex; //设置SPI单向或者双向的数据模式:SPI设置为双线双向全双工
SPI_InitStructure.SPI_Mode = SPI_Mode_Master; //设置SPI工作模式:设置为主SPI
SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b; //设置SPI的数据大小:SPI发送接收8位帧结构
SPI_InitStructure.SPI_CPOL = SPI_CPOL_High; //串行同步时钟的空闲状态为高电平
SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge; //串行同步时钟的第二个跳变沿(上升或下降)数据被采样
SPI_InitStructure.SPI_NSS = SPI_NSS_Soft; //NSS信号由硬件(NSS管脚)还是软件(使用SSI位)管理:内部NSS信号有SSI位控制
SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_256; //定义波特率预分频的值:波特率预分频值为256
SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB; //指定数据传输从MSB位还是LSB位开始:数据传输从MSB位开始
SPI_InitStructure.SPI_CRCPolynomial = 7; //CRC值计算的多项式
SPI_Init(SPI2, &SPI_InitStructure); //根据SPI_InitStruct中指定的参数初始化外设SPIx寄存器
SPI_Cmd(SPI2, ENABLE); //使能SPI外设
//master_reset();
SPI2_ReadWriteByte(0xff);//启动传输
SPI2_SetSpeed(SPI_BaudRatePrescaler_16);//4.5M传输速度
AD9864_Reset();
//master_reset();
AD9854_Ctr(0x104a0021);//控制指令
//一定要写在控制指令后面
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5; //PB5:UPDATE
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //推挽输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOC, &GPIO_InitStructure);
//AD9854_Ctr(0x10040020);//0x104a0040 0x1040031
}
//SPI 速度设置函数
//SpeedSet:
//SPI_BaudRatePrescaler_2 2分频 (SPI 36M@sys 72M)
//SPI_BaudRatePrescaler_8 8分频 (SPI 9M@sys 72M)
//SPI_BaudRatePrescaler_16 16分频 (SPI 4.5M@sys 72M)
//SPI_BaudRatePrescaler_256 256分频 (SPI 281.25K@sys 72M)
void SPI2_SetSpeed(u8 SpeedSet)
{
SPI_InitStructure.SPI_BaudRatePrescaler = SpeedSet;
SPI_Init(SPI2, &SPI_InitStructure);
SPI_Cmd(SPI2,ENABLE);
}
//SPIx 读写一个字节
//TxData:要写入的字节
//返回值:读取到的字节
u8 SPI2_ReadWriteByte(u8 TxData)
{
u8 retry=0;
while (SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_TXE) == RESET) //检查指定的SPI标志位设置与否:发送缓存空标志位
{
retry++;
if(retry>200)return 0;
}
SPI_I2S_SendData(SPI2, TxData); //通过外设SPIx发送一个数据
retry=0;
while(SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_RXNE) == RESET)//检查指定的SPI标志位设置与否:接受缓存非空标志位
{
retry++;
if(retry>200)return 0;
}
return SPI_I2S_ReceiveData(SPI2); //返回通过SPIx最近接收的数据
}
/*
FTW = (Desired Output Frequency × 2^N)/SYSCLK N=48
入口参数:要求的频率hz
写入控制字
*/
void AD9854_Write_FTW(unsigned long int frequency){
u8 fwt[6]={0}; //fwt的缓存,一共有48bit,6位保存,1位保存8bit
u32 freq=0; //计算乘积
u8 freq_buff[4]={0};
for(int i=0;i<4;i++){ //将frequency拆分进freq里
freq_buff[i]=frequency>>(8*i);
}
for(int i=0;i<6;i++){ //计算的到频率控制字并拆分到freq中
if(i<4){
freq += AD9854_FWT_TEMP * freq_buff[i];
fwt[i] = freq;
freq >>= 8;
}else{
fwt[i] = freq;
freq>>=8;
}
}
AD9854_CS = 0;
SPI2_ReadWriteByte(AD9854_FRE1); //频率1的控制字地址
for(int i=5;i>=0;i--){ //发送数据,先发高位
SPI2_ReadWriteByte(fwt[i]);
}
AD9854_CS=1;
AD9854_Update();//更新
}
/*
设置正弦波
frequency:频率
shap:幅度 0-4096
*/
void AD9854_SetSine(u8 f,u16 shape){
unsigned long int frequency=f*1000000;
//shape=shape*AM;
AD9854_Write_FTW(frequency); //设置频率控制字
AD9854_CS=0;
SPI2_ReadWriteByte(AD9854_I_MUL); //如果最高位是1则读,最高位是0则写 默认是0
SPI2_ReadWriteByte(shape>>8); //先传高位
SPI2_ReadWriteByte(shape&0xff);
AD9854_CS=1;
AD9854_Update();//更新
AD9854_CS=0;
SPI2_ReadWriteByte(AD9854_Q_MUL);
SPI2_ReadWriteByte(shape>>8);
SPI2_ReadWriteByte(shape&0xff);
AD9854_CS=1;
AD9854_Update();//更新
//发送阶梯电压
JTB2_Control(f*80);//控制DAC
}
/*
复位
*/
void AD9864_Reset(void){
AD9854_RESET=1;
delay_ms(1);
AD9854_RESET=0;
delay_ms(1);
}
/*
控制指令
control 16位
*/
void AD9854_Ctr(unsigned long int control){
AD9854_CS=0;
SPI2_ReadWriteByte(AD9854_CTR_REG); //传地址
for(int i=3;i>=0;i--){
SPI2_ReadWriteByte(control>>(i*8)); //先传高位
}
AD9854_CS=1;
AD9854_Update();//更新
delay_ms(1);
}
/*
更新
*/
void AD9854_Update(){
AD9854_UPDATE_LOCK =1;
delay_ms(1);
AD9854_UPDATE_LOCK = 0;
}
//void master_reset(){
// AD9854_MASTER_RESET=1;
// delay_ms(1);
// AD9854_MASTER_RESET=0;
// delay_ms(1);
//}
h文件:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
<pre class="line-numbers prism-highlight" data-start="1">`#ifndef _AD9854_H
#define _AD9854_H
#include "sys.h"
#include "delay.h"
#include "libincludes.h"
#define AD9854_UPDATE_LOCK PCout(5)
#define AD9854_CS PCout(6)
#define AD9854_RESET PCout(7)
//#define AD9854_MASTER_RESET PAout(4)
#define SPI_MISO PAout(6)
#define SPI_MOSI PAout(7)
#define SPI_SCK PAout(5)
//serial address write
#define AD9854_PHA1 0x00 // 2 Bytes
#define AD9854_PHA2 0x01 // 2 Bytes
#define AD9854_FRE1 0x02 // 6 Bytes
#define AD9854_FRE2 0x03 // 6 Bytes
#define AD9854_DELTA 0x04 // 6 Bytes
#define AD9854_UPDATA 0x05 // 4 Bytes
#define AD9854_RAMP_CLK 0x06 // 3 Bytes
#define AD9854_CTR_REG 0x07 // 4 Bytes
#define AD9854_I_MUL 0x08 // 2 Bytes
#define AD9854_Q_MUL 0x09 // 2 Bytes
#define AD9854_SHAPED 0x0A // 1 Bytes
#define AD9854_Q_DAC 0x0B // 2 Bytes
#define AD9854_FWT_TEMP 1407375 // 2^48/20M 用来计算fwt 1407374.883
#define AM 15
void AD9854_Init(void); //初始化SPI口
void SPI2_SetSpeed(u8 SpeedSet); //设置SPI速度
u8 SPI2_ReadWriteByte(u8 TxData);//SPI总线读写一个字节
void AD9854_Update(void);
void AD9854_Ctr(unsigned long int control);
void AD9864_Reset(void);
void AD9854_SetSine(u8 f,u16 shape); //设置正弦波幅度和频率
//void master_reset(void);
#endif