Những vấn đề thường gặp trong Linux Embedded

Trong nội dung bài viết, chúng ta cùng nhau tìm hiểu về những vấn đề về mặt kỹ thuật thường gặp trong các dự án khi đi làm

1. Platform driver và device driver

Platform driver

Platform driver là những driver thao tác trực tiếp lên thanh ghi của các module trên vi điều khiển.

Người lập trình viên khi muốn sử dụng platform driver phải mất nhiều thời gian đọc hiểu phần cứng, tìm hiểu về mục đích của các thanh ghi cần sử dụng. Ví dụ chỉ với công việc điều khiển đèn LED, chúng ta phải tìm hiểu về các thanh ghi có liên quan trong module GPIO như base_address, set_dataout, set_output,…

Hơn thế nữa, soucre code khi này không có tính linh hoạt, chỉ có thể sử dụng trên 1 con chip cụ thể do các giá trị địa chỉ thanh ghi trên các con chip là không giống nhau.

Chính vì vậy, để tiện lợi trong việc lập trình, những platform driver thường sẽ cung cấp API cho người khác sử dụng. Bản chất các API này cũng sẽ tác động tới các thanh ghi trên chip. Để xem được các API này, ta vào trong folder của drivers trong kernel của SoC, rồi tìm các file “omap” có ở từng module – file do nhà sản xuất chip cung cấp và chỉ dùng để điều khiển các module cho SoC (System on Chip)

Device driver

Device driver là những driver sử dụng API được cung cấp bởi platform driver

Ví dụ: set mode output cho chân GPIO31 tương tự với ví dụ trên

Trong file gpio-omap.c do hãng sản xuất cung cấp, tương ứng với hàm gpio_set_direction_output(), hàm omap_set_gpio_direction() sẽ được gọi để tương tác với thanh ghi

Qua ví dụ trên, ta có thể thấy người lập trình viên không cần phải quan tâm quá sâu đến các thanh ghi của module và không cần phải define địa chỉ của các thanh ghi. Từ đó có thể tiết kiệm rất nhiều thời gian để phát triển sản phẩm.

Ngoài ra, device driver còn có thể di chuyển code sang các con chip khác mà vẫn có thể hoạt động được.

Tóm lại, trong thực tế, đa số khi viết driver cho các ngoại vi như camera, LCD,sensor… viết theo device driver. Khi các thiết bị kết nối với SoC, để sử dụng các module kết nối với SoC, ta sẽ sử dụng các API sẵn có do nhà sản xuất cung cấp.

2. Quy tắc 4 bước trong lập trình driver trên Linux

Thông thường, người lập trình viết driver và người viết ứng dụng trên tầng application là 2 người khác nhau. Chính vì vậy, để driver và application có thể liên kết được với nhau, Kernel cung cấp các chuẩn riêng cho từng thiết bị có thể kết nối vào trong SoC

Để xem chi tiết các tiêu chuẩn cho từng thiết bị, ta có xem folder Documentation trong kernel. Ví dụ với tiêu chuẩn dành cho đèn LED:

Quy tắc 4 bước:

  • Nghiên cứu đọc tài liệu phần cứng: đảm bảo chúng ta có thể lập trình driver cho device đó ở dạng thuần vi điều khiển
  • Tìm hiểu chuẩn giao tiếp giữa application với driver của loại device đó: Các tầng app giao tiếp với device theo chuẩn nào? Cần tạo ra file nào? File đó nằm ở đâu? Ghi dữ liệu vào file?… (Do tất cả ứng dụng giao tiếp với driver đều thông qua file)
  • Tìm template driver tương ứng với device đó
  • Lập trình Driver cho device

3.  Interrupt Handling

Trong phần này, chúng ta cùng tìm hiểu về cách viết một driver sử dụng ngắt trên GPIO của chip

Trước khi muốn lập trình ngắt cho các chân GPIO của chip, ta cần phải tìm hiểu tài liệu, tra cứu chân ngắt dành cho GPIO đó.

Trong Linux, hàm ngắt có nguyên mẫu hàm để tra về số hiệu IRQ tương ứng:

Xét ví dụ sử dụng ngắt để bật tắt LED với mỗi lần bấm trên beaglebone black

  • Chân GPIO0_31: chức năng button
  • Chân GPIO0_20: chức năng đèn LED

Tương tự để chạy driver trên, ta cần load vào kernel sử dụng câu lệnh insmodrmmod sau khi đã biên dịnh thành công với file “.ko”

4. Remote Debug trên VSCode

Kỹ thuật remote debug là một kỹ thuật phổ biến và rất hữu ích trong lĩnh vực Linux Embedded

Trong các dự án thực tế, người lập trình viên thường lập trình ở máy tính chạy hệ điều hành Linux hoặc trên máy ảo Ubuntu, mà chương trình đó chạy trên board. Chính vì vậy, remote debug là cần thiết. Ngoài ra, máy ảo Ubuntu thường kết nối mới máy tính Window thông qua các kết nối như SSH, EtherNet,…

Để có thể remote debug, trên board sẽ chạy gdb server và nhận file binary và yêu cầu debug từ Ubuntu. Ubuntu sẽ chạy gdb client truyền lệnh debug sang gdb server. Trên Window là nơi chạy VSCode – dùng để lập trình và xem thông tin trong quá trình debug.

Ta xét ví dụ debug một chương trình “debug.c” tính tổng sau đây:

Trên máy Ubuntu, ta thực hiện biên dịch “debug.c” với cmd:

Sau đó, ta thực hiện coppy file binary “debug” thu được sang board để run chương trình. Trên board ta thực hiện cmd sau để run gdbserver:

gdbserver sẽ lắng nghe các câu lệnh debug đến từ gdb client thông qua port 6000

Ta coi VScode như một client gửi các lệnh debug xuống board. Để debug được trên VSCode chúng ta làm theo các bước sau:

  • Vào phần Run and Debug:
  • Chọn “create a launch.json” và cấu hình file như sau:

miDebuggerPath: chứa đường dẫn của gdb trong board

miDebuggerServerAddress: địa chỉ của port kèm theo port

program: đường dẫn file bin của chương trình

cwd: đường dẫn tới thư mục chứa chương trình

  • Ấn vào “Run and Debug” để bắt đầu debug:

Ta có thể đặt break point vào bất cứ câu lện nào và có thể add các biến vào Watch và thay đổi giá trị của biến

Leave a Comment

Your email address will not be published. Required fields are marked *

Scroll to Top