AD5689是双通道、16位的DAC,用于输出模拟电压信号。SPI协议传输。
一、了解芯片各个引脚的功能
写驱动前,需要读懂时序图,从时序图中提取SPI传输的有用信息
1、SCLK为时钟线
在空闲的时为高电平(即DIN没有数据的时候),由此可见,SPI协议的时钟极性为高电平(CPOL=1)。
2、SYNC(片选)
在SYNC(片选)拉低之后,在SCLK时钟的下降沿进行数据采样(如图所示,DIN在SCLK下降沿的时候保持稳定),因此是在第一个时钟沿进行采样(CPHA=0)。
3、SDIN引脚
SDIN,数据传输引脚传输的第一位数据是DB23,为MSB(高位优先;另一种则是低位优先LSB)。24位数据具体的含义如下图:
4、SDO引脚
SDO,用于数据输出。SPI通信拥有数据输入和输出两个信号线,可以推测其为全双工模式;通信双方共用时钟线,为同步通信。
5、其它引脚
关于其它的引脚,如Vcc,RESET,Vout,为电源、复位、输出等功能,不是SPI特有,本文就不一一介绍。
二、初始化芯片引脚
上电后对需对芯片进行重启,保证其工作状态稳定。硬件连接根据自身情况设计。直接上代码。
/**
* @brief DAC1初始化
* @Param None
* @retval None
*/
void Dac1_init(void)
{
rcu_periph_clock_enable(RCU_GPIOA);//使能GPIOA时钟
rcu_periph_clock_enable(RCU_GPIOB);
rcu_periph_clock_enable(RCU_GPIOC);
//PA4-片选 PA5-CLK PA6-MISO PA7-MOSI
gpio_init(GPIOA,GPIO_MODE_OUT_PP,GPIO_OSPEED_50MHZ,GPIO_PIN_4 | GPIO_PIN_5 | GPIO_PIN_7); //推挽输出
gpio_init(GPIOA,GPIO_MODE_IN_FLOATING,GPIO_OSPEED_50MHZ,GPIO_PIN_6); //浮空输入
//更新数据引脚
gpio_init(GPIOC,GPIO_MODE_OUT_PP,GPIO_OSPEED_50MHZ,GPIO_PIN_4); //推挽输出 PC4 LDAC
gpio_init(GPIOB,GPIO_MODE_OUT_PP,GPIO_OSPEED_50MHZ,GPIO_PIN_0); //推挽输出 PB0 reset
GPIO_BOP(CSS_PORT) = CSS_PIN; //拉高片选,空闲状态
//复位AD5689 拉高PC4和PB0
// GPIO_BOP(RESET_PORT) = RESET_PIN;
// GPIO_BOP(LDAC_PORT) = LDAC_PIN; //引脚输出高电平
// delay_1ms(1);
GPIO_BC(RESET_PORT) = RESET_PIN; //拉低reset,芯片复位
delay_1ms(1);
GPIO_BOP(RESET_PORT) = RESET_PIN; //拉高reset
}
三、读写操作
芯片手册上对于写操作的描述如下图
代码根据其写操作设计
1、写一位
/**
* @brief SPI发送bit为数据数据
* @Param data:选择发送的数据
* @retval None
*/
uint8_t Spi_send_bit(uint8_t data)
{
uint8_t d=0;
//MSB,最高有效位发送数据
if(data == 1)
GPIO_BOP(MOSI_PORT) = MOSI_PIN; //输出高电平
else
GPIO_BC(MOSI_PORT) = MOSI_PIN; //输出低电平
//设置SCLK引脚为低电平,这个时候,从机会开始读取MOSI引脚电平
GPIO_BC(SCK_PORT) = SCK_PIN; //输出低电平
delay_1us(2);
//设置SCLK引脚为高电平,告诉从机,主机准备采集MISO电平
GPIO_BOP(SCK_PORT) = SCK_PIN; //输出高电平
delay_1us(2);
//主机采集MISO引脚电平
if(GPIO_ISTAT(MISO_PORT)&(MISO_PIN))
d = 1;
return d;
}
2、写一个字节
/**
* @brief SPI发送字节数据
* @Param data:选择发送的数据
* @retval None
*/
uint8_t Spi_send_byte(uint8_t data)
{
int32_t i=0;
uint16_t d=0;
for(i=7; i>=0; i--)
{
//MSB,最高有效位发送数据
if(data & (1<<i))
GPIO_BOP(MOSI_PORT) = MOSI_PIN; //输出高电平
else
GPIO_BC(MOSI_PORT) = MOSI_PIN; //输出低电平
//设置SCLK引脚为低电平,这个时候,从机会开始读取MOSI引脚电平
GPIO_BC(SCK_PORT) = SCK_PIN; //输出低电平
delay_1us(2);
//设置SCLK引脚为高电平,告诉从机,主机准备采集MISO电平
GPIO_BOP(SCK_PORT) = SCK_PIN; //输出高电平
delay_1us(2);
//主机采集MISO引脚电平
if(GPIO_ISTAT(MISO_PORT)&(MISO_PIN))
d|=1<<i;
}
return d;
}
3、写半字(16bit)
/**
* @brief SPI发送半字数据
* @Param data:选择发送的数据
* @retval None
*/
uint16_t Spi_send_halfword(uint16_t data)
{
int32_t i=0;
uint16_t d=0;
for(i=15; i>=0; i--)
{
//MSB,最高有效位发送数据
if(data & (1<<i))
GPIO_BOP(MOSI_PORT) = MOSI_PIN; //输出高电平
else
GPIO_BC(MOSI_PORT) = MOSI_PIN; //输出低电平
//设置SCLK引脚为低电平,这个时候,从机会开始读取MOSI引脚电平
GPIO_BC(SCK_PORT) = SCK_PIN; //输出低电平
delay_1us(2);
//设置SCLK引脚为高电平,告诉从机,主机准备采集MISO电平
GPIO_BOP(SCK_PORT) = SCK_PIN; //输出低电平
delay_1us(2);
//主机采集MISO引脚电平
if(GPIO_ISTAT(MISO_PORT)&(MISO_PIN))
d|=1<<i;
}
return d;
}
4、读操作
之前已述SPI为全双工通信(发送的同时会给你回数据)。但他本次回给你的数据,是在会有你上次发的命令。所以,在发数据之后,再次发送一次数据时,回的才是你想要的数据。如下图所示
回读操作包含在了写操作,可去看写操作中的回去逻辑。
四、应用
读写操作完成之后,即可根据不同厂家SPI芯片提供的通信协议,编写不同的功能逻辑代码,来实现自身的需求。
以下有我自己的例程,仅供大家参考
设置命令0x39-->0011(写入并更新DAC通道) 1001(同时设置A、B两个通道)
回读命令0x91-->1001(回读使能) 0001(回读DAC通道A的值)
/**
* @brief 设置AD7689的ad值0~65535
* @Param data:选择发送的数据
* @retval None
*/
uint16_t AD5689_setval(float val)
{
if(val <= 3.3)
{
/*gain = 0,输出电压 0~Vref(2.5V)
0~65535 <--> 0~2.5v*/
uint16_t num = val/2.5*65535/1.028;
GPIO_BC(CSS_PORT) = CSS_PIN; //拉低片选
delay_1us(1);
Spi_send_byte(0x39);
Spi_send_halfword(num);
delay_1us(1);
GPIO_BOP(CSS_PORT) = CSS_PIN; //拉高片选
// printf("set val %f ok\r\n",val);
}
return 0;
}
/**
* @brief 回读DAC寄存器的值
* @Param None
* @retval None
*/
uint16_t AD5689_readval(void)
{
uint16_t num = 0;
GPIO_BC(CSS_PORT) = CSS_PIN; //拉低片选
delay_1us(1);
Spi_send_byte(0x91);
Spi_send_halfword(0x0000);
GPIO_BOP(CSS_PORT) = CSS_PIN; //拉高片选
delay_1us(1);
GPIO_BC(CSS_PORT) = CSS_PIN; //拉低片选
delay_1us(1);
for(int i = 0; i < 4 ;i++)
{
Spi_send_bit(0);
}
num = Spi_send_halfword(0x0000);
for(int i = 0; i < 4 ;i++)
{
Spi_send_bit(0);
}
GPIO_BOP(CSS_PORT) = CSS_PIN; //拉高片选
//printf("0");
return num;
}