外设驱动库开发笔记1:AD56xx系列DAC驱动
DAC在我們的項目中經(jīng)常使用到,而使用最多的就是AD56xx系列,包括有單通道的AD5662、雙通道的AD5623和AD5663、以及四通道的AD5624和AD5664等。出于方便復(fù)用的原因,我們設(shè)計并實現(xiàn)AD56xx系列DAC的驅(qū)動。
1、功能概述
AD56xx系列DAC屬于nanoDAC系列,是低功耗,12位、14位或者16位緩沖電壓輸出數(shù)模轉(zhuǎn)換器(DAC),采用2.7V至5.5V單電源供電。AD56xx采用多功能三線式串行接口,能夠以最高50 MHz的時鐘速率工作,并與標(biāo)準(zhǔn)SPI、QSPI、MICROWIRE、DSP接口標(biāo)準(zhǔn)兼容。它內(nèi)置片內(nèi)精密輸出放大器,能夠?qū)崿F(xiàn)軌到軌輸出擺幅。其功能框圖如下所示:
AD56xx系列DAC都有一個24位的移位寄存器,所有的操作都是通過寫移位寄存器來實現(xiàn)的。對于不同的型號其移位寄存器的各位略有差異。具體如下圖所示:
單通道沒有通道選擇位,命令位只有2位,所以我們的軟件實際上就是針對不同的功能需求配置移位寄存器。
2、驅(qū)動設(shè)計與實現(xiàn)
前面已經(jīng)說過,對AD56xx的操作,實際就是根據(jù)需要配置移位寄存器。接下來我們將在此基礎(chǔ)上分析并實現(xiàn)AD56xx系列DAC的驅(qū)動。
2.1、對象定義
在使用對象之前,我們需要抽象對象的定義。對于AD56xx系列DAC我們需要定義類型枚舉,因為該系列包含有多種DAC模塊。此外我們還要定義AD56xx系列DAC的對象類型。
/*定義DAC器件的類型*/ typedef enum AD56xx{AD5662=0,AD5623=1,AD5643=2,AD5663=3,AD5624=4,AD5644=5,AD5664=6,TypeNumber, }AD56xxType;/* 定義AD56XX對象類型 */ typedef struct AD56xxObject {AD56xxType objectType;??????? //DAC的類型void (*WriteDataToDAC)(uint8_t *tData,uint16_t tSize);??????? //向DAC發(fā)送數(shù)據(jù)void (*ChipSelcet)(AD56xxCSType cs);???? //片選信號 }AD56xxObjectType;我們抽象了對象,在我們使用這個對象定義聲明了一個具體的對象時,它只是一個代表對象的變量,我們需要對它進(jìn)行初始化才可使用。于是我們定義初始化對象函數(shù)。
/* 初始化AD56xx對象 */ void AD56xxInitialization(AD56xxObjectType *dacObj,AD56xxType objectType,AD56xxWrite write,AD56xxChipSelcet cs) {if((dacObj==NULL)||(write==NULL)||(cs==NULL)){return;}if(objectType<TypeNumber){dacObj->objectType=objectType;}dacObj->WriteDataToDAC=write;dacObj->ChipSelcet=cs; }2.2、對象操作
我們已經(jīng)將AD56xx抽象為對象,那么對AD56xx的操作都轉(zhuǎn)化為對某一個對象的操作。接下來我們來實現(xiàn)對象的操作函數(shù)。
2.2.1、軟件復(fù)位
軟件復(fù)位也是通過操作輸入移位寄存器來實現(xiàn)的。命令位的定義沒有變化,數(shù)據(jù)段的最后一位作為軟件復(fù)位的模式設(shè)定,其它位無效。最后一位為0時,會清除DAC寄存器和輸入寄存器,而最后一位為1時清除掉全部寄存器。最后一位為1時,實際就是上電復(fù)位模式。輸入移位寄存器的數(shù)據(jù)格式如下:
其軟件實現(xiàn)如下:
/* 對AD56xx進(jìn)行軟件復(fù)位 */ void Ad56xxSoftwareReset(AD56xxObjectType *dacObj,AD56xxResetType resetMode) {uint32_t inputShiftData=0;if(resetMode==ResetSoftware){inputShiftData=RESET|Register_Reset_Software;}if(resetMode==ResetPoweron){inputShiftData=RESET|Register_Reset_Poweron;}uint8_t txData[3];txData[0]=inputShiftData>>16;txData[1]=inputShiftData>>8;txData[2]=inputShiftData;dacObj->ChipSelcet(AD56xxCS_Enable);dacObj->WriteDataToDAC(txData,3);dacObj->ChipSelcet(AD56xxCS_Disable); }2.2.2、上電復(fù)位
上電復(fù)位也是通過操作輸入移位寄存器來實現(xiàn)的。命令位的定義沒有變化,數(shù)據(jù)段的DB5和DB4定義掉電的模式,而DB1和DB0定義操作的通道。輸入移位寄存器的數(shù)據(jù)格式如下:
其軟件實現(xiàn)如下:
/* 設(shè)置AD56xx上電/掉電工作模式 */ void Ad56xxPowerUpDownMode(AD56xxObjectType *dacObj,AD56xxChannelType channel,AD56xxPowerdownType powerdownType) {uint32_t inputShiftData=0;uint32_t pdc=0;uint32_t pdm=0;uint32_t cmd=Power_Down;uint32_t pdChannel[]={DAC_A,DAC_B,DAC_C,DAC_D,DAC_ALL,DAC_None};pdc=pdChannel[channel];uint32_t pdMode[]={Normal_Operation,_1K_GND,_100K_GND,Three_State};pdm=pdMode[powerdownType];if(dacObj->objectType==AD5662){pdc=DAC_None;pdm=(pdm<<12);cmd=Write_to_Input_Register;}inputShiftData=cmd|pdc|pdm;uint8_t txData[3];txData[0]=inputShiftData>>16;txData[1]=inputShiftData>>8;txData[2]=inputShiftData;dacObj->ChipSelcet(AD56xxCS_Enable);dacObj->WriteDataToDAC(txData,3);dacObj->ChipSelcet(AD56xxCS_Disable); }2.2.3、LDAC功能
除去單通道的設(shè)備外,其他的AD56xx設(shè)備都具有LDAC操作功能。而對LDAC操作的寄存器設(shè)置如下圖所示:
其軟件實現(xiàn)如下:
/* 設(shè)置AD56xx及同類器件LDAC功能 */ void SetAd56xxLdacFunction(AD56xxObjectType *dacObj,AD56xxChannelType channel) {uint32_t inputShiftData=0;uint32_t pdChannel[]={DAC_A,DAC_B,DAC_C,DAC_D,DAC_ALL,DAC_None};inputShiftData=pdChannel[channel];inputShiftData=inputShiftData|LDAC_Register_Setup;uint8_t txData[3];txData[0]=(uint8_t)(inputShiftData>>16);txData[1]=(uint8_t)(inputShiftData>>8);txData[2]=(uint8_t)inputShiftData;dacObj->ChipSelcet(AD56xxCS_Enable);dacObj->WriteDataToDAC(txData,3);dacObj->ChipSelcet(AD56xxCS_Disable); }2.2.4、內(nèi)部基準(zhǔn)電壓源設(shè)置
有一些型號以R結(jié)尾的AD56xx器件是包含有內(nèi)部參考電源的。片內(nèi)基準(zhǔn)電壓源在上電時默認(rèn)關(guān)閉。通過設(shè)置控制寄存器中的軟件可編程位DB0,可以開啟或關(guān)閉此基準(zhǔn)電壓源。 具體的寄存器設(shè)置如下圖所示:
其軟件實現(xiàn)如下:
/* 開啟或關(guān)閉內(nèi)部參考電壓源 */ void SetInternalReference(AD56xxObjectType *dacObj,AD56xxRefType ref) {uint32_t inputShiftData=0;inputShiftData=Reference_Set;if(ref==AD56xxRef_ON){inputShiftData=inputShiftData|Reference_ON;}uint8_t txData[3];txData[0]=(uint8_t)(inputShiftData>>16);txData[1]=(uint8_t)(inputShiftData>>8);txData[2]=(uint8_t)inputShiftData;dacObj->ChipSelcet(AD56xxCS_Enable);dacObj->WriteDataToDAC(txData,3);dacObj->ChipSelcet(AD56xxCS_Disable); }2.2.5、輸出操作
對各輸出通道值的操作也是通過輸入移位寄存器來完成。其數(shù)據(jù)格式如前面輸入移位寄存器的介紹。后16位是數(shù)據(jù)(0-65535),然后是3位地址和3位命令。通訊的時序圖如下所示:
其軟件實現(xiàn)如下:
/* 設(shè)置DA通道的值 */ void SetAD56xxChannelValue(AD56xxObjectType *dacObj,AD56xxChannelType channel,uint16_t data) {uint32_t inputShiftData=0;uint32_t dac=0;uint32_t cmd=WriteTo_Update_DAC_Channel;uint32_t dacChannel[]={DAC_Channel_A,DAC_Channel_B,DAC_Channel_C,DAC_Channel_D,DAC_Channel_ALL};uint32_t shiftV[]={0,4,2,0,4,0};if(channel>=ChannelNone){return;}dac=dacChannel[channel];if(dacObj->objectType==AD5662){dac=DAC_Channel_A;cmd=Write_to_Input_Register;}inputShiftData=dac|cmd|(data<<shiftV[dacObj->objectType]);uint8_t txData[3];txData[0]=(uint8_t)(inputShiftData>>16);txData[1]=(uint8_t)(inputShiftData>>8);txData[2]=(uint8_t)inputShiftData;dacObj->ChipSelcet(AD56xxCS_Enable);dacObj->WriteDataToDAC(txData,3);dacObj->ChipSelcet(AD56xxCS_Disable); }3、驅(qū)動的使用
我們已經(jīng)實現(xiàn)了AD56xx系列DAC的驅(qū)動,接下來我們就可以使用我們的這個驅(qū)動實現(xiàn)我們的應(yīng)用了。
3.1、聲明并初始化對象
首先需要使用AD56xx對象類型AD56xxObjectType聲明一個對象變量。具體聲明形式如下:AD56xxObjectType ad56xx;
對象變量需要使用AD56xxInitialization函數(shù)進(jìn)行初始化。這個函數(shù)的參數(shù)除了對象變量外還有對象類型以及寫數(shù)據(jù)操作和片選操作2個函數(shù)指針。在調(diào)用初始化函數(shù)之前必須準(zhǔn)備好這些參數(shù)。所以我們需要按如下類型定義相關(guān)函數(shù)。
/* 向DAC發(fā)送數(shù)據(jù)函數(shù)指針類型 */ typedef void (*AD56xxWrite)(uint8_t *tData,uint16_t tSize);/* 片選操作函數(shù)指針類型 */ typedef void (*AD56xxChipSelcet)(AD56xxCSType cs);我們實現(xiàn)這幾個函數(shù)并將函數(shù)指針作為參數(shù)傳遞給初始化函數(shù)。初始化函數(shù)的調(diào)用樣式如下:
AD56xxInitialization(&ad56xx,objectType,write,cs);
后兩個參數(shù)即是上面定義的2個函數(shù)的函數(shù)指針。這兩個函數(shù)根據(jù)具體的硬件電路來實現(xiàn)。第二個參數(shù)為對象類型,為AD56xxType枚舉類型。
3.2、基于對象進(jìn)行操作
初始化完成后就可以操作對象了。對AD56xx系列DAC對象的操作包括:軟件復(fù)位操作,上下電模式控制,LDAC控制,參考電壓操作以及輸出控制。下面將調(diào)用驅(qū)動函數(shù)實現(xiàn)相應(yīng)的應(yīng)用。
AD56xx系列DAC擁有1到4個通道,所以我們需要為操作制定通道。還有向該通道設(shè)定的數(shù)據(jù),由于AD56xx系列DAC為12到16位,所以我們要發(fā)送一個不超過16位的無符號整數(shù)。有了這兩個參數(shù)我們就可以調(diào)用SetAD56xxChannelValue函數(shù)為AD56xx系列DAC設(shè)定輸出了。
SetAD56xxChannelValue(&ad56xx,channel,data);
第二個參數(shù)為設(shè)定的通道,是一個AD56xxChannelType類型的枚舉,以此決定我們當(dāng)前操作的是哪一個通道。而其它的函數(shù):
/*設(shè)置AD56xx上電/掉電工作模式*/ void Ad56xxPowerUpDownMode(AD56xxObjectType *dacObj,AD56xxChannelType channel,AD56xxPowerdownType powerdownType);/*對AD56xx進(jìn)行軟件復(fù)位*/ void Ad56xxSoftwareReset(AD56xxObjectType *dacObj,AD56xxResetType resetMode);/* 開啟或關(guān)閉內(nèi)部參考電壓源 */ void SetInternalReference(AD56xxObjectType *dacObj,AD56xxRefType ref);/*設(shè)置AD56xx及同類器件LDAC功能*/ void SetAd56xxLdacFunction(AD56xxObjectType *dacObj,AD56xxChannelType channel);其調(diào)用方式是類似的。需要指出的是SetInternalReference函數(shù),只有具有內(nèi)部參考電源的器件調(diào)用這個函數(shù)才有作用。
4、應(yīng)用總結(jié)
我們使用AD56xx系列DAC實現(xiàn)過多種應(yīng)用,都是基于我們的驅(qū)動開發(fā)的。使用的結(jié)果基本都與我們的預(yù)期一樣。
需要注意對象的類型,特別是AD5662的移位寄存器有很大區(qū)別。雖然驅(qū)動在這一方面作了處理,但是基于初始化時配置的類型執(zhí)行的。所以在調(diào)用初始化函數(shù)初始化對象時一定要傳遞正確的類型。
?源碼公布到GitHUB:https://github.com/foxclever/ExPeriphDriver
歡迎關(guān)注:
總結(jié)
以上是生活随笔為你收集整理的外设驱动库开发笔记1:AD56xx系列DAC驱动的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 共享内存实践总结
- 下一篇: 外设驱动库开发笔记8:GPIO模拟I2C