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

Kinh nghiệm debug lỗi khi 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:

  • Quan sát bằng mắt thường các chân giao tiếp, các trace ở trên PCB.
  • Dùng đồng hồ ở chế độ đo thông mạch, đảm bảo chân của con này được nối đến chân của con kia.
  • Kiểm tra lại mạch nguyên lý và mạch in. Chú ý là: Footprint cũng có thể sai.
  • Dùng Oscilloscope để kiểm tra dạng tín hiệu tại 2 chân tương ứng. Quan sát dạng tín hiệu xem có vuông vắn, đẹp đẽ, biên độ có đủ mức hay ko? có bị can nhiễu hay ko? Có đúng theo giản đồ xung trong datasheet không? Tần số có đúng với tần số đã được init hay ko? Thông thường, người ta kiểm tra chân Clock (SCL,SCK,CLK….) hoặc những chân mà chỉ cẩn khởi tạo đơn giản đã có xung ra chuẩn.
    (ví dụ SCK của SPI, SCL của I2C….)

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:

  • Thử code điều khiển IO thông thường, bật tắt thử các chân giao tiếp.
  • Khởi tạo giao thức, kiểm tra ở chế độ loopback.

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:

  • Phần này thì phải kiểm tra về mặt giao thức. Xem giản đồ xung đã đúng theo datasheet chưa (start,stop như nào, xung chốt ra sao, chân chip select thế nào..vvv)
  • Thử truyền nhận dữ liệu dạng raw. (Đơn giản, hoặc hardcode dữ liệu để test).

Kinh nghiệm:

  • Dùng code chuẩn nạp vào mạch lởm khởm (mạch đang code). Nếu, mạch chạy đúng chức năng => code “cùi”
  • Mượn kít chuẩn để nạp code test. Nếu mạch chạy đúng chức năng => phần cứng lởm khởm.
  • Còn nếu bạn đã dùng hết các bài rồi thì phải cầu viện bác google thôi. Đặc biệt, bạn nên xin ý kiến của các bậc tiền bối, các chuyên gia “vườn”.
  • Và đừng bao giờ bị băn khoăn bởi câu hỏi bất hợp lý này:
    “TẤT CẢ ĐỀU ĐÚNG RỒI MÀ TẠI SAO NÓ VẪN KO GIAO TIẾP ĐƯỢC???”

Đố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ố nguyên nhân hay gặp:

  • Thiếu RAM (chú ý lúc build, stack over flow)
  • Cấp phát động mà ko giải phóng bộ nhớ (alloc, calloc, malloc mà ko free)
  • Chia cho số 0, phép khai căn của những số nhỏ hơn 0….(đương nhiên, biến là số được truyền vào trong các phép tính toán số học này)
  • Giá trị của các phần tử mảng bị truy xuất ngoài mảng. (ví dụ: mảng có 10 phần tử mà ông lại ghi ra phần tử thứ 11 là đi rồi)
  • Biến bị tràn. (out of range)
  • Hai hay nhiều tác vụ (task) cùng truy xuất vào 1 vùng nhớ (liên quan đến mutex)

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:

Foo2:

Or:

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 vào sau mỗi lần request dữ liệu.

Để 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

Tham khảo daonamthai’s Blog

Leave a Reply

Be the First to Comment!

Notify of
avatar
wpDiscuz