0

Bringup SSD1306 trên uboot cho openwrt image với Pi4

Để build được U-Boot cho OpenWrt image trên Pi 4, các bạn tham khảo bài này nhé:

https://viblo.asia/p/bringup-uboot-tren-openwrt-image-AoJe8p5341j


Sau khi boot được Pi 4 với U-Boot, công việc của chúng ta bây giờ là thêm tính năng cho màn SSD1306 vào đây.

Ta cần tham khảo flow bring-up SSD1306 trên Linux Kernel.

Mọi người tham khảo code ở đây nhé:

Thật ra đây cũng không phải driver mình viết từ đầu đâu, mình cóp nhặt trên mạng về rồi sửa thôi 😃)

1. Trace flow i2c_master_send() trong Linux Kernel

Anh em vào đọc code của ssd1306_driver, cụ thể là file ssd1306_lib.c, sẽ thấy một điều:

Gần như mọi hàm đều được xây dựng từ hàm i2c_master_send().

Đây là một API có sẵn trong Linux. Bình thường nếu viết driver trên Linux thì chỉ cần gọi API này ra dùng.

Ta trace lần lượt hàm này:

i2c_master_send
    --> i2c_transfer_buffer_flags (include/linux/i2c.h)
        --> i2c_transfer (drivers/i2c/i2c-core-base.c)
            --> __i2c_transfer (drivers/i2c/i2c-core-base.c)
                --> adap->algo->master_xfer (drivers/i2c/i2c-core-base.c)

Dòng cuối cùng này khá quan trọng:

adap->algo->master_xfer

Tức là một function pointer có tên master_xfer sẽ được gọi.

Nếu anh em nào có kinh nghiệm trace code Linux Kernel thì đều biết function pointer thường nằm trong một struct có sẵn, sau đó được implement kiểu như:

.master_xfer = <func>

OK, vậy bây giờ ta trace tiếp.

cd drivers
grep -r ".master_xfer"

Ta sẽ thấy trong thư mục drivers/i2c/busses có rất nhiều dòng theo kiểu:

.master_xfer = ...

Vậy câu hỏi đặt ra là:

Làm sao biết chính xác .master_xfer mà mình cần là cái nào?

Đây chính là một cơ chế khá kinh điển trong Linux Kernel.

Anh em chú ý sẽ thấy mỗi .master_xfer nằm trong một file .c riêng biệt.

Điều đó có nghĩa là:

File .c nào được build thì .master_xfer được định nghĩa trong file đó chính là implementation mà kernel sử dụng.

Vậy ta tiếp tục trace:

drivers/i2c/busses/Makefile

Trong file này, mỗi file .c sẽ được build thành .o khi một CONFIG_* tương ứng được bật.

Vậy bây giờ chỉ cần kiểm tra trong .config của kernel xem config nào đang được bật.

Với Raspberry Pi 4:

CONFIG_I2C_BCM2835

sẽ được bật, từ đó:

i2c-bcm2835.o

được build.

=> File .c mà chúng ta cần tìm là:

drivers/i2c/busses/i2c-bcm2835.c

2. Port BCM2835 I2C sang U-Boot

OK, đến đây câu hỏi đặt ra là:

Một file như i2c-bcm2835.c đã được U-Boot support sẵn chưa?

Câu trả lời là chưa.

Chúng ta cần port phần I2C BCM2835 này vào U-Boot trước.

Hướng dẫn port, anh em có thể tham khảo commit này:

https://github.com/u-boot/u-boot/commit/954d39716a2f06a1e8390c649d723b8feed4fd26

Trong đoạn port này mình có hardcode ở một vài chỗ. Anh em có ý kiến gì thì tích cực comment nhé 😃)


3. Bring-up SSD1306 trên U-Boot

Sau khi port xong BCM2835 I2C, chúng ta sẽ đến bước chính:

Bring-up SSD1306.

3.1. Thêm Device Tree

Anh em thêm node SSD1306 vào Device Tree như sau:

&i2c1 {
    status = "okay";

    ssd1306: ssd1306@3c {
        compatible = "tnt19,ssd1306";
        reg = <0x3c>;
        status = "okay";
    };
};

Ở đây:

0x3c

là địa chỉ I2C của màn SSD1306.


3.2. Thêm SSD1306 Driver

Bước này thì gần như là:

Copy driver từ Linux sang + thêm cơ chế build driver mới vào U-Boot.

Anh em có thể tham khảo commit này:

https://github.com/u-boot/u-boot/commit/31129834b31f91e2b2b04c3aefe2aa8d0c208970


4. Build và test

OK, xong rồi thì giờ build thôi.

Sau khi build được:

u-boot.bin
bcm2711-rpi-4-b_owrt.dtb

ta lại làm tương tự như phần trước:

  • Thay thế u-boot.bin trong /boot trên board bằng file vừa build.
  • Thay thế bcm2711-rpi-4-b_owrt.dtb trong /boot bằng file vừa build.

Sau đó:

Cắm lại SD card vào Pi 4
        ↓
Boot
        ↓
U-Boot
        ↓
SSD1306
        ↓
Xem kết quả :)


All rights reserved

Viblo
Hãy đăng ký một tài khoản Viblo để nhận được nhiều bài viết thú vị hơn.
Đăng kí