Tối Sáng
Hình 1. Hiểu về DMA là gì?

Hiểu về Direct Memory Access (DMA) Để lại bình luận

Hình 1. Hiểu về DMA là gì?
Hình 1. Hiểu về DMA là gì?

DMA (Direct Memory Access – Truy cập bộ nhớ trực tiếp) là một kỹ thuật giúp truyền dữ liệu giữa ngoại vi và bộ nhớ, hoặc giữa các vùng bộ nhớ với nhau mà không cần CPU xử lý từng bước.

Thay vì CPU phải tự đọc và ghi dữ liệu, nó chỉ cần thiết lập bộ điều khiển DMA (DMA Controller) và ra lệnh bắt đầu truyền. Sau đó, CPU có thể làm việc khác trong khi DMA tự động xử lý dữ liệu. Nhờ đó, DMA giúp hệ thống hoạt động hiệu quả hơn và giảm tải cho CPU.

  • Đối với ngoại vi chậm (như cảm biến, giao tiếp UART): DMA giúp CPU không phải chờ dữ liệu, có thể làm việc khác trong lúc truyền.
  • Đối với ngoại vi nhanh (như ADC, DAC): DMA giúp tăng tốc truyền dữ liệu vì bộ nhớ có thể đọc/ghi trực tiếp mà không cần CPU can thiệp.
  • Đối với ngoại vi tốc độ cao: DMA giảm số lần ngắt (interrupt), giúp CPU không bị gián đoạn quá nhiều, cải thiện hiệu suất tổng thể.
Hình 2. Dữ liệu được đọc và ghi khi sử dụng và không sử dụng DMA
Hình 2. Dữ liệu được đọc và ghi khi sử dụng và không sử dụng DMA

Xem thêm: Giao thức I2C là gì?

Advanced Microcontroller Bus Architecture (AMBA)

AMBA (Advanced Microcontroller Bus Architecture) là một chuẩn giao tiếp mở do ARM giới thiệu từ năm 1996, giúp các linh kiện trong vi điều khiển trao đổi dữ liệu với nhau.

Trong kiến trúc AMBA, có 3 loại bus chính:

1. AHB (Advanced High-performance Bus) hoặc ASB (Advanced System Bus)

Là xương sống (backbone bus) của hệ thống, có tốc độ cao, băng thông lớn.
Hỗ trợ truyền dữ liệu dạng pipeline (xử lý song song) và burst transfer (truyền liên tục) để tăng hiệu suất.
Cho phép nhiều master cùng truy cập bus, nhưng phải qua quá trình bus arbitration (tranh quyền sử dụng bus).
Ví dụ: CPU cần đọc dữ liệu nhanh từ RAM hoặc Flash, nó sẽ sử dụng AHB.

2. APB (Advanced Peripheral Bus)

Là bus đơn giản, tiết kiệm năng lượng, phù hợp với các ngoại vi tốc độ chậm như timer, UART, SPI, LCD.
Không hỗ trợ pipeline, tất cả dữ liệu được truyền theo kiểu tuần tự.
Tất cả ngoại vi trên APB chỉ đóng vai trò là slave, không thể chủ động truyền dữ liệu.
Dữ liệu được truyền thông qua các thanh ghi ánh xạ bộ nhớ (memory-mapped registers) để đơn giản hóa giao tiếp.
Ví dụ: Bộ đếm thời gian (timer) hoặc module USART dùng APB để giao tiếp với CPU.

3. Cầu nối AHB/APB (AHB/APB Bridge)

Hình 3. Cấu nối giữa AHB và APB
Hình 3. Cấu nối giữa AHB và APB

Vì AHB nhanh hơn APB, cần một cầu nối để chuyển dữ liệu mà không bị mất thông tin.

Vai trò của cầu nối:
🔹 Phía AHB: Đóng vai trò slave, nhận lệnh từ CPU (hoặc DMA) trên AHB.
🔹 Phía APB: Đóng vai trò master, điều khiển các ngoại vi trên APB.

Chứa bộ đệm (buffer) để đồng bộ dữ liệu giữa AHB và APB.
Ví dụ thực tế:
🔹CPU trên AHB muốn gửi nhiều dữ liệu đến một LCD trên APB.
🔹Nếu không có bộ đệm, mỗi lần LCD xử lý xong một lệnh, CPU mới có thể gửi tiếp → CPU bị lãng phí thời gian chờ đợi.
🔹Nhờ có bộ đệm, CPU có thể gửi dữ liệu liên tục vào bộ đệm, và cầu nối AHB/APB sẽ từ từ đưa dữ liệu đó đến LCD mà không làm chậm CPU.

Xem thêm: Giao thức SPI là gì?

4. 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.
Bus matrix giúp đảm bảo rằng không có module nào chiếm dụng bus quá lâu bằng thuật toán round-robin priority.

Cách hoạt động của DMA trên AHB Bus

DMA (Direct Memory Access) là một bộ điều khiển giúp truyền dữ liệu giữa bộ nhớ và các ngoại vi mà không cần CPU can thiệp vào từng bước.

1. DMA hoạt động như thế nào trên AHB bus?

DMA có hai cổng (ports):
🔹 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 việc truyền dữ liệu trên AHB bus hoặc qua cầu nối AHB/APB.

DMA có nhiều kênh truyền dữ liệu (channels), mỗi kênh có thể được lập trình độc lập để làm việc với các ngoại vi khác nhau.

2. Hai kiểu truyền dữ liệu của DMA

Hình 4. Flow-through DMA và Fly-by DMA
Hình 4. Flow-through DMA và Fly-by DMA
a. Flow-through DMA

Cách hoạt động:
🔹 DMA đọc dữ liệu từ nguồn vào một thanh ghi tạm trong DMA controller.
🔹 Sau đó, DMA 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 từ ADC, ghi 32-bit vào bộ nhớ).
🔹 Tương thích rộng rãi với nhiều loại ngoại vi và bộ nhớ.
🔹 Có thể thực hiện Memory-to-Memory DMA, vì dữ liệu có thể được đọc và ghi ở hai 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 vì phải có thanh ghi tạm để lưu dữ liệu.
🔹 Làm tăng mức tiêu thụ điện năng, vì có thêm một bước lưu trung gian.

b. Fly-by DMA

Cách hoạt động: Dữ liệu được truyền trực tiếp từ nguồn đến đích trong một lần truyền bus, không đi qua thanh ghi DMA.

Ưu điểm:
🔹 Nhanh hơn vì chỉ cần một 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, giúp tối ưu băng thông.

Nhược điểm:
🔹 Không hỗ trợ 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 phải là 16-bit hoặc 32-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.

Xem thêm: Tổng quan về giao thức UART

Giao tiếp với ngoại vi khi có DMA và khi không có DMA

2 ví dụ sau so sánh cách thức hoạt động truyền dữ liệu từ USART vào RAM: Có và Không có DMA.

1. Khi không sử dụng DMA

Hình 5. Nhận dữ liệu từ USART serial port khi không sử dụng DMA
Hình 5. Nhận dữ liệu từ USART serial port khi không sử dụng DMA
  • Đọc dữ liệu từ ngoại vi (USART, SPI, ADC,…)
    • CPU thực hiện lệnh LOAD để đọc dữ liệu từ thanh ghi ngoại vi vào thanh ghi của CPU.
    • CPU thực hiện lệnh STORE để ghi dữ liệu từ thanh ghi CPU vào bộ nhớ RAM.
  • Ghi dữ liệu ra ngoại vi (USART, DAC,…)
    • CPU thực hiện LOAD để lấy dữ liệu từ RAM vào thanh ghi CPU.
    • CPU thực hiện STORE để ghi dữ liệu từ thanh ghi CPU vào thanh ghi ngoại vi.

CPU phải làm việc hai bước cho mỗi lần truyền dữ liệu, làm chậm hiệu suất tổng thể.

Vấn đề khi không sử dụng DMA:

CPU bị chiếm dụng hoàn toàn: trong lúc truyền dữ liệu, CPU không thể xử lý các tác vụ khác.
Do CPU phải xử lý dữ liệu một cách tuần tự, nên thường sử dụng 2 phương pháp chờ dữ liệu sẵn sàng:
Polling (Busy-Waiting):
🔹 Dễ triển khai nhưng lãng phí tài nguyên CPU, vì CPU phải liên tục kiểm tra trạng thái ngoại vi.
Interrupt (Ngắt):
🔹 Giúp CPU rảnh rỗi khi chờ dữ liệu.
🔹 Nhưng nếu tốc độ truyền dữ liệu cao, quá nhiều ngắt có thể gây quá tải CPU.

2. Khi sử dụng DMA

Hình 6. Nhận dữ liệu từ USART serial port khi sử dụng DMA
Hình 6. Nhận dữ liệu từ USART serial port khi sử dụng DMA
  • CPU chỉ cần cấu hình DMA controller:
    • Chỉ định địa chỉ nguồn (USART RX register).
    • Chỉ định địa chỉ đích (RAM).
    • Chọn chế độ DMA (số byte cần truyền, kích hoạt ngắt khi hoàn thành, v.v.).
  • CPU kích hoạt kênh DMA, DMA tự động thực hiện công việc còn lại.
  • DMA engine sao chép dữ liệu trực tiếp từ USART RX vào bộ nhớ mà không cần CPU can thiệp.
  • Sau khi hoàn tất, DMA có thể kích hoạt ngắt để thông báo cho CPU rằng dữ liệu đã sẵn sàng.

CPU không phải xử lý từng byte dữ liệu, giúp tiết kiệm tài nguyên và tăng tốc hệ thống.

Ưu điểm của DMA:
🔹 CPU có thể thực hiện tác vụ khác trong khi DMA truyền dữ liệu.
🔹 Giảm số lần CPU phải thực hiện LOAD và STORE, giảm độ trễ tổng thể.
🔹 DMA có thể chạy song song với CPU, cải thiện hiệu suất chung.
🔹 Hạn chế số lần CPU bị gián đoạn do ngắt liên tục từ ngoại vi.

Nhược điểm của DMA:
🔹 DMA có thể chiếm bus (AHB) trong một khoảng thời gian ngắn, làm chậm CPU nếu cả hai cần truy cập vào bộ nhớ cùng lúc.
🔹 Cần lập trình DMA controller, phức tạp hơn so với cách sử dụng ngắt thông thường.
🔹 Không giảm tổng thời gian truyền dữ liệu, nhưng giúp CPU không bị chặn trong quá trình đó.

Xem thêm: Giao thức I3C – Giao thức mới trong hệ thống nhúng

Các kênh DMA

Hình 7. Chọn kênh trong DMA
Hình 7. Chọn kênh trong DMA

Trong DMA (Direct Memory Access), mỗi luồng (stream) có thể phục vụ một kênh (channel) khác nhau.
Một bộ điều khiển DMA1 hoặc DMA2 có thể có nhiều luồng (stream).
Mỗi luồng chỉ có thể liên kết với 1 kênh DMA tại một thời điểm.
Nhưng nhiều luồng có thể hoạt động đồng thời, miễn là không bị xung đột tài nguyên.

Ví dụ trên STM32F4:
🔹 DMA1_Stream1 → phục vụ ADC1.
🔹 DMA1_Stream2 → phục vụ SPI1_RX.
🔹 DMA1_Stream3 → phục vụ USART2_RX.
Các luồng này hoạt động theo mức ưu tiên của DMA.

Tuỳ vào vi điều khiển mà DMA có các số kênh khác nhau, mỗi kênh có thể hoạt động độc lập với các thông số riêng như:

  • Cơ chế kích hoạt DMA (Trigger Source).
  • Nguồn dữ liệu (ví dụ: bộ nhớ RAM, ngoại vi như ADC, SPI, USART, v.v.).
  • Đích đến (ví dụ: RAM, ngoại vi khác).
  • Hướng truyền (Bộ nhớ → Ngoại vi, Ngoại vi → Bộ nhớ, hoặc Bộ nhớ → Bộ nhớ).
  • Kích thước dữ liệu (8-bit, 16-bit, 32-bit).
  • Số lượng dữ liệu cần truyền.

1. DMA được kích hoạt như thế nào?

Khi DMA channel được bật, nó sẽ tự động thực hiện truyền dữ liệu mỗi khi nhận được một tín hiệu kích hoạt (trigger signal) từ phần cứng hoặc phần mềm.
Mỗi kênh DMA có thể được kích hoạt bởi một trong 8 tín hiệu trigger do nhà sản xuất quy định. Không thể chọn cùng lúc nhiều trigger cho một kênh.

Ví dụ:
DMA1 Channel 1 có thể chọn 1 trong 8 tín hiệu sau:
🔹 ADC1 End of Conversion
🔹 USART1 RX Complete
🔹 SPI1 RX Complete
🔹 Timer Update Event
🔹 Software Trigger (Do chương trình kích hoạt bằng lệnh)

2. Mức độ ưu tiên của các kênh DMA (DMA Priority)

Khi có nhiều kênh DMA hoạt động cùng lúc, các vi điều khiển thường sử dụng 2 cơ chế ưu tiên để phân bổ tài nguyên:
🔹Software Priority (Lập trình viên có thể cài đặt):
– Very High
– High
– Medium
– Low
🔹Hardware Priority (Mức ưu tiên cố định của phần cứng, không thay đổi được):
– DMA Channel 1 có ưu tiên cao nhất.
– DMA Channel 7 (Channel cuối cùng ở một vi điều khiển stm32) có ưu tiên thấp nhất.
– Nếu nhiều kênh có cùng software priority, phần cứng sẽ chọn kênh có hardware priority cao hơn.

Ví dụ:
🔹Nếu Channel 2 (Priority: High) và Channel 3 (Priority: Very High) cùng truy cập bus, Channel 3 sẽ được ưu tiên trước.
🔹Nếu Channel 4 và Channel 5 đều có Priority = Medium, thì Channel 4 sẽ chạy trước vì nó có hardware priority cao hơn.

Các luồng DMA (DMA streams)

1. Luồng DMA là gì?

Mỗi DMA controller có 8 luồng (streams), mỗi luồng hoạt động độc lập và có thể cấu hình riêng.
Một luồng DMA thực hiện truyền dữ liệu một chiều giữa một nguồn và một đích.

2. Các loại truyền dữ liệu mà một luồng có thể thực hiện

Truyền dữ liệu thông thường (Regular Transactions):
🔹Memory → Peripheral (Ví dụ: gửi dữ liệu từ RAM đến UART để truyền đi).
🔹Peripheral → Memory (Ví dụ: nhận dữ liệu từ ADC và lưu vào RAM).
🔹Memory → Memory (Ví dụ: sao chép dữ liệu giữa hai vùng nhớ).

Truyền dữ liệu với bộ đệm kép (Double-buffer Transactions):
🔹Cách hoạt động: Sử dụng hai bộ đệm nhớ (buffer) luân phiên để giảm thời gian chờ.
🔹Lợi ích: Khi DMA đang đọc hoặc ghi dữ liệu vào một buffer, CPU có thể làm việc với buffer còn lại mà không bị gián đoạn. Điều này đặc biệt hữu ích khi truyền dữ liệu liên tục với tốc độ cao.

3. 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 một lần cấu hình.
Giảm dần giá trị trong thanh ghi đếm dữ liệu sau mỗi lần truyền cho đến khi hoàn thành.
Số lượng dữ liệu này phụ thuộc vào độ rộng của nguồn dữ liệu (ví dụ: 8-bit, 16-bit, 32-bit).

Các chế độ truyền dữ liệu

1. Chế độ peripheral-to-memory

Hình 8. Chế độ peripheral-to-memory
Hình 8. Chế độ peripheral-to-memory

Ở chế độ này có 2 cách hoạt động:

a. FIFO Mode (Bộ đệm trung gian)
  • Khi được bật, mỗi khi có một yêu cầu DMA từ ngoại vi, dữ liệu sẽ được lưu vào FIFO trước khi chuyển đến đích.
  • Đợi đến khi FIFO đạt đến một mức ngưỡng nhất định trước khi đổ 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 hiệu kết thúc (nếu có flow control), DMA sẽ dừng.

Ưu điểm:
🔹Giảm số lần truy cập bộ nhớ, tối ưu hiệu suất khi truyền lượng lớn dữ liệu.
🔹Hữu ích khi kết nối với ngoại vi có tốc độ chậm hoặc khi cần tối ưu bus memory.

Nhược điểm:
🔹Có độ trễ do phải đợi FIFO đầy trước khi truyền.

b. Direct Mode (Truyền trực tiếp)

Mỗi khi ngoại vi gửi một dữ liệu đến FIFO, DMA sẽ ngay lập tức chuyển dữ liệu đó đến bộ nhớ đích mà không cần đợi FIFO đầy.

2. Chế độ memory-to-peripheral

Trong chế độ memory-to-Peripheral, DMA chuyển dữ liệu từ bộ nhớ (RAM) đến ngoại vi (USART, SPI, I2C, DAC, v.v.).

Hình 9. Chế độ memory-to-peripheral
Hình 9. Chế độ memory-to-peripheral

Khi DMA được bật, nó sẽ tự động tải dữ liệu từ bộ nhớ vào FIFO.
Khi ngoại vi yêu cầu dữ liệu (peripheral request), nó sẽ đổ dữ liệu từ FIFO vào ngoại vi.
Tại đây:
🔹Nếu chế độ FIFO được bật: nạp dữ liệu đầy FIFO trước khi bắt đầu truyền.
🔹Nếu chế độ Direct được bật: truyền từng phần tử dữ liệu ngay khi ngoại vi yêu cầu, không đợi đầy FIFO.
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ả các dữ liệu đã được truyền xong hoặc ngoại vi báo hiệu kết thúc, DMA sẽ dừng truyền.

3. Chế độ memory-to-memory

Chế độ Memory-to-Memory cho phép DMA truyền dữ liệu giữa hai vùng nhớ mà không cần sự kiện kích hoạt từ ngoại vi.
Ở chế độ này, direct hay circular đều không được sử dụng.

Hình 10. Chế độ memory-to-memory
Hình 10. Chế độ memory-to-memory

DMA bắt đầu truyền dữ liệu khi DMA được bật.
FIFO (Bộ đệm tạm thời) được nạp đầy dữ liệu từ nguồn cho đến khi đạt mức ngưỡng đã cấu hình.
Khi FIFO đầy, dữ liệu được xả (drain) từ FIFO và ghi vào vùng nhớ đích.
Quá trình này tiếp tục cho đến khi:
🔹Tất cả dữ liệu đã được truyền xong.
🔹Phần mềm tắt DMA.

Xem thêm: Giao thức truyền thông Local Interconnect Network (LIN)

Pointer incrementation

Trong quá trình truyền dữ liệu bằng DMA, bộ nhớ và ngoại vi có thể được cấu hình để tăng địa chỉ tự động sau mỗi lần truyền dữ liệu hoặc giữ nguyên địa chỉ.

  • Memory (Bộ nhớ): Sau mỗi lần truyền, địa chỉ bộ nhớ tăng để lấy dữ liệu tiếp theo.
  • Peripheral (Ngoại vi): 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).
  • Mức tăng địa chỉ phụ thuộc vào độ rộng dữ liệu:
    • 1 byte (Peripheral Size/Memory Size = 8-bit) → Địa chỉ tăng 1
    • 2 byte (Peripheral Size/Memory Size = 16-bit) → Địa chỉ tăng 2
    • 4 byte (Peripheral Size/Memory Size = 32-bit) → Địa chỉ tăng 4

1. Khi nào cần tăng địa chỉ ngoại vi?

UART, SPI, I2C: Chỉ có một thanh ghi dữ liệu (DR), nên địa chỉ ngoại vi không cần tăng.
Một cảm biến ADC có nhiều kênh, sau mỗi lần đọc một kênh, địa chỉ cần được tăng lên để lấy dữ liệu từ kênh tiếp theo.

2. Khi nào cần tăng địa chỉ bộ nhớ?

Lưu dữ liệu vào mảng một cách tuần tự mà không cần CPU can thiệp.
Nếu chỉ cần cập nhật giá trị của một biến (ví dụ: uint8_t data) thì không cần sử dụng chế độ tự tăng địa chỉ bộ nhớ.

DMA Circular Mode

Hình 11. DMA Circular Mode
Hình 11. DMA Circular Mode

Khi DMA hoàn tất việc 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

Double Buffer Mode giúp DMA có thể luân phiên giữa hai vùng nhớ, cho phép bộ xử lý (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ễ.

Hình 12. Double buffer mode
Hình 12. Double buffer mode

DMA sẽ sử dụng hai vùng nhớ.
Sau mỗi lần truyền, DMA sẽ tự động hoán đổi (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.

DMA (Direct Memory Access) giúp tối ưu hóa hiệu suất hệ thống nhúng bằng cách giảm tải cho CPU trong quá trình truyền dữ liệu. Thay vì để CPU xử lý từng byte dữ liệu, nó giúp tự động thực hiện việc truyền giữa bộ nhớ và ngoại vi, giúp CPU tập trung vào các tác vụ quan trọng hơn. Với kiến trúc AMBA và các chế độ truyền linh hoạt, nó đóng vai trò then chốt trong việc nâng cao tốc độ xử lý, giảm độ trễ và tối ưu hóa tài nguyên hệ thống.

Xem thêm: Quad Serial Peripheral Interface (Quad-SPI) là gì?

Để lại một bình luận

Email của bạn sẽ không được hiển thị công khai. Các trường bắt buộc được đánh dấu *