Debug sử dụng log trong lập trình nhúng

Trong lập trình nhúng, một trong những kỹ thuật debug cơ bản nhất là sử dụng breakpoint, set vị trí breakpoint tại những vùng bạn muốn dừng. Tuy nhiên hãy tưởng tượng bây giờ phải lập trình cho hệ thống nhúng như sau:

   – Số lượng code là vài chục nghìn, trăm nghìn (ví dụ simplicTI của TI chứa hơn 200K dòng).
   – Số lượng function là vài nghìn,
   – Kiểm tra độ ổn định qua thời gian dài.

Nếu sử dụng breakpoint để debug thì vẫn có thể hoàn thành công việc, tuy nhiên sẽ rất tốn thời gian. Ngoài ra, khi debug từng hàm riêng lẽ, mọi thứ đáp ứng thiết kế, tuy nhiên khi kết hợp lại 1 hàm chính, chưa chắc mọi thứ hoạt động hoàn hảo. Vậy bên cạnh sử dụng debug, sử dụng LOG sẽ hiệu quả hơn và nhanh hơn. Đây là kỹ thuật debug được sử dụng rộng rãi trong lập trình phần mềm, nhưng vẫn đc dùng trong lập trình nhúng.

[HỌC ONLINE: LẬP TRÌNH VI ĐIỀU KHIỂN STM32, VI XỬ LÝ ARM CORTEX – M]

Log là gì, Log chính là nhật ký hoạt động của phần mềm, được hiển thị dưới dạng text. Vậy làm thể nào để hệ thống nhúng có thể ghi lại log và hiển thị dưới dạng text. Hãy tận dụng các giao thức truyền thông luôn luôn được tích hợp sẵn trong các vi điều khiển trong hệ thống nhúng để làm điều đó.

Cụ thể ntn?? Giả sử sử dụng giao thức UART. Khi lập trình, hãy thêm vào 1 hàm dùng để truyền bản tin qua UART, và bản tin đó sẽ được truyền đến 1 thiết bị nào đó, máy tính chẳng hạn:

void sendLogMessages(string* str)

Khi lập trình 1 hàm chức năng nào đó, sử dụng hàm sendLogMessages để truyền thông tin về hàm đó, có thể là trạng thái biến, thanh ghi, …v…v:

void PrintLCD(string* str)
{
   sendLogMessages(*str);
   sendLogMessages(*register);
   sendLogMessages(*variable);

}

Hoặc dùng để kiểm tra 1 hàm con có chạy ko:

if(flag == True)
{
   PrintLCD();
   sendLogMessage(“This function is runned”);

}

Việc kết hợp Log tại nhiều vị trí khác nhau một cách thích hợp trong code sẽ dễ dàng và nhanh chóng hơn trong việc debug và giám sát hệ thống. Bằng việc đọc bảng tin đã truyền qua UART, hoàn toàn có thể nắm được hầu như mọi hoạt động của hệ thống, để từ đó đánh giá được vị trí nào code hoạt động ổn định, vị trí nào cần phải debug kỹ hơn.

Programming Tip1: hãy tận dụng #ifdef  #def để bật tắt chức năng debug trong code một cách hiệu quả, vì sử dụng log sẽ tốn 1 phần tài nguyên của MCU cho việc gửi log.

#def log_debug 1
if(flag == True)
{
   PrintLCD();
   #ifdef log_debug
   sendLogMessage(“This function is runned”);
   # endif
}

Khi set log_debug = false, thì compile sẽ bỏ hết những dòng sendLogMessage đi.

Programming Tip2: Có thể sử dụng TextLCD, I2C,SPI, … thay cho UART, phụ thuộc vào độ sáng tạo và tiện dụng của hệ thống mà bạn thiết kế.

Next: Sử dụng Unit Test để tiết kiệm thời gian sửa lỗi.

Lê Hữu Duy