一、前言
之前在FastBond2阶段1的项目中展示了使用Scheme-it设计的原理图,介绍了程控放大模块的设计原理,也展示了项目中所使用到的活动规定厂家的芯片。本设计是程序控制的放大器模块,使用微控制器来控制SPI接口数字电位器AD5270的电阻值,从而调节仪表放大器AD8220的放大倍数,编程语言采用C语言,测试平台为arduino,十分方便移植到其它平台。
阶段1项目链接如下:https://www.eetree.cn/project/detail/2032
本文的内容是使用kicad设计原理图和PCB,样板的功能测试和主要程序的说明。
二、原理图及PCB介绍
阶段1的流程图及原理图初步设计都是由Scheme-it网页来绘制的,使用体验非常好,自带了很多元器件库和模块,还有其它伙伴的设计分享。使用了FastBond活动中要求的厂商芯片,ADI公司的AD5270数字电位器芯片和AD8220仪表放大器芯片。这里是链接:https://www.digikey.cn/schemeit/project/基于ad8220的程控放大器模块设计-686eb1feb7274c3493ea08b4616fa8db
如下图所示,输入信号和电源由排针接口输入,输出也是通过排针接口,输入采用了电容和电阻构成的高通滤波器,电容可以隔离直流信号,输出预留了RC低通滤波电路,可以根据实际应用需要焊接不同的电阻电容。
仪表放大器AD8220的增益通过调节RG管脚2和3之间的电阻值,数字电位器AD5270电阻输出A、W管脚连接到RG脚上,AD5270采用SPI接口驱动,只需片选、数据输入、时钟即可。这样通过微控制驱动AD5270调节输出电阻就能控制仪表放大器的增益了。
之后设计PCB如下, 采用双面板设计,尺寸是追求mini一些,硬禾学堂提供的kicad教程十分有用,快速教我掌握了新版kicad设计要点。
三、样板功能测试
首先焊接板子,电源退耦电容先不焊接,先测试下功能的正确性,图中有一根飞线,果然第一次设计容易出问题,AD5270如果采用双电源供电,C4电容另一端应连接VSS而不是GND,如果用单电源供电就没问题,本次测试用双电源供电,所以飞线一下,还请大佬们见谅菜鸟的失误:
微控制器采用teensy开发板进行测试,SPI接口连接板子即可,电源、信号发生器、示波器均采用ADALM2000口袋仪表,下图是连线:
四、程序功能说明
下面是完整的arduino测试程序,首先定义了SPI时钟等参数,然后定义了AD5270的控制命令(AD5270的数据手册详细说明了控制时序和各个命令的功能,这里就不赘述了),接下来封装了AD5270的控制函数:
#include "SPI.h"
#define SPI_FREQ_FAST 500000
#define SPI_FREQ_SLOW 500000
#define MOSI_PIN 5
#define SCK_PIN 4
#define CHIP_SEL_MEAS 13
// AD5270 commands - new digital potentiometer
#define CMD_WR_RDAC 0x01
#define CMD_RD_RDAC 0x02
#define CMD_ST_RDAC 0x03
#define CMD_RST 0x04
#define CMD_RD_MEM 0x05
#define CMD_RD_ADDR 0x06
#define CMD_WR_CTRL 0x07
#define CMD_RD_CTRL 0x08
#define CMD_SHTDN 0x09
/* Write a 4-bit command and a 10-bit data word */
void AD5270_Write(const int chip_sel, uint8_t cmd, uint16_t data)
{
uint16_t data_word = ((cmd & 0x0F) << 10) | (data & 0x03FF);
digitalWrite(chip_sel, LOW);
delayMicroseconds(500);
spi_write(MOSI_PIN, SCK_PIN, SPI_FREQ_FAST, MSBFIRST, SPI_MODE1, 16, data_word);
delayMicroseconds(500);
digitalWrite(chip_sel, HIGH);
}
/* Shift a byte out serially with the given frequency in Hz (<= 500kHz) */
void spi_write(uint8_t data_pin, uint8_t clock_pin, uint32_t freq, uint8_t bit_order, uint8_t mode, uint8_t bits, uint32_t val){
uint32_t period = (freq >= 500000) ? 1 : (500000 / freq); // Half clock period in uS
uint8_t cpol = (mode == SPI_MODE2 || mode == SPI_MODE3);
uint8_t cpha = (mode == SPI_MODE1 || mode == SPI_MODE3);
uint8_t sck = cpol ? HIGH : LOW;
uint8_t i;
uint32_t start_time;
// Set clock idle for 2 periods
digitalWrite(clock_pin, sck);
delayMicroseconds(period*4);
for (i = 0; i < bits; i++) {
start_time = micros();
// Shift bit out
if (bit_order == LSBFIRST)
digitalWrite(data_pin, !!(val & (1 << i)));
else
digitalWrite(data_pin, !!(val & (1 << ((bits-1) - i))));
// Toggle clock leading edge
sck = !sck;
if (cpha) {
digitalWrite(clock_pin, sck);
while(micros() - start_time < period);
} else {
while(micros() - start_time < period);
digitalWrite(clock_pin, sck);
}
// Toggle clock trailing edge
start_time = micros();
sck = !sck;
if (cpha) {
digitalWrite(clock_pin, sck);
while(micros() - start_time < period);
} else {
while(micros() - start_time < period);
digitalWrite(clock_pin, sck);
}
}
}
/* Enable/disable rheostat value changes */
void AD5270_LockUnlock(const int chip_select, uint8_t lock){
AD5270_Write(chip_select, CMD_WR_CTRL, lock ? 0 : 0x002);
}
/* Enable/disable hardware shutdown */
void AD5270_Shutdown(const int chip_select, uint8_t shutdown){
AD5270_Write(chip_select, CMD_SHTDN, shutdown ? 1 : 0);
}
/* Set the value of the digital rheostat - range is 0-0x3FF (0-100kOhm) */
void AD5270_Set(const int chip_select, uint16_t val)
{
AD5270_Write(chip_select, CMD_WR_RDAC, val);
}
void setup()
{
Serial.begin(115200);
pinMode(CHIP_SEL_MEAS, OUTPUT);
digitalWrite(CHIP_SEL_MEAS, HIGH);
pinMode(MOSI_PIN, OUTPUT);
pinMode(SCK_PIN, OUTPUT);
Serial.println("starting with ");
Serial.println(SPI_FREQ_FAST);
delay(100);
AD5270_LockUnlock(CHIP_SEL_MEAS, 0);
delay(100);
AD5270_Shutdown(CHIP_SEL_MEAS, 0);
delay(100);
AD5270_Set(CHIP_SEL_MEAS, 1023);
delay(100);
}
int i = 0;
void loop()
{
for(i=0;i<1000;i+=10)
{
AD5270_Set(CHIP_SEL_MEAS, i);
Serial.print("dat:");
Serial.println(i);
delay(2000);
}
}
程序开始初始化了驱动管脚,SPI这里采用的是GPIO管脚模拟SPI时序的方法,这样相比用库更加灵活,初始化完成后就在主循环里面设置AD5270的输出电阻值,可以设置值为0~1023对应输出电阻值为0~50kΩ。根据AD8220数据手册中增益公式,G=1+49.4kΩ/RG,可以知道设置值越大最终放大器的增益越低。
这里有一个大坑需要注意的是AD5270的稳定时间较长,350ms左右,另外信号的稳定也需要时间,所以主循环中设置值后延时2秒再设置下一个,实际测试中如果延时1S就会出问题!!
最后关于测试的结果,在视频结尾给出了展示。
四、活动总结
感谢eetree和digkey举办的FastBond2活动,让我有机会分享一些电子模块的DIY,通过活动学习到了不少新技能,希望活动明年继续。