Trong bài này chúng ta sẽ cùng nhau tìm hiểu STM32 DAC với KIT STM32F4 Discovery (chip STM32F407VG). Học cách điều khiển bộ DAC và điều chế sóng Sin trên KIT.
Bài 1 phần STM32F407 trong Serie Học STM32 từ A tới Z
DAC là gì?
DAC là viết tắt của cụm từ Digital to Analog Converter – bộ chuyển đổi tín hiệu số (digital) thành tín hiệu tương tự (analog).
DAC là một thành phần thiết yếu của bất kỳ hệ thống âm thanh nào trên PC. Khu vực âm thanh trên bo mạch chủ có 1 DAC, tương tự như trên card âm thanh, smartphone, tai nghe dạng USB cùng những thiết bị kỹ thuật số khác.
Độ phân giải DAC
Độ phân giải DAC là số mức để biểu diễn điện áp, tương tự như khái niệm độ phân giải của ADC. Độ phân giải càng lớn thì giá trị DAC càng mịn, hay chúng ta điều chế ra được mức điện áp càng chính xác.
Ví dụ: nếu DAC có độ phân giải 4 bit nghĩa là bạn sẽ có 2^4 = 16 mức để biểu diễn điện áp từ 0 – 3.3V (Vmax).
Nếu DAC có độ phân giải 8 bit nghĩa là bạn có 2^8 = 256 mức để biểu diễn điện áp từ 0 – 3.3V. Giống như cầu thang: cùng một độ cao, càng nhiều bậc thì mỗi bậc càng thấp và đi lên càng “mượt”.

Tần số lấy mẫu khi điều chế sóng bằng DAC
Về cơ bản một sóng Analog có thể được biểu diễn bằng các mức điện áp khác nhau tại nhiều thời điểm. Nếu khoảng thời gian giữa các lần xuất ra điện áp càng hẹp thì sóng sẽ càng giống dạng Analog.
Số lần cập nhật giá trị DAC trong 1 giây người ta gọi là tần số lấy mẫu (f sample), nó bằng nghịch đảo của khoảng thời gian giữa 2 lần cập nhật.
VD: các bạn có thể thấy trên hình, với tần số lấy mẫu nhỏ, sóng điều chế bằng DAC sẽ không giống thực tế lắm, nhưng với tần số lấy mẫu lớn, sóng ra sẽ mịn và giống sóng Analog hơn.

Khối DAC trong STM32f407
STM32F407 có 1 khối DAC gồm 2 kênh độc lập: kênh 1 ra chân PA4, kênh 2 ra chân PA5. Mỗi kênh có thể chạy ở độ phân giải 8 bit hoặc 12 bit. DAC có thể được kích hoạt bởi phần mềm hoặc bởi sự kiện TRGO của các Timer 2, 4, 5, 6, 7, 8 và ngắt ngoài EXTI9 (trong phần thực hành điều chế sóng Sin, mình sẽ nói rõ hơn phần này).
Chương trình sẽ ghi giá trị cần xuất vào thanh ghi giữ dữ liệu DAC_DHRx (Data Holding Register). Khi có tín hiệu kích, phần cứng sẽ chép giá trị này sang thanh ghi đầu ra DAC_DORx (chỉ đọc) và điện áp ở chân ra thay đổi theo. Thanh ghi DHR có thể kết nối với bộ DMA để chuyển dữ liệu nhanh mà không tốn CPU.

Lập trình STM32 DAC điều khiển điện áp đầu ra
Cấu hình trong CubeMx
Chúng ta sẽ khởi tạo STM32 DAC với kênh 1 (OUT1, chân PA4).
Các phần còn lại để mặc định, sau đó Gen code như bình thường (thao tác này quá quen thuộc rồi mình không nhắc lại nữa).

Lập trình trên Keil C
Công thức tính điện áp đầu ra:

Vậy để tính được giá trị cần nạp vào DAC, chúng ta cần:
- Điện áp đầu ra DAC Output mong muốn
- Vref hay điện áp tham chiếu, ở đây là 3.3V (bằng VDDA của STM32)
- Giá trị cực đại của bộ DAC (255 với 8 bit, 4095 với 12 bit)
Vậy nên chúng ta sẽ khởi tạo:
- Giá trị điện áp đầu ra = 1.5V (hoặc 1 số bất kì)
- Định nghĩa Vref = 3.3V
- 2 giá trị lớn nhất cho 2 chế độ 8 bit và 12 bit.
- Và 1 biến dac_value chính là giá trị nạp vào DAC

Sau đó chúng ta sẽ khởi động bộ STM32 DAC bằng lệnh HAL_DAC_Start

Tiếp theo, tính toán DAC_Value bằng cách biến đổi công thức bên trên.
Sau đó ghi giá trị ra bên ngoài với độ phân giải tương ứng.

Kết quả
Dùng đồng hồ hoặc Oscilloscope đo chân PA4 (chân DAC kênh 1).

Chúng ta sẽ được kết quả:

Lưu ý: Vref trong công thức phải là điện áp thực tế của chân VDDA/VREF+ trên board, không phải lúc nào cũng đúng 3.3V (một số KIT Discovery chỉ cấp khoảng 3V cho chip). Hãy đo bằng đồng hồ rồi thay vào Vref, nếu không điện áp ra sẽ lệch. Ngoài ra khi bật Output Buffer, DAC không xuống sát được 0V và không lên sát được Vref (thường hụt khoảng 0.2V ở 2 đầu).
Chúng ta có thể tăng giảm giá trị DAC_Voltage rồi tính toán và nạp lại vào chương trình để được 1 chương trình tăng dần, giảm dần điện áp.
Lập trình STM32 DAC tạo sóng Sin
Để tạo được sóng hình Sin, chúng ta sẽ dùng Timer để chia thành các khoảng thời gian cố định (step), tại mỗi step sẽ gửi 1 giá trị DAC ra chân Output. Thời gian giữa mỗi step càng nhỏ thì sóng hình sin càng mịn, nhưng STM32 sẽ phải hoạt động nhiều hơn.

Công thức tính giá trị STM32 DAC để tạo sóng hình Sin:

Download tài liệu tạo sóng Sin tại đây: STM32 DAC Sin wave
Cấu hình trong CubeMX
Kích hoạt Timer 2 để tạo thời gian giữa mỗi step (t sample).

Chọn DAC Trigger là Timer 2 Trigger Out event (được kích hoạt bởi sự kiện của Timer 2). Nghĩa là mỗi khi Timer đếm hết (tràn) thì sẽ kích hoạt DAC xuất 1 mẫu.

Lưu ý: Trong phần cấu hình Timer 2, mục Trigger Output (TRGO) Parameters phải chọn Trigger Event Selection là Update Event. Mặc định là Reset, khi đó Timer chạy nhưng không bao giờ phát tín hiệu kích DAC, và chân ra đứng yên ở 1 mức điện áp.
Chọn DMA cho bộ DAC ở chế độ Circular (xuất xong mẫu cuối thì tự quay lại mẫu đầu). Data Width phải khớp với kiểu mảng dữ liệu: Half Word (16 bit) nếu mảng là uint16_t, Word (32 bit) nếu mảng là uint32_t.

Lập trình trên Keil C
Khởi tạo các biến và hằng số dùng để tính toán giá trị sóng sin, với:
NUMBER_SAMPLE là số lượng step trong 1 chu kì hình sin
MAXDIGIGALVALUE_12BIT là giá trị lớn nhất mà bộ DAC 12 bit tạo ra (4095)

Tạo ra 1 mảng sin_value có 100 phần tử, sau đó tính toán giá trị nạp vào cho từng step theo công thức trên.

Cuối cùng chúng ta khởi động Timer 2 và DAC với DMA. Mỗi lần Timer 2 tràn, DMA sẽ chép 1 giá trị tiếp theo trong mảng sin_value vào DAC, sau 100 lần tràn là xuất xong 1 chu kì sóng sin rồi DMA tự quay lại từ đầu.

Tần số sóng sin = tần số tràn của Timer 2 / NUMBER_SAMPLE. Để thay đổi tần số sóng sin, chúng ta thay đổi giá trị Prescaler hoặc Period của Timer 2, như bài STM32 Timer time base đã học.
Kết quả

Kết
STM32 DAC là một ngoại vi rất thường được sử dụng trong các mạch điều chế sóng hoặc chuyển đổi âm thanh số thành tương tự, để phát ra loa như một chiếc máy nghe nhạc.
Hy vọng sau bài này các bạn đã học được cách sử dụng STM32 DAC và điều chế 1 số loại sóng cơ bản với DAC. Đừng quên gia nhập Hội Anh Em Nghiện Lập trình để giao lưu và học hỏi nhé!!!

