基于stm32F4 HAL固件库16BIT DAC AD5676驱动代码

  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





你可能感兴趣的:(stm32-HAL库,stm32,硬件设计相关,stm32,单片机,嵌入式硬件)