DAC在我們的項(xiàng)目中經(jīng)常使用到,而使用最多的就是AD56xx系列,包括有單通道的AD5662、雙通道的AD5623和AD5663、以及四通道的AD5624和AD5664等。出于方便復(fù)用的原因,我們?cè)O(shè)計(jì)并實(shí)現(xiàn)AD56xx系列DAC的驅(qū)動(dòng)。
1 、功能概述
AD56xx系列DAC屬于nanoDAC系列,是低功耗,12位、14位或者16位緩沖電壓輸出數(shù)模轉(zhuǎn)換器(DAC),采用2.7V至5.5V單電源供電。AD56xx采用多功能三線式串行接口,能夠以最高50 MHz的時(shí)鐘速率工作,并與標(biāo)準(zhǔn)SPI、QSPI、MICROWIRE、DSP接口標(biāo)準(zhǔn)兼容。它內(nèi)置片內(nèi)精密輸出放大器,能夠?qū)崿F(xiàn)軌到軌輸出擺幅。其功能框圖如下所示:
AD56xx系列DAC都有一個(gè)24位的移位寄存器,所有的操作都是通過(guò)寫移位寄存器來(lái)實(shí)現(xiàn)的。對(duì)于不同的型號(hào)其移位寄存器的各位略有差異。具體如下圖所示:
單通道沒(méi)有通道選擇位,命令位只有2位,所以我們的軟件實(shí)際上就是針對(duì)不同的功能需求配置移位寄存器。
2 、驅(qū)動(dòng)設(shè)計(jì)與實(shí)現(xiàn)
前面已經(jīng)說(shuō)過(guò),對(duì)AD56xx的操作,實(shí)際就是根據(jù)需要配置移位寄存器。接下來(lái)我們將在此基礎(chǔ)上分析并實(shí)現(xiàn)AD56xx系列DAC的驅(qū)動(dòng)。
2.1 、對(duì)象定義
在使用對(duì)象之前,我們需要抽象對(duì)象的定義。對(duì)于AD56xx系列DAC我們需要定義類型枚舉,因?yàn)樵撓盗邪卸喾NDAC模塊。此外我們還要定義AD56xx系列DAC的對(duì)象類型。
/*定義DAC器件的類型*/
typedef enum AD56xx{
AD5662=0,
AD5623=1,
AD5643=2,
AD5663=3,
AD5624=4,
AD5644=5,
AD5664=6,
TypeNumber,
}AD56xxType;
/* 定義AD56XX對(duì)象類型 */
typedef struct AD56xxObject {
AD56xxType objectType; //DAC的類型
void(*WriteDataToDAC)(uint8_t *tData,uint16_t tSize); //向DAC發(fā)送數(shù)據(jù)
void(*ChipSelcet)(AD56xxCSType cs); //片選信號(hào)
}AD56xxObjectType;
我們抽象了對(duì)象,在我們使用這個(gè)對(duì)象定義聲明了一個(gè)具體的對(duì)象時(shí),它只是一個(gè)代表對(duì)象的變量,我們需要對(duì)它進(jìn)行初始化才可使用。于是我們定義初始化對(duì)象函數(shù)。
/* 初始化AD56xx對(duì)象 */
void AD56xxInitialization(AD56xxObjectType *dacObj,AD56xxTypeobjectType,AD56xxWritewrite,AD56xxChipSelcetcs)
{
if((dacObj==NULL)||(write==NULL)||(cs==NULL))
{
return;
}
if(objectTypeobjectType=objectType;
}
dacObj->WriteDataToDAC=write;
dacObj->ChipSelcet=cs;
}
2.2 、對(duì)象操作
我們已經(jīng)將AD56xx抽象為對(duì)象,那么對(duì)AD56xx的操作都轉(zhuǎn)化為對(duì)某一個(gè)對(duì)象的操作。接下來(lái)我們來(lái)實(shí)現(xiàn)對(duì)象的操作函數(shù)。
2.2.1 、軟件復(fù)位
軟件復(fù)位也是通過(guò)操作輸入移位寄存器來(lái)實(shí)現(xiàn)的。命令位的定義沒(méi)有變化,數(shù)據(jù)段的最后一位作為軟件復(fù)位的模式設(shè)定,其它位無(wú)效。最后一位為0時(shí),會(huì)清除DAC寄存器和輸入寄存器,而最后一位為1時(shí)清除掉全部寄存器。最后一位為1時(shí),實(shí)際就是上電復(fù)位模式。輸入移位寄存器的數(shù)據(jù)格式如下:
其軟件實(shí)現(xiàn)如下:
/* 對(duì)AD56xx進(jìn)行軟件復(fù)位 */
void Ad56xxSoftwareReset(AD56xxObjectType *dacObj,AD56xxResetTyperesetMode)
{
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ù)位也是通過(guò)操作輸入移位寄存器來(lái)實(shí)現(xiàn)的。命令位的定義沒(méi)有變化,數(shù)據(jù)段的DB5和DB4定義掉電的模式,而DB1和DB0定義操作的通道。輸入移位寄存器的數(shù)據(jù)格式如下:
其軟件實(shí)現(xiàn)如下:
/* 設(shè)置AD56xx上電/掉電工作模式 */
void Ad56xxPowerUpDownMode(AD56xxObjectType *dacObj,AD56xxChannelTypechannel,AD56xxPowerdownTypepowerdownType)
{
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操作功能。而對(duì)LDAC操作的寄存器設(shè)置如下圖所示:
其軟件實(shí)現(xiàn)如下:
/* 設(shè)置AD56xx及同類器件LDAC功能 */
void SetAd56xxLdacFunction(AD56xxObjectType *dacObj,AD56xxChannelTypechannel)
{
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è)置
有一些型號(hào)以R結(jié)尾的AD56xx器件是包含有內(nèi)部參考電源的。片內(nèi)基準(zhǔn)電壓源在上電時(shí)默認(rèn)關(guān)閉。通過(guò)設(shè)置控制寄存器中的軟件可編程位DB0,可以開(kāi)啟或關(guān)閉此基準(zhǔn)電壓源。具體的寄存器設(shè)置如下圖所示:
其軟件實(shí)現(xiàn)如下:
/* 開(kāi)啟或關(guān)閉內(nèi)部參考電壓源 */
void SetInternalReference(AD56xxObjectType*dacObj,AD56xxRefTyperef)
{
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.3.5 、輸出操作
對(duì)各輸出通道值的操作也是通過(guò)輸入移位寄存器來(lái)完成。其數(shù)據(jù)格式如前面輸入移位寄存器的介紹。后16位是數(shù)據(jù)(0-65535),然后是3位地址和3位命令。通訊的時(shí)序圖如下所示:
其軟件實(shí)現(xiàn)如下:
/* 設(shè)置DA通道的值 */
void SetAD56xxChannelValue(AD56xxObjectType *dacObj,AD56xxChannelTypechannel,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<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ū)動(dòng)的使用
我們已經(jīng)實(shí)現(xiàn)了AD56xx系列DAC的驅(qū)動(dòng),接下來(lái)我們就可以使用我們的這個(gè)驅(qū)動(dòng)實(shí)現(xiàn)我們的應(yīng)用了。
3.1 、聲明并初始化對(duì)象
首先需要使用AD56xx對(duì)象類型AD56xxObjectType聲明一個(gè)對(duì)象變量。具體聲明形式如下:AD56xxObjectType ad56xx;
對(duì)象變量需要使用AD56xxInitialization函數(shù)進(jìn)行初始化。這個(gè)函數(shù)的參數(shù)除了對(duì)象變量外還有對(duì)象類型以及寫數(shù)據(jù)操作和片選操作2個(gè)函數(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);
我們實(shí)現(xiàn)這幾個(gè)函數(shù)并將函數(shù)指針作為參數(shù)傳遞給初始化函數(shù)。初始化函數(shù)的調(diào)用樣式如下:
AD56xxInitialization(&ad56xx,objectType,write,cs);
后兩個(gè)參數(shù)即是上面定義的2個(gè)函數(shù)的函數(shù)指針。這兩個(gè)函數(shù)根據(jù)具體的硬件電路來(lái)實(shí)現(xiàn)。第二個(gè)參數(shù)為對(duì)象類型,為AD56xxType枚舉類型。
3.2 、基于對(duì)象進(jìn)行操作
初始化完成后就可以操作對(duì)象了。對(duì)AD56xx系列DAC對(duì)象的操作包括:軟件復(fù)位操作,上下電模式控制,LDAC控制,參考電壓操作以及輸出控制。下面將調(diào)用驅(qū)動(dòng)函數(shù)實(shí)現(xiàn)相應(yīng)的應(yīng)用。
AD56xx系列DAC擁有1到4個(gè)通道,所以我們需要為操作制定通道。還有向該通道設(shè)定的數(shù)據(jù),由于AD56xx系列DAC為12到16位,所以我們要發(fā)送一個(gè)不超過(guò)16位的無(wú)符號(hào)整數(shù)。有了這兩個(gè)參數(shù)我們就可以調(diào)用SetAD56xxChannelValue函數(shù)為AD56xx系列DAC設(shè)定輸出了。
SetAD56xxChannelValue(&ad56xx,channel,data);
第二個(gè)參數(shù)為設(shè)定的通道,是一個(gè)AD56xxChannelType類型的枚舉,以此決定我們當(dāng)前操作的是哪一個(gè)通道。而其它的函數(shù):
/*設(shè)置AD56xx上電/掉電工作模式*/
void Ad56xxPowerUpDownMode(AD56xxObjectType *dacObj,AD56xxChannelTypechannel,AD56xxPowerdownType powerdownType);
/*對(duì)AD56xx進(jìn)行軟件復(fù)位*/
void Ad56xxSoftwareReset(AD56xxObjectType *dacObj,AD56xxResetTyperesetMode);
/* 開(kāi)啟或關(guān)閉內(nèi)部參考電壓源 */
void SetInternalReference(AD56xxObjectType *dacObj,AD56xxRefTyperef);
/*設(shè)置AD56xx及同類器件LDAC功能*/
void SetAd56xxLdacFunction(AD56xxObjectType*dacObj,AD56xxChannelType channel);
其調(diào)用方式是類似的。需要指出的是SetInternalReference函數(shù),只有具有內(nèi)部參考電源的器件調(diào)用這個(gè)函數(shù)才有作用。
4 、應(yīng)用總結(jié)
我們使用AD56xx系列DAC實(shí)現(xiàn)過(guò)多種應(yīng)用,都是基于我們的驅(qū)動(dòng)開(kāi)發(fā)的。使用的結(jié)果基本都與我們的預(yù)期一樣。
需要注意對(duì)象的類型,特別是AD5662的移位寄存器有很大區(qū)別。雖然驅(qū)動(dòng)在這一方面作了處理,但是基于初始化時(shí)配置的類型執(zhí)行的。所以在調(diào)用初始化函數(shù)初始化對(duì)象時(shí)一定要傳遞正確的類型。
**源碼公布到GitHUB:**https://github.com/foxclever/ExPeriphDriver
評(píng)論