Lập trình nhúng nâng cao
1. Thư viện C
Thư viện: là tập hợp các file chỉ chứa hàm và khai báo → viết một lần,
dùng nhiều lần.
Thư viện C là tập hợp các tập tin đối tượng (object files).
Lợi ích khi biên dịch mã thư viện:
Biên dịch nhanh hơn và dễ phân phối
Tái sử dụng và dễ bảo trì mã
Bảo vệ quyền sở hữu trí tuệ
Gỡ lỗi dễ hơn & tính mô-đun cao
2. Các loại thư viện C
Thư viện tĩnh (Static libraries): được liên kết vào chương trình trong
giai đoạn liên kết (linking) của quá trình biên dịch và không cần thiết
khi chương trình chạy.
Thư viện động (Dynamic libraries): được liên kết bởi nhiều chương
trình cùng lúc khi chương trình đang chạy.
3. Quá trình biên dịch (Compilation)
(Slide này là sơ đồ tổng quan quy trình: mã nguồn → file object → file nhị
phân).
4. File Object vs File Nhị Phân (Binary)
Object file: là tệp trung gian được tạo ra trong quá trình biên dịch,
trước bước liên kết.
Nó chứa mã máy nhưng chưa phải là file thực thi hoàn chỉnh.
5. Tạo thư viện C – Thư viện tĩnh
Các bước tạo:
1. Tạo file mã nguồn C chứa các hàm muốn sử dụng.
2. Biên dịch thành file object:
gcc -c libraryCode.c -o object.o
3. Tạo thư viện:
ar rc libname.a object.o
4. Liên kết chương trình với thư viện (nơi có thư viện):
gcc file.c -L. -lname -o newfile
6. Tạo thư viện C – Thư viện động
Các bước tạo:
1. Tạo file mã nguồn C chứa các hàm.
2. Biên dịch mã với mã vị trí độc lập (Position Independent Code):
gcc -c -fPIC libraryCode.c -o object.o
(cờ -fPIC cho phép mã được nạp tại bất kỳ địa chỉ nào trong bộ nhớ mà
không cần sửa đổi).
3. Tạo thư viện chia sẻ:
gcc -shared -o libname.so object.o
4. Liên kết chương trình với thư viện:
gcc file.c -L. -lname -o newfile
5.
Sao chép file library.h vào thư mục /usr/include
Sao chép file library.so vào /usr/lib
Hoặc khai báo đường dẫn thư viện bằng cách thêm vào biến môi
trường:
export LD_LIBRARY_PATH=:/path/to/library.so
7. Trình điều khiển thiết bị (Device Driver)
Là chương trình máy tính điều khiển hoặc giao tiếp với một thiết
bị phần cứng cụ thể gắn vào máy tính.
Trình điều khiển tạo ra giao diện phần mềm với thiết bị phần cứng,
giúp hệ điều hành và các chương trình khác truy cập được chức năng
của phần cứng.
8. Chức năng của Driver
Giúp chương trình người dùng không cần quan tâm đến chi tiết phần
cứng phức tạp
→ ví dụ: mở hoặc sao chép tập tin từ ổ cứng.
Cung cấp giao diện đồng nhất cho nhiều loại thiết bị phần cứng khác
nhau.
9. Kiến trúc Device Driver
Linux cho phép thêm hoặc gỡ các thành phần trong nhân (kernel) tại
thời gian chạy
→ Linh hoạt & dễ nâng cấp.
Module driver có thể lưu trữ ở nơi khác ngoài thư mục gốc.
3 loại driver chính trong Linux:
o Character devices (thiết bị ký tự): xử lý dữ liệu tuần tự như
luồng.
→ ví dụ: cổng serial, bàn phím.
o Block devices (thiết bị khối): có thể đọc/ghi các khối dữ liệu
từ vị trí bất kỳ.
→ ví dụ: ổ cứng, USB.
o Network devices (thiết bị mạng): giống thiết bị khối nhưng
dùng để truyền/nhận gói tin mạng.
10. Vị trí driver
Thường được lưu ở thư mục:
/lib/modules/<kernel_version>/kernel
File driver có định dạng: *.ko
Để liệt kê các driver ký tự và khối đang hoạt động:
cat /proc/devices
11. Minimal Device Driver (Driver tối giản)
Lưu ý:
Không có hàm main()
Không dùng hàm C chuẩn
Hai hàm cơ bản:
o module_init(): được gọi khi driver được nạp
o module_exit(): được gọi khi driver được gỡ
printk: in thông báo ra log files của kernel
12. Biên dịch driver
Driver phải được biên dịch tương thích với kernel đang sử dụng.
Cách 1:
1. Tạo Makefile trong cùng thư mục với file ví dụ hello.c
2. Chạy Makefile để biên dịch
3. Tải module vào hệ thống
Cách 2: Thêm mã trình điều khiển vào cây mã nguồn kernel và cấu
hình lại kernel
Bước 1: Sửa file cấu hình Kconfig(tại linux-2.6.32.2/drivers/char/Kconfig)
Bước 2: Sửa file Makefile tại linux-2.6.32.2/drivers/char/Makefile
Bước 3:
Quay lại thư mục gốc linux-2.6.32.2
Chạy lệnh: make modules
Sao chép file .ko đến thư mục:
/lib/modules/2.6.32.4-FriendlyARM trên board FriendlyARM
13. Nạp và gỡ driver
Nạp module:
modprobe: Tiện ích dùng để nạp trình điều khiển vào kernel:
modprobe mini2440_hello_module
Giống với insmod
Gỡ module:
modprobe –r:
modprobe -r mini2440_hello_module
Hoặc dùng rmmod mini2440_hello_module
Xem danh sách module đã nạp:
lsmod
14. Thực hành Device Driver
Ngoài module_init và module_exit, cần thêm các hàm để giao tiếp với
chương trình:
open(): chuẩn bị cho các thao tác tiếp theo sau khi driver đã được tải
release(): dọn dẹp sau khi thao tác xong
ioctl(): gọi hệ thống đặc biệt để thực hiện các giao tiếp không tiêu
chuẩn
15. Device Nodes và lệnh mknod
Device node: là tệp đặc biệt đại diện cho thiết bị trong Linux.
Các node được đặt trong thư mục /dev
Được ánh xạ với trình điều khiển thông qua:
o Major number (12-bit): ánh xạ node đến driver
o Minor number (20-bit): cho thiết bị biết giao diện đang được
truy cập
Tạo device node:
mknod /dev/hello1 c 234 0
o c: tạo thiết bị kiểu ký tự
o 234: major number đã đăng ký với kernel
o 0: minor number (chưa đăng ký)
16. Cách sử dụng device driver
Gọi hàm open()
Gọi các lệnh theo nhu cầu
17. Linux Client Driver
Client driver là loại driver tương tác với thiết bị phần cứng cụ thể.
Xây dựng trình điều khiển client trên Raspberry Pi
Bước 1: Cài đặt kernel header
sudo apt update
sudo apt install raspberrypi-kernel-headers