嵌入式系統 training - HT32F175x275x 袁世一 逢甲通訊系 1 Outline • • • • • • Embedded system vs. … Clock Control GPIO – General purpose I/O Counter Interrupt AFIO – Alternate Function I/O 2 Embedded system vs. … PC Embedded Single chip Purpose General Purpose Special Special SoC No Yes Yes IO Functions Easy Complicated Easy Program type Complicated Complicated Easy IO programming Easy Complicated Easy Memory External Internal/External Internal/External Internal Memory size Generally 0 ~ Kbyte ~ 100 Byte Block Func Less / Fast More / Medium Less / Slow So, programming in Embedded system different from … • care about special purposes • care about memory • care about HW considerations • care about COST 3 上課預計時程 日期 上午(0900-1200) 下午(1300-1600) 備註 7/1 Clock, GPIO教學 程式練習 GPIO設定與 Clock設定有關, 必須同時練習 7/2 Counter教學、 程式練習 中斷教學、 程式練習 以不同Counter程式設 計方式(迴圈, 中斷) 做為練習目標 7/3 AFIO+中斷教學 程式練習 王磊老師上課, 下午時間需要確認 AFIO將以ADC為例 作為練習目標 *希望7/1進度可以提前,以增加7/3的程式說明時間 4 Clock control (7/1) • 基礎 ARM 時脈概念 • HT32F125x 時脈控制單元 (clock control unit, CKCU) • 範例程式 5 General ARM clock concept • 時脈是控制嵌入式系統動作同步的訊號 • ARM為: 系統晶片SoC (System on Chip) – 許多功能區塊整合在IC內部 • 連在不同的Bus (匯流排)上,以提升IC效能 • 不同Bus可以使用不同的時脈 – Bus種類: 高/低速bus • AHB: High speed bus • APB: Low speed (Peripheral) bus 6 7 ARM 時脈種類 1. HSI & LSI – High/Low speed Internal RC oscillator – HSI: • • • – LSI: • • • • 2. 系統預設時鐘,內部RC振盪 可以直接作為系統時鐘或作為PLL輸入(PLL=HSI/2) 精度較差 內部RC振盪 低功耗時脈源 可以在停機和待機模式下保持系統運做 提供看門狗和自動喚醒單元時脈 HSE & LSE – High/Low speed External crystal – HSE:外部振盪器 • – 提供非常精確的主時鐘 LSE:低速外部晶體 • 一般專門用於RTC 8 9 10 3. PLL – phase lock loop (倍頻/除頻) • • prescalers/multiplexers (倍頻/除頻設定) System clock (CK_SYS) -> AHB/APB 4. gating (停止某些電路 功能) 11 Clk setup: 以PLL設定為例 12 CKCU Registers 設定舉例 • Global Clock Configuration Register (GCFGR) – 32 bits – specifies clock source for PLL/USART/Watchdog Timer/CKOUT circuits • 使用C即可 • 如需深入了解,請見 SPEC中Registers說明 CKCU_APBPerip0ClockConfig(CKCU_APBEN0_AFIO, ENABLE); CKCU_APBPerip0ClockConfig(BUTTON_GPIO_PIN, ENABLE); 13 GPIO – General purpose I/O (7/1) • ARM GPIO 架構 • ARM IO 控制 14 15 ARM GPIO architecture • 32個GPIO Pin – PA0~PA15 / PB0~PB15 – 其他功能腳位也可以分享GPIO port來增加功能 的彈性 – 透過相關的組態暫存器的設定 16 GPIO控制 • 方向:輸入 OR 輸出 • 輸入腳位控制 – 弱拉升/弱拉降 • 輸出腳位控制 – 推拉式控制 OR 開汲極 – 推動電流強度 – 類比/數位 (AFIO控制) – 之後會說明 • 組態鎖定 17 RESET(或初供電)時GPIO之預設值 – 均為input • 無拉升/拉降電阻 (no pull-up/pull-down) – 例外: • PA9(拉降)、PA10 (拉升) 、PA13 (拉升) 、PA14 (拉升) • For boot/debug 18 GPIO Registers設定舉例 • Port A Data Direction Control Register (PADIRCR) – 32 bits – control the direction of the GPIO Port • 同時脈設定,使用C即 可 • 如需深入了解,請見 SPEC中Registers說明 GPIO_DirectionConfig(KEY1_BUTTON_GPIO_PORT, KEY1_BUTTON_GPIO_PIN, GPIO_DIR_IN); GPIO_DirectionConfig(LED1_GPIO_PORT, LED1_GPIO_PIN, GPIO_DIR_OUT); 19 程式範例 int main(void) { system_init(); while(1) { x = read_input_pin; write_output(x); } while(1) } { TmpStatus = GPIO_ReadInBit(WAKEUP_BUTTON_GPIO_PORT, WAKEUP_BUTTON_GPIO_PIN); GPIO_WriteOutBits(LED1_GPIO_PORT, LED1_GPIO_PIN, TmpStatus); TmpStatus = GPIO_ReadInBit(KEY1_BUTTON_GPIO_PORT, KEY1_BUTTON_GPIO_PIN); GPIO_WriteOutBits(LED2_GPIO_PORT, LED2_GPIO_PIN, TmpStatus); TmpStatus = GPIO_ReadInBit(KEY2_BUTTON_GPIO_PORT, KEY2_BUTTON_GPIO_PIN); GPIO_WriteOutBits(LED3_GPIO_PORT, LED3_GPIO_PIN, TmpStatus); } } 20 程式範例 • system_init: – Enable APB clock 1. 2. 3. 4. 5. enable APB clock for 3 pins connect 3 pins to GPIO function (Port, Pin, Func) 3 pins’ GPIO as Input enable 3 pins same as 1-4 for 3 output pins • loop – x=read input – output x -> y int main(void) { … CKCU_APBPerip0ClockConfig(CKCU_APBEN0_AFIO, ENABLE); CKCU_APBPerip0ClockConfig(DVB_GpioClock[WAKEUP_BUTTON_G PIO_ID], ENABLE); … HT32F_DVB_GPxConfig(WAKEUP_BUTTON_GPIO_ID, WAKEUP_BUTTON_AFIO_PIN, WAKEUP_BUTTON_AFIO_MODE); … GPIO_DirectionConfig(WAKEUP_BUTTON_GPIO_PORT, WAKEUP_BUTTON_GPIO_PIN, GPIO_DIR_IN); … GPIO_InputConfig(WAKEUP_BUTTON_GPIO_PORT, WAKEUP_BUTTON_GPIO_PIN, ENABLE); … //5: 3 output pins … • Too many codes – see code example while(1) { … } } 21 Practice • Target 1. 使用for, 控制LED閃爍 2. 讀取按鈕值, 控制LED閃爍 • 按一次亮, 再一次暗 3. 讀取按鈕值, 控制LED閃爍的開始/停止 • 按一次開始閃爍, 再一次停止閃爍 22 Counter (計數器) (7/2) • HT32Fx has 4 counters: – GPTM0/1: General Purpose Timer 0 & 1 – BFTM0/1: Basic Function Timer 0 & 1 23 Counter • This training uses BFTM0 • Two method: 1. loop method – this training 2. Interrupt method – next training • BFTM需要設定: – Counter Reg: up counter – Compare Reg: max value – Status Reg: Counter==Compare • Use C-lib 24 Counter loop programming 1. clock Init, LED(GPIO) Init 2. BFTM setting 1. max value – – 2. 3. sysCLK: 1sec sysCLK/2: 0.5sec counter value (=0) BFTM as OneShot int main(void) { CKCU_APBPerip1ClockConfig(…); HT32F_DVB_LEDInit(LED2); BFTM_SetCompare(BFTM1, SystemCoreClock); BFTM_SetCounter(BFTM1, 0); BFTM_OneShotModeCmd(BFTM1, ENABLE); while (1) { BFTM_EnaCmd(BFTM1, ENABLE); 3. loop(1) 1. 2. 3. start BFTM (enable) wait for BFTM.status change toggle LED while (BFTM_GetFlagStatus(BFTM1) != SET); BFTM_ClearFlag(BFTM1); HT32F_DVB_LEDToggle(LED2); } } 25 Counter programming • Interrupt counter control: – Training latter 26 Interrupt (7/2) • Interrupt concept • ARM NVIC • sample code 27 Interrupt concept • 中斷是一個訊號,會促使電 腦改變其正常的運作流程。 • 在接收到來自外部硬體信號 之後,CPU將進行相應的硬 /軟體處理 – 發出的信號稱為中斷請求 (interrupt request,IRQ) – IRQ導致CPU執行資訊切換 (context switch)來保存執行 狀態 – 中斷會將控制權轉換到中斷 處理常式(Interrupt Service Routine, ISR) • 軟體中斷則為CPU指令集中 的一個中斷指令 28 29 • 種類 – 狀態觸發 – 邊沿觸發 • 中斷向量表 – 中斷向量表包含數個中 斷向量,每個向量包含 中斷處理程序的起始地 址 30 • 中斷處理過程 – 外部硬體信號發出IRQ – CPU結束執行上一個機械 碼 – CPU同意中斷 – CPU儲存CPU執行狀態 – CPU取得中斷位址 – CPU執行ISR – ISR執行完成 – CPU取得中斷前CPU執行 狀態 – CPU繼續執行原本程式 31 ARM NVIC • NVIC – Nested Vectored Interrupt Controller • Interrupt Number: 31 peripheral Int NVIC_EnableIRQ(BFTM0_IRQn); • Interrupt Types: – – – – – USART, SPI, I2C Timer (BFTM, GPTM) ADC, Comparator, GPIO input WakeUP signal, RTC, Low Vdd – Clock (HSE, HIS, LSE, LSI, PLL) • Priority: configurable, 16 levels 32 Counter Interrupt programming 1. clock Init, LED(GPIO) Init 2. BFTM_INT unmask 3. BFTM setting 1. 2. 3. 4. int main(void) { CKCU_APBPerip1ClockConfig(…); HT32F_DVB_LEDInit(LED1); NVIC_EnableIRQ(BFTM0_IRQn); max value BFTM_SetCompare(BFTM0, SystemCoreClock/2); BFTM_SetCounter(BFTM0, 0); BFTM_IntConfig(BFTM0, ENABLE); BFTM_EnaCmd(BFTM0, ENABLE); – – while (1) { } } sysCLK: 1sec sysCLK/2: 0.5sec counter value (=0) BFTM Interrupt enable begin BFTM 4. loop(1) do_nothing(); //in ht32f…_it.c: // Interrupt service routing (ISR): void BFTM0_IRQHandler(void) { HT32F_DVB_LEDToggle(LED1); BFTM_ClearFlag(BFTM0); } 33 AFIO – Alternate Function I/O (7/3) • • • • 擴大GPIO 的靈活性 GPIO外設功能 每個GPIO腳 配置為有四個不同的功能(設置GPxCFGR 暫 存器) • 根據IP 資源的使用情況和應用需求,可以 使用週邊I/O 映射機制來選擇合適的功能 34 35 AFIO 功能 36 AFIO 功能 37 Example: ADC • Set AFIO to ADC • Set ADC to get Analog data from potentionmeter (電位 計) 38 HT32F ADC 特性 • • • • 12-bit ADC Sample rate: Up to 1 uS/S 8 external channels 2 int_ref_voltage:Vssa & Vdda • sampling time for each channel • Three conversion modes – One shot – Continuous – Discontinuous • 8 dedicated sequencers and data registers • Triggered by – Software – external interrupt – GPTM (MTO and PWM CHnO) • Interrupts for ... – – – – – Single conversion end Subgroup conversion end Cycle conversion end Analog Watchdog Data register overwrite 39 • Function descriptions Configuration – ADRST [0] = 1: ADC reset • Clock setup: – CK_ADC = APB_PCLK • ADC Trigger – ADCTCR (Trigger Control Registers) • ADTM = ADCTCR[2]: GPTM enable • ADEXTI = ADCTCR[1]: EXTI enable • ADSW = ADCTCR[2]: SW enable – ADCTSR (Trigger Source Registers) • GPTME = ADCTSR[26:24]: GPTM Event selection (all at rising edge_ – 0: GPTM MTO – 1-4: CH0-CH3 • GPTMS = ADCTSR[18:16] GPTM selection – 2/3 = GPTM0/GPTM1 • ADEXTIS = ADCTSR[11:8] : EXTI line selection – 0-F: EXTI line 0-15 • ADSC = ADCSTR[0]: – set: SW Event begin once – reset: automatic when this ADC complet 40 • Data save register • ADCDRn (n=0-7) • flag ADVLDn goes to 1, automatically , if ADCDRn is valid • flag ADVLDn goes to 0, automatically, if ADCDRn is read • if ADCDRn not read and overwrited by another ADC round, ADIAWO of ADCIRAW = 1 • Status Flags • ADIRAWO = ADCIRAW[24]: data register overwrite error • ADIRAWS = ADCIRAW[2]: register: single sample finish • ADIRAWG = ADCIRAW[1]: register: subgroup finish • ADIRAWC = ADCIRAW[0]: register: cycle (group) finish 41 • Interrupt • ADIMASKO = ADCIMSK[24]: ADC Data overwrite INT mask • ADIMASKC = ADCIMSK[2]: cycle (group) finish INT mask • ADIMASKG = ADCIMSK[1]: sub-group finish INT mask • ADIMASKS = ADCIMSK[0]: single ADC finish INT mask • Trigger begin: • SW trigger: ADSC of ADCTSR (when start ADC, ADSC reset) • 5 GPTM trigger: MTO (master), 4 GPTM-CHn (n=03) • EXTInt trigger: – setup: ADEXIS register EXTInt (n=0,1) – ADEXTI=1 42 • Sample time: • ADSTn of ADCSTRn[7:0] (n=0-7): – sampling time of channel n – T_conv = Tsample + Tlat – (conversion time, sampling time, latency) – Tasmple = ADSTn + 1.5 cycle – minimum Tlat = 12.5 cycle • Example: – CK_ADC = 14MHz, ADSTn = 0 – Tconv = 1.5 + 12.5 = 14 cycles (=1us) 43 • Turn off ADC: ADCEN reset • Interrupt setup • All flags are set by SW for clearing, and automatically reset by HW • ADCICLRO = ADCICLR[24]: ADC Data overwrite INT Clear • ADCICLRC = ADCICLR[2]: cycle (group) finish INT clear • ADCICLRG = ADCICLR[1]: subgroup finish INT mask clear • ADCICLRS = ADCICLR[0]: single ADC finish INT mask clear 44 Sample Code int main(void) { USART_Configuration(); //for PC Enable_ADC_IRQ(); ADC_Clock_Enable(); AFIO_PIN6_SetTo_ADC(); ADC_Configure(ContinuousMode, 1 channel, sample rate, SW_trigger); ADC_enable(); begin_ADC(); while (1) { /* Output gPotentiometerLevel if needed. */ printf("\rPotentiometer level is %d %% ", (int)gPotentiometerLevel); } } 45 USART_Configuration void USART_Configuration(void) { USART_InitTypeDef USART_InitStructure; USART_InitStructure.USART_BaudRate = 115200; USART_InitStructure.USART_WordLength = USART_WORDLENGTH_8B; USART_InitStructure.USART_StopBits = USART_STOPBITS_1; USART_InitStructure.USART_Parity = USART_PARITY_NO; USART_InitStructure.USART_Mode = USART_MODE_NORMAL; HT32F_DVB_COMInit(COM1, &USART_InitStructure); } 46 Enable_ADC_IRQ NVIC_EnableIRQ(ADC_IRQn); 47 ADC_Clock_Enable /* Enable peripheral clock of ADC */ CKCU_APBPerip1ClockConfig(CKCU_APBEN1_ADC, ENABLE); CKCU_APBPerip0ClockConfig(CKCU_APBEN0_AFIO, ENABLE); /* ADCLK frequency is set to 72/64 MHz = 1.125MHz */ CKCU_SetADCPrescaler(CKCU_PCLK_DIV64); 48 AFIO_PIN6_SetTo_ADC /* Config AFIO mode as ADC function */ AFIO_GPAConfig(AFIO_PIN_6 , AFIO_MODE_1); 49 ADC_Configure /* Continuous Mode, Length 1, SubLength 1 */ ADC_RegularGroupConfig(ADC, CONTINUOUS_MODE, 1, 1); /* ADC Channel 6, Rank 0, Sampling clock is (1.5 + 0) ADCLK Conversion time = (sampling clock + 12.5) / ADCLK = 12.4 uS */ ADC_RegularChannelConfig(ADC, ADC_CH_6, 0, 0); /* Use Software Trigger as ADC trigger source */ ADC_RegularTrigConfig(ADC, ADC_TRIG_SOFTWARE); 50 ADC_enable() /* Enable ADC single end of conversion interrupt, The ADC ISR will store the ADC result into global variable gPotentiometerLevel. */ ADC_IntConfig(ADC,ADC_INT_SINGLE_EOC, ENABLE); //in: ht32f175x_275x_it.c void ADC_IRQHandler(void) { ADC_ClearIntPendingBit(ADC, ADC_FLAG_SINGLE_EOC); gPotentiometerLevel = (((ADC->DR[0]&0x0FFF)*100)/4095); } 51 begin_ADC /* Software trigger to start continuous mode */ ADC_SoftwareStartConvCmd(ADC, ENABLE); 52 Sample Code int main(void) { USART_Configuration(); Enable_ADC_IRQ(); ADC_Clock_Enable(); AFIO_PIN6_SetTo_ADC(); ADC_Configure(ContinuousMode, 1 channel, sample rate, SW_trigger); ADC_enable(); begin_ADC(); while (1) { /* Output gPotentiometerLevel if needed. */ printf("\rPotentiometer level is %d %% ", (int)gPotentiometerLevel); } } 53 Sample Code int main(void) { USART_Configuration(); NVIC_EnableIRQ(ADC_IRQn); CKCU_APBPerip1ClockConfig(CKCU_APBEN1_ADC, ENABLE); CKCU_APBPerip0ClockConfig(CKCU_APBEN0_AFIO, ENABLE); CKCU_SetADCPrescaler(CKCU_PCLK_DIV64); AFIO_GPAConfig(AFIO_PIN_6 , AFIO_MODE_1); ADC_RegularGroupConfig(ADC, CONTINUOUS_MODE, 1, 1); Conversion time = (sampling clock + 12.5) / ADCLK = 12.4 uS */ ADC_RegularChannelConfig(ADC, ADC_CH_6, 0, 0); ADC_RegularTrigConfig(ADC, ADC_TRIG_SOFTWARE); ADC_IntConfig(ADC,ADC_INT_SINGLE_EOC, ENABLE); ADC_SoftwareStartConvCmd(ADC, ENABLE); while (1) { printf("\rPotentiometer level is %d %% ", (int)gPotentiometerLevel); } } 54 Practice Target 1 (first practice) 1. read sample code – knowing each line’s meaning 2. connect the behavior in mind 3. compiling/executing code Target 2 (second practice) 1. change PC’s ADC value to binary 2. check the stability of ADC 3. change ADC channel to 2 if possible Note: 下午是王壘老師上課,下午上課時間 需要確認 55