DAC在我們的項目中經(jīng)常使用到,而使用最多的就是AD56xx系列,包括有單通道的AD5662、雙通道的AD5623和AD5663、以及四通道的AD5624和AD5664等。出于方便復用的原因,我們設(shè)計并實現(xiàn)AD56xx系列DAC的驅(qū)動。
1 、功能概述
AD56xx系列DAC屬于nanoDAC系列,是低功耗,12位、14位或者16位緩沖電壓輸出數(shù)模轉(zhuǎn)換器(DAC),采用2.7V至5.5V單電源供電。AD56xx采用多功能三線式串行接口,能夠以最高50 MHz的時鐘速率工作,并與標準SPI、QSPI、MICROWIRE、DSP接口標準兼容。它內(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;
我們抽象了對象,在我們使用這個對象定義聲明了一個具體的對象時,它只是一個代表對象的變量,我們需要對它進行初始化才可使用。于是我們定義初始化對象函數(shù)。
/* 初始化AD56xx對象 */
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 、對象操作
我們已經(jīng)將AD56xx抽象為對象,那么對AD56xx的操作都轉(zhuǎn)化為對某一個對象的操作。接下來我們來實現(xiàn)對象的操作函數(shù)。
2.2.1 、軟件復位
軟件復位也是通過操作輸入移位寄存器來實現(xiàn)的。命令位的定義沒有變化,數(shù)據(jù)段的最后一位作為軟件復位的模式設(shè)定,其它位無效。最后一位為0時,會清除DAC寄存器和輸入寄存器,而最后一位為1時清除掉全部寄存器。最后一位為1時,實際就是上電復位模式。輸入移位寄存器的數(shù)據(jù)格式如下:
其軟件實現(xiàn)如下:
/* 對AD56xx進行軟件復位 */
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 、上電復位
上電復位也是通過操作輸入移位寄存器來實現(xiàn)的。命令位的定義沒有變化,數(shù)據(jù)段的DB5和DB4定義掉電的模式,而DB1和DB0定義操作的通道。輸入移位寄存器的數(shù)據(jù)格式如下:
其軟件實現(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操作功能。而對LDAC操作的寄存器設(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)部基準電壓源設(shè)置
有一些型號以R結(jié)尾的AD56xx器件是包含有內(nèi)部參考電源的。片內(nèi)基準電壓源在上電時默認關(guān)閉。通過設(shè)置控制寄存器中的軟件可編程位DB0,可以開啟或關(guān)閉此基準電壓源。具體的寄存器設(shè)置如下圖所示:
其軟件實現(xiàn)如下:
/* 開啟或關(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 、輸出操作
對各輸出通道值的操作也是通過輸入移位寄存器來完成。其數(shù)據(jù)格式如前面輸入移位寄存器的介紹。后16位是數(shù)據(jù)(0-65535),然后是3位地址和3位命令。通訊的時序圖如下所示:
其軟件實現(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ū)動的使用
我們已經(jīng)實現(xiàn)了AD56xx系列DAC的驅(qū)動,接下來我們就可以使用我們的這個驅(qū)動實現(xiàn)我們的應(yīng)用了。
3.1 、聲明并初始化對象
首先需要使用AD56xx對象類型AD56xxObjectType聲明一個對象變量。具體聲明形式如下:AD56xxObjectType ad56xx;
對象變量需要使用AD56xxInitialization函數(shù)進行初始化。這個函數(shù)的參數(shù)除了對象變量外還有對象類型以及寫數(shù)據(jù)操作和片選操作2個函數(shù)指針。在調(diào)用初始化函數(shù)之前必須準備好這些參數(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 、基于對象進行操作
初始化完成后就可以操作對象了。對AD56xx系列DAC對象的操作包括:軟件復位操作,上下電模式控制,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類型的枚舉,以此決定我們當前操作的是哪一個通道。而其它的函數(shù):
/*設(shè)置AD56xx上電/掉電工作模式*/
void Ad56xxPowerUpDownMode(AD56xxObjectType *dacObj,AD56xxChannelTypechannel,AD56xxPowerdownType powerdownType);
/*對AD56xx進行軟件復位*/
void Ad56xxSoftwareReset(AD56xxObjectType *dacObj,AD56xxResetTyperesetMode);
/* 開啟或關(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)用這個函數(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
評論