Nếu CPU yêu cầu module thực hiện một công việc nào đó. Để biết rằng công việc đó đã được thực hiện xong chưa, CPU có thể liên tục đọc một bit flag (cờ) trên một SFR nào đó (module sẽ set bit này lên 1 nếu công việc hoàn thành).
Tuy nhiên, cách này có một số vấn đề sau:
1. Định nghĩa ngắt
Ngắt là cơ chế giúp CPU phát hiện event từ module để thực hiện chương trình đáp ứng ISR (Interrupt Service Routine) của event đó.
Từ hình trên ta có thể thấy rằng, trong khi chương trình của chúng ta đang chạy, nếu có interrupt xảy ra thì CPU sẽ chuyển qua thực hiện chương trình ISR, sau khi thực hiện ISR xong, CPU sẽ quay lại thực hiện tiếp chương trình chính từ chỗ mà CPU đã bỏ đi.
2. Phân loại ngắt
Tùy theo tiêu chí, ta có thể phân loại ngắt như sau:
3. Nguyên lý của ngắt
Nói một cách đơn giản, các ngắt đều được định nghĩa trước (không phải ta muốn ngắt nào là có ngắt đó). Khi xảy ra cho một sự kiện ngắt, CPU sẽ nhảy đến một vị trí xác định trong vùng nhớ để chạy chương trình ở đó.
Điều ta cần làm là cấu hình có cho phép ngắt nếu sự kiện xảy ra hay không và ghi chương tình ngắt của chúng ta vào vị trí xác định trong bộ nhớ chương trình.
Hình trên là Interrupt Vector Table của STM8. Khi xảy ra loại ngắt nào, nếu ngắt đó được enable thì CPU sẽ nhảy đến vị trí tương ứng trong bảng để thực hiện chương trình ở đó.
Ví dụ: Ở module UART1, nếu ta cho phép ngắt TX complete thì khi module UART1 gửi xong dữ liệu trong TX buffer, module UART sẽ bật cờ TX complete trong một ISR nào đó lên 1 đồng thời đưa tín hiệu đến CPU, CPU sẽ nhảy đến địa chỉ 0x00804C để thực hiện chương trình ở đó.
Trước khi chạy hàm main, chương trình của chúng ta tự động sẽ ghi vào Interrupt Vector Table địa chỉ của các hàm phục vụ ngắt (ISR - Interrupt Service Routine). Nhờ đó, các chương trình phục vụ ngắt có thể được đặt ở các vị trí phân tán trong bộ nhớ chương trình. Đây cũng là lý do tại sao người ta gọi vùng nhớ này là Interrupt Vector Table: bảng chứa các con trỏ hàm trỏ tới các vị trí của các chương trình ngắt.
4. Độ ưu tiên ngắt (Interrupt priority)
Khi sử dụng ngắt nảy sinh ra các vấn đề sau:
Ba mức ưu tiên đặc biệt đó là:
Trong khi chương trình chính Main đang chạy thì RQ_B (Request B) xảy ra. CPU sẽ lưu lại context (context store), context ở đây có thể là địa chỉ của câu lệnh tiếp theo trong hàm Main mà CPU phải chạy khi thực hiện xong ISR, là giá trị các thanh ghi riêng của CPU. Sau đó, CPU chạy IRQ_B, trong khi chạy IRQ_B thì có RQ_A xảy ra. Vì priority của RQ_A cao hơn priority của RQ_B (thấp hơn về giá trị) nên CPU sẽ lưu lại context của IRQ_B và chuyển qua chay IRQ_A. Sau khi chạy IRQ_A xong thì CPU sẽ khôi phục lại context (Context restore) của IRQ_B và chạy tiếp IRQ_B. Sau khi chạy IRQ_B xong thì CPU sẽ khôi phục lại context của Main và tiếp tục chạy Main.
Lưu ý:
5. Ngắt trong STM32F103C8T6
Trong các VĐK 8-bit, 16-bit, việc quản lý ngắt cho từng module được thực hiện thông qua các SFR của module đó.
Tuy nhiên, khi số lượng ngắt tăng lên (trong VĐK 32-bit) việc quản lý ngắt được thực hiện bởi một module riêng là NVIC (Nested Vector Interrupt Controller).
Trong hình trên, ta đã cấu tình 5 tín hiệu ngắt với các độ ưu tiên khác nhau. Trong đó có 2 ngắt trong (từ UART1, Timer1) và 3 ngắt ngoài.
Tuy nhiên, cách này có một số vấn đề sau:
- Nếu CPU còn việc khác để làm thì câu hỏi đặt ra sẽ là khi nào ta nên đọc bit flag đó.
- Nếu đọc quá nhiều thì sẽ ảnh hưởng đến năng suất công việc hiện tại (đang làm việc này mà cứ phải để ý việc khác).
- Nếu đọc quá chậm thì lại chậm đáp ứng nhu cầu của module, ảnh hưởng đến việc lấy kết quả của công việc. Một ví dụ cụ thể là nếu ta dùng module UART để giao tiếp với các module bên ngoài VĐK. Khi module UART nhận được dữ liệu, nó sẽ ghi dữ liệu đó vào một thành ghi buffer (cũng là một SFR) và bật cờ nhận. Nếu CPU không đọc cờ nhận kịp thời và lấy dữ liệu đó ra xử lý thì khi dữ liệu tiếp theo đến. Module UART sẽ ghi đè vào thanh ghi buffer khiến dữ liệu cũ bị mất. Điều này ảnh hưởng đến quá trình giao tiếp.
- Một trường hợp ít xảy ra hơn là, nếu CPU không còn việc gì để làm. Chỉ ngồi đọc cái cờ và chờ cho đến khi nó bật để làm việc gì đó thì việc chờ này gây lãng phí năng lượng. CPU nên đi vào chế độ tiết kiệm năng lượng và chỉ chạy lại khi có kết quả từ module.
1. Định nghĩa ngắt
Ngắt là cơ chế giúp CPU phát hiện event từ module để thực hiện chương trình đáp ứng ISR (Interrupt Service Routine) của event đó.
2. Phân loại ngắt
Tùy theo tiêu chí, ta có thể phân loại ngắt như sau:
- Dựa theo khả năng điều khiển
- Reset: được tạo ra bằng cách kích reset bằng phần mềm hoặc bằng phần cứng (nhấn nút Reset), đây là interrupt có độ ưu tiền cao nhất. CPU chắc chắn sẽ reset khi có ngắt này xảy ra.
- Non-maskable interrupt (NMI): là loại hardware interrupt không có bit để disable nó đi, CPU bắt buộc phải thực hiện ngắt này và gần như phải thực hiện với độ ưu tiên cao nhất. Ngắt này có thể đến từ SRAM parity error, flash double ECC error hoặc là clock failure. Các lỗi này xảy ra không phải do lỗi của chương trình viết sai mà có thể do điều kiện môi trường khiến cho VĐK chạy sai và VĐK có thể phát hiện ra điều đó.
- Hard Fault: Ta cũng không thể có disable ngắt này được. Ngắt này xảy ra do phần mềm làm những điều không được phép làm. Ví dụ như ghi hoặc đọc một ô nhớ không tồn tại trong phần cứng.
- Maskable interrupt: là loại hardware interrupt có bit điều khiển enable-disable. Nếu enable, CPU bắt buộc phải thực hiện ISR của interrupt này nhưng với độ ưu tiên có thể cấu hình được.
- Dựa theo nguồn gốc của ngắt
- Internal Interrupt: Ngắt trong được tạo ra bởi các module bên trong VĐK
- External Interrupt: Được tạo ra từ bên ngoài, đưa vào VĐK thông qua các chân của VĐK
- Dựa theo cách gọi ngắt
- Hardware interrupt: Là loại ngắt được tạo ra bởi phần cứng. Muốn bật tắt loại ngắt này nhất định phải thay đổi giá trị của biến điều khiển ngắt.
- Sofware interrupt: Là loại ngắt được tạo ra bởi phần mềm. Bắt buộc phải có nguồn gốc từ hardware interrupt. Ví dụ: ta có sự kiện ngắt phần mềm: nếu nhận được chữ a từ module UART thì sẽ gửi lại chữ a qua module này, các chữ khác bỏ qua. Sự kiện này bắt nguồn từ sự kiện phần cứng: nhận được ký tự, nhưng việc có gọi đến service để truyền lại không lại do CPU (phần mềm) quyết định.
3. Nguyên lý của ngắt
Nói một cách đơn giản, các ngắt đều được định nghĩa trước (không phải ta muốn ngắt nào là có ngắt đó). Khi xảy ra cho một sự kiện ngắt, CPU sẽ nhảy đến một vị trí xác định trong vùng nhớ để chạy chương trình ở đó.
Điều ta cần làm là cấu hình có cho phép ngắt nếu sự kiện xảy ra hay không và ghi chương tình ngắt của chúng ta vào vị trí xác định trong bộ nhớ chương trình.
Ví dụ: Ở module UART1, nếu ta cho phép ngắt TX complete thì khi module UART1 gửi xong dữ liệu trong TX buffer, module UART sẽ bật cờ TX complete trong một ISR nào đó lên 1 đồng thời đưa tín hiệu đến CPU, CPU sẽ nhảy đến địa chỉ 0x00804C để thực hiện chương trình ở đó.
Trước khi chạy hàm main, chương trình của chúng ta tự động sẽ ghi vào Interrupt Vector Table địa chỉ của các hàm phục vụ ngắt (ISR - Interrupt Service Routine). Nhờ đó, các chương trình phục vụ ngắt có thể được đặt ở các vị trí phân tán trong bộ nhớ chương trình. Đây cũng là lý do tại sao người ta gọi vùng nhớ này là Interrupt Vector Table: bảng chứa các con trỏ hàm trỏ tới các vị trí của các chương trình ngắt.
4. Độ ưu tiên ngắt (Interrupt priority)
Khi sử dụng ngắt nảy sinh ra các vấn đề sau:
- Có 2 hay nhiều ngắt cùng xảy ra một lúc
- Một ngắt đang được thực hiện thì có ngắt khác xảy ra.
Trong đa số VĐK STM32 sẽ có 16 mức ưu tiên 0->16 và 3 mức ưu tiên đặc biệt, giá trị ưu tiên càng nhỏ thì độ ưu tiên càng lớn.Ba mức ưu tiên đặc biệt đó là:
Interrupt | Priority |
---|---|
Reset | -3 |
Non-Maskable Interrupt (NMI) | -2 |
Hard Fault | -1 |
Lưu ý:
Khi nói priority cao thì mặc định hiểu là số biểu thị priority đó nhỏ.
Khi nói priority thấp thì mặc định hiểu là số biểu thị priority đó lớn.
5. Ngắt trong STM32F103C8T6
Trong các VĐK 8-bit, 16-bit, việc quản lý ngắt cho từng module được thực hiện thông qua các SFR của module đó.
Tuy nhiên, khi số lượng ngắt tăng lên (trong VĐK 32-bit) việc quản lý ngắt được thực hiện bởi một module riêng là NVIC (Nested Vector Interrupt Controller).
Trong hình trên, ta đã cấu tình 5 tín hiệu ngắt với các độ ưu tiên khác nhau. Trong đó có 2 ngắt trong (từ UART1, Timer1) và 3 ngắt ngoài.
Configured Interrupt | Priotity |
---|---|
USART1 global interrupt | 0 |
TIM1 update interrupt | 1 |
EXTI line0 interrupt | 2 |
EXTI line1 interrupt | 3 |
EXTI line2 interrupt | 4 |
Last edited: