S32K系列之ADC

簡介

在S32K中,不同的芯片型號支持的ADC通道不同,S32K144UAVLL有兩個ADC,每個ADC有12位、10位、8位和6位可選,每個ADC有16個外部通道。學習ADC的第一步是要掌握ADC的功能框圖,對ADC的工作過程和編程過程有個整體的瞭解。

ADC功能框圖

對ADC的配置主要涉及三種寄存器,控制狀態寄存器、觸發寄存器和數據寄存器。控制狀態寄存器主要有SC2SC3CFG1CFG2;觸發寄存器主要有SC1SC2;數據寄存器主要有Rn
1

電壓輸入範圍

ADC的輸入電壓範圍爲:VREFLVINVREFHV_{REFL}≤V_{IN}≤V_{REFH},ADC的輸入範圍取決於4個參考電源VREFLVREFHVDDAVSSAV_{REFL}、V_{REFH}、V_{DDA}、V_{SSA}

​ADC的電壓輸入範圍取決於4個參考電源​,我們在設計原理圖的時候一般把​VREFLV_{REFL}VSSA​V_{SSA} 接地,把​VREFHV_{REFH}VDDA​V_{DDA} 接3.3V,可以得到ADC的輸入範圍是0~3.3V。在設計原理圖時,應該把ADC設置爲可以配置成外用輸入電壓參考源,以備不時之需,如下圖所示。
2
如上圖所示,​有三個選項。

  1. 焊接上R103,拆掉R99,R109和D7,電壓參考源爲VDD_MCU,一般爲3.3V
  2. 焊接上D7和R99,拆掉R103和R109,R99進行分壓之後爲3V
  3. 焊接上R109,拆掉R103,R99和D7。這裏的​是外部輸入電壓引腳,可以配置爲外部電壓參考源

時鐘配置

可以選擇4個時鐘源ALTCLKx之一來作爲ADC模塊的時鐘源。ADC具有多個時鐘源。 選擇取決於配置PCC_ADCn[PCS]。 分頻器的配置應使ADC轉換時鐘頻率在ADC要求的有效範圍內(請參見數據手冊)。如下圖所示爲ADC的時鐘分配圖。
3
如圖所示,ADC的時鐘源輸入通過PCC_ADCn[PCS]來選擇SOSCDIV2_CLKSIRCDIV2_CLKFIRCDIV2_CLKSPLLDIV2_CLK四種,然後經過ADC_CFG1[ADIV]來時鐘分頻,最後產生ADC的輸入時鐘ADCKADCK由數據手冊可得,最大50MHZ,最小2MHZ,典型值爲40MHZ,如果超過最大頻率,ADC的轉換結果會變得不可靠。ADC時鐘設置流程如下:

  1. 設置PCC_ADCn[PCS]:選擇時鐘源
  2. 設置ADC_CFG1[ADICLK]:選擇時鐘輸入
  3. 設置ADC_CFG1[ADIV]:選擇時鐘分頻

轉換時間

數據手冊顯示,ADC的轉換時間取決於:

  • ADC_CFG2[SAMPLTS]確定的採樣時間
  • MCU的Bus總線時鐘頻率
  • ADC_CFG1[MODE]確定的轉換模式
  • fADCKf_{ADCK}即ADC的轉換時鐘頻率

由數據手冊可得,ADC的總轉換時間=採樣相位時間(SMPLTS設置的再+1)+保持相位(1個ADC週期)+比較相位時間(8位模式=20個ADC週期,10位模式=24個ADC週期,12位模式=28個ADC週期)+單個或第一個連續時間加法器(5個ADC週期+5個總線時鐘週期)

例:設置BUS時鐘爲40MHZ,ADC時鐘選擇40MHZ,12位ADC,採樣週期選擇255個ADC週期,計算ADC的一次轉換時間爲:
Tconv=255+1+1+28+54×106+54×106=73.75μsT_{conv}=\frac{255+1+1+28+5}{4×10^6 }+\frac{5}{4×10^6}=73.75μs

觸發設置

4
ADC觸發設置主要包括寄存器SC2SC1。ADC支持軟件觸發和硬件觸發兩種,軟件觸發就是在ADC轉換完畢之後產生中斷;在硬件觸發方面,ADC模塊具有可選的異步硬件轉換觸發器ADHWT,主要通過PDB來觸發。觸發設置可見PDB觸發ADC。設置ADC_SC2[ADTRG]來選擇是硬件觸發還是軟件觸發。觸發方式的設置流程如下:

  1. 設置ADC_SC2[ADTRG]:選擇觸發方式
  2. 設置ADC_SC1n[ADCH]:選擇ADC通道
  3. 如果上一步使用了具有硬件交錯功能的通道,則需要設置SIM_CHIPCTL[ADC_INTERLEAVE_EN]
  4. 設置ADC_SC1n[AIEN]:開啓中斷觸發(軟件觸發模式下)

獲得ADC數據

最後轉換成功後,ADC的轉換結果會被存放在ADC_Rn寄存器,ADC_Rn寄存器對應的是ADC_SC1n寄存器,比如ADC_SC1A的數據會存放在ADC_RAADC_SC1B的數據會存放在ADC_RB,以此類推。

在不同的轉換位數下,ADC_Rn寄存器的數據位數也不同,如下圖所示。
5
注:ADC_Rn寄存器是隻讀的

電壓轉換

模擬電壓經過ADC轉換後,是一個相對精度的數字值,如果通過串口以16進制打印出來的話,可讀性比較差,故需要把數字電壓轉換爲模擬電壓,也可以根據實際的模擬電壓(用萬用表測)對比,看看轉換是否準確。

在設計原理圖時,一般會把ADC的輸入電壓範圍定在0~3.3V,若設置的ADC爲12位,那麼12位滿量程對應的就是3.3V,12位滿量程對應的數字值是:2122^{12} 。數值0對應的就是0V。如果轉換後的數值爲X,X對應的模擬電壓爲Y,那麼:
2123.3=XYY=3.3×X212\frac{2^{12}}{3.3}=\frac{X}{Y} → Y=\frac{3.3\times X}{2^{12}}

實例:ADC觸發中斷

功能概述

  • 平臺:S32K144

現在使用S32K144的ADC0通道8,軟件觸發模式下,轉換結束後觸發中斷。

編程順序

  1. 初始化ADC0的時鐘
  2. 初始化ADC0的位數
  3. 選擇ADC0的通道,開啓中斷
    • 如果該通道有硬件交錯功能,需要選擇是哪個ADC通道
  4. 選擇軟件觸發
  5. NVIC開啓ADC中斷
// ADC初始化函數
void ADC0_Init(void)  
{
	PCC->PCCn[PCC_PORTA_INDEX] |= PCC_PCCn_CGC_MASK;   /* Enable clock for PORTA */
	SIM->CHIPCTL |= (1 << 2);   /* 具有硬件交錯功能,選擇PTB13 */
	 
	PCC->PCCn[PCC_ADC0_INDEX] &= ~PCC_PCCn_CGC_MASK;  
	PCC->PCCn[PCC_ADC0_INDEX] |= PCC_PCCn_PCS(6);     /* PCS=6: 選擇內核時鐘80MHZ */
	PCC->PCCn[PCC_ADC0_INDEX] |= PCC_PCCn_CGC_MASK;  
	 
	ADC0->CFG1 = ADC_CFG1_ADIV(2) |     /* ADIV=2:輸入內核時鐘兩分頻=40MHZ */
	             ADC_CFG1_MODE(1) |     /* MODE=1: 12位ADC */
	             ADC_CFG1_ADICLK(0);    /* ADICLK=0: 默認選擇PCC分配的時鐘 */
		 
	ADC0->SC1[0] = ADC_SC1_AIEN_MASK |    /* AIEN=1: 開啓中斷觸發 */
		          ADC_SC1_ADCH(8);     /* ADCH=8: 序號0選擇通道8 */
	 
	ADC0->SC2 |= ADC_SC2_ADTRG(0);    /* ADTRG=0: 開啓軟件觸發 */
	ADC0->SC3 = 0;       
		  
    S32_NVIC->ICPR[1] = 1 << (39 % 32);  /* 註冊ADC0中斷 */
	S32_NVIC->ISER[1] = 1 << (39 % 32);  /* 使能ADC0中斷 */
	S32_NVIC->IP[39] = 0xA0;             /* 優先級爲10 */
}
/*
 * \brief adcChan通道開啓一次ADC轉換
 *
 * \param adcChan 需要進行ADC轉換的通道
 *
 */
void convertAdcChan(uint16_t adcChan) 
{   
	ADC0->SC1[0] &= ~ADC_SC1_ADCH_MASK;  /* Clear prior ADCH bits */
	ADC0->SC1[0] = ADC_SC1_ADCH(adcChan); /* Initiate Conversion*/
}
 
/*
 * \brief ADC轉換判斷函數
 *
 * \return >0 轉換已完成
 * \return =0 轉換未完成
 *
 */
uint8_t adc_complete(void)  
{
	return((ADC0->SC1[0] & ADC_SC1_COCO_MASK) >> ADC_SC1_COCO_SHIFT); 
}
 
/*
 * \brief ADC值轉換函數
 *
 * \return 返回轉換後的ADC電壓值
 *
 */
uint32_t read_adc_chx(uint8_t ChanIndex)  
{
	uint16_t adc_result = 0;
	adc_result = ADC0->R[ChanIndex]; 
	/* For SW trigger mode, R[0] is used */
	return(uint32_t)((5000 * adc_result) / 0xFFF); 
	/* Convert result to mv for 0-5V range */
}
 
void ADC0_IRQHandler(void)
{
	adcRawValue1 = read_adc_chx(0);
	adcRawValue2 = read_adc_chx(1);
	adcConvDone = true;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章