一、 概述
ADC 轉換就是輸入模擬的信號量轉換成數字量,讀取數字量必須等 ADC 轉換完成後,完成一個通道的讀取叫做採樣周期;採樣周期 = 轉換時間 + 讀取時間,而轉換時間 = 採樣時間 + 轉化時間;採樣時間通過寄存器進行設置,設置越長越精確,E3 ADC 固定轉化時間為 13.5 個時鐘周期;在某些領域對 ADC 採樣頻率要求極高,通常需要精確計算 ADC 的採樣頻率;本文通過 ADC 同步採樣模式,RC 定時器觸發 ADC 採樣,採用中斷讀取的方式實時讀取 ADC 轉化時間,做到 ADC 採樣頻率的精準計算。
硬體平台:E3640 官方開發板 (SD103_E3_GATEWAY_ePOWERTRAIN_A03_019),如下圖所示;
軟體平台:e3_gateway_E3640_mcu_demo_E3_SSDK_PTG3.0 中 driver_demo adc_sync_poll、adc_Async_int 例程。
圖1 E3640 官方開發板
二、 ADC 配置詳解
1. ADC 引腳設置
配置管腳相應 scr,使得片外管腳信號與片內 ADC 電路導通。
const scr_signal_t adc_scr[] = {
SCR_SF_ANA_SF_CFG_APD_A_A12_CTRL_3_0,
SCR_SF_ANA_SF_CFG_APD_A_A13_CTRL_3_0,
SCR_SF_ANA_SF_CFG_APD_A_A14_CTRL_3_0,
SCR_SF_ANA_SF_CFG_APD_A_A15_CTRL_3_0
};
for (i = 0; i < sizeof(adc_scr) / sizeof(adc_scr[0]); i++) {
/* set APD_A ctrl to 1 */
scr_set(&scr_ctrl, &adc_scr[i], 1);
}
用 ADC_CH_SEL_TAISHAN 構建單端通道號,通過設置 ADC_CH_SEL_TAISHAN 的變量設置 ADC 模塊與外部引腳的對應,從 E3 DataSheet 截取 ADC 引腳對應部分如下表1,參數設置主要包含:採集通道,採集極性,引腳復用 MUX 配置,詳細對應關係如下圖所示。
enum adc1_ch5n_mux {
ADC1_CH5N_MUX_A0 = 0u,
ADC1_CH5N_MUX_A2,
ADC1_CH5N_MUX_A4,
ADC1_CH5N_MUX_A6,
ADC1_CH5N_MUX_A8,
ADC1_CH5N_MUX_A10,
ADC1_CH5N_MUX_A12, // CH5_N.MUX_6
ADC1_CH5N_MUX_A14
};
2. 採樣模擬量設置
sdrv_adc_ana_param_cfg_t 這個結構體主要設置 ADC 模擬量採集相關的參數,主要設置模擬量的採樣時間、參考電壓、採樣模式(單端採樣、差分採樣)。
typedef struct sdrv_adc_ana_param_cfg {
uint32_t sample_time : 3; /* ADC採樣時間設置 */
uint32_t : 1;
uint32_t ref_sel : 1; /* ADC參考電壓設置 */
uint32_t input_mode : 1; /* ADC 採樣模式:單端採樣,差分採樣 */
} sdrv_adc_ana_param_cfg_t;
sdrv_adc_ana_param_cfg_t ana_param[] = {
{SDRV_ADC_SAMPLE_TIME_10D5, SDRV_ADC_REF_VREFP1, SDRV_ADC_INPUT_SINGLE},
{SDRV_ADC_SAMPLE_TIME_34D5, SDRV_ADC_REF_VREFP1, SDRV_ADC_INPUT_SINGLE},
{SDRV_ADC_SAMPLE_TIME_18D5, SDRV_ADC_REF_VREFP1, SDRV_ADC_INPUT_DIFF},
};
/* 將ana_param依次配置到 0~2 位置上 */
for (i = 0; i < sizeof(ana_param) / sizeof(ana_param[0]); i++) {
sdrv_adc_ana_param_cfg(ADC_DEV_TEST, i, ana_param[i]);
}
3. RC寄存器設置
ADC有兩種觸發方式,包含:HTC、RC0、RC1、RC2、RC3,HTC 為硬體通道觸發,RC 可以通過定時器方式定時觸發 ADC 採樣,HTC 和 RC 將觸發信息發送給 SCHEDULER,SCHEDULER 通過仲裁方式優先處理優先級高的觸發信號,RC0、RC1、RC2、RC3 均可單獨配置使用,也可以將 RC0 設置為主模式,將 RC1、RC2、RC3 設置成從模式組合使用; RC 對於 RC0 中的計時器 r0,它將向RC1/2/3 中的計時器 r1/2/3 生成計數器清除信號;對於 RC1/2/3 中的時間 1/2/3,它可以選擇獨立工作或通過計數器獲取清除兩者來自時間 r0 的閾值或清除信號。
sdrv_adc_rc_entry_cfg_t 主要是設置 ADC 採樣通道、模擬量採集設置、ADC RC 觸發模式、ADC RC 重複採樣次數;
typedef struct sdrv_adc_rc_entry_cfg {
uint32_t channel : 9; /**ADC 採樣通道設置 */
uint32_t : 3;
uint32_t cfg_sel : 4; /**選擇模擬量設置通道 */
uint32_t repeat_mode : 1; /**RC 硬體觸發模式或軟體觸發模式 */
uint32_t : 7;
uint32_t repeat_cnt : 5; /**ADC 重複採集次數 */
} sdrv_adc_rc_entry_cfg_t;
在上述 sdrv_adc_ana_param_cfg_t 結構體中 sample time 參量主要設置 ADC 採樣時間,而sdrv_adc_rc_cfg_t 結構體中 terminal compare 是採樣觸發的時間點,通過修改 Terminal 的數據更改 ADC 採樣頻率,RC entry 採樣序列,RC 是否使能等設置。
typedef struct sdrv_adc_rc_cfg {
uint16_t terminal; /**< rc timer terminal value */
uint16_t compare; /**< rc timer compare value */
uint32_t q_cur : 4; /**rc_entry 當前位置*/
uint32_t q_start : 4; /**rc_entry 起始位置 */
uint32_t q_end : 4; /**rc_entry 終止位置 */
uint32_t : 1;
uint32_t tmr_mode : 1; /**RC模式:主模式、從模式 */
uint32_t trg_mode : 1; /**RC觸發模式:軟體觸發、硬體觸發 */
uint32_t : 2;
uint32_t trg_en : 1; /**< RC使能 */
} sdrv_adc_rc_cfg_t;
4. ADC模式設置
配置同步模式 slot 間隔最大值為 50clock ,其中根據 ADC 最大採樣時間 34.5clock,ADC固定轉化時間 13.5clock,再預留 2clock 時間間隔,將 RC entry 變量依次添加至 cid_buf 數組中,ADC 同步開啟後將按照 cid_buf 數組的順序存放 ADC 轉化結果。
sdrv_adc_sync_cfg_t sync_cfg = {50, 0}; //max samctrl 5 (48 + 2);
uint8_t cid_buf[8];
/* RC0 repeat_cnt 總數為 2,需要占用 2 個 slot。 */
cid_buf[0] = SDRV_ADC_SYNC_CID_RC0;
cid_buf[1] = SDRV_ADC_SYNC_CID_RC0;
/* RC1 repeat_cnt 總數為 3,需要占用 3 個 slot。 */
cid_buf[2] = SDRV_ADC_SYNC_CID_RC1;
cid_buf[3] = SDRV_ADC_SYNC_CID_RC1;
cid_buf[4] = SDRV_ADC_SYNC_CID_RC1;
sdrv_adc_sync_cfg(ADC_DEV_TEST, sync_cfg, cid_buf, 5);
5. 中斷設置
irq_initialize(VIC1_BASE, IRQ_MAX_INTR_NUM);
sdrv_adc_clear_int_status(ADC_DEV_TEST, 0xFFFFFFFFu);
/* 使能所有中斷狀態的記錄 */
sdrv_adc_int_status_en_cfg(ADC_DEV_TEST, 0xFFFFFFFFu, 1);
/* 使能 FIFO 閾值中斷的觸發功能 */
sdrv_adc_int_status_sig_en_cfg(ADC_DEV_TEST, SADC_INT_STAT_SUB_FIFO3, 1);
/* 捕獲 ADC2 中斷,並設置中斷回調函數 */
irq_attach(ADC_DEV_IRQ, adc_demo_int, (void *)ADC_DEV_TEST);
/* 中斷使能 */
irq_enable(ADC_DEV_IRQ);
/* 中斷禁止 */
irq_detach(ADC_DEV_IRQ);
6. ADC 頻率計算
計算 ADC 採樣頻率需要精準的系統計數,需要初始化 ARM 性能監視器周期計數器,用於得到系統計數,通過 pmu_get_cycle_cntr() 得到系統計數周期,通過 sdrv_ckgen_bus_get_rate() 讀取系統時鐘頻率, ADC 頻率 = CNT(sample) * F(系統時鐘) * (CYCLE_CNT(ADC採樣後)- CYCLE_CNT(ADC採樣前)) ;
//初始化 ARM 性能監視器周期計數器
sdrv_pmu_counter_init(); /* 用於 udelay 及獲取時間*/
udelay(1);
cnt_per_us = sdrv_ckgen_bus_get_rate(CLK_NODE(g_ckgen_bus_cr5_sf),
CKGEN_BUS_CLK_OUT_M) / (1000 * 1000);
//讀取 ADC 轉化之前系統計數值
pmu_cnt_stamp[0] = pmu_get_cycle_cntr();
/* 開啟 ADC 轉化模式 */
//在 ADC 中斷回調函數中讀取最後一次 ADC 轉化的系統計數值
static int adc_demo_int(uint32_t irq, void *arg)
{
uint32_t temp;
if (sdrv_adc_read_int_status(arg) & SADC_INT_STAT_SUB_FIFO3) {
while (!(sdrv_adc_fifo_status(arg) & SADC_SUB_FIFO_EMPTY)) {
temp = sdrv_adc_read_fifo(ADC_DEV_TEST); //讀取 ADC 數值
adc_data_cnt++;
if (adc_data_cnt == ADC_DATA_CNT_FOR_SAMPLE_RATE)
{
pmu_cnt_stamp[1] = pmu_get_cycle_cntr(); //獲取循環計數器的值
adc_data_sample_Finish_flag = 1;
}
}
sdrv_adc_clear_int_status(arg, SADC_INT_STAT_SUB_FIFO3);
}
return 0;
}
//ADC採樣頻率計算公式
printf("Sample rate %f Msps\n", ADC_DATA_CNT_FOR_SAMPLE_RATE * (float)cnt_per_us /
(pmu_cnt_stamp[1] - pmu_cnt_stamp[0]));
7. 結果驗證
結果驗證如下圖:
圖2 ADC 頻率輸出結果
三、 參考文檔
《AppNote_E3_Boot_and_OTA_Rev01.05》
《AppNote_E3_燒錄流程_Rev2.0》
《E3110_MCU_TRM_Rev00.13》
《E3110_MCU_Datasheet_Rev00.17》
歡迎在博文下方留言評論,我們會及時回復您的問題如有更多需求,歡迎聯繫大聯大世平集團 ATU 部門:atu.sh@wpi-group.com
作者:Linna Wang /王麗娜
評論