You are currently viewing FRDM-KL46Z #3: Hướng dẫn dùng MDK-ARM Keil uVision để tạo, biên dịch và nạp ứng dụng

FRDM-KL46Z #3: Hướng dẫn dùng MDK-ARM Keil uVision để tạo, biên dịch và nạp ứng dụng

1. Giới thiệu

     Hướng dẫn cách sử dụng công cụ phần mềm Keil MDK-ARM để thiết lập một project, phát triển mã nguồn chương trình ứng dụng, biên dịch, nạp chương trình và chạy thử nghiệm trên bo mạch phát triển FRDM-KL46Z.

Link video hướng dẫn sử dụng phần mềm Keil MDK-ARM để tạo project, biên dịch, và nạp chương trình ứng dụng vào bo mạch FRDM-KL46Z ở đây.

Link download các tệp mã nguồn ở đây.

Bạn có thể mua bo mạch FRDM-KL46Z trên trang thương mại điện tử Lazada ở đây.

2. Tạo một project mới

     Mở phần mềm KEIL µVision5 nếu phần mềm chưa được mở.  Để tạo ra một Project mới, từ thanh menu chọn Project>New µVision Project… sau đó xác định thư mục nơi sẽ lưu project và đặt tên cho project.  Chẳng hạn, trong ví dụ minh họa này tôi đặt tên Project như sau: C:\FRDM_KL46Z\Lab1\Lab1.uvproj.  Nói chung nên đặt cho mỗi project một tên riêng gần với chức năng của project đó để dễ quản lý. Bấm Save để chuyển sang bước tiếp theo.

Tạo ra một project mới

Hình B – 1. Tạo ra một project mới.

Tiếp đến chúng ta cần xác định tên bộ vi điều khiển sẽ được dùng để thực thi chương trình trong project. Trong trường hợp này chúng ta chúng ta sẽ chọn tên vi điều khiển là MKL46Z256VLL4. Vi điều khiển này có thể được tìm thấy trong đường dẫn NXP MKL46Z4 MKL46Z256xxx4 MKL46Z256VLL4 như chỉ ra trong Hình B – 2.  Bấm OK để tiếp tục.

Xác định bộ vi điều khiển được sử dụng trong project

Hình B – 2. Xác định bộ vi điều khiển được sử dụng trong project.

Trong hộp thoại Manage Run-Time Enviroment thêm vào project các thành phần phần mềm ::CMSIS:CORE::DEVICE:Startup bằng cách đánh dấu vào các checkbox như chỉ ra trong Hình B – 3. Các thành phần này cung cấp các tệp trung tâm sau:

  • Tệp startup_<device>.s khai báo trình điều khiển ngắt reset handler và các vector ngoại lệ
  • Tệp cấu hình system_<device>.c thiết lập chế độ làm việc các thiết bị cơ bản (chẳng hạn như nguồn phát xung nhịp, bộ nhớ, BUS, ..).
  • Tệp <device>.h bao gồm các khai báo thanh ghi, hằng số, … cho phép mã nguồn của người truy xuất tới cấu trúc phần cứng của vi điều khiển.

Tệp tiêu đề <device> .h cần phải được bao gồm (include) trong các tệp mã nguồn C của người sử dụng để định nghĩa:

  • Truy cập ngoại vi với thanh ghi chuẩn hóa.
  • Truy cập vào các ngắt và ngoại lệ và bộ điều khiển véc tơ lồng nhau (NVIC).
  • Chức năng nội tại để tạo các lệnh đặc biệt, chẳng hạn để kích hoạt chế độ ngủ.
  • Chức năng Systick Timer (SYSTICK) để định cấu hình và bắt đầu ngắt timer định kỳ.

Thêm các thành phần phần mềm vào project

Hình B – 3. Thêm các thành phần phần mềm vào project.

Nhấp chuột vào nút “OK” để kết thúc quá trình tạo project. Nếu các bước khởi tạo ở trên được thực hiện đúng thì cửa sổ project sẽ xuất hiện giống như trong Hình B – 4 với các tệp tin của hai thành phần mềm CMSIS:CORE và DEVICE:Startup đã được thêm vào project.

Cửa sổ project

Hình B – 4. Cửa sổ project.

Tiếp theo chúng ta sẽ cần thêm một tập tin c vào project. Để thực hiện việc này, nhấp chuột phải vào thư mục Source Group 1 và chọn Add New Item to Group ‘Source Group 1’…. Điều này sẽ cho phép chúng ta tạo một tệp mới để đưa vào project. Vì tệp này được dự định chứa mã nguồn chương trình, nó cần phải là tệp C. Chọn C file (.c), sau đó đặt tên cho nó, chẳng hạn tôi sẽ đặt tên tệp là main.c như thể hiện trong Hình B – 6.

Thêm một hạng mục mới tơi project

Hình B – 5. Thêm một hạng mục mới tới project.

Thêm một tệp C tới project
Hình B – 6. Thêm một tệp C tới project.

Include tệp MKL46Z.h vào tệp mã nguồn

Hình B – 7

Để kích hoạt các thành phần của MCU, chúng ta sẽ thao tác trên các thanh ghi cơ sở của nó. Để giúp thực hiện điều này, nhấp chuột phải vào cửa sổ mã và chọn Insert ‘#include <MKL46Z4.H>. Tệp tiêu đề này chứa tên các thanh ghi và “mặt nạ” cho phép việc các thao tác trên các thanh ghi đó đỡ rối hơn. Nếu bạn muốn xem toàn bộ tệp, nhấp chuột phải vào <MKL46Z4.H> và chọn Open Document <MKL46Z4.H>. Đối với hầu hết các phần, các mặt nạ được đặt tên dựa trên tài liệu tham khảo hướng dẫn sử dụng chip KL46 (tài liệu [14]) theo định dạng ‘CHAPTER NAME’_’REGISTER NAME’_’BIT NAME’_MASK, tất cả đều ở dạng viết hoa. Một ví dụ về việc sử dụng mặt nạ để sửa đổi một thanh ghi được chỉ ra trong Ví dụ B – 1 dưới đây. Có nhiều cách để làm điều này cả có và không có mặt nạ, tôi sẽ chỉ ra một vài cách và giải thích tại sao một số có thể tốt hơn những cách khác.

Ví dụ B – 1: Thao tác với các bit của thanh ghi
/*In order to allow PortA to be used we must first enable the clock to it.  The PortA clock enable is bit 9 of SIM_SCGC5.  All of the following lines of code do this, but it is much easier to see what is happening with some of them.*/

SIM->SCGC5 |= SIM_SCGC5_PORTA_MASK;

/*MKL46Z4.h defines SIM_SCGC5_PORTA_MASK as 0x200u, or 1 left shifted by 9.  Using this line makes it clear that we are enabling PORTA as we are setting the PORTA mask.*/

SIM->SCGC5 |= (1u << SIM_SCGC5_PORTA_SHIFT); 

/*This is very similar to the previous line, but it defines SIM_SCGC_PORTA_SHIFT as 9, or the number of the bit in the SIM_SCGC5 register.*/

SIM->SCGC5 |= (1u << 9); 

/*This one is harder to follow.  All we know is that we are setting the 9th bit of SIM_SCGC5, and an outside reader (or possibly you when you proofread your code) will have a hard time discerning what this line means.*/

SIM->SCGC5 |= (0x200u); 

/*This works, but it doesn't even tell what bit you're setting immediately.  It's hex, so it's in groups of 4 bits, which is its one saving grace.*/

SIM->SCGC5 |= (512u); 

/*This also works, but makes no sense.  Using a decimal number to describe which bit to set is unintuitive and almost impossible to read unless you're the author or the code is very well commented (at which point it's easier to just use the mask)*/

 

Lưu ý việc sử dụng lệnh gán “| =” trong ví dụ trên. Lệnh này thực hiện lấy đối số đầu tiên và tiến hành phép tính logic OR với đối số thứ hai sau đó trả kết quả về đối số thứ nhất. Đây là một lệnh hữu ích được sử dụng để thiết lập một số bit trong một thanh ghi mà không thay đổi các bit khác.

Mặt nạ được sử dụng trong các lệnh ở dòng 4 và 8 có thể hữu ích vì nhiều lý do. Đầu tiên (như trong ví dụ) là khả năng đọc. Nó cho phép người đọc nhanh chóng hiểu những gì đang xảy ra. Bằng cách sử dụng sơ đồ đặt tên theo quy chuẩn, người đọc có thể thấy thanh ghi nào và bit nào trong thanh ghi đó đang được thiết lập. Một lý do thứ hai là tính di động. Giả sử mã C được viết hoàn hảo và người lập trình muốn sử dụng lại nó khi chuyển sang thiết bị khác, điều này có thể được thực hiện đơn giản bằng cách thay đổi tệp tiêu đề (header) được bao gồm (include) trong tệp mã ngưồn.

3. Viết chương trình ứng dụng

Bây giờ chúng ta có thể viết các chương trình để thực hiện điều khiển nhấp nháy LED xanh trên Kit FRDM-KL46Z. Chúng ta bắt đầu bằng viết một hàm khởi tạo các chân cổng PTD5 đường dùng để điều khiển LED xanh như trong Ví dụ B – 2.

Ví dụ B – 2: Cấu hình cho các chân điều khiển LED

void InitLED(void){ 

/*This function enables the red LED on the FRDM-KL46Z development board*/

/*Note, each chapter from the KL46 Reference Manual is a structure, while each register is a member of that structure, so we address them by Chapter -> Register*/

SIM->SCGC5 |= SIM_SCGC5_PORTD_MASK; 

//This enables the clock to PORTD

PORTD->PCR[5] = PORT_PCR_MUX(1u); 

//This sets the Mux control of PTD5 to 001, or GPIO

PTD->PDDR |= (1u<<5); 

/*This sets PTD5 as an output.  There are no masks defined for each pin so we have to do it by hand and just comment well.*/

}

Trong mã trên SIM (System Integration Module) là mô-đun tích hợp hệ thống cho phép điều khiển cấp xung nhịp tới một thiết bị ngoại nào đó trên MCU. Bằng cách ngắt cấp xung nhịp tới một ngoại vi sẽ giúp MCU tiết giảm năng lượng tiêu thụ nhưng lại khiến ngoại vi không thể hoạt động. Trong mô-đun SIM, thanh ghi điều khiển xung nhịp hệ thống số (System Clock Gating Control Register) 5 ký hiệu là SIM_SCGC5 và được truy xuất tới trong Keil dưới định dạng SIM->SCGC5. Thanh ghi này giữ chức năng kích hoạt tín hiệu xung nhịp cho các cổng khác nhau trên MCU. ĐỂ SỬ DỤNG BẤT KỲ CHÂN NÀO TRÊN MỘT CẢNG THÌ CẢNG ĐÓ PHẢI ĐƯỢC KÍCH HOẠT TÍN HIỆU XUNG NHỊP. Ví dụ, để sử dụng đèn LED màu xanh trên chân PTD5, trước tiên chúng ta phải bật tín hiệu xung nhịp cho Cổng D trong thanh ghi SCGC5.

Thanh ghi điều khiển cổng PCR (Pin Control Register) được sử dụng để xác định một chân cổng được sử dụng cho thiết bị ngoại vi nào trên MCU. Thanh ghi này được truy xuất bằng cấu trúc PORTx->PCR[n] trong phần mềm Keil. Ví dụ, chúng ta cần điều khiển đèn LED màu xanh trên bo mạch FRDM-KL46, vì vậy chúng ta phải truy xuất thanh ghi PCR số 5 trong mảng thanh ghi PCR của cổng PORTD bằng cấu trúc như được chỉ ra trong lệnh trong dòng 7 của Ví dụ B – 2.

Ngay sau khi một chân cổng được thiết lập kết nối với một khối GPIO thì thanh ghi hướng dữ liệu cổng GPIO_PDDR (Port Data Direction Register) (được truy xuất tới trong Keil bằng cấu trúc PTx->PDDR) được dùng để cấu hình khối GPIO hoạt động ở chế độ đầu vào hay đầu ra. Số thứ tự của chân tương ứng với số thứ tự bit trong thanh ghi. Giá trị 0 trong một bit của PDDR sẽ cấu hình chân cổng tương ứng là đầu vào và giá trị 1 cấu hình chân là đầu ra. Vì vậy để cấu hình chân PTD5 làm đầu ra, chúng ta phải đặt bit số 5 của PTD->PDDR thành 1.

Bây giờ chúng ta viết các hàm điều khiển nháy LED. Điều này có thể được thực hiện theo một trong ba cách như sẽ được trình bày trong Ví dụ B – 3, Ví dụ B – 4 và Ví dụ B – 5 dưới đây.

Ví dụ B – 3: Điều khiển nháy LED thông qua cặp thanh ghi PSOR và PCOR

void BlinkLED1(void){

//This method turns the LED off, then back on using two separate commands.

    uint32_t i = 0; //Create a loop variable
     

    PTD->PSOR = (1u<<5); //Set PTD5 = 1, turns LED OFF (Cathode connected to PTD5)

    for(i=0; i < 3000000; i++){}; //Burn some time

    PTD->PCOR = (1u<<5); //Clear PTD5 = 0, turns LED ON

    for(i=0; i < 3000000; i++){}; //Burn some time

}

Thanh ghi đặt dữ liệu cổng GPIO_PSOR (Port Data Set Register) – Thanh ghi này sẽ đặt đầu ra của một chân lên 1. Ghi giá trị 0 vào thanh ghi PSOR sẽ không thay đổi giá trị hiện tại của chân, trong khi giá trị 1 trong một bit của thanh ghi PSOR sẽ đặt chân tương ứng thành 1.

Thanh ghi xóa dữ liệu cổng GPIO_PCOR (Port Data Clear Register) – Thanh ghi này sẽ xóa đầu ra của một chân về 0. Ghi giá trị 0 vào thanh ghi PCOR sẽ không thay đổi giá trị hiện tại của chân, trong khi giá trị 1 trong một bit của thanh ghi PSOR sẽ đặt chân tương ứng thành 0.

Ví dụ B – 4: Điều khiển nháy LED thông qua thanh ghi PDOR

void BlinkLED2(void){

 //This method turns the LED off, then back on using PDOR

    /*Note the use of |= and &=.  This allows you to change the 5th bit of PDOR without disturbing the other bits.  The other methods do not require this as setting PSOR/PCOR/PTOR = 0 does not change the output.*/

    uint32_t i = 0; //Create a loop variable

     

PTD->PDOR |= (1u<<5);

 //Change PTD5 to 1, turns LED OFF (Cathode connected to PTD5)

    for(i=0; i < 3000000; i++){}; //Burn some time

PTD->PDOR &= ~((uint32_t)(1u<<5));

 /*Change PTD5 to 0 to turns LED ON.  This line is a bit weird.  First it takes 1u<<5 and typecasts it to a 32 bit value.  It then takes the inverse of it, so all bits are 1 except bit 5.  It then logical ands it with the current PDOR, which will retain all values except bit 5 which will be changed to 0.*/

    for(i=0; i < 3000000; i++){}; //Burn some time

}

Thanh ghi đầu ra dữ liệu cổng GPIO_PDOR (Port Data Output Register) được dùng để sẽ thay đổi đầu ra của một chân tới một giá trị đã cho. Vì vậy, ghi giá trị 0 tới thanh ghi này sẽ thay đổi đầu ra trên chân cổng thành 0, trong khi ghi giá trị 1 tới thanh ghi này sẽ thay đổi đầu ra trên chân cổng thành 1.

Ví dụ B – 5: Điều khiển nháy LED thông qua thanh ghi PTOR

void BlinkLED3(void){

/*This method turns the LED off, then back on using a single command.  It must be run twice in order to blink the LED.*/

    uint32_t i = 0; //Create a loop variable

     

    PTD->PTOR = (1u<<5); //Toggles PTD5 and the LED

    for(i=0; i < 3000000; i++){}; //Burn some time

}

Thanh ghi đảo dữ liệu cổng GPIO_PTOR (Port Data Toggle Register) – Thanh ghi này sẽ gây ra giá trị trên đầu ra của một chân đảo giá trị so với giá trị hiện tại. Ghi giá trị 0 tới thanh ghi này sẽ không làm thay đổi giá trị hiện tại của chân, trong khi một bit có giá trị 1 sẽ thay đổi trạng thái của chân tương ứng thành nghịch đảo của trạng thái hiện tại.

Cuối cùng chúng ta viết cho mã cho hàm main() như chỉ ra trong Ví dụ B – 6. Chúng ta tạo ra giữ mọi thứ trong một vòng lặp để đảm bảo rằng chúng tôi không bao giờ rời khỏi chính vì điều đó có thể gây ra hành vi không xác định.

Ví dụ B – 6: Hàm Main()
int main(void){

    InitLED(); //Initialize LED for use

    while(1){ //Main loop

        BlinkLED3(); 

    } //End main loop

} //End main

4. Biên dịch và nạp chương trình vào kit

Project sau khi thêm vào các tệp mã nguồn

Hình B – 8. Project sau khi thêm vào các tệp mã nguồn.

Để lập trình MCU trên bo mạch FRDM-KL46Z chúng ta cần thiết lập một số tùy chọn. Để thực hiện điều này nhấp chuột phải vào thư mục “Target” trong cửa sổ Project và chọn “Options for Target ‘Target 1’…”. Trong hộp thoại “Options for Target ‘Target 1’…” chuyển đến tab Debug và chọn “PEMicro Debuger” như thể hiện trong Hình B – 9 và bấm nút “Setting” bên cạnh để cấu hình cho Debuger.

Hộp thoại chọn trình debugger

Hình B – 9. Hộp thoại chọn trình debugger.

Trong hộp thoại “P&E Connection Manager” cấu hình cho trình Debugger như thể hiện trong Hình B – 10.

Hộp thoại thiết lập cấu hình cho trình Debugger

Hình B – 10. Hộp thoại thiết lập cấu hình cho trình Debugger.

Để biên dịch chương trình nhấp chuột vào nút “Rebuild” trên thanh toolbar. Đợi cho quá trình biên dịch kết thúc thì bấm nút “Download” trên thanh toolbar để nạp chương trình vào MCU trên bo mạch. Sau khi quá trình nạp kết thúc, bấm nut Reset trên bo mạch, nếu mọi bước ở trên thực hiện đúng sẽ thấy đèn LED màu xanh trên bo mạch FRMD-KL46Z nhấp nháy.

Biên dịch và nạp chương trình

Hình B – 11. Biên dịch và nạp chương trình.

Link video hướng dẫn sử dụng phần mềm Keil MDK-ARM để tạo project, biên dịch, và nạp chương trình ứng dụng vào bo mạch FRDM-KL46Z ở đây.

Link download các tệp mã nguồn ở đây.

Bạn có thể mua bo mạch FRDM-KL46Z trên trang thương mại điện tử Lazada ở đây.

Video hướng dẫn sử dụng phần mềm Keil MDK-ARM:

Nguyễn Kiêm Hùng

Hung K. Nguyen studied “Electronic Engineering” in both his bachelor’s and master’s degrees at the Vietnam National University, Hanoi, Vietnam. He received the bachelor’s degree in 2003. After receiving his bachelor’s degree, He worked as an internship in the Research Center of Electronics and Telecommunications. In 2006, He received the master’s degree in electronic engineering from VNU University of Engineering and Technology (VNU-UET). Before pursuing his Ph.D’s degree, He worked as a researcher at the Laboratory for Smart Integrated Systems in VNU University of Engineering and Technology for two years. In 2008, He went to Southeast University, Nanjing, China to get his Ph.D degree. He received the Ph.D. degree in Microelectronics and Solid State Electronics from Southeast University in 2013. After got his Ph.D’s degree, He returned to VNU University of Engineering and Technology to continue his research in VLSI design. He works currently as an assistant professor and senior researcher at VNU Key Laboratory for Smart Integrated Systems. His research interests mainly include multimedia processing, reconfigurable computing, and SoC designs.

This Post Has 4 Comments

  1. Nguyễn Ngọc Tuấn

    Thưa thầy của em không có NXP mà chỉ có của ARM thôi ạ

    1. Nguyễn Ngọc Tuấn

      À do em chưa cài các gói của nó ạ. Giờ em làm được rồi

  2. Phương Bắc Nguyễn

    Thầy có thể hướng dẫn thêm phần tạo project trong linux, biên dịch mã nguồn bằng GNU make được không ạ!

    1. Nguyễn Kiêm Hùng

      Em tự tìm cách cài đặt phần mềm Keil MDK-ARM trong Linux, sau đó cách tạo project giống như trong Windows

Trả lời