
Hãy tưởng tượng bạn có 20 nút nhấn kết nối với vi điều khiển, và nhiệm vụ của bạn là kiểm tra xem có nút nào được nhấn hay không.
Cách làm với polling:
- Bạn viết một đoạn chương trình chạy vòng lặp để kiểm tra từng nút một:
- Nút 1: “Có bị nhấn không?”
- Nút 2: “Có bị nhấn không?”
- … (lặp lại đến nút 20)
- Khi kiểm tra xong nút 20, chương trình lại quay lại kiểm tra nút 1, rồi tiếp tục như vậy mãi.
Nhược điểm của polling:
Tình huống:
Giả sử chương trình vừa bắt đầu kiểm tra nút số 1, và nút số 20 được nhấn ngay lúc đó.
- Chậm phản hồi:
- Chương trình phải hoàn tất kiểm tra toàn bộ các nút từ 1 đến 20 trước khi quay lại nút 20. Điều này khiến hệ thống phản ứng chậm hơn so với thời điểm thực tế nút 20 được nhấn.
- Bỏ sót sự kiện:
- Nếu người dùng chỉ nhấn nút 20 trong một thời gian rất ngắn (ví dụ: nhanh hơn thời gian chương trình kiểm tra hết 19 nút còn lại), chương trình có thể bỏ lỡ sự kiện này.
- Tốn tài nguyên:
- Dù không có nút nào được nhấn, chương trình vẫn phải kiểm tra tất cả 20 nút, gây lãng phí thời gian xử lý.
- Khó mở rộng:
- Nếu số lượng nút tăng lên (ví dụ: 50 hoặc 100 nút), thời gian kiểm tra mỗi vòng lặp sẽ càng kéo dài, làm hệ thống kém hiệu quả hơn.
Do đó ta sử dụng cơ chế ngắt.
Xem thêm: Hệ thống nhúng là gì?
Giới thiệu về ngắt
Ngắt (Interrupt) là một cơ chế cho phép bộ xử lý tạm dừng công việc hiện tại để thực hiện một nhiệm vụ quan trọng khác, sau đó quay lại hoàn thành công việc bị dừng.
Nó giúp hệ thống phản ứng nhanh chóng với các sự kiện mà không cần phải liên tục kiểm tra (polling) trạng thái của thiết bị ngoại vi.
Ngắt hoạt động như thế nào?

- Sự kiện xảy ra: Tín hiệu từ phần cứng hoặc phần mềm (Nút nhấn được nhấn) gửi đến bộ xử lý.
- Dừng công việc hiện tại: Bộ xử lý tạm dừng công việc đang làm và lưu trạng thái công việc đó để sau này tiếp tục.
- Thực hiện ISR: Bộ xử lý chuyển sang thực thi một đoạn mã đặc biệt gọi là Interrupt Service Routine (ISR), ISR là nơi sự kiện được xử lý (Thông báo nút nhấn đã được nhấn).
- Quay lại công việc: Sau khi ISR hoàn thành, bộ xử lý khôi phục trạng thái trước đó và tiếp tục công việc bị gián đoạn.
Do đó, ngắt giống như một cuộc gọi khẩn cấp. Bộ xử lý sẽ tạm dừng công việc hiện tại để nghe điện thoại (ISR) và sau khi xử lý xong thì nó sẽ tiếp tục công việc bị gián đoạn.
Interrupt Service Routines
Một Interrupt Service Routine (ISR), hay còn gọi là Interrupt Handler, là một đoạn mã đặc biệt (hàm) mà phần cứng sẽ tự động gọi khi có một ngắt xảy ra. Khi được kích hoạt, vi xử lý sẽ tạm dừng công việc hiện tại và chuyển ngay đến ISR để xử lý sự kiện liên quan đến ngắt đó.
Và để bộ xử lý biết được đoạn mã này đang nằm ở đâu, thì cần phải có địa chỉ cho mỗi ISR, do đó ta sử dụng Interrupt Vector Table để tra cứu địa chỉ.
Interrupt Vector Table

Khi bộ xử lý ARM Cortex-M3 gặp phải ngắt, nó cần một cách để tìm và thực thi đoạn mã xử lý ngắt (ISR) tương ứng. Cách mà vi xử lý tìm thấy ISR là thông qua Interrupt Vector Table.
Mỗi ngắt có một Interrupt Number (Position) tương ứng một address bộ nhớ riêng biệt trong theo hình 3.
Vậy Interrupt Number để làm gì? hãy cùng tìm hiểu phần Enable and Disable Peripheral Interrupts của bài đọc nhé!
Điều gì xảy ra khi thực hiện một ngắt?
Khi vi điều khiển Cortex-M3 xử lý một ngắt, nó thực hiện hai bước quan trọng để lưu trữ và khôi phục trạng thái của chương trình hiện tại trước khi và sau khi ngắt xong: stacking và unstacking.

1. Interrupt stacking
- Trước khi vào xử lý ngắt, vi điều khiển cần “lưu lại” trạng thái hiện tại của chương trình (các giá trị trong các thanh ghi quan trọng) để khi hoàn tất, nó có thể quay lại công việc ban đầu.
- Vi điều khiển sẽ tự động đẩy (push) các giá trị của 8 thanh ghi quan trọng vào stack (bộ nhớ tạm). Các thanh ghi này bao gồm:
- r0, r1, r2, r3 (bốn thanh ghi dữ liệu)
- r12 (một thanh ghi tạm thời)
- LR (Link Register) – chứa địa chỉ trở lại sau khi thực thi ngắt.
- PSR (Program Status Register) – lưu trữ trạng thái của bộ vi xử lý.
- PC (Program Counter) – lưu trữ địa chỉ lệnh tiếp theo sẽ được thực thi.
2. Interrupt handler
- Xác định ISR: Bộ xử lý tra cứu số thứ tự ngắt trong Interrupt Vector Table và nhảy tới địa chỉ của ISR tương ứng.
- Thực thi ISR: Mã xử lý ngắt (ISR) sẽ được thực thi. ISR này có thể là một đoạn mã được lập trình sẵn trong bộ nhớ.
3. Interrupt unstacking
Sau khi xử lý xong, vi điều khiển cần khôi phục lại trạng thái ban đầu của chương trình để tiếp tục công việc trước khi ngắt xảy ra.
Vi điều khiển sẽ tự động lấy (pop) các giá trị đã được lưu trong stack (8 thanh ghi đã đẩy vào trước đó) và khôi phục lại các thanh ghi: r0, r1, r2, r3, r12, LR, PSR, PC.
Xem thêm: Tổng quan kiến trúc ARM Cortex-M3
Interrupt Priority
Ưu tiên ngắt (Interrupt Priority) là một cơ chế quan trọng trong hệ thống vi xử lý để xác định thứ tự mà các sự kiện ngắt sẽ được xử lý. Mỗi sự kiện có một giá trị ưu tiên, và sự kiện có mức độ ưu tiên cao hơn sẽ được thực thi trước.
Giá trị 0 có mức ưu tiên cao nhất, và các giá trị tăng dần có mức ưu tiên thấp hơn. Ví dụ, sự kiện với giá trị ưu tiên 0 có độ ưu tiên cao nhất, trong khi sự kiện với giá trị ưu tiên 15 (trong hệ thống hỗ trợ 16 mức ưu tiên) có độ ưu tiên thấp nhất.
Hai cơ chế đa nhiệm với ngắt
1. Preemptive (Ưu tiên cao)
Nếu xuất hiện một sự kiện mới quan trọng hơn sự kiện hiện tại, thì có thể tạm dừng sự kiện hiện tại mà không cần sự cho phép để xử lý sự kiện mới (Xử lý ngắt phụ thuộc vào Priority).
2. Non-preemptive (Không ưu tiên)
Sự kiện mới phải chờ sự kiện hiện tại hoàn thành, hoặc sự kiện hiện tại tự nguyện nhường quyền xử lý (Xử lý ngắt không phụ thuộc vào Priority).
External Interrupt

Ngắt ngoại vi (External Interrupt) là các ngắt do các thiết bị ngoại vi hoặc các thiết bị bên ngoài vi xử lý tạo ra, ví dụ như nút bấm hoặc bàn phím. Chúng rất hữu ích vì giúp vi điều khiển (microcontroller) theo dõi tín hiệu từ bên ngoài và phản hồi nhanh chóng với các sự kiện xảy.
Cách hoạt động của ngắt ngoại vi:
- Các sự kiện ngoại vi trong microcontroller: vi điềuk hiển hỗ trợ 16 kênh ngoại vi, từ EXTI0 đến EXTI15. Mỗi kênh này được liên kết với một chân GPIO (General Purpose Input/Output) cụ thể. Tuy nhiên, vì microcontroller có nhiều hơn 16 chân GPIO, cần một cơ chế để ánh xạ các chân GPIO với các kênh ngoại vi.
- Ánh xạ chân GPIO với kênh ngoại vi: Các chân GPIO với cùng số chân sẽ được ánh xạ vào cùng một kênh ngoại vi. Ví dụ, chân PA0, PB0, PC0… có thể được ánh xạ vào EXTI0, chân PA1, PB1, PC1… vào EXTI1, và cứ thế cho đến EXTI15. Điều này có nghĩa là, nếu chân PA3 được cấu hình để kích hoạt EXTI3, các chân PB3, PC3, PD3, hoặc PE3 không thể được sử dụng cho EXTI3 nữa.
- EXTI sẽ gửi tín hiệu đến NVIC để xử lý.
Enable và Disable Peripheral Interrupts

NVIC có 8 thanh ghi 32 bit Interrupt Set-Enable, ISER0 – ISER7, đây là những thanh ghi dùng để bật hoặc tắt ngắt.
ISER Register: Mỗi bit trong một thanh ghi ISER (Interrupt Set Enable Register) có thể bật một ngắt ngoại vi (peripheral interrupt).
Để chọn vị trí của một ISER trong số 8 ISER:

Sau đó, để chọn vị trí bit trong một ISER:
IRQ_number mod 32.
Xem thêm: Xung Clock: Nhịp tim của Hệ thống nhúng
Software Interrupt
Ngắt phần mềm (Software Interrupt) là một loại ngắt không phải do phần cứng gây ra mà do phần mềm tạo ra. Phần mềm có thể tạo ra ngắt bằng cách thay đổi các thanh ghi ngắt (pending registers) hoặc sử dụng các lệnh đặc biệt. Các ngắt phần mềm có hai mục đích chính: xử lý ngoại lệ và truy cập phần cứng có quyền hạn.
1. Xử lý ngoại lệ (Exception Handling)
Khi có điều kiện bất thường xảy ra trong quá trình thực thi chương trình (ví dụ: chia cho 0, lệnh không hợp lệ, truy cập bộ nhớ sai), vi xử lý cần phải xử lý các tình huống này để khắc phục lỗi phần mềm.
2. Truy cập phần cứng có quyền hạn (Privileged Hardware Access)
Trong vi xử lý, có hai chế độ: chế độ người dùng (unprivileged mode) và chế độ có quyền hạn (privileged mode). Một số tài nguyên phần cứng chỉ có thể truy cập khi vi xử lý ở chế độ có quyền hạn.
Khi đang ở chế độ người dùng (unprivileged mode) cần truy cập những tài nguyên này, ta có thể sử dụng một lệnh đặc biệt gọi là supervisor call (SVC) để tạo ra ngắt phần mềm, yêu cầu vi xử lý chuyển từ chế độ người dùng (unprivileged mode) sang chế độ có quyền hạn (privileged mode).
Các bộ controller ngắt hiện nay
1. Nested Vectored Interrupt Controller (NVIC):
Chức năng chính của NVIC là sau khi nhận tín hiệu từ EXTI, NVIC sẽ quản lý toàn bộ các yêu cầu ngắt, bao gồm việc bật/tắt, thiết lập mức độ ưu tiên và xử lý trạng thái của chúng.
Được sử dụng trong các bộ xử lý ARM Cortex-M (như Cortex-M0, M3, M4, M7).
Các chức năng chính của NVIC:
- Bật và tắt:
- NVIC cho phép bật (enable) hoặc tắt (disable) các ngắt.
- Để bật ngắt, bạn chỉ cần viết một giá trị 1 vào bit bật của ngắt tương ứng.
- Để tắt ngắt, bạn viết một giá trị 1 vào bit tắt của ngắt.
- Cấu hình mức độ ưu tiên của ngắt:
- NVIC cho phép cấu hình hai mức độ ưu tiên cho mỗi ngắt:
- Mức độ ưu tiên (preemption priority): Quyết định ngắt nào có thể ngắt ngắt khác.
- Mức độ phụ (sub-priority): Nếu có nhiều ngắt cùng mức độ ưu tiên chính, mức độ phụ sẽ quyết định thứ tự xử lý giữa chúng.
- NVIC cho phép cấu hình hai mức độ ưu tiên cho mỗi ngắt:
- Cài đặt và xóa trạng thái ngắt:
- Nếu một ngắt nào đó không thể được xử lý ngay lập tức, thì sẽ xuất hiện bit pending (chờ xử lý) cho ngắt đó.
- Bạn có thể xóa trạng thái pending này nếu cần thiết.
- Một khi một ngắt bị tắt nhưng trạng thái pending đã được thiết lập, ngắt đó vẫn sẽ được xử lý trước khi bị tắt.
2. Generic Interrupt Controller (GIC)
GIC (Generic Interrupt Controller) là một thành phần quan trọng trong ARM Cortex-A (vi xử lý hiệu năng cao), chịu trách nhiệm quản lý và phân phối các tín hiệu ngắt (interrupts) từ phần cứng đến các CPU trong một hệ thống đa CPU (multi-core).
Được sử dụng trong các bộ xử lý ARM Cortex-A (như Cortex-A7, A9, A15).
GIC có hai phần chính: Distributor và CPU Interface.
Distributor (Phân phối ngắt):
- Đây là phần chịu trách nhiệm phân phối tín hiệu ngắt từ các thiết bị ngoại vi hoặc phần cứng tới các lõi CPU.
- Distributor có thể quản lý hàng trăm tín hiệu ngắt (tuỳ thuộc vào hệ thống) và quyết định ngắt nào sẽ được gửi đến CPU nào.
- Phân phối tín hiệu ngắt có thể dựa trên mức độ ưu tiên, thông tin cấu hình, và tình trạng của các CPU.
- GIC có thể phân phối ngắt tới một hoặc nhiều lõi CPU (tùy vào cấu hình hệ thống).
CPU Interface (Giao diện CPU):
- CPU Interface chịu trách nhiệm nhận tín hiệu ngắt từ Distributor và chuyển chúng tới CPU.
- GIC có thể sử dụng cơ chế “vectored interrupts”, giúp CPU xác định chính xác ngắt nào đang đến.
- Mỗi CPU có thể có giao diện riêng để nhận và xử lý các ngắt từ Distributor.
Ngắt là một cơ chế quan trọng trong các hệ thống vi xử lý, giúp quản lý hiệu quả các sự kiện và phản hồi kịp thời từ các thiết bị ngoại vi. Tóm lại, hiểu và khai thác tốt cơ chế ngắt là một phần không thể thiếu trong việc thiết kế và phát triển các hệ thống vi xử lý, giúp mang lại hiệu suất cao, độ ổn định và phản ứng nhanh trong việc xử lý các sự kiện ngoài ý muốn.