DMA hoạt động như Master, dùng để điều khiển việc truy cập trực tiếp vào bộ nhớ.
Các Slave gồm:
- Memory: SRAM, DRAM,.... (RAM vật lý)
- Peripheral: UART, ADC,....
DMA có 2 cổng:
- Cổng Slave: Nhận lệnh từ CPU để thiết lập quá trình truyền dữ liệu
- Cổng Master: Chủ động thực hiện truyền dữ liệu trên AHB bus hoặc qua cầu nối AHB/APB
1 DMA Controller có thể có nhiều luồng (stream). Mỗi luồng có thể phục vụ 1 kênh (channel) khác nhau. Mỗi luồng chỉ có thể liên kết với 1 kênh tại 1 thời điểm. Nhiều luồng có thể hoạt động đồng thời, miễn là không xung đột tài nguyên.
Khi Channel được bật, nó sẽ tự động truyền dữ liệu mỗi khi nhận được 1 tín hiệu trigger. Trigger đến từ:
- Hardware trigger: Ngoại vi (ADC, USART, SPI, Timer,...)
- Software trigger: Do chương trình kích hoạt bằng lệnh
Mức độ ưu tiên của các kênh DMA (để phân bổ tài nguyên, theo thứ tự:
- Software Priority: Very High, High, Medium, Low. Có thể cài đặt và thay đổi
- Hardware Priority: Các Channel đã được fix cố định mức ưu tiên (về mặt phần cứng). Nếu nhiều kênh có cùng Software Priority, phần cứng chọn kênh có Hardware Priority cao hơn
2. Hai kiểu truyền dữ liệu của DMA
a. Flow-through DMA
DMA đọc dữ liệu từ nguồn vào 1 thanh ghi tạm trong DMA Controller, sau đó ghi dữ liệu từ thanh ghi này đến đích
Ưu điểm:
- Hỗ trợ thiết bị có kích thước thanh ghi khác nhau (ví dụ đọc 16 bit ADC, ghi 32 bit vào bộ nhớ)
- Có thể thực hiện Memory-to-Memory DMA, vì dữ liệu có thể được đọc và ghi ở 2 thời điểm khác nhau
Nhược điểm:
- Chậm hơn do cần 2 lần truyền bus (đọc -> lưu vào DMA Controller -> ghi)
- Tốn thêm tài nguyên trong DMA Controller (thanh ghi tạm để lưu dữ liệu)
- Tăng tiêu thụ điện năng, vì có thêm bước lưu trung gian
b. Fly-by DMA
Dữ liệu được truyền trực tiếp từ nguồn đến đích trong 1 lần truyền bus
Ưu điểm:
- Nhanh hơn vì chỉ cần 1 lần truyền bus
- Tiết kiệm điện năng vì không cần lưu dữ liệu vào thanh ghi DMA
- Giảm tải cho hệ thống bus, tối ưu băng thông
Nhược điểm:
- Không hỗ tợ Memory-to-Memory DMA, vì bộ nhớ thường không cho phép đọc và ghi cùng lúc
- Chỉ hoạt động với các thiết bị có cùng kích thước thanh ghi (ví dụ: cả nguồn và đích đều là 16 bit)
- Cần phần cứng hỗ trợ, vì DMA phải có khả năng thiết lập kết nối trực tiếp giữa nguồn và đích
3. Các loại truyền dữ liệu mà 1 luồng có thể thực hiện:
a. Truyền dữ liệu thông thường (Regular Transactions):
- Memory -> Peripheral: Khi DMA được bật, nó sẽ tự động tải dữ liệu từ bộ nhớ vào FIFO (Bộ đệm trung gian). Khi ngoại vi yêu cầu dữ liệu, nó sẽ đổ dữ liệu từ FIFO vào ngoại vi. Nếu FIFO sắp hết, nó sẽ nạp thêm dữ liệu từ bộ nhớ vào FIFO. Khi tất cả dữ liệu được truyền xong hoặc ngoại vi báo hiệu kết thúc, DMA dừng truyền
- FIFO Mode: nạp dữ liệu đầy FIFO trước khi bắt đầu truyền
- Direct Mode: truyền từng phần tử dữ liệu ngay khi ngoại vi yêu cầu
- Peripheral -> Memory
- FIFO Mode: Mỗi khi có 1 yêu cầu DMA từ ngoại vi, dữ liệu được lưu vào FIFO. Khi FIFO đầy mới đổ toàn bộ dữ liệu vào bộ nhớ đích. Khi hết dữ liệu cần truyền hoặc ngoại vi báo kết thúc (nếu có flow control), DMA dừng.
- Direct Mode: Mỗi khi ngoại vi gửi dữ liệu đến FIFO, DMA ngay lập tức chuyển dữ liệu đó vào bộ nhớ đích.
- Memory -> Memory (Ví dụ: Sao chép dữ liệu giữa 2 bộ nhớ)
- DMA bắt đầu truyền dữ liệu khi DMA được bật
- FIFO được nạp đầy dữ liệu từ nguồn cho đến khi đạt mức ngưỡng đã cấu hình
- Dữ liệu được xả từ FIFO và ghi vào vùng nhớ đích
- Quá trình tiếp tục đến khi tất cả dữ liệu được truyền xong hoặc phần mềm tắt DMA
b. Truyền dữ liệu với bộ đệm kép (Double-buffer Transactions):
- Dùng 2 bộ đệm nhớ (buffer) luân phiên để giảm thời gian chờ
- Khi DMA đang đọc hoặc ghi dữ liệu vào 1 buffer, CPU có thể làm việc với buffer còn lại mà không bị gián đoạn.
Số lượng dữ liệu có thể truyền
- DMA có thể truyền tối đa 65535 đơn vị dữ liệu trong 1 lần cấu hình
- Mỗi lần truyền -> hoàn thành, giảm giá trị trong thanh ghi đếm dữ liệu
- Số lượng dữ liệu phụ thuộc vào độ rộng của nguồn dữ liệu (ví dụ: 8 bit, 16 bit, 32 bit)
Memory (Bộ nhớ):
- Khi lưu dữ liệu vào mảng 1 cách tuần tự: Cấu hình để sau mỗi lần truyền, địa chỉ bộ nhớ tăng để lấy dữ liệu tiếp theo
- Nếu chỉ cần cập nhật giá trị của 1 biến, thì không cần tự tăng địa chỉ bộ nhớ
Peripheral (Ngoại vi):
- Cấu hình để sau mỗi lần truyền, địa chỉ ngoại vi tăng (dành cho ngoại vi có nhiều thanh ghi như ADC buffer). Ví dụ: cảm biến ADC có nhiều kênh, sau mỗi lần đọc kênh, địa chỉ cần được tăng lên để lấy dữ liệu từ kênh tiếp theo
- UART, SPI, I2C: Chỉ có 1 thanh ghi dữ liệu (DR), nên địa chỉ ngoại vi không cần tăng
1 byte -> địa chỉ tăng 1
2 byte -> địa chỉ tăng 2
4 byte -> địa chỉ tăng 4
DMA Circular Mode
- Khi DMA hoàn tất truyền dữ liệu đến bộ nhớ (buffer đầy), nó sẽ tư động quay lại đầu buffer mà không cần cấu hình lại.
- DMA tiếp tục nhận và ghi dữ liệu mới mà không bị gián đoạn
Double buffer mode
- giúp DMA có thể luân phiên giữ 2 vùng nhớ, cho phép CPU xử lý dữ liệu trong khi DMA tiếp tục truyền dữ liệu, giúp tối ưu hiệu suất và giảm độ trễ
- DMA dùng 2 vùng nhớ
- Sau mỗi lần truyền, DMA sẽ tự động swap con trỏ bộ nhớ
- CPU có thể xử lý dữ liệu ở vùng nhớ chưa được ghi dữ liệu mới, trong khi tiếp tục truyền dữ liệu vào vùng còn lại
- Khi bật chế độ này thì Circular Mode sẽ tự động được bật
Bus Matrix - Điều phối giao tiếp
- Xử lý xung đột khi nhiều module muốn truy cập bus cùng lúc
- Round-robin priority: đảm bảo không có module nào chiếm dụng bus quá lâu
6. Ưu và nhược điểm của DMA
a. Ưu điểm:
- DMA tự động xử lý dữ liệu, trong khi CPU có thể làm việc khác
- Tăng tốc truyền dữ liệu (vì truy cập trực tiếp bộ nhớ)
- Giảm số lần ngắt
b. Nhược điểm:
- DMA có thể chiếm bus (AHB) trong khỏng thời gian ngắn, sẽ làm chậm CPU nếu cả 2 truy cập bộ nhớ cùng lúc