Lập trình STM32F103 thanh ghi – Cấu hình SysTick Timer STM32F103RCT6

Trong quá trình lập trình STM32F103 thanh ghi, việc tạo delay chính xác và đo thời gian ổn định là yêu cầu nền tảng cho hầu hết các ứng dụng nhúng. Thay vì sử dụng delay vòng lặp không chính xác, SysTick timer – bộ định thời tích hợp trong lõi ARM Cortex-M3 – cung cấp cơ chế tạo ngắt định kỳ với độ chính xác cao, phù hợp cho các hệ thống real-time.

Trong bài viết này, chúng ta sẽ cấu hình SysTick timer STM32F103RCT6 ở mức thanh ghi, tạo ngắt mỗi 1ms, xây dựng hàm delay chính xác và ứng dụng thực tế để điều khiển LED bật/tắt mỗi 15 giây. Đồng thời, bài viết cũng giải thích chi tiết vai trò của từ khóa volatile, nguyên lý hoạt động của SysTick và kiểm chứng độ chính xác của timer trong thời gian dài, giúp bạn nắm vững nền tảng quan trọng khi lập trình STM32 bare-metal.

Mục tiêu bài viết Lập trình STM32F103 thanh ghi: Cấu hình Systick Timer STM32F103RCT6

Trong bài viết này, chúng ta sẽ thực hiện lập trình STM32F103 thanh ghi để:

  • Cấu hình SysTick timer tạo ngắt chính xác 1ms
  • Sử dụng SysTick để tạo delay chính xác
  • Điều khiển LED tại chân PA8 bật/tắt mỗi 15 giây
  • Kiểm tra độ chính xác của SysTick timer STM32F103 trong thời gian dài (2 phút)

Bài viết sử dụng STM32F103RCT6, lập trình bare-metal, không dùng HAL, phù hợp cho người học lập trình thanh ghi STM32F103.

Define Struct thanh ghi SysTick control and status register (STK_CTRL) cho lập trình STM32F103 thanh ghi: Cấu hình Systick Timer STM32F103RCT6

Dựa trên PM0056, Section 4.5 (trang 151-152): https://www.st.com/resource/en/programming_manual/pm0056-stm32f10xxx20xxx21xxxl1xxxx-cortexm3-programming-manual-stmicroelectronics.pdf

Thanh ghi SysTick control (SysTick_CTRL)

Thanh ghi SysTick control and status register (SysTick_CTRL) - Lập trình STM32F103 Thanh ghi bài cấu hình Systick Timer STM32f103RCT6
SysTick control and status register (SysTick_CTRL)

SysTick register map

SysTick register map - Hướng dẫn cấu hình systick timer STM32F103
SysTick register map

#define SYSTICK ((SysTick_TypeDef *)0xE000E010UL)

Giải thích về các thanh ghi trong SysTick control

  • CTRL: Điều khiển timer và ngắt (Section 4.5.1, trang 151). ENABLE khởi động timer, TICKINT bật ngắt khi về 0, CLKSOURCE chọn clock xử lý hoặc clock chia.
  • LOAD: Giá trị nạp lại cho tick (Section 4.5.2, trang 152).
  • VAL: Chứa giá trị hiện tại của bộ đếm SysTick, đếm ngược từ giá trị được nạp trong thanh ghi LOAD (Reload Value Register) về 0.  (Section 4.5.3, trang 153).
  • CALIB: Cung cấp thông tin hiệu chuẩn cho SysTick, giúp xác định tần số clock hoặc các thông số khác để đảm bảo độ chính xác thời gian. Tuy nhiên, trên STM32F103RCT6, giá trị này thường không được sử dụng hoặc mặc định là 0. (Section 4.5.4, trang 153).

Cấu hình SysTick Timer STM32F103

Thông số cấu hình SysTick Timer 1ms

  • SYSCLK = 72 MHz
  • Chu kỳ mong muốn: 1 ms
  • LOAD = 71999
    (72 MHz / 1000 = 72.000 → LOAD = 72000 − 1)

Cấu hình SysTick theo tài liệu PM0056

Theo PM0056 – STM32F10xxx Reference Manual, Section 4.5.1 (trang 151):

  • CLKSOURCE = 1 → SysTick sử dụng AHB clock
  • TICKINT = 1 → Cho phép ngắt SysTick
  • ENABLE = 1 → Bật SysTick timer

Tại sao cần dùng từ khóa volatile?

Trong C, từ khóa volatile được dùng để thông báo cho trình biên dịch rằng giá trị của biến có thể thay đổi bất ngờ, ngoài luồng thực thi thông thường.

Ngăn tối ưu hóa không mong muốn

Trình biên dịch có thể:

  • Lưu biến vào register
  • Bỏ qua việc đọc lại bộ nhớ nếu nghĩ rằng biến không đổi

Khi khai báo volatile, trình biên dịch (compiler) sẽ không giả định giá trị của biếncố định và sẽ luôn đọc/ghi trực tiếp vào bộ nhớ. Điều này đảm bảo rằng mọi thay đổi đối với biến được phản ánh chính xác.

Các trường hợp cần dùng volatile

  • Biến bị thay đổi bởi phần cứng: Ví dụ, một thanh ghi phần cứng (như GPIOC->IDR) có thể thay đổi do sự kiện bên ngoài (như nhấn nút).
  • Biến dùng trong ngắt (interrupt): Một biến như msTicks, được tăng trong hàm xử lý ngắt (SysTick_Handler), có thể thay đổi bất kỳ lúc nào, ngay cả khi mã chính (main) không trực tiếp sửa đổi nó.
  • Biến dùng trong đa luồng (multithreading): Trong các hệ thống đa luồng, một biến có thể được thay đổi bởi luồng khác.

Vì sao msTicks cần volatile?

  • msTicks được tăng trong ngắt SysTick_Handler (xử lý ngắt SysTick, được gọi mỗi 1ms)
  • main()Delay_ms() đọc giá trị msTicks
  • Nếu không có volatile, compiler có thể không đọc lại msTicks từ RAM.
  • Ví dụ, nó có thể lưu giá trị msTicks vào một thanh ghi và không đọc lại từ bộ nhớ, dẫn đến việc bỏ qua các cập nhật từ ngắt.
  • Điều này làm delay sai thời gian

➡️ Khai báo volatile đảm bảo msTicks luôn phản ánh đúng giá trị thực tế

Code cấu hình SysTick timer 1ms STM32F103

➡️ SysTick interrupt mỗi 1ms → msTicks tăng chính xác → delay ổn định

Giá trị 71999 được sử dụng trong SYSTICK->LOAD để cấu hình SysTick timer tạo ra ngắt mỗi 1ms khi hệ thống chạy ở tần số 72MHz.

Link Github: Download chương trình cấu hình Systick timer 1ms STM32F103

Chương trình main điều khiển LED PA8 bật/tắt mỗi 15 giây

Chương trình sử dụng systick timer 1ms để delay thời gian bât/tắt LED (PA8) mỗi 15 giây.

Link Github: Download chương trình cấu hình Systick timer 1ms STM32F103

Nguyên lý hoạt động của SysTick Timer

  • SysTick là một bộ đếm giảm (down-counter) 24-bit trong lõi ARM Cortex-M3.
  • SysTick đếm ngược từ giá trị được đặt trong thanh ghi LOAD (Reload Value Register) về 0, sau đó tạo ngắt (nếu được kích hoạt) và nạp lại giá trị từ LOAD để tiếp tục đếm.
  • Tần số ngắt phụ thuộc vào:
    • Tần số clock của SysTick (được chọn bởi CLKSOURCE).
    • Giá trị trong thanh ghi LOAD.

Công thức tính chu kỳ ngắt SysTick

Tinterrupt = (LOAD+1) / Clock Frequency

Trong đó:

  • Tinterrupt : thời gian giữa 2 ngắt (giây)
  • LOAD: Giá trị trong SYSTICK->LOAD.
  • Clock Frequency: tần số clock SysTick (Hz)

Tần số clock của SysTick

  • Khi CLKSOURCE = 1, SysTick sử dụng tần số AHB clock (HCLK), không chia tần (PM0056, Section 4.5.1, page 151).
  • Trong cấu hình ở trên, tần số clock của SysTick là 72MHz (72,000,000 Hz):
    • Hệ thống sử dụng HSE 8MHz với PLL x9, dẫn đến SYSCLK = 72MHz.
    • AHB prescaler (HPRE = 0) không chia tần, do đó HCLK = SYSCLK = 72MHz.

Tính toán LOAD cho SysTick 1ms

  • Clock SysTick = 72 MHz
  • Chu kỳ mong muốn = 1 ms = 0.001 s
  • Để tạo ngắt mỗi 1ms (0.001 giây), ta cần tính số chu kỳ clock cần thiết:

Number of clock cycles = TInterrupt x Clock Frequency

Thay số:

Number of clock cycles = 0.001s x 72000000 Hz = 72000

  • Theo công thức SysTick, số chu kỳ clock bằng LOAD + 1 (vì đếm từ LOAD về 0, tổng cộng LOAD + 1 chu kỳ):

       LOAD + 1 = 72000 ==> LOAD = 72000 - 1 = 71999 

  • Do đó, đặt SYSTICK->LOAD = 71999 sẽ tạo ra ngắt mỗi 1ms khi tần số clock là 72MHz.

Tham chiếu: PM0056, Section 4.5 (trang 150 – 154).

➡️ Đặt SYSTICK->LOAD = 71999 là chính xác

Chương trình kiểm tra độ chính xác SysTick Timer (2 phút)

Link Github: Download chương trình cấu hình Systick timer 1ms STM32F103

Kết quả kiểm tra thực tế

Chương trình reset checkSysTickTimer1s bằng 0 và cập nhật giá trị timeStart mỗi khi nút nhấn (PC1) được nhấn.

Kiểm tra bằng cách so sánh thời gian hệ thống windows hoặc thời gian bấm giờ tại thời điểm nút nhấn được nhấn. Cách này chỉ kiểm tra tương đối thời gian systick.

Thời gian hệ thống tại lúc nhấn nút nhấn.

Cấu hình SysTick Timer 1ms STM32F103RCT6 trong Lập trình STM32F103 thanh ghi: Cấu hình SysTick Timer STM32F103RCT6
Kiếm tra SysTick Timer 1ms – Thời điểm bắt đầu kiểm tra

Thời gian hệ thống và thời gian systick timer đếm tại thời điểm 60 giây.

Hướng dẫn cấu hình SysTick Timer STM32F103RCT6 trong bài lập trình STM32F103 thanh ghi cấu hình Systick timer STM32F103RCT6
Kiểm tra Systick timer 1ms STM32F103RCT6 – Thời điểm hệ thống sau 1 phút đếm

Thời gian systick timer đếm mỗi  giây sau 2 phút là 120 và thời gian hệ thống windows là 4:42:00 – 4:40:00, đúng 2 phút. Như vậy thời gian systick đếm gần chính xác.

➡️ Cấu hình SysTick timer STM32F103 đếm thời gian gần như chính xác tuyệt đối

Kết luận

  • SysTick timer là giải pháp chuẩn để tạo delay chính xác trong lập trình STM32F103 thanh ghi
  • Việc sử dụng volatilebắt buộc khi làm việc với ngắt
  • SysTick phù hợp cho:
    • Delay không blocking
    • Scheduler đơn giản
    • Đo thời gian chính xác

👉 Đây là nền tảng quan trọng cho các bài tiếp theo như:

  • FSM
  • Debounce nút nhấn
  • Non-blocking delay
  • RTOS cơ bản

Viết một bình luận

This site uses Akismet to reduce spam. Learn how your comment data is processed.