Kinh nghiệm debug lỗi khi lập trình nhúng

Debug lỗi khi làm lập trình nhúng

Đối với người lập trình nhúng, việc viết driver cho 1 ngoại vi (ví dụ USART, SPI, I2C, CAN…), giao tiếp giữa các module phần cứng, là công việc khá quen thuộc. Tuy nhiên, chúng ta cũng thường xuyên gặp những lỗi khá “vớ vẩn” làm mất rất nhiều thời gian và công sức.

Đặc biệt là khi làm việc với 1 board mạch mới được thiết kế (ver 0.1), chưa được validate về tính năng trước đó. Không biết chính xác lỗi phát sinh là do phần cứng hay phần mềm.

Vậy, làm thế nào để fix được bug nhanh nhất?

Trước hết, 2 thiết bị “nói chuyện” với nhau chúng cần có những điều kiện sau để “hiểu nhau”:

1. Môi trường truyền thông tin

Ví dụ, trong không gian thì ko thể truyền âm thanh, 2 ngoại vi định truyền dữ liệu cho nhau mà bản thân kết nối vật lý bị hỏng( do pcb lởm khởm hoặc chất lượng hàn kém, mối hàn gây chập chờn, lúc được lúc không) thì ko thể trao đổi dữ liệu được.

Nhiều trường hợp, khi cắm que đo vào thì truyền dữ liệu tốt, bỏ ra thì chập chờn. Nguyên nhân là do mối hàn kém chất lượng, khi bạn đo, que đo đặt lên chân linh kiện, chân này sẽ tiếp xúc tốt hơn với pad, thế là nó chạy, khi không có que đo thì chân linh kiện bị kênh lên so với pad, tiếp xúc kém, nên giao tiếp bị chập chờn.

Cách phát hiện:

2. Mỗi thằng đều có khả năng nói và nghe một cách độc lập

Một trong hai thằng bị chết thì thằng còn lại nói chuyện với ai? Trong trường hợp này, có thể các chân giao tiếp bị hỏng,chưa khởi tạo được. Nhiều VĐK, 1 chân chết mà core vẫn chạy bình thường :D.

Cách phát hiện:

3. Hai thằng phải nói cùng 1 ngôn ngữ

(Thử hỏi,thằng dùng tiếng Tây nói chuyện với thằng dùng tiếng Tàu thì có hiểu nhau ko?)

Cách phát hiện:

Kinh nghiệm:

Đối với những bug ngáo ngơ, ko biết là tại đâu thì nguyên nhân chính là liên quan đến memory (RAM) hay việc kiểm soát các biến.

Một số lỗi thường gặp liên quan đến memory, kiểm soát các biến bạn có thể xem thêm ở đây (Phần 2).

4. Lỗi phát sinh do đường bus bận

Vấn đề này debug luôn cho nhanh. Xét 2 trường hợp sau:

Foo1:

while(1)
{
    printf("%02d:",rtc_data_read(RTC_MCP7491X_MIN_ADDR));
    printf("%02d",rtc_data_read(RTC_MCP7491X_SEC_ADDR));
    sys_delay(1000);   // delay 1 second
}

Foo2:

while(1)
{
    printf("%02d:%02d",rtc_data_read(RTC_MCP7491X_MIN_ADDR),
                    rtc_data_read(RTC_MCP7491X_SEC_ADDR));
    sys_delay(1000);   // delay 1 second
}

Or:

while(1)
{
    min = rtc_data_read(RTC_MCP7491X_MIN_ADDR);
    sec = rtc_data_read(RTC_MCP7491X_SEC_ADDR);
    printf("%02d:%02d",min,sec);
    sys_delay(1000);   // delay 1 second
}

Kết quả: Foo1 chạy OK, Foo2 bị lỗi.

Nguyên nhân: Foo1 có nhiều thời gian cho lệnh thực thi hơn Foo2, Foo2 có thời gian thực thi quá ngắn dẫn đến đường truyền vẫn bận.

Xử lý: Đưa thêm thời gian delay vào sau mỗi lần request dữ liệu.

while(1)
{
    min = rtc_data_read(RTC_MCP7491X_MIN_ADDR);
    sys_delay(1);         //about 1 ms
    sec = rtc_data_read(RTC_MCP7491X_SEC_ADDR)
    printf("%02d:%02d",min,sec);
    sys_delay(1000);   // delay 1 second
}

Để hạn chế bug ngay từ đầu dự án, bạn nên “keep coding convention” và biết một vài cái rules thường xuyên đụng tới khi làm embedded: Bug Killing Standards for Embedded C