- 2024/07/27 添加nvme,bluetoothcli 相关内容
- 2024/10/26 添加使用非pd电源遇到的Usb电流问题
- 2024/12/14更新i2c 写入eeprom , 定制启动动画和开始菜单图标
0. 前车之鉴
0.1 glibc 兼容性问题
刚开始的时候,pi5的板子用了官方的镜像,即 Debian 12 bookworm. 但是交叉编译的镜像使用了Ubuntu 23.10 mantic, 交叉编译了Qt5 和程序后,放到板子上运行时,提示glibc版本不兼容, 是因为 bookworm和ubuntu 23.10的 libc 和libcxx版本不同导致,ubuntu23.10 2.38, bookworm 2.36,后面板子和交叉编译的docker镜像统一之后就ok了
0.2 Qt程序显示不正常,半透明的图形不显示,窗口有黑边
虽然Qt正常编译过了,但是部署到板子上后,程序显示不正常,后经排查,是由于 Qt配置 EGL on X11失败,需要在编译配置/src/qt5/qtbase/mkspecs/devices/linux-rasp-pi4-v3d-g++/qmake.confr
中添加编译选项 -fpermissive
1
|
QMAKE_CXXFLAGS = $$QMAKE_CFLAGS -fpermissive
|
否则qt 源码中的configure工具 生成的EGL on X11 的单元测试会执行失败,导致配置失败
0.3 检测不到I2C
初遇0.1中所述问题时,我把板子和docker环境的系统都 刷成ubuntu 23.10,之后板子一直检测不到i2c,叫大师帮忙检测硬件接线问题,无果,用示波器测量波形,正常。其他硬件没有测试,但应该也是有问题的,是因为官方虽然给了ubuntu23.10的镜像,但却没有预装硬件相关的工具,例如i2cdetect, 于是我用apt安装了一个,于是不能正常工作 ,如果克隆内核源码,单独编译工具应该也可以行得通,但我解决的方法简单粗暴,把板子和docker的系统都换为bookworm了,bookworm的工具是齐全的。
0.4 GPIO C++编码后,不能正常初始化,提示系统不是树莓派
由于 PI5 做了很大的变更,所以GPIO相关的系统工具虽然内置了,但并不能适用 于pi5,pigpio在 /usr/include和/usr/lib中头文件库可以正常编译,链接,但编好的程序会提示初始化失败,解决的方法是使用开始的源 libgpiod,不要使用pigpio
https://github.com/joan2937/pigpio/issues/589
1. I2C
树莓波5支持3路i2c通讯,默认只打开 一组,即pin3,pin5,通过修改/boot/fireware/config.txt可以打开其他两路,后面会简单介绍一下,目前我的项目只用了一路,所以使用默认配置 即可。
![image-20240311173712795](image-20240311173712795.png)
也可以参考下图, 标注4的是只有raspberry pi 4才有的功能, 没有标注4的,表示raspberry pi 5也可以使用
![image-20240811164856744](image-20240811164856744.png)
2.1配置
1
2
|
sudo raspi-config
找到i2c的选项,切换为打开
|
也可以直接修改配置 文件
/boot/fireware/config.txt
1
2
3
4
5
6
7
8
|
#省略
dtparam=i2c_arm=on#默认
dtparam=spi=on #默认
#配置i2c 0 为管脚x和y ,xy需要查看官方文档确定支持i2c的管脚号再配置
#dtoverlay=i2c0,pins_x_y
#省略
|
2.2 bookworm配套i2c工具
编码之前,可以使用这些工具验证一下 设备是否正常
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
|
# 枚举i2c 总线
dv@rsap5:/opt/dv_app $ i2cdetect -l
i2c-11 i2c 107d508200.i2c I2C adapter
i2c-12 i2c 107d508280.i2c I2C adapter
#由于没有开光机,所以i2c-1没有显示出来
# 查看i2c-1 上的设备
dv@rsap5:/opt/dv_app $ i2cdetect -y 1
0 1 2 3 4 5 6 7 8 9 a b c d e f
00: -- -- -- -- -- -- -- --
10: -- -- -- -- -- -- -- -- -- -- -- 1b -- -- -- --
20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
70: -- -- -- -- -- -- -- --
#如果光机有上电的放在,应该是这样,1b表示光机的设备总线地址
# 查看设备0x1b中寄存器的值
i2cdump -y 1 0x1b
# 获取设备0x1b上寄存器0x2ff的值
i2cget -y 1 0x1b 0x2f
# 设置i2c上0x1b设备0x2f寄存器的值为0xff
i2cset -y 1 0x1b 0x2f 0xff
|
2.3 编码
如果使用bookworm, 这些头文件 应该就在系统目录
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
|
#include <i2c/smbus.h>
#include <linux/i2c-dev.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include <unistd.h>
void rasp_I2c_helper::private_read()
{
int file;
int adapter_nr = 1;
char filename[20];
snprintf(filename, 19, "/dev/i2c-%d", adapter_nr);
file = open(filename, O_RDWR);
if (file < 0) {
exit(1);
}
int addr = 0x40;
if (ioctl(file, I2C_SLAVE, addr) < 0) {
exit(1);
}
__u8 reg = 0x10;
__s32 res;
res = i2c_smbus_read_word_data(file, reg);
if (res < 0) {
/* ERROR HANDLING: i2c transaction failed */
return;
} else {
/* res contains the read word */
}
}
void rasp_I2c_helper::private_write(l)
{
prism::qt::core::QEventLoopGuard raii(el) ;
//光机命令
std::vector<uint8_t> writeMode = {0x05,0x01}; // solid color
std::vector<uint8_t> writeRgbLedDisable = {0x52,0x00};
std::vector<uint8_t> writeRgbLedEnable = {0x52,0x07};
int file;
int adapter_nr = 1;
char filename[20];
snprintf(filename, 19, "/dev/i2c-%d", adapter_nr);
file = open(filename, O_RDWR);
if (file < 0) {
ZLOGE(tag_) << "i2c open error, dev: " << filename;
return;
}
ZLOGI(tag_) << "i2c open success, dev: " << filename;
int addr = 0x1b;
if (ioctl(file, I2C_SLAVE, addr) < 0) {
ZLOGE(tag_) << "i2c ioctl error, addr: 0x" << std::hex << addr;
return;
}
ZLOGI(tag_) << "i2c ioctl success, addr: 0x" << std::hex << addr;
//writeMode
{
if (write(file, writeMode.data(), writeMode.size()) != static_cast<int>(writeMode.size())) {
ZLOGE(tag_) << "i2c write error:" << "writeMode";
return;
}
ZLOGI(tag_) << "i2c write success:" << "writeMode";
}
//writeRgbLedEnable
{
if (write(file, writeRgbLedEnable.data(), writeRgbLedEnable.size()) != static_cast<int>(writeRgbLedEnable.size())) {
ZLOGE(tag_) << "i2c write error:" << "writeRgbLedEnable";
return;
}
ZLOGI(tag_) << "i2c write success:" << "writeRgbLedEnable";
}
std::this_thread::sleep_for(std::chrono::milliseconds(3000));
//writeRgbLedDisable
{
if (write(file, writeRgbLedDisable.data(), writeRgbLedDisable.size()) != static_cast<int>(writeRgbLedDisable.size())) {
ZLOGE(tag_) << "i2c write error:" << "writeRgbLedDisable";
return;
}
ZLOGI(tag_) << "i2c write success:" << "writeRgbLedDisable";
}
std::this_thread::sleep_for(std::chrono::milliseconds(150));
close(file);
}
|
2. GPIO
2.1 bookworm配套GPIO工具
查看pin脚位置
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
|
#查看管脚位置,
dv@rsap5:/opt/dv_app $ pinout
Description : Raspberry Pi 5B rev 1.0
Revision : d04170
SoC : BCM2712
RAM : 8GB
Storage : MicroSD
USB ports : 4 (of which 2 USB3)
Ethernet ports : 1 (1000Mbps max. speed)
Wi-fi : True
Bluetooth : True
Camera ports (CSI) : 2
Display ports (DSI): 2
,--------------------------------.
| oooooooooooooooooooo J8 : +====
| 1ooooooooooooooooooo : |USB2
| Wi Pi Model 5B V1.0 fan +====
| Fi +---+ +---+ |
| |RAM| |RP1| +====
||p +---+ +---+ |USB3
||c ------- +====
||i SoC |c|c J14 |
( ------- J7|s|s 12 +======
| J2 bat uart 1|i|i oo | Net
| pwr\..|hd|...|hd|o|1|0 +======
`-| |-1o|m0|---|m1|--------------'
J8:
3V3 (1) (2) 5V
GPIO2 (3) (4) 5V
GPIO3 (5) (6) GND
GPIO4 (7) (8) GPIO14
GND (9) (10) GPIO15
GPIO17 (11) (12) GPIO18
GPIO27 (13) (14) GND
GPIO22 (15) (16) GPIO23
3V3 (17) (18) GPIO24
GPIO10 (19) (20) GND
GPIO9 (21) (22) GPIO25
GPIO11 (23) (24) GPIO8
GND (25) (26) GPIO7
GPIO0 (27) (28) GPIO1
GPIO5 (29) (30) GND
GPIO6 (31) (32) GPIO12
GPIO13 (33) (34) GND
GPIO19 (35) (36) GPIO16
GPIO26 (37) (38) GPIO20
GND (39) (40) GPIO21
J2:
RUN (1)
GND (2)
J7:
COMPOSITE (1)
GND (2)
J14:
TR01 TAP (1) (2) TR00 TAP
TR03 TAP (3) (4) TR02 TAP
For further information, please refer to https://pinout.xyz/
|
查看Pin脚功能,状态
例如配置了了串口后,这里会显示哪些pin脚为uart tx 或 rx
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
|
dv@rsap5:/opt/dv_app $ pinctrl
0: ip pu | hi // ID_SDA/GPIO0 = input
1: ip pu | hi // ID_SCL/GPIO1 = input
2: no pu | -- // GPIO2 = none
3: no pu | -- // GPIO3 = none
4: no pu | -- // GPIO4 = none
5: no pu | -- // GPIO5 = none
6: ip pu | hi // GPIO6 = input
7: ip pu | hi // GPIO7 = input
8: op dh pu | hi // GPIO8 = output
9: op dl pd | lo // GPIO9 = output
10: no pd | -- // GPIO10 = none
11: no pd | -- // GPIO11 = none
12: no pd | -- // GPIO12 = none
13: no pd | -- // GPIO13 = none
14: no pd | -- // GPIO14 = none
15: no pd | -- // GPIO15 = none
16: no pd | -- // GPIO16 = none
17: no pd | -- // GPIO17 = none
18: no pd | -- // GPIO18 = none
19: no pd | -- // GPIO19 = none
20: no pd | -- // GPIO20 = none
21: no pd | -- // GPIO21 = none
22: no pd | -- // GPIO22 = none
23: no pd | -- // GPIO23 = none
24: no pd | -- // GPIO24 = none
25: no pd | -- // GPIO25 = none
26: no pd | -- // GPIO26 = none
27: no pd | -- // GPIO27 = none
28: ip pd | lo // PCIE_RP1_WAKE/GPIO28 = input
29: no pu | hi // FAN_TACH/GPIO29 = none
30: no pu | -- // HOST_SDA/GPIO30 = none
31: no pu | -- // HOST_SCL/GPIO31 = none
32: op dh pd | hi // ETH_RST_N/GPIO32 = output
33: no pd | lo // GPIO33 = none
34: op dl pd | lo // CD0_IO0_MICCLK/GPIO34 = output
35: no pd | lo // CD0_IO0_MICDAT0/GPIO35 = none
36: no pd | lo // RP1_PCIE_CLKREQ_N/GPIO36 = none
37: no pd | lo // GPIO37 = none
38: ip pd | hi // CD0_SDA/GPIO38 = input
39: ip pd | hi // CD0_SCL/GPIO39 = input
40: ip pd | hi // CD1_SDA/GPIO40 = input
41: ip pd | hi // CD1_SCL/GPIO41 = input
42: a2 pd | hi // USB_VBUS_EN/GPIO42 = VBUS_EN1
43: a2 pu | hi // USB_OC_N/GPIO43 = VBUS_OC1
44: op dh pd | hi // RP1_STAT_LED/GPIO44 = output
45: a0 pd | hi // FAN_PWM/GPIO45 = PWM1_CHAN3
46: op dl pd | lo // CD1_IO0_MICCLK/GPIO46 = output
47: no pd | lo // 2712_WAKE/GPIO47 = none
48: no pd | lo // CD1_IO1_MICDAT1/GPIO48 = none
49: op dh pd | hi // EN_MAX_USB_CUR/GPIO49 = output
50: no pd | -- // GPIO50 = none
51: no pd | -- // GPIO51 = none
52: no pu | -- // GPIO52 = none
53: no pu | hi // GPIO53 = none
100: ip pd | lo // GPIO0 = input
101: op dh pu | hi // 2712_BOOT_CS_N/GPIO1 = output
102: a6 pn | hi // 2712_BOOT_MISO/GPIO2 = VC_SPI0_MISO
103: a5 pn | hi // 2712_BOOT_MOSI/GPIO3 = VC_SPI0_MOSI
104: a6 pn | lo // 2712_BOOT_SCLK/GPIO4 = VC_SPI0_SCLK
105: ip pd | lo // GPIO5 = input
106: ip pd | lo // GPIO6 = input
107: ip pd | lo // GPIO7 = input
108: ip pd | lo // GPIO8 = input
109: ip pd | lo // GPIO9 = input
110: ip pd | lo // GPIO10 = input
111: ip pd | lo // GPIO11 = input
112: ip pd | lo // GPIO12 = input
113: ip pd | lo // GPIO13 = input
114: a1 pd | lo // PCIE_SDA/GPIO14 = SPI_S_MOSI_OR_BSC_S_SDA
115: a1 pd | lo // PCIE_SCL/GPIO15 = SPI_S_SCK_OR_BSC_S_SCL
116: ip pd | lo // GPIO16 = input
117: ip pd | lo // GPIO17 = input
118: ip pd | lo // GPIO18 = input
119: ip pd | lo // GPIO19 = input
120: ip pu | hi // PWR_GPIO/GPIO20 = input
121: ip pd | lo // 2712_G21_FS/GPIO21 = input
122: ip pd | lo // GPIO22 = input
123: ip pd | lo // GPIO23 = input
124: a3 pn | lo // BT_RTS/GPIO24 = UART_RTS_0
125: a4 pu | lo // BT_CTS/GPIO25 = UART_CTS_0
126: a4 pn | hi // BT_TXD/GPIO26 = UART_TXD_0
127: a4 pu | hi // BT_RXD/GPIO27 = UART_RXD_0
128: op dh pd | hi // WL_ON/GPIO28 = output
129: op dh pd | hi // BT_ON/GPIO29 = output
130: a4 pn | lo // WIFI_SDIO_CLK/GPIO30 = SD2_CLK
131: a4 pu | hi // WIFI_SDIO_CMD/GPIO31 = SD2_CMD
132: a4 pd | hi // WIFI_SDIO_D0/GPIO32 = SD2_DAT0
133: a3 pu | hi // WIFI_SDIO_D1/GPIO33 = SD2_DAT1
134: a4 pn | hi // WIFI_SDIO_D2/GPIO34 = SD2_DAT2
135: a3 pn | hi // WIFI_SDIO_D3/GPIO35 = SD2_DAT3
200: ip pd | hi // RP1_SDA/AON_GPIO0 = input
201: ip pd | hi // RP1_SCL/AON_GPIO1 = input
202: op dh pd | hi // RP1_RUN/AON_GPIO2 = output
203: op dh pd | hi // SD_IOVDD_SEL/AON_GPIO3 = output
204: op dh pd | hi // SD_PWR_ON/AON_GPIO4 = output
205: a6 pu | lo // SD_CDET_N/AON_GPIO5 = SD_CARD_PRES_G
206: ip pu | hi // SD_FLG_N/AON_GPIO6 = input
207: ip pd | lo // AON_GPIO7 = input
208: ip pd | lo // 2712_WAKE/AON_GPIO8 = input
209: op dh pd | hi // 2712_STAT_LED/AON_GPIO9 = output
210: ip pd | lo // AON_GPIO10 = input
211: ip pd | lo // AON_GPIO11 = input
212: ip pd | lo // PMIC_INT/AON_GPIO12 = input
213: a3 pd | hi // UART_TX_FS/AON_GPIO13 = VC_TXD0
214: a3 pd | lo // UART_RX_FS/AON_GPIO14 = VC_RXD0
215: ip pd | lo // AON_GPIO15 = input
216: ip pu | hi // AON_GPIO16 = input
232: a1 -- | hi // HDMI0_SCL/AON_SGPIO0 = HDMI_TX0_BSC_SCL
233: a1 -- | hi // HDMI0_SDA/AON_SGPIO1 = HDMI_TX0_BSC_SDA
234: a1 -- | hi // HDMI1_SCL/AON_SGPIO2 = HDMI_TX1_BSC_SCL
235: a1 -- | hi // HDMI1_SDA/AON_SGPIO3 = HDMI_TX1_BSC_SDA
236: a2 -- | hi // PMIC_SCL/AON_SGPIO4 = BSC_M2_SCL
237: a2 -- | hi // PMIC_SDA/AON_SGPIO5 = BSC_M2_SDA
|
gpiod 常用指令
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
#libgpiod radme中有使用方法,raspberry pi 5 内置了它https://github.com/brgl/libgpiod
gpiodetect #查看可用的gpio芯片
gpioinfo 4 #查看第4块芯片管脚
gpioget 4 29 #配置第4块芯片第29脚为input,并打印其电平状态
gpioset 4 29=0 #置第4块芯片第29脚为output,并打印其电平状态
#下面这种方法是不推荐的方法,sysctl的方式已经被部分系统禁用了,包括pi5
#pi4可能还能用
#/sys/class/gpio/export(只读) 中写入导出的管脚号
# echo 26 >> cat /sys/kernel/debug/gpio
#写入成功后会多一个文件
#/sys/class/gpio/gpio26/value
#这个文件 的值就是管脚的状态
#可以通过 cat /sys/kernel/debug/gpio 打印所有管脚信息状态,
|
2.2 编译libgpiod
gpiod是一个c语言的库,不过有多种语言的绑定,包括c++
两者都是LGPL, 2.1中介绍的好些工具则是GPL, 可以自己编译,也可以直接使用bookworm内置的
我们项目使用c++绑定,c++写的代码相对c来说会比较面向对象
1
2
3
|
mkdir -p ~/source/repos
cd ~/source/repos
git clone https://github.com/brgl/libgpiod.git
|
配置
1
|
./autogen.sh --enable-tools=yes --prefix=/usr
|
配置可能会失败,会提示需要安装几个库, 安装好就可以正常配置了
然后进入bindings/cxx
编译,安装
1
2
3
|
cd bindings/cxx
sudo make
sudo make install
|
安装后需要手动把cxx绑定的头文件复制进去/usr/include里,不知道是不是姿势不对,只复制了c的头文件
然后把sysroot同步到交叉编译的docker镜像中就可以编码了
2.3 编码
github repo中也有example,我就直接复制我工程里的了
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
|
#include </sysroot/usr/include/gpiod.hpp>
void rasp_gpio_helper::async_watch_line_value()
{
/*
* Assume a button connecting the pin to ground, so pull it up and
* provide some debounce.
*/
auto request = ::gpiod::chip(chip_path)
.prepare_request()
.set_consumer("async-watch-line-value")
.add_line_settings(
il_ofsets,
::gpiod::line_settings()
.set_direction( ::gpiod::line::direction::INPUT)
.set_edge_detection( ::gpiod::line::edge::BOTH)
.set_bias(::gpiod::line::bias::PULL_UP)
.set_debounce_period( std::chrono::milliseconds(10)))
.do_request();
gpiod::edge_event_buffer event_buffer = gpiod::edge_event_buffer(1);
struct pollfd poll_fd;
poll_fd.fd = request.fd();
poll_fd.events = POLLIN;
while (m_poll_flag) {
int ret = poll(&poll_fd,1,1);
if(ret != -1)
{
if(poll_fd.revents & POLLPRI)
{
request.read_edge_events(event_buffer);
for (const gpiod::edge_event& event : event_buffer)
{
::std::cout << "offset: " << event.line_offset()
<< " type: " << ::std::setw(7)
<< ::std::left << edge_event_type_str(event)
<< " event #" << event.line_seqno()
<< ::std::endl;
}
}
}
else
ZLOGE(tag_) << "async watch line value poll error";
}
}
void rasp_gpio_helper::async_write_line_value()
{
auto request =
::gpiod::chip(chip_path)
.prepare_request()
.set_consumer("toggle-multiple-line-values")
.add_line_settings(
ol_ofsets,
::gpiod::line_settings().set_direction(
::gpiod::line::direction::OUTPUT))
.set_output_values(o_values)
.do_request();
struct pollfd poll_fd;
poll_fd.fd = request.fd();
poll_fd.events = POLLOUT;
while(m_poll_flag)
{
int ret = poll(&poll_fd,1,1);
if(ret != -1)
{
request.set_values(ol_ofsets, o_values);
}
else
ZLOGE(tag_) << "async watch line value poll error";
}
}
|
2.4 配置权限
1
2
3
|
cat << EOF > /etc/udev/rules.d/99-gpio-rules
SUBSYSTEM=="gpio", KERNEL=="gpiochip4", OWNER="dv", GROUP="root", MODE="0660"
EOF
|
3 . PWM调制脉冲
3.1 Installation
- On the Raspberry Pi, add
dtoverlay=pwm-2chan
to /boot/config.txt
. This defaults to GPIO_18
as the pin for PWM0
and GPIO_19
as the pin for PWM1
.
- Alternatively, you can change
GPIO_18
to GPIO_12
and GPIO_19
to GPIO_13
using dtoverlay=pwm-2chan,pin=12,func=4,pin2=13,func2=4
.
- On the Pi 5, use channels 0 and 1 to control GPIO_12 and GPIO13, respectively; use channels 2 and 3 to control GPIO_18 and GPIO_19, respectively
- On all other models, use channels 0 and 1 to control GPIO-18 and GPIO_19, respectively
- Reboot your Raspberry Pi.
- You can check everything is working on running
lsmod | grep pwm
and looking for pwm_bcm2835
- Install this library:
sudo pip3 install rpi-hardware-pwm
3.2 Examples
For Rpi 1,2,3,4, use chip=0; For Rpi 5, use chip=2
1
2
3
4
5
6
7
8
9
|
from rpi_hardware_pwm import HardwarePWM
pwm = HardwarePWM(pwm_channel=0, hz=60, chip=0)
pwm.start(100) # full duty cycle
pwm.change_duty_cycle(50)
pwm.change_frequency(25_000)
pwm.stop()
|
History
The original code is from jdimpson/syspwm, We’ve updated it to Python3 and
made it look like the RPi.GPIO
library’s API (but more Pythonic than that.), and we use it in Pioreactor bioreactor system.
4 . NVME启动
4.1 方式一:rasp-config
使用rasp-bian系统的话,有一个名为rasp-config
的工具,可以进入类似bios的界面,选择一些cli工具配置,其中有一个boot order, 进入后可以选择nvme优先于emmc,sd或usb
配置时可能会失败, 提示说少一个eeprom相关的apt包没有安装最新的版本, 按提示安装一下就可以
4.2 方式一, 修改config.txt
4.2.1 pcie接口接单个设备
在/boot/fireware/config.txt
末尾添加
1
2
3
4
5
6
7
8
|
# Add to bottom of /boot/firmware/config.txt
dtparam=pciex1
# Note: You could also just add the following (it is an alias to the above line)
# dtparam=nvme
# Optionally, you can control the PCIe lane speed using this parameter
dtparam=pciex1_gen=2 #单个pcie设备,这里可以使用gen3, gen2可达450mb/s,gen3可达 900mb/s
|
42.2 pcie 接口通过switcher 接两个pcie设备
我们的项目中,除了外接一块nvme m2 ssd
之外,还有一个pcie接口的 ai推理硬件模块
这时候如果3.2.1 pcie中的配置方法, 引导程序会不知道要从哪个位置启动系统,所以/boot/fireware/config.txt
需要再添加
1
2
3
|
# /boot/fireware/config.txt
dtparam=pciex1_no_l0s=on
|
然后设置EEPROM
1
2
3
4
|
sudo ≈rpi-eeprom-config --edit # 这将以nano 打开配置文件编辑
#如果想使用vim进行编辑
#sudo EDITOR=vim rpi-eeprom-config --edit
|
把原来的配置
1
2
3
4
|
[all]
BOOT_UART=1
POWER_OFF_ON_HALT=0
BOOT_ORDER=0xf461
|
修改为
1
2
3
4
5
|
# Change the BOOT_ORDER line to the following:
BOOT_ORDER=0xf416
# Add the following line if using a non-HAT+ adapter:
PCIE_PROBE=1
|
使用官方刷系统的工具把系统刷进nvme后, 接好之后,启动后可以使用下面的命令查看系统是否挂载到nvme
原来系统挂载在emmc sd卡上
1
2
3
4
5
6
7
8
9
|
dv@rsap5:/boot/firmware $ df -h
Filesystem Size Used Avail Use% Mounted on
udev 3.8G 0 3.8G 0% /dev
tmpfs 805M 6.2M 799M 1% /run
/dev/mmcblk0p2 29G 11G 18G 38% /
tmpfs 4.0G 496K 4.0G 1% /dev/shm
tmpfs 5.0M 48K 5.0M 1% /run/lock
/dev/mmcblk0p1 510M 74M 437M 15% /boot/firmware
tmpfs 805M 144K 805M 1% /run/user/1000
|
正确修改后,上面的mmcblk应该变为nvme
5 使用非PD电源
5.1 遇到的问题
raspberry pi 5 官方的电源是带pd协议的,会协商电源参数
我们在我们以raspberry pi 5 为核心板扩展了底板,电源由我们自己提供,遇到两个问题
- usb hub外设供电不足,有概率的导致崩溃
- 接通电源后进入raspbin系统后右上角有气泡提示低电压报警, 如果是在系统中直接使用reboot则不会提示低电压报警
5.2 解决供电问题
在论坛上查找资料后, 据说原因是没有pd协商,所以raspberry 会认为接入的电源是3A的,并且只会给4个usb 总共600mA的电流
如果想使用5A的非PD电源,按下面的步骤添加配置后, usb外设可以有1.6A的电流
编辑config.txt
加入一行
usb_max_current_enable=1
执行下面这条命令配置 eeprom
配置板上的参数文件
1
|
sudo EDITOR=vim rpi-eeprom-config --edit
|
添加一行
这两个配置后可以使用非pd的5v电源,不过仍然会提示低电压报警
在config.txt
添加忽略无视警告的配置,可以去掉低电压的报警
但是我们还是有一个其他的电源报警去不掉,首次上电开机后,将一直停留在右上角,需要人为的点击才消除掉
只需要在任务栏右键设置,把电源和电池的两个图标移除掉就行了
5.3 其他
ps:
raspberry pi的各个电压电流指标可以通过vcgencmd pmic_read_adc
获取
1
|
vcgencmd pmic_read_adc [name] #name是可选的,不填列出所有
|
论坛上一些低电压相关的帖
https://forums.raspberrypi.com/viewtopic.php?t=373841
6. UART
6.1 查看uart管脚
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
#查看
dtoverlay -a |grep uart
dtoverlay -h uart1 #这里显示的gpio号不要当真,具体从pinctrl 命令看
#临时应用
sudo dtoverlay uart0,<param>
#持久化,写到/boot/fireware/config.txt
dtoverlay=uart0
dtoverlay=uart2
#uart0管脚8,10
#uart2管脚7,29
#与rock5c的uart2-m0和uart4-m2 管脚号一样
|
配置 - Raspberry Pi 文档
6.2 测试uart读写的Python脚本
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
|
import serial
import argparse
import threading
import time
from datetime import datetime
def send_data(ser):
while True:
current_time = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
ser.write(current_time.encode())
print("Sent: {}".format(current_time))
time.sleep(5) # 每5秒发送一次
def receive_data(ser):
while True:
if ser.in_waiting > 0:
received_data = ser.readline().decode().strip()
print("Received: {}".format(received_data))
def main():
parser = argparse.ArgumentParser(description="Serial port listener and responder")
parser.add_argument('--port', type=str, required=True, help='Serial port to use, e.g., /dev/ttyUSB0 or COM3')
parser.add_argument('--baudrate', type=int, required=True, help='Baud rate for the serial communication')
args = parser.parse_args()
try:
with serial.Serial(args.port, args.baudrate, timeout=1) as ser:
print("Listening on {} at {} baud.".format(args.port,args.baudrate))
# 创建发送和接收线程
send_thread = threading.Thread(target=send_data, args=(ser,))
receive_thread = threading.Thread(target=receive_data, args=(ser,))
# 启动线程
send_thread.start()
receive_thread.start()
# 确保主线程不会提前结束
send_thread.join()
receive_thread.join()
except serial.SerialException as e:
print("Error: {}".format(e))
if __name__ == "__main__":
main()
|
用法
1
2
3
4
|
python -m venv test
cd text
source bin/active
(test) dv@rsap5:~/test $ sudo python ./tst_uart.py --port /dev/ttyAMA0 --baudrate 115200
|
7. I2C EEPROM
以下方法适用于kernal版本为6.6.20的版本
根据这个帖可知道, 在linux kernal版本6.6.60之前,没有打补丁之前,在设备树源文件中, gpio 0 1管脚的名称为
rp1_i2c0_0_1
之后打了补丁取了一个别名为i2c0_pins
所以从别的设备上复制了设备树源文件过来使用,一直没有初始化成功,没有at24驱动,
创建at24.dts 设备树源文件写入:
/dts-v1/;
/plugin/;
/ {
fragment@0 {
target = <&i2c0>; // Reference to the I2C controller
__overlay__ {
pinctrl-names = "default";
pinctrl-0 = <&rp1_i2c0_0_1>; //kernal 6.6.y可用 &i2c0_pins
clock-frequency = <400000>;
status = "okay";
#address-cells = <1>; // Define addressing scheme
#size-cells = <0>; // No size information for I2C
at24@50 {
compatible = "atmel,24c64", "at24"; // EEPROM compatibility
reg = <0x50>; // I2C address of the EEPROM
pagesize = <32>; // EEPROM page size in bytes
size = <8192>; // EEPROM size in bytes
address-width = <16>; // Address width in bits
};
};
};
};
然后编译设备树,并把编译结果复制到/boot/firmware/overlays
1
2
|
dtc -@ -I dts -O dtb -o at24.dtbo at24.dts
sudo cp at24.dtbo /boot/firmware/overlays/
|
在/boot/firmware/confit.txt中需要打开
dtparam=i2c_arm=on #i2c pin27 28, gpio 0 1
dtparam=i2c_vc=on #
dtoverlay=at24 #at24驱动
重启一下
在/etc/modules
文件中加入一行at24
1
|
echo "at24" | sudo tee -a /etc/modules
|
测试读写eeprom
1
2
3
|
test:
echo 'Hello World' | sudo tee /sys/class/i2c-dev/i2c-0/device/0-0050/eeprom
sudo cat /sys/class/i2c-dev/i2c-0/device/0-0050/eeprom
|
8. 定制开机动画,开始菜单icon
替换这些位置的png图标
1
2
3
4
5
6
7
8
9
10
|
#开始菜单图标
scp ./usr/share/icons/PiXflat/16x16/places/start-here.png root@10.2.1.203:/usr/share/icons/PiXflat/16x16/places/start-here.png
scp ./usr/share/icons/PiXflat/24x24/places/start-here.png root@10.2.1.203:/usr/share/icons/PiXflat/24x24/places/start-here.png
scp ./usr/share/icons/PiXflat/48x48/places/start-here.png root@10.2.1.203:/usr/share/icons/PiXflat/48x48/places/start-here.png
scp ./usr/share/icons/PiXflat/32x32/places/start-here.png root@10.2.1.203:/usr/share/icons/PiXflat/32x32/places/start-here.png
scp ./usr/share/icons/Adwaita/22x22/places/start-here.png
#开机
scp ./usr/share/plymouth/themes/pix/splash.png
root@10.2.1.203:/usr/share/plymouth/themes/pix/splash.png
|
然后update-initramfs -u
固化一下,否则boot阶段还没有挂载上 rootfs, 没办法加载替换的图片.
100. 其他
100.1 隐藏任务栏
~/.config/wf-panel-pi.ini
1
2
|
autohide=true
autohide_duration=500
|
100.2 raspbian蓝牙设备配对
raspberry pi 5 的raspbian系统好像没有蓝牙配的gui程序,不过有一个cli工具,大致用法,
-
开启cli 工具进入交互交互式
-
开启agent +
-
确认设备可以被扫描到
-
扫描设备
-
停止扫描
-
配对
-
退出cli
1
2
3
4
5
6
7
8
9
10
11
12
|
#树莓派蓝牙
bluetoolthctl
agent on
scan on
scan off
pair <device's mac>
quit
|
>> Home
Comments