You are currently viewing FRDM-KL46Z #8: Lập trình Systick timer trên các vi xử lý Cortex-M

FRDM-KL46Z #8: Lập trình Systick timer trên các vi xử lý Cortex-M

Mỗi lõi vi xử lý ARM Cortex-M đều được trang bị sẵn một bộ đếm thời gian gọi là System tick timer, viết tắt là Systick timer.  Mục đích chính của bộ đếm thời gian này là tạo ra một ngắt định kỳ cho hệ điều hành thời gian thực (RTOS) hoặc phần mềm điều khiển sự kiện. Bộ định thời Systick cho phép hệ thống khởi tạo một hành động theo chu kỳ. Ví dụ, trong một ứng dụng nhất định, chúng ta có thể sử dụng SysTick timer để xác định khoảng thời gian đọc cảm biến sau mỗi khoảng thời gian là 200 msec. SysTick timer cũng được sử dụng rộng rãi bởi các hệ điều hành để phân chia các khoảng thời gian cho việc giám sát và kiểm soát các hoạt động của hệ thống như cho phép một đoạn mã phần mềm ứng dụng có thể thực hiện định kỳ theo một khoảng thời gian nào đó.

Sơ đồ khối cấu trúc và các thanh ghi điều khiển của Systick timer được thể hiện trong Hình 8‑7. SysTick timer là bộ đếm lùi 24 bit với khả năng tự động nạp lại giá trị đếm. được điều khiển bởi tín hiệu xung nhịp hệ thống hoặc bộ dao động bên trong của chip vi điều khiển. Nó đếm ngược từ một giá trị khởi tạo xuống 0. Khi đếm đến 0, bộ đếm sẽ đặt cờ trạng thái COUNT và tạo ra một ngắt (ngắt số 15) đồng thời nạp lại giá trị khởi tạo và lặp lại quá trình đếm mới. Chúng ta có thể đặt giá trị khởi tạo tới một giá trị bất kỳ trong khoảng từ 0x000000 đến 0xFFFFFF.

systick timer ARM cortex-M

Hình 8‑7. Sơ đồ khối cấu trúc của Systick timer và các thanh ghi bên trong nó (Mục 10.3, [31]).

Nguồn xung nhịp mặc định cho bộ đếm thời gian SysTick là cùng nguồn xung nhịp với bộ xử lý trung tâm Cortex-M. Tuy nhiên, chúng ta có thể chuyển sang nguồn xung nhịp khác, nhưng điều này sẽ thay đổi tùy thuộc vào vi điều khiển thực tế bạn đang sử dụng. Chẳng hạn trong vi điều khiển Cortex-M0+, trường CLKSOURCE trong thanh ghi trạng thái và điều khiển (Control and Status register) được dùng để chọn nguồn xung nhịp cho SysTick Timer hoặc là xung nhịp của lõi vi xử lý (khi CLKSOURCE = 1) hoặc xung nhịp lõi vi xử lý chia cho 16 (khi CLKSOURCE = 0). Vì tham chiếu thời gian là tần số biến thiên, trường TENMS trong thanh ghi giá trị hiệu chuẩn (Calibration Value Register) của SysTick luôn là 0.

Mặc dù bộ đếm thời gian SysTick là phổ biến cho tất cả các bộ xử lý Cortex-M, các thanh ghi của nó chiếm cùng một vị trí trong không gian bộ nhớ của Cortex-M3/-M4 và -M7. Trong Cortex-M0 và Cortex-M0+, các thanh ghi SysTick được đặt trong khối điều khiển hệ thống và có các tên tượng trưng khác nhau để tránh nhầm lẫn. Đường ngắt từ SysTick timer và tất cả các đường ngoại vi của vi điều khiển được kết nối với Bộ điều khiển ngắt Vector lồng nhau NVIC (Nested Vectored Interrupt Controller).

Các thanh ghi của Systick timer

Tiếp theo, chúng ta sẽ tìm hiểu định dạng các thanh ghi SysTick. Có ba thanh ghi trong mô-đun SysTick: thanh ghi trạng thái và điều khiển SysTick, thanh ghi giá trị nạp lại SysTick và thanh ghi giá trị hiện tại của SysTick.

Thanh ghi trạng thái và điều khiển STCTRL (Systick -> CTRL)

Thanh ghi trạng thái và điều khiển Systick timer STCTRL được đặt tại địa chỉ 0xE000E010. Chúng ta dùng thanh ghi này để khởi động Systick timer.

Ký hiệu Định dạng Địa chỉ
STCTRL

SysTick®CTRL

systick timer ARM cortex-M Địa chỉ cơ sở + 0x010

Hình 8‑8. Thanh ghi trạng thái và điều khiển STCTRL.

Bảng 8‑1. Mô tả các bit của thanh ghi STCTRL

Bit Tên Miêu tả
0 Enable Tín hiệu kích hoạt Systick timer

–       0: Cấm Systick timer hoạt động

–       1: Cho phép Systick timer hoạt động      

1 INTEN

(Interrupt Enable)

–       0: Cấm systick timer tạo ngắt

–       1: Cho phép systick timer tạo ra một yêu cầu ngắt khi đếm đến 0

2 CLK_SRC (Clock Source) Chọn nguồn xung nhịp

–       0: Xung nhịp từ bộ dao động bên trong có độ chính xác cao (PIOSC: Precision Internal Oscillator) chia 4

–       1: Xung nhịp hệ thống

16 Count Cờ đếm

–       0: Systick timer vẫn chưa đếm đến 0 kể từ lần cuối cùng bit này được đọc

–       1: Systick timer đã đếm đến 0

(Lưu ý: bit này được xóa bằng thao tác đọc thanh ghi STCRTL hoặc viết tới thanh ghi STCURRENT)

 

ENABLE (D0): bật hoặc tắt bộ đếm. Khi bit ENABLE được thiết lập, bộ đếm khởi tạo STCURRENT với giá trị của thanh ghi STRELOAD và nó sẽ đếm ngược cho đến khi giá trị bộ đếm bằng 0. Sau đó, trong xung nhịp tiếp theo, bộ đếm bị tràn dẫn đến cờ COUNT được đặt thành 1 và bộ đếm nạp lại thanh ghi STCURRENT với giá trị của thanh ghi STRELOAD và sau đó quá trình được lặp lại như được mô tả trong Hình 8‑9.

systick timer ARM cortex-M

Hình 8‑9. Quá trình đếm của bộ định thời Systick.

INTEN (Cho phép ngắt, D1): Nếu INTEN = 1, ngắt xảy ra khi cờ COUNT được đặt (xem thêm Chương 9).

CLK_SRC (Nguồn xung nhịp, D2): Chúng ta có thể lựa chọn xung nhịp đến từ xung nhịp hệ thống hoặc bộ dao động bên trong có độ chính xác cao (PIOSC: Precision Internal Oscillator). Nếu CLK_SRC = 0 thì xung nhịp đến từ PIOSC/4. Nếu CLK_SRC = 1, thì nguồn cung cấp xung nhịp cho bộ đếm SysTick là xung nhịp hệ thống.

COUNT (D16): Bộ đếm đếm lùi từ giá trị ban đầu cho đến khi bằng 0, trong xung nhịp tiếp theo bộ đếm bị tràn và cờ COUNT được đặt lên mức cao (xem Hình 8‑9). Cờ này duy trì ở mức cao cho đến khi nó được xóa bằng phần mềm. Cờ có thể được xóa bằng cách đọc thanh ghi STCTRL hoặc ghi vào thanh ghi CTCURRENT.

Thanh ghi giá trị nạp lại Systick (STELOAD – Systick Reload Value)

Thanh ghi STRELOAD được đặt ở vị trí 0xE000E014. Thanh ghi này được sử dụng để lập trình giá trị bắt đầu của bộ đếm systick – thanh ghi STCURRENT. STRELOAD phải chứa giá trị N – 1 để cờ COUNT được đặt sau mỗi N chu kỳ xung nhịp vì bộ đếm đếm ngược về 0. Ví dụ, nếu chúng ta cần tạo một khoảng thời gian tương ứng với 1000 xung nhịp thì chúng ta đặt STRELOAD = 999. Mặc dù đây là một thanh ghi 32-bit, chỉ có 24 bit thấp được sử dụng. Điều đó có nghĩa là giá trị cao nhất có thể được nạp vào thanh ghi này là 0xFFFFFF hay 16,777,216 dưới dạng biểu diễn thập phân. Hình 8‑7 và Hình 8‑10 chỉ ra định dạng của các thanh ghi này.

Ký hiệu Định dạng Địa chỉ
STRELOAD

SysTick®LOAD

systick timer ARM cortex-M Địa chỉ cơ sở + 0x014
STCURRENT

SysTick®VAL

systick timer ARM cortex-M Địa chỉ cơ sở + 0x018

Hình 8‑10. Thanh ghi STRELOAD và STCURRENT.

Chương trình 8‑1 nạp giá trị khởi tạo cho thanh ghi STRELOAD bằng giá trị tối đa và xuất giá trị hiện tại của SysTick trên đèn LED màu xanh lá cây được kết nối tới PORTB. Giá trị của thanh ghi STCURRENT (SysTick-> VAL) được dịch sang phải 4 vị trí để bit quan trọng nhất được căn chỉnh với chân cổng PTB19 là chân được kết nối với đèn LED màu xanh lá cây. SysTick được cấu hình để sử dụng xung nhịp hệ thống mặc định là 41,94 MHz. Thanh ghi STRELOAD (SysTick-> LOAD) có 24 bit và được đặt tới giá trị lớn nhất, vì vậy bộ đếm có tần số là:

(8‑1)

Đây cũng là tần số nháy của LED màu xanh. LED màu đỏ được kết nối tới chân PTB18, do đó nháy với tốc độ nhanh gấp đôi LED màu xanh ở chân PTB19. Việc kết nối thêm các LED này tới bo mạch FRDM-KL46Z được thực hiện như được chỉ ra trong Hình 5‑13.

Chương trình 81: Giám sát giá trị của thanh ghi STCURRENTon LEDs
/* p8_1.c Đảo trạng thái của các LED ba màu bằng bộ định thời SysTick
Chương trình này cho phép bộ đếm SysTick chạy tự do và liên tục kết xuất các giá trị của bộ đếm vào các LED ba màu.
Giá trị của bộ đếm được dịch sang phải 4 vị trí sao cho sự thay đổi của các LED đủ chậm để có thể quan sát được.
Bộ đếm SysTick có 24 bit.
red LED được kết nối tới chân PTB18.
green LED được kết nối tới chân PTB19.
*/
#include <MKL46Z4.H>
int main (void) {
int c;
SIM->SCGC5 |= 0x400; /* cho phép cấp xung nhịp tới chân cổng B */
PORTB->PCR[18] = 0x100; /* thiết lập chân PTB18 làm GPIO */
PORTB->PCR[19] = 0x100; /* thiết lập chân PTB19 làm GPIO */
PTB->PDDR |= 0xC0000; /* thiết lập PTB18, 19 làm lối ra */
/* Cấu hình SysTick */
SysTick->LOAD = 0xFFFFFF; /* đặt thanh ghi nạp lại với giá trị cực đại */
SysTick->CTRL = 5; /* cho phép bộ đếm, không ngắt, sử dụng xung nhịp hệ thống */
while (1) {
c = SysTick->VAL; /* Đọc giá trị hiện tại của bộ đếm */
PTB->PDOR = c >> 4; /* kết nối các bit MSB của bộ đếm với các LED */
}
}

 

Các ví dụ sau chỉ ra một số ứng dụng của bộ đinh thời Systick.

Ví dụ 81
Xét một vi điều khiển ARM có xung nhịp hệ thống là 8 MHz. Tính thời gian trễ được tạo bởi hàm sau:

void delay() {
SysTick->LOAD = 9;
SysTick->CTRL = 5; /*Cho phép bộ định thời và chọn xung nhịp hệ thống làm nguồn xung nhịp */
while((SysTick->CTRL &0x10000) == 0) /*Đợi đến khi Count flag được đặt */
{ }
SysTick->CTRL = 0; /*Dừng bộ định thời (Enable = 0) */
}
Đáp án:

Vì timer được khởi tạo với giá trị 9 (trong dòng 2), nên nó sẽ trải qua 10 trạng thái như sau:

Vì xung nhịp hệ thống được dùng làm nguồn cấp xung nhịp cho bộ đếm nên mỗi xung kéo dài một khoảng thời gian bằng:

Vì vậy chương trình sẽ tạo ra một khoảng thời gian trễ bằng 10×0,125µs = 1,25 µs.

Lưu ý: lệnh gọi hàm và quá trình thực hiện lệnh cũng tiêu tốn một vài chu kỳ xung nhịp. Nếu chúng ta muốn tính toán lượng thời gian trễ chính xác, chúng ta phải bao gồm cả khoảng thời gian phụ trội này. Tuy nhiên, trong cuốn sách này, chúng ta không xem xét nó vì phần lớn trường hợp thời gian đó là không đáng kể.

Ví dụ 82

Xét một vi điều khiển ARM có xung nhịp hệ thống được chọn làm nguồn cấp xung nhịp cho bộ định thời gian Systick. Tính thời gian trễ được tạo bởi bộ định thời nếu thanh ghi STRELOAD được nạp giá trị N.

Đáp án:

Vì timer được khởi tạo với giá trị N, nên nó sẽ trải qua N+1 trạng thái.

Vì xung nhịp hệ thống được dùng làm nguồn cấp xung nhịp cho bộ đếm nên mỗi xung kéo dài một khoảng thời gian bằng 1/sysclk .

Vì vậy chương trình sẽ tạo ra một khoảng thời gian trễ bằng (N+1)/sysclk.

Ví dụ 83

Viết một hàm điều khiển bộ định thời Systick tạo ra một khoảng thời gian trễ 1ms. Giả thiết rằng tần số xung nhịp hệ thống là sysclk = 41,94MHz.

Đáp án:

Từ phương trình được rút ra trong Ví dụ 8‑2, ta có thời gian trễ được tính như sau:

Delay = (N+1)/sysclk

Suy ra:

N + 1 = Delay × sysclk = 0.001(s) × 41,94MHz = 41.940

Do đó:           N = 41.939

Hàm tạo ra trễ 1 ms như sau:

void delay1ms(void) {
SysTick->LOAD = 41939;
SysTick->CTRL = 0x5; /* Cho phép timer và chọn sysclk làm nguồn xung nhịp */
while((SysTick->CTRL & 0x10000) == 0) /* đợi đến khi cờ COUNT được đặt */
{ }
SysTick->CTRL = 0; /* Dừng timer (Enable = 0) */
}

 

 

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.

Trả lời