PDB(可編程延遲模塊)提供從觸發源到ADC的硬件觸發器輸入的可控延遲,觸發源來自內部、外部觸發器或可編程間隔時鐘。PDB可以選擇性的提供脈沖輸出,脈沖輸出可用作CMP(比較器)中的采樣窗口。
CKS32K148有兩個PDB,每個PDB模塊有4個通道、一次脈沖輸出和1個觸發器,每個通道有8個預觸發器。因此,一個PDB模塊一次可以觸發ADC多達32個輸入通道。
結構與框圖
CKS32K148系列MCU的PDB框圖如下所示,大體可劃分成六個部分。
圖1 AIPS結果框圖
①觸發源選擇部分:PDB的觸發源選擇通過PDB_SC寄存器中的TRGSEL位確定,其可以是軟件觸發-通過向PDB_SC寄存器的SWTRIG位寫入1實現;也可以是外部觸發源-如外部觸發引腳Trigger_In0。
②計數器部分:PDB的時鐘源經過PDB_SC寄存器中的PRESCALER位選擇的分配系數進行分頻,通過PDB_SC寄存器中的MULT位選擇倍頻系數,之后計數器開始工作。計數器當前計數值可以通過計數器寄存器PDB_CNT讀取。計數器的周期通過PDB_MOD模數寄存器指定,當計數器達到該值時,將被重置為零。
計數器的控制邏輯通過PDB_SC寄存器中的CONT位實現:當該位無效時,計數器達到周期值時被重置為零,直至下一次觸發出現后重新開始計數;當該位有效時,計數器達到周期值時自動重新開始。
③預觸發器輸出部分:PDB通道n(n = 0 ~ 3)預觸發器輸出0~m(m最大值為7),每個預觸發輸出連接ADC硬件觸發選擇和硬件觸發輸入,預觸發可以使用PDB通道預觸發使能(CHn1C1[EN[m]])啟用或禁止。
為方便敘述,定義觸發器輸入事件為:在所選觸發輸入源上檢測到上升沿,或者選擇軟件觸發器并將軟件觸發器位(SC[SWTRIG])寫入1。預觸發源輸出對應三種情況:
a)當觸發器輸入事件發生時,在2個外圍時鐘周期后置位預觸發器m。這種情況下,需要清零CHnC1[TOS[m]]。
b)使用通道延遲寄存器CHnDLYm指定延遲值,當計數器計數值達到該值時,經過兩個外圍時鐘周期后置位預觸發器m。這種情況下,需要置位CHnC1[TOS[m]]。
c)PDB配置成背靠背操作,背靠背操作使得ADC轉換完成觸發下一個PDB通道預觸發和觸發輸出。換句話說,預觸發m-1觸發ADC轉換完成之后產生的Ack信號會使預觸發輸出m置位兩個外圍時鐘周期。這種情況下,需要置位CHnC1[BB[m]]。
④觸發輸出部分:預觸發輸出用于在實際觸發器發生之前對ADC塊進行預處理。當ADC接收到觸發器的上升沿時,ADC將根據預觸發器決定的先決條件開始轉換,PDB通道n的預觸發和觸發輸出如下圖所示。
圖2 預觸發輸出和觸發輸出
如果PDB通道n的預觸發器被置位時置位一個新的預觸發器m,那么會產生PDB通道序列錯誤標志(CHnS[ERR[m]]置位)。如果使能PDB序列錯誤中斷,則產生序列錯誤中斷。序列錯誤通常是由于延遲m設置的太短,并且預觸發m在先前觸發的ADC轉換之前置位。例如預觸發m-1置位并觸發ADC轉換這一過程還未結束時,此時預觸發m置位則會產生序列錯誤。
⑤脈沖輸出部分:PDB可以產生可配置寬度的脈沖輸出。當PDB計數器達到PonDLY[DLY1]中設置的值時,脈沖輸出拉高;當PDB計數器達到PonDLY[DLY2]中設置的值時,脈沖輸出拉低。PonDLY[DLY2]可以設置為大于或者小于PonDLY[DLY1]中的值。
⑥中斷部分:中斷延遲寄存器PDB_IDLY指定PDB中斷的延遲值,可以用來在PDB周期的某個點安排一個獨立的中斷。如果使能中斷(PDB_SC[PDBIE]置位),當計數器等于IDLY時,將產生一個PDB中斷。
PDB延遲觸發ADC多通道實驗
CKS32K148 PDB最常用的功能就是為ADC提供硬件觸發源,我們這里展示PDB延遲觸發ADC功能。即前文介紹過預觸發輸出的b)情況-使用通道延遲寄存器CHnDLYm指定延遲值,當計數器計數值達到該值時,經過兩個外圍時鐘周期后置位預觸發器m。
前面介紹過,每個PDB模塊有4個通道、1個觸發器和一次脈沖輸出,每個通道有8個預觸發輸出,這里我們只用到1個通道、1個觸發器和8個預觸發輸出,用來觸發ADC的8個輸入通道。為了避免出現PDB序列錯誤,需要確保預觸發器之間有足夠的延遲。
編程要點如下:
1. 使能相關外設時鐘,如ADC、PDB等,并配置用到的引腳
status = CLOCK_DRV_Init(&clockMan1_InitConfig0);
DEV_ASSERT(status == STATUS_SUCCESS);
status=PINS_DRV_Init(NUM_OF_CONFIGURED_PINS0, g_pin_mux_InitConfigArr0);
DEV_ASSERT(status == STATUS_SUCCESS);
2. 配置ADC結構體參數、輸入通道。此處僅展示前2個通道配置函數
ADC_DRV_ConfigConverter(INST_ADC_0, &ADC_0_ConvConfig0);
PDB_DRV_ConfigAdcPreTrigger(INST_PDB_0, 0U, &pdb_1_adcTrigConfig0);
PDB_DRV_ConfigAdcPreTrigger(INST_PDB_0, 0U, &pdb_1_adcTrigConfig1);
/*** ADC初始化結構體***/
const adc_converter_config_t ADC_0_ConvConfig0 = {
.clockDivide = ADC_CLK_DIVIDE_4,
.sampleTime = 255U,
.resolution = ADC_RESOLUTION_12BIT,
.inputClock = ADC_CLK_ALT_1,
.trigger = ADC_TRIGGER_HARDWARE,
.pretriggerSel = ADC_PRETRIGGER_SEL_PDB,
.triggerSel = ADC_TRIGGER_SEL_PDB,
.dmaEnable = false,
.voltageRef = ADC_VOLTAGEREF_VREF,
.continuousConvEnable = false,
.supplyMonitoringEnable = false
};
關鍵在于配置ADC為硬件觸發方式,預觸發源和觸發源均為PDB,禁止連續模式。配置ADC8個輸入通道:指定外部/內部輸入通道,每個通道均使能轉換完成中斷。
3.PDB計數器配置和使能
PDB_DRV_Init(INST_PDB_0, &pdb_1_timerConfig0);
PDB_DRV_Enable(INST_PDB_0);
/*** PDB計數器初始化結構體***/
const pdb_timer_config_t pdb_1_timerConfig0 = {
.loadValueMode = PDB_LOAD_VAL_IMMEDIATELY,
.seqErrIntEnable = false,
.clkPreDiv = PDB_CLK_PREDIV_BY_128,
.clkPreMultFactor = PDB_CLK_PREMULT_FACT_AS_10,
.triggerInput = PDB_SOFTWARE_TRIGGER,
.continuousModeEnable = true,
.dmaEnable = false,
.intEnable = false,
.instanceBackToBackEnable = false,
};
參數loadValueMode:用于選擇加載模式,控制PDB操作時間的寄存器(如模數寄存器、中斷延遲寄存器等)可能需要同時變得有效。這些寄存器被寫入的值會先更新到它們的緩沖區,因此加載模式就用來選擇達到何種條件時緩沖區的值更新到內部寄存器的情況。這里我們選擇默認值,即立即更新緩沖區的加載值。
參數seqErrIntEnable:用于設置PDB序列錯誤中斷的使能與否。這里我們關閉使能。
參數clkPreDiv:用于選擇預分頻系數。這里我們設置成128分頻。
參數clkPreMultFactor:用于選擇倍頻系數。這里我們設置成10倍頻。
參數triggerInput:用于選擇觸發輸入源。這里選擇軟件觸發方式。
參數continuousModeEnable:用于選擇是否使能連續模式。配置使能連續模式,所以當計數器達到周期值時,自動從零開始重新計數。
參數dmaEnable:用于選擇是否使能DMA。如果使能DMA,當PDB計數器達到中斷延遲寄存器PDB_IDLY指定的延遲值時,PDB中斷標志置位,PDB請求一個DMA傳輸。這里我們禁止DMA。
參數intEnable:用于選擇是否使能計數器中斷。只有當DMA失能時才會產生計數器延遲中斷。這里我們禁止計數器中斷。
參數instanceBackToBackEnable:用于選擇是否使能背靠背操作,對應前面介紹的預觸發輸出情況c)。這里我們禁止背靠背操作。
4. PDB計數器周期值配置
calculateIntValue(&pdb_1_timerConfig0, PDLY_TIMEOUT, &delayValue0);
PDB_DRV_SetTimerModulusValue(INST_PDB_0, (uint32_t) delayValue0);
PDLY_TIMEOUT為用戶設置的周期值,我們設為1s。calculateIntValue函數可將用戶設置的計數器周期根據計數器的時鐘頻率轉換成對應的十六進制數,之后將該十六進制數寫入PDB_MOD寄存器中。
5. PDB預觸發輸出配置(此處僅展示通道0的前兩個預觸發輸出函數配置)
PDB_DRV_ConfigAdcPreTrigger(INST_PDB_0, 0U, &pdb_1_adcTrigConfig0);
PDB_DRV_ConfigAdcPreTrigger(INST_PDB_0, 0U, &pdb_1_adcTrigConfig1);
/*** 預觸發輸出配置結構體***/
const pdb_adc_pretrigger_config_t pdb_1_adcTrigConfig0 = {
.adcPreTriggerIdx = 0U,
.preTriggerEnable = true,
.preTriggerOutputEnable = true,
.preTriggerBackToBackEnable = false
};
上述參數分別為:預觸發輸出序號(0~7),是否使能預觸發,是否使能預觸發輸出以及是否使能背靠背操作。其余預觸發輸出除輸出序號不同外其他配置均相同。
6. 設置預觸發延遲值
PDB_DRV_SetAdcPreTriggerDelayValue(INST_PDB_0, 0UL, 0UL,(uint32_t) delayValue0 / 9);
PDB_DRV_SetAdcPreTriggerDelayValue(INST_PDB_0, 0UL, 1UL,(uint32_t) delayValue0 / 8);
PDB_DRV_SetAdcPreTriggerDelayValue(INST_PDB_0, 0UL, 2UL,(uint32_t) delayValue0 / 7);
PDB_DRV_SetAdcPreTriggerDelayValue(INST_PDB_0, 0UL, 3UL,(uint32_t) delayValue0 / 6);
PDB_DRV_SetAdcPreTriggerDelayValue(INST_PDB_0, 0UL, 4UL,(uint32_t) delayValue0 / 5);
PDB_DRV_SetAdcPreTriggerDelayValue(INST_PDB_0, 0UL, 5UL,(uint32_t) delayValue0 / 4);
PDB_DRV_SetAdcPreTriggerDelayValue(INST_PDB_0, 0UL, 6UL,(uint32_t) delayValue0 / 3);
PDB_DRV_SetAdcPreTriggerDelayValue(INST_PDB_0, 0UL, 7UL,(uint32_t) delayValue0 / 2);
前面我們設置PDB周期為1s,因此預觸發輸出1和預觸發輸出0之間的延遲為1 * (1/8 - 1/9) = 13.88ms。同理,預觸發2和預觸發1之間的延遲為17.925ms,預觸發3和預觸發2之間的延遲為11.9ms,預觸發4和預觸發3之間的延遲為16.65ms,預觸發5和預觸發4之間的延遲為25ms,預觸發6和預觸發5之間的延遲為41.65ms,預觸發7和預觸發6之間的延遲為83.3ms。
7.執行加載命令,使能軟件觸發
PDB_DRV_LoadValuesCmd(INST_PDB_0);
PDB_DRV_SoftTriggerCmd(INST_PDB_0);
執行加載命令后,先前設置好的相關寄存器值(PDB_MOD、PDB_CHnDLYm)立即從緩沖區更新到內部寄存器。軟件觸發PDB后,計數器開始工作。
8. 使能ADC中斷
INT_SYS_InstallHandler(ADC0_IRQn, &ADC0_IRQHandler, (isr_t*) 0);
INT_SYS_EnableIRQ(ADC0_IRQn);
9. 編寫中斷服務函數:在中斷中獲取ADC結果,同時翻轉IO電平
void ADC0_IRQHandler(void)
{
ADC_DRV_GetChanResult(INST_ADC_0, 0UL, (uint16_t *)&adcRawValue0[0]);
ADC_DRV_GetChanResult(INST_ADC_0, 1UL, (uint16_t *)&adcRawValue0[1]);
ADC_DRV_GetChanResult(INST_ADC_0, 2UL, (uint16_t *)&adcRawValue0[2]);
ADC_DRV_GetChanResult(INST_ADC_0, 3UL, (uint16_t *)&adcRawValue0[3]);
ADC_DRV_GetChanResult(INST_ADC_0, 4UL, (uint16_t *)&adcRawValue0[4]);
ADC_DRV_GetChanResult(INST_ADC_0, 5UL, (uint16_t *)&adcRawValue0[5]);
ADC_DRV_GetChanResult(INST_ADC_0, 6UL, (uint16_t *)&adcRawValue0[6]);
ADC_DRV_GetChanResult(INST_ADC_0, 7UL, (uint16_t *)&adcRawValue0[7]);
PINS_DRV_TogglePins(LED_PORT, 1 << LED0);
adc0ConvDone = true;
}
至此,PDB多通道延遲觸發ADC的例程基本講述完畢。程序編譯后燒錄至開發板,PDB預觸發每置位并觸發ADC轉換完成后即進入中斷翻轉IO電平。用戶根據抓取到的IO電平波形即可驗證延遲值是否與預期一致。此外,如果想要查看ADC轉換值,用戶可使能串口,通過adc0ConvDone標志位在主函數while循環中打印輸出結果,此處不再詳細展開。
-
mcu
+關注
關注
146文章
17837瀏覽量
360436 -
模塊
+關注
關注
7文章
2783瀏覽量
49581 -
adc
+關注
關注
99文章
6639瀏覽量
548263 -
比較器
+關注
關注
14文章
1840瀏覽量
108526 -
觸發器
+關注
關注
14文章
2032瀏覽量
61878
原文標題:MCU微課堂|CKS32K148 PDB
文章出處:【微信號:中科芯MCU,微信公眾號:中科芯MCU】歡迎添加關注!文章轉載請注明出處。
發布評論請先 登錄
MCU微課堂|CKS32F4xx系列產品時鐘配置
中科芯CKS32K148系列MCU的外設橋模塊解析

中科芯CKS32F030K6T6 高性能32位RISC內核MCU 程序兼容STM32F030K6T6
《電子發燒友電子設計周報》聚焦硬科技領域核心價值 第5期:2025.03.24--2025.03.28
中科芯智能家居系統應用方案解析
中科芯與IAR共建生態合作,IAR集成開發環境全面支持CKS32系列MCU

評論