2014年3月23日 星期日

TM4C123G LaunchPad 第一個程式 - LED 閃爍

在上一篇中我們在Keil中建立了一個新的專案. 但是還沒開始進行Blinky的程式. 這裡我們把這個程式完成, 我們先用直接控制暫存器的方法, 控制LED閃爍, 第二部分再用TIveWare裡的API來實現.

在開始進行程式之前, 先來了解一下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

2014年3月19日 星期三

如何使用Keil建立一個新project for TM4C123G Launchpad

1. 開啟Keil MDK-ARM uVision4.73 , 並點選Project --> New uVision Project...


2. 建立一個資料夾儲存Project , 我是在Documents\Keil MDK473\TM4C123 底下建一個Blinky資料夾 , 並將project命名為Blinky



3. 選擇CPU的型號 , 在左邊的Data Base中找到Texas Instruments , 點一下 " + " 號 , 往下拉 , 選擇TM4C123GH6PM , 按OK 



4. 詢問是否加入startup_TM4C123.s檔案 , 選擇 " 是 " , 按OK 也可以選否,稍後加入自己的startup.s , 不過以我這種初學者來說 , 選 " 是 "是一個簡單的選擇  



    此時在左側可以看到專案List以及我們剛剛加入的startup_TM4C123.s檔案

5. 設定Options for Target"Target1" 
      5a. 點一下圖中的紅圈處會出現 Options for Target"Target1"對話框或是在左側的Target1上按右鍵選擇 Options for Target"Target1"  也可以。

      5b. 確認Xtal(Mhz)是16MHz 
   
    5c. 在Define裡加入rvmdk, PART_TM4C123GH6PM和TARGET_IS_BLIZZARD_RB1。這是因為在TivaWare裡會參照這裡的定義來提供相對應的定義 , 有點繞舌。當然也可以在main.c裡來定義這些。底下的Include Path當然就是TivaWare安裝的路徑 


    5d. 在Linker的Misc controls裡加入 --entry Reset_Handler 

    5e. 在Debug中, 點選右邊的check, 並下拉選單選Stellaris ICDI

    5f. 按一下剛剛Debug中右邊的Settings , 如果Launchpad有接上電腦, 會出現下圖, 這裡的設定維持原來的就好

    5g. 在Utilities下拉選單選Stellaris ICDI。如果沒有下拉選單, 取消掉右邊的Use Debug Driver, 就會出現下拉選單

6. 接下來要加入system_TM4C123.c , 在剛剛的startup_TM4C123.s中會呼叫SystemInit() , 而此函式是在system_TM4C123.c裡面

    6a. 點一下圖中的紅圈處會出現Manage Project Items對話框 , 接著按右下角的Add Files

    6b. 選擇system_TM4C123.c檔案 , 如果安裝Keil時選用預設的路徑的話 , 該檔案會在 : C:\Keil\ARM\Startup\TI\TM4C123\system_TM4C123.c 

    6c. 加入後在右邊的Files:裡可以看到system_TM4C123.c

    6d. 最後在Project -->Target1-->Source Group 1下就加入了system_TM4C123.c了

7. 最後只剩下加入main.c了. 當然也可以是其他的檔名 
    7a. 在Source Group 1上按右鍵 , 選擇Add New Item to Group "Source Group 1" 

  7b. 選擇C File(.c) , 在底下Name:部分輸入檔名 

    7c. 在Project的地方可以看到剛剛輸入的檔名 , 右邊的地方可以開始輸入我們的程式了 

我們先試一下, 先在main.c裡輸入 :
int main(){
}



記得在 " } " 後面要多空一行. 否則會出現下面的警告 :
main.c(2): warning:  #1-D: last line of file ends without a newline

 按下build button(或是F7) , 太好了! 0 Error(s), 0 Warning(s)


好了,  休息一下. 下一篇再寫Blinky程式

2014年3月12日 星期三

初會Tiva C Series TM4C123G Launchpad


在某個因緣際會之下買了這個板子, 在此之前沒有接觸過任何ARM Cortex-M4的Microcontroller  於是乎開始尋找相關的資訊, 發現資料實在是太多了, 那我該如何開始呢? 著實花了不少時間其實TI的網站內容是相當的豐富, 只是對於我這種談不上入門的初學者來說, 一時半刻還真無法消化 所以我想就把它整理一下, 有需要時可以參考

話說這板子是TI出的Cortex-M4評估板(Evaluation Board), 板上的Microcontroller 是 TM4C123GH6PM 大致上分成兩個部分, 上半部是Debug和程式下載 也就是說透過USB連接到電腦就可以把我們寫好的程式下載到目標的MCU, 也就是位於下半部的TM4C123GH6PM 不需要額外購買燒錄器, 除了方便之外也可省下燒錄器的費用而且, 這個評估板價格也不貴, 還蠻適合我這種初學者的

圖片來源 : TM4C123G LaunchPad User Menu.

詳細的規格可以參考 - EK-TM4C123G LaunchPad 這裡就是我說的有非常豐富的資料, 有時間還是要研究一下

先下載幾個必要的工具:
1. SW-TM4C (TivaWare現在版本已更新到2.1.0.12573)選擇第一個
2. Keil MDK-ARM V4 (v4.73)

另外, TI 也有一個WorkShop, 一步一步教你如何使用TM4C123G LaunchPad, 內容相當詳細

安裝TivaWare和Keil MDK_ARM其實還蠻簡單的,就一直按下一步就可以了

接下來連接LaunchPad到電腦, 在連接之前確認左上角的開關位置切到Debug,如下圖:
                  
                      PS.放大後不清楚,直接看下一張圖的左上角

USB是連接上面那一個:


安裝Stellars ICDI Driver, 這個部分可以直接參考這份說明文件, Driver 安裝好了之後, 到裝置管理員確認一下以下訊息:

安裝成功可以看到Stellaris ICDI DFU Device, Stellaris ICDI JTAG/SWD Interface, 以及連接埠裡的Stellaris Virtual Serial Port(COMxx)

接下來玩一下TivaWare附的Blinky例子 如果你安裝TivaWare時選擇預設路徑的話, 可以在這裡找到 : 

C:\ti\TivaWare_C_Series-2.1.0.12573\examples\boards\ek-tm4c123gxl\blinky\blinky.uvproj

雙擊(Double click)專案名稱 blinky.uvproj 會自動開啟. 


接著將Crystal的值修改為16MHz. (LaunchPad上的Crystal是16MHz)
     1.按下紅色圈起的按鈕 

     2. 將8.0改為16, 再按OK



接下來編譯(compiler):
   按下紅色圈起的按鈕或F7

     編譯完成

下載到LaunchPad:
    按下紅色圈起的按鈕, 當然下載前要確認 LaunchPad 是接到電腦

    下載完成:

此時按一下 LaunchPad 上的 Reset 鍵, 可以看到綠色的LED閃爍 好啦, 到此先休息一下 

另外德州大學在edx開了一個免費課程UT.6.01x Embedded Systems - Shape the World , 課程到2014/5/13結束,有興趣可以參加