在開始進行程式之前, 先來了解一下LaunchPad的GPIO Ports. TM4C123GH6PM總共有6個GPIO Port, 43Pins. PortA(PA0~PA7), PortB(PB0~PB7), PortC(PC0~PC7), PortD(PD0~PD7), PortE(PE0~PE5) 和 PortF(PF0~PF4). 但在LaunchPad上並不是每個腳位都有接出來(LaunchPad只有40 Pins). 有些腳位除了GPIO的功能外 , 還有替代功能 (Alternate Function) 像是 UART , ADC , SSI(SPI) , CAN , I2C , USB...等 . 詳細部分可以參考TM4C123GH6PM 的 data sheet .
TM4C123GH6PM 腳位
在LaunchPad上下端有兩個Switch, SW1和SW2, SW1是位於左下角, 連接PF4, SW2是位於右下角,連接PF0. 這兩個都是負邏輯, 也就是平常是接3.3V(邏輯1), 按下按鍵時是接地(邏輯0).
另外在 J4 和 J2 的上方, Reset 按鍵的下方 , 有顆高亮度的三色LED(RGB) . 分別接到 PF1 (紅色 LED) , PF2 (藍色 LED) , PF3 (綠色 LED) . 這也是我們等一下要控制的 LED , 就不需要外接了 .
有個部分要注意的是有6支腳平常是鎖住的 :
PD7, PF0 , PC0 ~PC3 . 解開要對LOCK暫存器下 0x4C4F434B .
PC0 ~ PC3 : 這部分是給JTAG/SWD使用, 負責程式下載到Launchpad和Debug用的 . 建議除非腳位真的不夠用了, 否則還是不要用這幾腳 , 免得操作不當 , 屆時無法下載和Debug .
底下是LaunchPad的 J1 , J2 , J3 , J4 的腳位說明 , 注意在左邊的是 J1 和 J3 , 右邊的是 J4 和 J2 . 這是LaunchPad上的排列.
J1
|
J3
|
J4
|
J2
|
|
1
|
3.3V
|
VBUS
|
PF2
|
GND
|
2
|
PB5
|
GND
|
PF3
|
PB2
|
3
|
PB0
|
PD0
|
PB3
|
PE0
|
4
|
PB1
|
PD1
|
PC4
|
PF0
|
5
|
PE4
|
PD2
|
PC5
|
RST
|
6
|
PE5
|
PD3
|
PC6
|
PB7
|
7
|
PB4
|
PE1
|
PC7
|
PB6
|
8
|
PA5
|
PE2
|
PD6
|
PA4
|
9
|
PA6
|
PE3
|
PD7
|
PA3
|
10
|
PA7
|
PF1
|
PF4
|
PA2
|
LaunchPad的 J1 , J2 , J3 , J4 的腳位
在使用GPIO之前要先打開它的Clock, 平常是關閉的, 這樣可以節省電源的消耗 . 然而 Clock 的部分還分PIOSC , MAINOSC , LFIOSC , 休眠Clock Source , PLL 等 . 這部分這裡先不說了 , 不過記得內部OSC 是16MHz +/- 1%.
直接控制暫存器 :
現在來看看程式的部分 ~~
#include <stdint.h>
#include "inc/tm4c123gh6pm.h"
//延遲100ms
void Delay(void){
volatile unsigned long time;
time = 145448;
while(time){
time--;
}
}
int main(){
volatile unsigned long delay;
SYSCTL_RCGC2_R |= 0x20; //啟動PORTF的Clock
delay = SYSCTL_RCGC2_R; //3~5 Clock等待PORTF的Clock穩定
GPIO_PORTF_AMSEL_R &= ~0x0E; //Disable PA3-PA1的Analog功能
GPIO_PORTF_PCTL_R &= ~0x0000FFF0; //設定PA3-PA1為GPIO功能
GPIO_PORTF_DIR_R |= 0x0E; //設定PA3-PA1為輸出
GPIO_PORTF_AFSEL_R &= ~0x0E; //Disable PA3-PA1的Alternate功能
GPIO_PORTF_DEN_R |= 0x0E; //Enable PA3-PA1的Digital I/O功能
while(1){
GPIO_PORTF_DATA_R |= 0x02; //點亮紅色LED
Delay();
GPIO_PORTF_DATA_R &= ~0x02; //熄滅紅色LED
Delay();
}
}
還記得前面說過預設所有的GPIO Clock都是關掉的. 所以我們要使用任何一個PORT之前都要先將它打開, 也就是
SYSCTL_RCGC2_R |= 0x20; //啟動PORTF的Clock
RCGC2是一個控制GPIO Clock的暫存器, 請看下圖:
我們要啟動PORTF的Clock, PortF是在 bit 5, 也就是 b0010.0000 (放了一個 " . "是為了方便閱讀) . 所以就等於 0x20. 如果要啟動PORTA的話, 就是 b0000.0001 = 0x01. 那為什麼是 " |= " 而不是 " = " 就好 ? 我們稱這個叫 " Friendly code ", 當我們使用 " |= " 時 , 只會改變我們設定的 bit , 其他的 bit 維持原來的設定, 這樣的好處是當你有很多的bit要獨立控制時就不會互相影響. 另外還有一個 " &= " 這是把相對應的bit清為 0 , 記得要clear的腳位要加個反向符號 " ~ " .
啟動PORTF的Clock之後, 需要等待3~5個Clock, 也就是給Clock時間穩定.
delay = SYSCTL_RCGC2_R; //3~5 Clock等待PORTF的Clock穩定
而我們這次是把 PortF 當數位腳使用, 所以Clear AMSEL 暫存器 : (Clear意思是把 bit 設為 0, Set的意思是把 bit 設為 1 .) AMSEL 暫存器相對應的 bit 如果是 0 : Disable Analog Function , 如果是 1 : Enable Analog Function .
GPIO_PORTF_AMSEL_R &= ~0x0E;
PCTL 暫存器是搭配 AFSEL使用. 當你使用替代功能時(Alternate Function) 設定腳位的.這個例子中並未使用替代功能, 所以把相對應的腳為Clear. (比較特殊是它是4個bits為一個腳位.所以你會看到它是 0x0000.FFF0.如下圖)
GPIO_PORTF_PCTL_R &= ~0x0000FFF0;
PMC7 : Pin 7, PMC6 :Pin 6.......PMC0 : Pin 0.
AFSEL 暫存器是替代功能(Alternate Function) 設定, (Pin7 ~ Pin0), 一樣 , 這個例子中並未使用替代功能, 所以把相對應的腳為Clear.
GPIO_PORTF_AFSEL_R &= ~0x0E;
DIR 暫存器是設定I/O Pin 輸入或輸出. 0 為輸入 , 1 為輸出 . 因為PF3,PF2,PF1要控制LED, 所以設為輸出.
GPIO_PORTF_DIR_R |= 0x0E;
DEN 暫存器是Enable 數位I/O功能 , 0 為Disable , 1 為Enable 在此我們Enable PF3,PF2,PF1三個腳位.
GPIO_PORTF_DEN_R |= 0x0E;
到這裡算是把 PORTF 的 PF3, PF2, PF1設定完成. 當然GPIO的暫存器不只這些, 例如 : PUR (PULL UP 暫存器) , PDR(PULL DOWN 暫存器), R2R 暫存器, R4R 暫存器, R4R 暫存器, LOCK 暫存器....嗯..慢慢來...
設定好了後, 現在我們利用 DATA 暫存器來控制 PF1(也就是紅色LED). 加了 Delay()是讓我們能看清楚一亮一滅 .
while(1){
GPIO_PORTF_DATA_R |= 0x02; //點亮紅色LED
Delay();
GPIO_PORTF_DATA_R &= ~0x02; //熄滅紅色LED
Delay();
}
好啦, 存檔並按下 Build (F7), 然後下載到 LaunchPad, 還記得下載的按鈕嗎?
按一下Launchpad的reset 鍵, 這時就看到了紅色LED快速的閃爍了. 希望閃爍的速度慢一點可以修改Delay()函式裡 time = 145448 數字增加就變慢了. 也可以點亮其他的LED, 藍色LED是 PF2, 所以是 0x04, 綠色是PF3, 所以是 0x08, 黃色 ? 紅色+綠色 = 0x0A, 白色? 紅色+綠色+藍色 = 0x0E...可以多試試其他顏色.
我想說明一下那些SYSCTL_RCGC2_R, GPIO_PORTF_DATA_R ....等等. 其實這些就是暫存器位址. 已經預先定義好在tm4c123gh6pm.h裡面了. 例如:
#define GPIO_PORTF_DATA_R (*((volatile unsigned long *)0x400253FC))
#define GPIO_PORTF_DIR_R (*((volatile unsigned long *)0x40025400))
#define GPIO_PORTF_AFSEL_R (*((volatile unsigned long *)0x40025420))
#define GPIO_PORTF_PUR_R (*((volatile unsigned long *)0x40025510))
#define GPIO_PORTF_DEN_R (*((volatile unsigned long *)0x4002551C))
#define GPIO_PORTF_LOCK_R (*((volatile unsigned long *)0x40025520))
#define GPIO_PORTF_CR_R (*((volatile unsigned long *)0x40025524))
#define GPIO_PORTF_AMSEL_R (*((volatile unsigned long *)0x40025528))
#define GPIO_PORTF_PCTL_R (*((volatile unsigned long *)0x4002552C))
#define SYSCTL_RCGC2_R (*((volatile unsigned long *)0x400FE108))
這些可以在data sheet裡查到, 比如說 GPIO_PORTF_DIR_R, 在data sheet(March 03, 2014)的663頁 中, PORTF(APB) BASE的位址是0x4002.5000 , DIR 暫存器位址是offset 0x400 , 也就是BASE + OFFSET 等於 0x4002.5400 . 這樣就能更了解與使用了.
可以實驗一下, 把剛剛程式 include 的部分註解掉, 把上面這些定義複製貼到include的下方, int main()之前, 存檔並按下 Build (F7), 然後下載到 LaunchPad . 按一下Launchpad的reset 鍵 , 結果是一樣的.
TivaWare的API :
那接下來說明一下使用TivaWare的API.
先建立一個新的Project , 例如 : B_TivaWare . 如何建立與設定參考前一篇 . 這裡有個地方要注意, 因為我們調用TivaWare的driverlib API, 需要把一些Driver(xxx.C)加到Project裡. 不過TivaWare 提供更方便的做法, 只需要加入driverlib.lib到Project裡就可以了. 方法如同加入system_TM4C123.c一樣. driverlib.lib的路徑如下:
C:\ti\TivaWare_C_Series-2.1.0.12573\driverlib\rvmdk\driverlib.lib
然後輸入以下的程式碼 :
#include <stdint.h>
#include <stdbool.h>
#include "inc/hw_memmap.h"
#include "inc/hw_types.h"
#include "driverlib/sysctl.h"
#include "driverlib/gpio.h"
int main(void)
{
SysCtlClockSet(SYSCTL_SYSDIV_5|SYSCTL_USE_PLL|SYSCTL_XTAL_16MHZ|SYSCTL_OSC_MAIN);
SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOF);
GPIOPinTypeGPIOOutput(GPIO_PORTF_BASE, GPIO_PIN_1|GPIO_PIN_2|GPIO_PIN_3);
while(1)
{
GPIOPinWrite(GPIO_PORTF_BASE, GPIO_PIN_1|GPIO_PIN_2|GPIO_PIN_3,0x02);
SysCtlDelay(2000000);
GPIOPinWrite(GPIO_PORTF_BASE, GPIO_PIN_1|GPIO_PIN_2|GPIO_PIN_3, 0x00);
SysCtlDelay(2000000);
}
}
對於System Clock的部分和之前控制暫存器時不一樣, 之前控制暫存器時並未使用PLL, 只用系統的預設16MHz, 而這裡是啟動PLL, 設定40MHz.如何得知是40MHz ? TM4C123GH6PM的PLL是400MHz, 經過一個除以2的除法器, 再除以5 (SYSCTL_SYSDIV_5), 就等於40MHz. 所以你如果要50MHz, 只要修改為SYSCTL_SYSDIV_4就可以了.
接著就對PORTF enable. 再設定為輸出.
然後底下這行就是對GPIO_PORTF_DATA_R 寫入0x02, 點亮PF1(紅色LED).
GPIOPinWrite(GPIO_PORTF_BASE, GPIO_PIN_1|GPIO_PIN_2|GPIO_PIN_3,0x02);
很簡單吧. 所以如果懂了如何使用暫存器, 對於解讀這些API應該不難. 可以直接打開這些檔案參考或是參考User Guide, 當你安裝好TivaWare, 在Doc資料夾裡可以找到. 例如 :
C:\ti\TivaWare_C_Series-2.1.0.12573\docs
好啦, 一樣 , 存檔並按下 Build (F7), 然後下載到 LaunchPad, 按一下Launchpad的reset 鍵 , 可以看到紅色 LED在閃爍了! 這次閃爍的比較慢, 因為Delay的時間比較長.
~~~~~~~~~~~~~~~~~休息一下吧 ! ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
參考文獻 :
Embedded Systems: Introduction to ARM® Cortex™-M Microcontrollers - Jonathan Valvano
Getting Started with the Tiva™ TM4C123G LaunchPad Workshop
TM4C123GH6PM DATA SHEET
Embedded Systems Shape The World


































