基于stm32F4 HAL固件库16BIT DAC AD5676驱动代码
AD5676为单片8通道DAC此程序同时驱动两片DAC硬件链接上两片DAC共用MOSIMISOSPI_CLKLDAC引脚。不共用SYNCRESET引脚。使用的引脚在H文件中有定义。/* * Copyright 2021 Minchul Jun (mcjun37naver.com). 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;pp1;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;pp8;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.PinSPI1_NCLR_Pin|SPI1_NLDAC_Pin|SPI1_SYNC_Pin; GPIO_Initure.ModeGPIO_MODE_OUTPUT_PP; GPIO_Initure.PullGPIO_PULLUP; //上拉 GPIO_Initure.SpeedGPIO_SPEED_HIGH; //高速 HAL_GPIO_Init(GPIOC,GPIO_Initure); GPIO_Initure.PinSPI1_SYNC_Pin; GPIO_Initure.ModeGPIO_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 (mcjun37naver.com). 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|08*2;} //PC9输入模式 #define SYNC_OUT() {GPIOC-MODER~(3(8*2));GPIOC-MODER|18*2;} //PC9输出模式 //IO方向设置 #define SYNC_1IN() {GPIOA-MODER~(3(4*2));GPIOA-MODER|04*2;} //P输入模式 #define SYNC_1OUT() {GPIOA-MODER~(3(4*2));GPIOA-MODER|14*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