AD5676为单片8通道DAC,此程序同时驱动两片DAC
硬件链接上,两片DAC共用MOSI,MISO,SPI_CLK,LDAC引脚。不共用SYNC,RESET引脚。
使用的引脚在H文件中有定义。
/*
* Copyright 2021 Minchul Jun ([email protected]). All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY MINCHUL JUN ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
* EVENT SHALL MINCHUL JUN OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* The views and conclusions contained in the software and documentation are
* those of the authors and should not be interpreted as representing official
* policies, either expressed or implied, of Minchul Jun.
*
*/
#include "AD5676.h"
#include "stdlib.h"
_dacConf* dac0Conf = NULL;
_dacConf* dac1Conf = NULL;
HAL_StatusTypeDef _AD5676R_init(_dacType dacType, SPI_HandleTypeDef* hspi)
{
HAL_StatusTypeDef result = HAL_OK;
_dacConf* dacConf;
uint8_t txLen = 3;
uint8_t sendBuf1[3] = {0};
if(dacType == AD5676R_DAC0)
{
dac0Conf = (_dacConf*)malloc(sizeof(_dacConf));
dac0Conf->type = dacType;
dac0Conf->hspi = hspi;
dac0Conf->nClr.port = SPI1_NCLR_GPIO_Port;
dac0Conf->nClr.pin = SPI1_NCLR_Pin;
dac0Conf->nLdac.port = SPI1_NLDAC_GPIO_Port;
dac0Conf->nLdac.pin = SPI1_NLDAC_Pin;
dac0Conf->sync.port = SPI1_SYNC_GPIO_Port;
dac0Conf->sync.pin = SPI1_SYNC_Pin;
dacConf = dac0Conf;
}
else
if(dacType == AD5676R_DAC1)
{
dac1Conf = (_dacConf*)malloc(sizeof(_dacConf));
dac1Conf->type = dacType;
dac1Conf->hspi = hspi;
dac1Conf->nClr.port = SPI1_1NCLR_GPIO_Port;
dac1Conf->nClr.pin = SPI1_1NCLR_Pin;
dac1Conf->nLdac.port = SPI1_NLDAC_GPIO_Port;
dac1Conf->nLdac.pin = SPI1_NLDAC_Pin;
dac1Conf->sync.port = SPI1_1SYNC_GPIO_Port;
dac1Conf->sync.pin = SPI1_1SYNC_Pin;
dacConf = dac1Conf;
}
else
{
result = HAL_ERROR;
return result;
}
// Reset Sequence
HAL_GPIO_WritePin(dacConf->nClr.port, dacConf->nClr.pin, GPIO_PIN_RESET);
// Keep always low, to update output simultaneously
HAL_GPIO_WritePin(dacConf->nLdac.port, dacConf->nLdac.pin, GPIO_PIN_RESET);
// Set low during send data
HAL_GPIO_WritePin(dacConf->sync.port, dacConf->sync.pin, GPIO_PIN_SET);
HAL_Delay(50);
HAL_GPIO_WritePin(dacConf->nClr.port, dacConf->nClr.pin, GPIO_PIN_SET);
// //第一片启用菊花链
// HAL_GPIO_WritePin(dacConf->sync.port, dacConf->sync.pin, GPIO_PIN_RESET);
// sendBuf1[0] = (AD5676R_CMD(AD5676R_CMD_DAISYCHAIN_ENABLE) | AD5676R_ADDR(0));
// sendBuf1[1] = (uint8_t)AD5676R_VAL_H(0x00);
// sendBuf1[2] = (uint8_t)AD5676R_VAL_L(0x01);
// for(int pp = 0;pp<1;pp++)
// {
// sendBuf1[0] = (AD5676R_CMD(AD5676R_CMD_DAISYCHAIN_ENABLE) | AD5676R_ADDR(pp));
// result = HAL_SPI_Transmit(dacConf->hspi, sendBuf1, txLen, 1000);
// }
// HAL_GPIO_WritePin(dacConf->sync.port, dacConf->sync.pin, GPIO_PIN_SET);
// HAL_Delay(10);
// //第二片启用
// HAL_GPIO_WritePin(dacConf->sync.port, dacConf->sync.pin, GPIO_PIN_RESET);
// result = HAL_SPI_Transmit(dacConf->hspi, sendBuf1, txLen, 1000);
// sendBuf1[0] = (AD5676R_CMD(AD5676R_CMD_NOOP_DAISYCHAIN_MODE) | AD5676R_ADDR(0));
// result = HAL_SPI_Transmit(dacConf->hspi, sendBuf1, txLen, 1000);
// HAL_GPIO_WritePin(dacConf->sync.port, dacConf->sync.pin, GPIO_PIN_SET);
//
// for(int pp = 0;pp<8;pp++)
// AD5676R_write(AD5676R_DAC0,AD5676R_CMD_DAISYCHAIN_ENABLE,pp,0x0001);
// AD5676R_write(AD5676R_DAC0,AD5676R_CMD_DAISYCHAIN_ENABLE,9,0x0001);
return result;
}
void AD5676_GPIO_init(void)
{
GPIO_InitTypeDef GPIO_Initure;
__HAL_RCC_GPIOC_CLK_ENABLE();
__HAL_RCC_GPIOA_CLK_ENABLE();
GPIO_Initure.Pin=SPI1_NCLR_Pin|SPI1_NLDAC_Pin|SPI1_SYNC_Pin;
GPIO_Initure.Mode=GPIO_MODE_OUTPUT_PP;
GPIO_Initure.Pull=GPIO_PULLUP; //上拉
GPIO_Initure.Speed=GPIO_SPEED_HIGH; //高速
HAL_GPIO_Init(GPIOC,&GPIO_Initure);
GPIO_Initure.Pin=SPI1_SYNC_Pin;
GPIO_Initure.Mode=GPIO_MODE_OUTPUT_PP; //GPIO_MODE_INPUT;
HAL_GPIO_Init(GPIOC,&GPIO_Initure);
//DAC 1 GPIO
GPIO_Initure.Pin = SPI1_1NCLR_Pin;
HAL_GPIO_Init(SPI1_1NCLR_GPIO_Port,&GPIO_Initure);
GPIO_Initure.Pin = SPI1_1SYNC_Pin;
HAL_GPIO_Init(SPI1_1SYNC_GPIO_Port,&GPIO_Initure);
}
void AD5676R_init(void)
{
AD5676_GPIO_init();
SPI1_Init();
_AD5676R_init(AD5676R_DAC0,&hspi1);
_AD5676R_init(AD5676R_DAC1,&hspi1);
}
static HAL_StatusTypeDef AD5676R_write(_dacType dacType, uint8_t cmd, uint8_t addr, uint16_t val)
{
HAL_StatusTypeDef result = HAL_OK;
uint8_t txLen = 3;
uint8_t sendBuf1[3] = {0};
uint8_t sendBuf2[3] = {0};
uint8_t zeroBuf[3] = {0};
_dacConf* dacConf;
int time_out =0;
if(dacType == AD5676R_DAC0)
SYNC_IN();
if(dacType == AD5676R_DAC1)
SYNC_1IN();
if(dacType == AD5676R_DAC0)
dacConf = dac0Conf;
if(dacType == AD5676R_DAC1)
dacConf = dac1Conf;
// if(dacType == AD5676R_DAC0)
// {
//
// }
// else
// {
// result = HAL_ERROR;
// return result;
// }
// Check availablity to send data
while(GPIO_PIN_RESET == HAL_GPIO_ReadPin(dacConf->sync.port, dacConf->sync.pin))
{
time_out++;
if(time_out < 500)
DEBUGF_INFO("AD5676R_sync error\r\n");
else
break;
}
if(dacType == AD5676R_DAC0)
SYNC_OUT();
if(dacType == AD5676R_DAC1)
SYNC_1OUT();
// HAL_GPIO_WritePin(dacConf->nLdac.port, dacConf->nLdac.pin, GPIO_PIN_SET);
HAL_GPIO_WritePin(dacConf->sync.port, dacConf->sync.pin, GPIO_PIN_RESET);
//result = HAL_SPI_Transmit_DMA(dacConf->hspi, sendBuf, txLen);
//准备数据
//第一片DAC的数据
sendBuf1[0] = (AD5676R_CMD(cmd) | AD5676R_ADDR(addr));
sendBuf1[1] = (uint8_t)AD5676R_VAL_H(val);
sendBuf1[2] = (uint8_t)AD5676R_VAL_L(val);
//发送数据
result = HAL_SPI_Transmit(dacConf->hspi, sendBuf1, txLen, 1000); //第一片数据
if(HAL_OK != result)
{
HAL_GPIO_WritePin(dacConf->sync.port,
dacConf->sync.pin,
GPIO_PIN_SET);
// DEBUGF_INFO("AD5676R_write error\r\n");
}
else
{
//DEBUGF_INFO("AD5676R_Transmit OK\r\n");
// DO NOTHING
}
HAL_GPIO_WritePin(dacConf->sync.port,
dacConf->sync.pin,
GPIO_PIN_SET);
// HAL_GPIO_WritePin(dacConf->nLdac.port, dacConf->nLdac.pin, GPIO_PIN_RESET);
return result;
}
//设置输出电压mv
//dacType : dac类型 这里只有 AD5676R_DAC0
// ch : 通道选择 0-7 共8个通道
//mVolt: 电压值 0-5000,000mv 单位mv
//引用示例 AD5676R_output_ch_mVolt(AD5676R_DAC0,1,200)
HAL_StatusTypeDef AD5676R_output_ch_mVolt(_dacType dacType,
uint8_t ch,
float mVolt)
{
HAL_StatusTypeDef result = HAL_OK;
const float dacPer1mv = (float)65535.0 / (float)5000.0; // 0xFFFF (16bit)
uint8_t cmd;
uint8_t addr;
uint16_t val;
//13.107/mv
cmd = AD5676R_CMD_WRITE_INPUT_N;//AD5676R_CMD_WRITE_INPUT_N
addr = ch;
val = (uint16_t)(mVolt * dacPer1mv);
result = AD5676R_write(dacType, cmd, addr, val);
return result;
}
HAL_StatusTypeDef AD5676R_set_ch_mVolt( uint8_t ch,
float mVolt)
{
HAL_StatusTypeDef result = HAL_OK;
const float dacPer1mv = (float)65535.0 / (float)5000.0; // 0xFFFF (16bit)
uint8_t cmd;
uint8_t addr;
uint16_t val;
if(ch >= 16)
return HAL_ERROR;
//13.107/mv
cmd = AD5676R_CMD_WRITE_INPUT_N;
addr = ch;
val = (uint16_t)(mVolt * dacPer1mv);
if(ch < 8)
result = AD5676R_write(AD5676R_DAC0, cmd, addr, val);
else
result = AD5676R_write(AD5676R_DAC1, cmd, addr-8, val);
return result;
/*
* Copyright 2021 Minchul Jun ([email protected]). All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY MINCHUL JUN ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
* EVENT SHALL MINCHUL JUN OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* The views and conclusions contained in the software and documentation are
* those of the authors and should not be interpreted as representing official
* policies, either expressed or implied, of Minchul Jun.
*
*/
#ifndef __AD5676R_HEADER
#define __AD5676R_HEADER
#include "stm32f4xx_hal.h"
#include "spi.h"
#define AD5676_NUMS ()
#define AD5676R_ADDR(x) ((x) & 0x0F)
#define AD5676R_CMD(x) (((x) << 4) & 0xF0)
#define AD5676R_VAL_H(x) (((x) >> 8) & 0x00FF)
#define AD5676R_VAL_L(x) ((x) & 0x00FF)
#define AD5676R_DAC_ADDR(ch) (0x1 << (ch))
#define AD5676R_DAC_ADDR_ALL 0xF
//AD5676 命令
#define AD5676R_CMD_NOOP 0x0
#define AD5676R_CMD_WRITE_INPUT_N 0x1
#define AD5676R_CMD_UPDATE_DAC_N 0x2
#define AD5676R_CMD_WRITE_INPUT_N_UPDATE_N 0x3
#define AD5676R_CMD_POWERDOWN_DAC 0x4
#define AD5676R_CMD_LDAC_MASK 0x5
#define AD5676R_CMD_SOFT_RESET 0x6
#define AD5676R_CMD_INTERNAL_REFER_SETUP 0x7
#define AD5676R_CMD_DAISYCHAIN_ENABLE 0x8
#define AD5676R_CMD_READBACK_ENABLE 0x9
#define AD5676R_CMD_UPDATE_ALLCH_IREG_WITH_INPUT 0xA
#define AD5676R_CMD_UPDATE_ALLCH_DACREG_WITH_INPUT 0xB
#define AD5676R_CMD_NOOP_DAISYCHAIN_MODE 0xF
//DAC 0
#define SPI1_NCLR_Pin GPIO_PIN_7 //RESET
#define SPI1_NCLR_GPIO_Port GPIOC
#define SPI1_NLDAC_Pin GPIO_PIN_6
#define SPI1_NLDAC_GPIO_Port GPIOC
#define SPI1_SYNC_Pin GPIO_PIN_8
#define SPI1_SYNC_GPIO_Port GPIOC
//DAC 1
#define SPI1_1NCLR_Pin GPIO_PIN_13 //RESET
#define SPI1_1NCLR_GPIO_Port GPIOH
#define SPI1_1SYNC_Pin GPIO_PIN_4
#define SPI1_1SYNC_GPIO_Port GPIOA
//IO方向设置
#define SYNC_IN() {GPIOC->MODER&=~(3<<(8*2));GPIOC->MODER|=0<<8*2;} //PC9输入模式
#define SYNC_OUT() {GPIOC->MODER&=~(3<<(8*2));GPIOC->MODER|=1<<8*2;} //PC9输出模式
//IO方向设置
#define SYNC_1IN() {GPIOA->MODER&=~(3<<(4*2));GPIOA->MODER|=0<<4*2;} //P输入模式
#define SYNC_1OUT() {GPIOA->MODER&=~(3<<(4*2));GPIOA->MODER|=1<<4*2;} //P输出模式
//IO 0-5 直接电压跟随输出
//IO 6-7 放大3倍输出。
typedef enum
{
AD5676R_DAC0,
AD5676R_DAC1
}_dacType;
typedef struct
{
GPIO_TypeDef* port;
uint16_t pin;
}_AD5676R_io;
typedef struct
{
_dacType type;
SPI_HandleTypeDef *hspi;
_AD5676R_io nClr;
_AD5676R_io nLdac;
_AD5676R_io sync;
}_dacConf;
void AD5676R_init(void);
extern HAL_StatusTypeDef _AD5676R_init(_dacType dacType, SPI_HandleTypeDef* hspi);
extern HAL_StatusTypeDef AD5676R_output_ch_mVolt(_dacType dacType, uint8_t ch, float mVolt);
static HAL_StatusTypeDef AD5676R_write(_dacType dacType, uint8_t cmd, uint8_t addr, uint16_t val);
HAL_StatusTypeDef AD5676R_set_ch_mVolt( uint8_t ch, float mVolt);
#endif // __AD5676R_HEADER