Skip to content

Commit e146bf0

Browse files
authored
Merge pull request #84 from 916BGAI/dev
add spi st7789 lcd document and example and fix maix_module dl_lib copy error
2 parents c3f20d3 + 27e52f8 commit e146bf0

File tree

6 files changed

+340
-1
lines changed

6 files changed

+340
-1
lines changed

docs/doc/en/modules/spilcd.md

Lines changed: 144 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,144 @@
1+
---
2+
title: MaixCAM MaixPy SPI LCD Screen
3+
update:
4+
- date: 2024-12-02
5+
author: 916BGAI
6+
version: 1.0.0
7+
content: Initial document
8+
---
9+
10+
## Introduction
11+
12+
`MaixCAM` is equipped with three hardware SPI interfaces, allowing you to connect and drive an LCD screen via the SPI interface.
13+
14+
> Currently, only hardware SPI is supported for driving the LCD screen, and it requires modification to the Linux kernel. Software SPI is not supported.
15+
16+
> **Note:** Reading this document requires a certain level of knowledge in kernel compilation, kernel configuration, and kernel driver development.
17+
18+
## Using the ST7789 Screen
19+
20+
This section uses the LCD screen driven by `ST7789` as an example.
21+
22+
### Get the LicheeRV-Nano-Build Source Code
23+
24+
The base system used by `MaixCAM` is [https://github.com/sipeed/LicheeRV-Nano-Build](https://github.com/sipeed/LicheeRV-Nano-Build).
25+
26+
First, pull the latest source code and follow the instructions in the [README](https://github.com/sipeed/LicheeRV-Nano-Build/blob/main/README.md) to build the system.
27+
28+
### Modify the Linux Kernel
29+
30+
First, modify the kernel configuration to enable `FB_TFT` support. You can execute `menuconfig_kernel` in the root directory of LicheeRV-Nano-Build, then use the text-based menu interface to configure it. The configuration option is located at:
31+
32+
`Device Drivers -> Staging drivers -> Support for small TFT LCD display modules`
33+
34+
Select the driver for the screen you are using; in this case, choose the `ST7789` driver, and compile it as a kernel module:
35+
36+
`<M> FB driver for the ST7789 LCD Controller`
37+
38+
> Alternatively, you can directly modify the configuration file `build/boards/sg200x/sg2002_licheervnano_sd/linux/sg2002_licheervnano_sd_defconfig`
39+
> by adding `CONFIG_FB_TFT=y` and `CONFIG_FB_TFT_ST7789=m`.
40+
41+
### Modify the Device Tree
42+
43+
Modify the device tree file `build/boards/sg200x/sg2002_licheervnano_sd/dts_riscv/sg2002_licheervnano_sd.dts`.
44+
45+
```c
46+
&spi2 {
47+
status = "okay";
48+
/delete-node/ spidev@0;
49+
st7789: st7789@0{
50+
compatible = "sitronix,st7789";
51+
reg = <0>;
52+
status = "okay";
53+
spi-max-frequency = <80000000>;
54+
spi-cpol;
55+
spi-cpha;
56+
rotate = <90>;
57+
fps = <60>;
58+
rgb;
59+
buswidth = <8>;
60+
dc = <&porte 20 GPIO_ACTIVE_HIGH>;
61+
reset = <&porte 21 GPIO_ACTIVE_LOW>;
62+
debug = <0>;
63+
};
64+
};
65+
```
66+
This example uses `SPI2`. Since the Wi-Fi module reuses the `SPI2` pins for `SDIO`, we need to modify the pin multiplexing. The method for modification is shown in the example below. After modification, the Wi-Fi functionality will be unavailable.
67+
68+
After modifying the device tree, recompile the image and generate the MaixCAM-compatible image following the instructions in the [Compiling a System for MaixCAM](https://wiki.sipeed.com/maixpy/doc/en/pro/compile_os.html) guide.
69+
70+
### Test the Screen
71+
72+
maixpy example:
73+
74+
```python
75+
from maix import pinmap, display, image, app
76+
import subprocess
77+
78+
try:
79+
result = subprocess.run(['lsmod'], capture_output=True, text=True, check=True)
80+
if "aic8800_bsp" in result.stdout:
81+
subprocess.run(['rmmod', 'aic8800_fdrv'], check=True)
82+
subprocess.run(['rmmod', 'aic8800_bsp'], check=True)
83+
else:
84+
print(f"aic8800 module is not currently loaded, skipping remove.")
85+
except Exception as e:
86+
print(e)
87+
88+
pinmap.set_pin_function("P18", "SPI2_CS")
89+
pinmap.set_pin_function("P22", "SPI2_MOSI")
90+
pinmap.set_pin_function("P23", "SPI2_SCK")
91+
pinmap.set_pin_function("P20", "GPIOP20")
92+
pinmap.set_pin_function("P21", "GPIOP21")
93+
94+
try:
95+
result = subprocess.run(['lsmod'], capture_output=True, text=True, check=True)
96+
if "fb_st7789" in result.stdout:
97+
print(f"module is already loaded, skipping loading.")
98+
else:
99+
subprocess.run(['insmod', '/mnt/system/ko/fb_st7789.ko'], check=True)
100+
print(f"load fb_st7789 success.")
101+
except Exception as e:
102+
print(e)
103+
104+
disp = display.Display(device="/dev/fb0")
105+
print("display init done")
106+
print(f"display size: {disp.width()}x{disp.height()}")
107+
108+
y = 0
109+
while not app.need_exit():
110+
img = image.Image(disp.width(), disp.height(), image.Format.FMT_RGB888)
111+
img.draw_rect(0, y, image.string_size("Hello, MaixPy!", scale=2).width() + 10, 80, color=image.Color.from_rgb(255, 0, 0), thickness=-1)
112+
img.draw_string(4, y + 4, "Hello, MaixPy!", color=image.Color.from_rgb(255, 255, 255), scale=2)
113+
114+
disp.show(img)
115+
116+
y = (y + 1) % disp.height()
117+
```
118+
- First, remove the aic8800 driver module to prevent it from occupying the SDIO bus, which could interfere with the screen driver.
119+
- Modify the pin multiplexing, mapping the corresponding pins to SPI functions. For detailed instructions on how to modify the pin multiplexing using pinmap, refer to [Using PINMAP in MaixCAM](https://wiki.sipeed.com/maixpy/doc/en/peripheral/pinmap.html).
120+
- Then, use `insmod` to load the screen driver module. Check the system logs to confirm that the driver has been successfully loaded. You can also find the generated `fb0` device in the /dev directory.
121+
122+
```bash
123+
[ 1029.909582] fb_st7789: module is from the staging directory, the quality is unknown, you have been warned.
124+
[ 1029.911792] fb_st7789 spi2.0: fbtft_property_value: buswidth = 8
125+
[ 1029.911814] fb_st7789 spi2.0: fbtft_property_value: debug = 0
126+
[ 1029.911828] fb_st7789 spi2.0: fbtft_property_value: rotate = 90
127+
[ 1029.911842] fb_st7789 spi2.0: fbtft_property_value: fps = 60
128+
[ 1030.753696] graphics fb0: fb_st7789 frame buffer, 320x240, 150 KiB video memory, 4 KiB buffer memory, fps=62, spi2.0 at 80 MHz
129+
```
130+
131+
- Using the screen is straightforward. Simply specify the corresponding `fb` device when creating the `Display` instance. After that, you can use the `SPI` screen in the usual way ([MaixPy Screen Usage](https://wiki.sipeed.com/maixpy/doc/en/vision/display.html)).
132+
133+
```python
134+
disp = display.Display(device="/dev/fb0")
135+
```
136+
## Notes
137+
### Screen Timing Issues
138+
The initialization timing for different screens may vary. For example, the `ST7789` includes different versions such as `ST7789V1` and `ST7789V2`, each with potentially different initialization timings. The drivers in the [LicheeRV-Nano-Build](https://github.com/sipeed/LicheeRV-Nano-Build) repository cannot guarantee that they will work properly with every st7789 screen. You can contact the supplier to obtain the specific initialization sequence for your screen and modify the `init_display` function in `LicheeRV-Nano-Build/linux_5.10/drivers/staging/fbtft/fb_st7789.c`.
139+
140+
### Pin Multiplexing
141+
When using `pinmap` to set pin multiplexing, ensure that it matches the pin configuration in the device tree. Generally, the `dc` and `reset` pins for SPI screens are not hardware-bound, so you can specify them arbitrarily in the device tree. Simply choose pins that are not in use on the `MaixCAM` board, and then map them to GPIO functions using `pinmap`.
142+
143+
### Drive Other Screens
144+
Currently, the `fb` device has tested the `st7789` screen driver. There are other screen drivers available for testing in `linux_5.10/drivers/staging/fbtft`. If you encounter any issues, feel free to submit a `commit` or a `PR` to contribute.

docs/doc/en/sidebar.yaml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -176,6 +176,8 @@ items:
176176
label: Power Management Unit
177177
- file: modules/fp5510.md
178178
label: Voice Coil Motor FP5510
179+
file: modules/spilcd.md
180+
label: SPI LCD Screen
179181

180182
- label: Projects
181183
items:

docs/doc/zh/modules/spilcd.md

Lines changed: 144 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,144 @@
1+
---
2+
title: MaixCAM MaixPy SPI LCD 屏幕
3+
update:
4+
- date: 2024-12-02
5+
author: 916BGAI
6+
version: 1.0.0
7+
content: 初版文档
8+
---
9+
10+
## 简介
11+
12+
`MaixCAM` 配备三路硬件SPI接口,可以通过 SPI 接口连接并驱动 LCD 屏幕。
13+
14+
> 目前仅支持通过硬件 SPI 驱动 LCD 屏幕,且需要修改 Linux 内核,不支持软件 SPI。
15+
16+
> **注意:** 阅读本文档需要具备一定的内核编译、内核配置和内核驱动开发的知识。
17+
18+
## 使用 ST7789 屏幕
19+
20+
这里以 `ST7789` 驱动的 LCD 屏为例。
21+
22+
### 获取 LicheeRV-Nano-Build 源代码
23+
24+
`MaixCAM` 使用的基础系统为 [https://github.com/sipeed/LicheeRV-Nano-Build](https://github.com/sipeed/LicheeRV-Nano-Build)
25+
26+
首先拉去最新的源码,按照 [README](https://github.com/sipeed/LicheeRV-Nano-Build/blob/main/README.md) 中的方法完成系统的构建。
27+
28+
### 修改 linux 内核
29+
30+
首先修改内核配置,开启 `FB_TFT` 支持,可以在 LicheeRV-Nano-Build 根目录执行 `menuconfig_kernel` 后使用文本界面菜单进行配置,配置项位于:
31+
32+
`Device Drivers -> Staging drivers -> Support for small TFT LCD display modules`
33+
34+
选择你所使用的屏幕驱动,这里选择 `ST7789` 驱动,并将其编译为内核模块:
35+
36+
`<M> FB driver for the ST7789 LCD Controller`
37+
38+
> 也可以直接修改配置文件 `build/boards/sg200x/sg2002_licheervnano_sd/linux/sg2002_licheervnano_sd_defconfig`
39+
> 添加 `CONFIG_FB_TFT=y``CONFIG_FB_TFT_ST7789=m` 即可。
40+
41+
### 修改设备树
42+
43+
修改设备树文件 `build/boards/sg200x/sg2002_licheervnano_sd/dts_riscv/sg2002_licheervnano_sd.dts`
44+
45+
```c
46+
&spi2 {
47+
status = "okay";
48+
/delete-node/ spidev@0;
49+
st7789: st7789@0{
50+
compatible = "sitronix,st7789";
51+
reg = <0>;
52+
status = "okay";
53+
spi-max-frequency = <80000000>;
54+
spi-cpol;
55+
spi-cpha;
56+
rotate = <90>;
57+
fps = <60>;
58+
rgb;
59+
buswidth = <8>;
60+
dc = <&porte 20 GPIO_ACTIVE_HIGH>;
61+
reset = <&porte 21 GPIO_ACTIVE_LOW>;
62+
debug = <0>;
63+
};
64+
};
65+
```
66+
这里使用的是 `SPI2`,由于 Wi-Fi 模块将 `SPI2` 引脚复用为 `SDIO`,因此我们需要修改引脚的复用功能,修改方法见下面的例程。修改后,Wi-Fi 功能将不可用。
67+
68+
修改完设备树后,重新编译镜像,并根据 [为 MaixCAM 编译系统](https://wiki.sipeed.com/maixpy/doc/zh/pro/compile_os.html) 的方法生成适用于 MaixCAM 的镜像。
69+
70+
### 测试屏幕
71+
72+
maixpy 例程:
73+
74+
```python
75+
from maix import pinmap, display, image, app
76+
import subprocess
77+
78+
try:
79+
result = subprocess.run(['lsmod'], capture_output=True, text=True, check=True)
80+
if "aic8800_bsp" in result.stdout:
81+
subprocess.run(['rmmod', 'aic8800_fdrv'], check=True)
82+
subprocess.run(['rmmod', 'aic8800_bsp'], check=True)
83+
else:
84+
print(f"aic8800 module is not currently loaded, skipping remove.")
85+
except Exception as e:
86+
print(e)
87+
88+
pinmap.set_pin_function("P18", "SPI2_CS")
89+
pinmap.set_pin_function("P22", "SPI2_MOSI")
90+
pinmap.set_pin_function("P23", "SPI2_SCK")
91+
pinmap.set_pin_function("P20", "GPIOP20")
92+
pinmap.set_pin_function("P21", "GPIOP21")
93+
94+
try:
95+
result = subprocess.run(['lsmod'], capture_output=True, text=True, check=True)
96+
if "fb_st7789" in result.stdout:
97+
print(f"module is already loaded, skipping loading.")
98+
else:
99+
subprocess.run(['insmod', '/mnt/system/ko/fb_st7789.ko'], check=True)
100+
print(f"load fb_st7789 success.")
101+
except Exception as e:
102+
print(e)
103+
104+
disp = display.Display(device="/dev/fb0")
105+
print("display init done")
106+
print(f"display size: {disp.width()}x{disp.height()}")
107+
108+
y = 0
109+
while not app.need_exit():
110+
img = image.Image(disp.width(), disp.height(), image.Format.FMT_RGB888)
111+
img.draw_rect(0, y, image.string_size("Hello, MaixPy!", scale=2).width() + 10, 80, color=image.Color.from_rgb(255, 0, 0), thickness=-1)
112+
img.draw_string(4, y + 4, "Hello, MaixPy!", color=image.Color.from_rgb(255, 255, 255), scale=2)
113+
114+
disp.show(img)
115+
116+
y = (y + 1) % disp.height()
117+
```
118+
- 首先移除 aic8800 驱动模块防止其占用 SDIO 总线影响屏幕驱动。
119+
- 修改引脚复用,将对应引脚映射为 SPI 功能,使用 `pinmap` 修改引脚复用的具体方法可以查看 [MaixPy Pinmap 使用介绍](https://wiki.sipeed.com/maixpy/doc/zh/peripheral/pinmap.html)
120+
- 然后使用 `insmod` 加载屏幕驱动模块即可,查看系统日志,可以看到驱动加载成功。在 /dev 目录下也可以找到生成的 `fb0` 设备。
121+
122+
```bash
123+
[ 1029.909582] fb_st7789: module is from the staging directory, the quality is unknown, you have been warned.
124+
[ 1029.911792] fb_st7789 spi2.0: fbtft_property_value: buswidth = 8
125+
[ 1029.911814] fb_st7789 spi2.0: fbtft_property_value: debug = 0
126+
[ 1029.911828] fb_st7789 spi2.0: fbtft_property_value: rotate = 90
127+
[ 1029.911842] fb_st7789 spi2.0: fbtft_property_value: fps = 60
128+
[ 1030.753696] graphics fb0: fb_st7789 frame buffer, 320x240, 150 KiB video memory, 4 KiB buffer memory, fps=62, spi2.0 at 80 MHz
129+
```
130+
131+
- 接下来使用屏幕就很简单了,只需要在创建 `Display` 实例时指定对应的 `fb` 设备即可。然后就可以按照正常方法使用 `SPI` 屏幕了 ([MaixPy 屏幕使用](https://wiki.sipeed.com/maixpy/doc/zh/vision/display.html))。
132+
133+
```python
134+
disp = display.Display(device="/dev/fb0")
135+
```
136+
## 注意事项
137+
### 屏幕时序问题
138+
不同屏幕的初始化时序可能有所不同。例如,`ST7789` 包括 `ST7789V1``ST7789V2` 等不同版本,每个版本的初始化时序可能不同,[LicheeRV-Nano-Build](https://github.com/sipeed/LicheeRV-Nano-Build) 仓库里驱动的不能保证在每个 st7789 屏幕上都能正常使用。具体屏幕的初始化时序可以联系商家获取,并修改 `LicheeRV-Nano-Build/linux_5.10/drivers/staging/fbtft/fb_st7789.c` 中的 `init_display` 函数。
139+
140+
### 引脚复用
141+
在使用 `pinmap` 设置引脚复用时,确保与设备树中的引脚配置一致。一般来说 SPI 屏的 `dc` 引脚和 `reset` 引脚不会和硬件绑定,可以在设备树中任意指定,选择 `MaixCAM` 中未被占用的引脚即可,然后在 `pinmap` 时将其映射为 GPIO 功能。
142+
143+
### 驱动其他屏幕
144+
目前,`fb` 设备已测试了 `st7789` 屏幕驱动。`linux_5.10/drivers/staging/fbtft` 中还有其他屏幕驱动可供测试。如遇问题,欢迎提交 `commit``PR` 做出贡献。

docs/doc/zh/sidebar.yaml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -177,6 +177,8 @@ items:
177177
label: 电源管理单元
178178
- file: modules/fp5510.md
179179
label: 音圈电机 FP5510
180+
file: modules/spilcd.md
181+
label: SPI LCD 屏幕
180182

181183
- label: 项目实战
182184
items:
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
from maix import pinmap, display, image, app
2+
import subprocess
3+
4+
# Please read the MaixPy SPI LCD Screen documentation (https://wiki.sipeed.com/maixpy/doc/zh/modules/spilcd.html) first.
5+
6+
try:
7+
result = subprocess.run(['lsmod'], capture_output=True, text=True, check=True)
8+
if "aic8800_bsp" in result.stdout:
9+
subprocess.run(['rmmod', 'aic8800_fdrv'], check=True)
10+
subprocess.run(['rmmod', 'aic8800_bsp'], check=True)
11+
else:
12+
print(f"aic8800 module is not currently loaded, skipping remove.")
13+
except Exception as e:
14+
print(e)
15+
16+
pinmap.set_pin_function("P18", "SPI2_CS")
17+
pinmap.set_pin_function("P22", "SPI2_MOSI")
18+
pinmap.set_pin_function("P23", "SPI2_SCK")
19+
pinmap.set_pin_function("P20", "GPIOP20")
20+
pinmap.set_pin_function("P21", "GPIOP21")
21+
22+
try:
23+
result = subprocess.run(['lsmod'], capture_output=True, text=True, check=True)
24+
if "fb_st7789" in result.stdout:
25+
print(f"module is already loaded, skipping loading.")
26+
else:
27+
subprocess.run(['insmod', '/mnt/system/ko/fb_st7789.ko'], check=True)
28+
print(f"load fb_st7789 success.")
29+
except Exception as e:
30+
print(e)
31+
32+
disp = display.Display(device="/dev/fb0")
33+
print("display init done")
34+
print(f"display size: {disp.width()}x{disp.height()}")
35+
36+
y = 0
37+
while not app.need_exit():
38+
img = image.Image(disp.width(), disp.height(), image.Format.FMT_RGB888)
39+
img.draw_rect(0, y, image.string_size("Hello, MaixPy!", scale=2).width() + 10, 80, color=image.Color.from_rgb(255, 0, 0), thickness=-1)
40+
img.draw_string(4, y + 4, "Hello, MaixPy!", color=image.Color.from_rgb(255, 255, 255), scale=2)
41+
42+
disp.show(img)
43+
44+
y = (y + 1) % disp.height()

tools/maix_module/compile/gen_binary.cmake

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,9 +27,12 @@ foreach(item ${g_dynamic_libs})
2727
endif()
2828
endforeach()
2929

30+
file(STRINGS "${PROJECT_PATH}/module_name.txt" ALL_LINES)
31+
list(GET ALL_LINES 0 MODULE_NAME)
32+
3033
if(final_dynamic_libs)
3134
set(copy_dynamic_libs_cmd COMMAND mkdir -p ${PROJECT_BINARY_DIR}/dl_lib && cp ${final_dynamic_libs} ${PROJECT_BINARY_DIR}/dl_lib)
32-
set(copy_dynamic_libs_cmd2 COMMAND mkdir -p ${PROJECT_PATH}/maix/dl_lib && cp -r ${PROJECT_BINARY_DIR}/dl_lib/* ${PROJECT_PATH}/maix/dl_lib)
35+
set(copy_dynamic_libs_cmd2 COMMAND mkdir -p ${PROJECT_PATH}/${MODULE_NAME}/dl_lib && cp -r ${PROJECT_BINARY_DIR}/dl_lib/* ${PROJECT_PATH}/${MODULE_NAME}/dl_lib)
3336
else()
3437
set(copy_dynamic_libs_cmd)
3538
set(copy_dynamic_libs_cmd2)

0 commit comments

Comments
 (0)