4092 views|1 replies

1

Posts

0

Resources
The OP
 

OpenHarmony 3.0 porting to Raspberry Pi 4B - learning record [Copy link]

This post was last edited by hazhuzhu on 2021-12-29 00:13

Preface

The following is a detailed process record of learning OpenHarmony3.0 Raspberry Pi 4B porting, with main references: Official Porting Guide , Official Raspberry Pi 3B Porting , Community Leader Raspberry Pi 4B Porting , LineageOS Raspberry Pi Porting Project: lineage-rpi , Android Raspberry Pi Porting Project: android-rpi .

The touch and display are realized, and the physical button shutdown function is added. I hope it can help embedded newbies like me who are first exposed to transplantation.

The following steps are performed on Ubuntu 20.04 LTS. The OHOS 3.0 LTS source code is extracted from the official mirror (the latest source code downloaded using repo has many changes, and the following steps are no longer applicable). Set the project root directory to OpenHarmony, and the console is in this directory by default. The ported system is OHOS standard, and the kernel is Linux-5.10.

Defining the development board

According to the official porting manual, the source code directory and several concepts that often appear in the code are explained and assigned in the context of this process:

product

device

vendor

socvendor

meaning

Embedded Product Name

SOC Name

Product Manufacturers

SOC Manufacturers

Examples

rpi4

bcm2711

raspberry

brcm

Therefore, we first define the SOC. Create the file OpenHarmony/productdefine/common/device/bcm2711.json:

{
"device_name": "bcm2711",
"device_company": "brcm",
"target_os": "ohos",
"target_cpu": "arm",
"kernel_version": "",
"device_build_path": "device/brcm/build"
}

Currently OHOS only supports arm.

Next, define the product. Create the file OpenHarmony/productdefine/common/products/rpi4.json:

{
"product_name": "rpi4",
"product_company": "raspberry",
"product_device": "bcm2711",
"version": "2.0",
"type": "standard",
"product_build_path": "device/brcm/build",
"parts": {
...
"brcm_products:brcm_products":{},
...
}
}

Among them, the ... part is copied from Hi3516DV300.json in the same directory, and the "hisilicon_products:hisilicon_products":{}, is changed to "brcm_products:brcm_products":{},.

brcm_products represents the subsystem of the kernel build. We need to define it in OpenHarmony/build/subsystem_config.json and add the key-value pair:

"brcm_products":{
"project": "hmf/brcm_products",
"path": "device/brcm/bcm2711/build",
"name": "brcm_products",
"dir": "device/brcm"
},

Create a compilation configuration component

Then create a compilation configuration component in OpenHarmony/device in the same way as ./hisilicon/hi3516dv300. Directory structure:

device
└── brcm
├── bcm2711
│ ├── build
│ │ └── rootfs
│ │ ├── BUILD.gn
│ │ └── init.rpi4.cfg
│ └── BUILD.gn
└── build
├── BUILD.gn
└── ohos.build

OpenHarmony/device/brcm/bcm2711/build/rootfs/BUILD.gn

import("//build/ohos.gni")

ohos_prebuilt_etc("init.rpi4.cfg") {
source = "init.rpi4.cfg"
install_images = [ "system" ]
part_name = "brcm_products"
}

group("init_configs") {
deps = [
":init.rpi4.cfg"
]
}

OpenHarmony/device/brcm/bcm2711/build/rootfs/init.rpi4.cfg复制自OpenHarmony/device/hisilicon/hi3516dv300/build/rootfs/init.Hi3516DV300.cfg

OpenHarmony/device/brcm/bcm2711/BUILD.gn

import("//build/ohos.gni")

print("bcm2711_group in")
group("bcm2711_group") {
deps = [
"build/rootfs:init_configs",
"//kernel/linux/build:linux_kernel"
]
}

OpenHarmony/device/brcm/build/BUILD.gn

import("//build/ohos.gni")

group("products_group") {
deps = [
"//device/brcm/bcm2711:bcm2711_group"
]
}

OpenHarmony/device/brcm/build/ohos.build

{
"subsystem": "brcm_products",
"parts": {
"brcm_products": {
"module_list": [
"//device/brcm/build:products_group"
]
}
}
}

Kernel porting

Kernel compilation process

First read OpenHarmony/kernel/linux/build/kernel.mk

$(KERNEL_IMAGE_FILE):
$(hide) echo "build kernel..."
$(hide) rm -rf $(KERNEL_SRC_TMP_PATH);mkdir -p $(KERNEL_SRC_TMP_PATH);cp -arfL $(KERNEL_SRC_PATH)/* $(KERNEL_SRC_TMP_PATH)/
$(hide) cd $(KERNEL_SRC_TMP_PATH) && patch -p1 < $(HDF_PATCH_FILE) && patch -p1 -s -N < $(DEVICE_PATCH_FILE)
ifneq ($(findstring $(BUILD_TYPE), small),)
$(hide) cd $(KERNEL_SRC_TMP_PATH) && patch -p1 < $(SMALL_PATCH_FILE)
endif
$(hide) cp -rf $(KERNEL_CONFIG_PATH)/. $(KERNEL_SRC_TMP_PATH)/
$(hide) $(KERNEL_MAKE) -C $(KERNEL_SRC_TMP_PATH) ARCH=$(KERNEL_ARCH) $(KERNEL_CROSS_COMPILE) distclean
$(hide) $(KERNEL_MAKE) -C $(KERNEL_SRC_TMP_PATH) ARCH=$(KERNEL_ARCH) $(KERNEL_CROSS_COMPILE) $(DEFCONFIG_FILE)
ifeq ($(KERNEL_VERSION), linux-5.10)
$(hide) $(KERNEL_MAKE) -C $(KERNEL_SRC_TMP_PATH) ARCH=$(KERNEL_ARCH) $(KERNEL_CROSS_COMPILE) modules_prepare
endif
$(hide) $(KERNEL_MAKE) -C $(KERNEL_SRC_TMP_PATH) ARCH=$(KERNEL_ARCH) $(KERNEL_CROSS_COMPILE) -j64 uImage
endif

Understand the kernel compilation process:

Generate patch

So first prepare the kernel patch required by Raspberry Pi 4B:

Select the official Raspberry Pi kernel rpi-5.10.y to generate the kernel source patch. Assume that the console is in the project root directory OpenHarmony, and execute the following in sequence:

mkdir ../rpi-kernel && cd $_
git clone git://github.com/raspberrypi/linux -b rpi-5.10.y --depth=1
cd ../OpenHarmony/kernel/linux
diff -uNr linux-5.10/ /home/username/Project/RPI/rpi-kernel/linux/ > bcm2711.patch
mkdir patches/linux-5.10/bcm2711_patch && cp bcm2711.patch $_ && cd $_
cp ../hi3516dv300_patch/hdf.patch ./

Note the diff command:

The actual compilation may be interrupted due to conflicts in the patch process. The solution is:

Generate defconfig

Add and modify based on the official bcm2711_defconfig of Raspberry Pi (currently located in the OpenHarmony directory):

cp ../rpi-kernel/linux/arch/arm/configs/bcm2711_defconfig kernel/linux/config/linux-5.10/arch/arm/configs/bcm2711_standard_defconfig

The main changes are:

Generate method:

Compile script fixes

The source code compilation script generates uImage by default, which requires the Raspberry Pi 4B to boot with u-boot, which is more troublesome. Therefore, change uImage to zImage in kernel.mk, build_kernel.sh, BUILD.gn, and kernel_module_build.sh in the kernel/linux/build/ directory.

In fact, it doesn't matter if you don't modify it. Before finally generating uImage, the kernel will first generate zImage under boot when compiling. You can manually copy it to the image output directory:

cp out/KERNEL_OBJ/kernel/src_tmp/linux-5.10/arch/arm/boot/zImage out/ohos-arm-release/packages/phone/images

Display and touch configuration

show

vi third_party/weston/weston.ini

Finally add:

[output]
name=card0

It doesn't matter if you don't set it. It will be displayed by card0 node by default. If the output node is HDMI-A-1 and needs to be rotated, add:

[output]
name=HDMI-A-1
transform=rotate-90

touch

vi third_party/eudev/rules.d/touchscreen.rules

Modified to:

ATTRS{name}=="WaveShare WS170120", ENV{ID_INPUT}="1", ENV{ID_INPUT_TOUCHSCREEN}="1"
ATTRS{name}=="VSoC keyboard", ENV{ID_INPUT}="1", ENV{ID_INPUT_KEYBOARD}="1"
DRIVERS=="hid-multitouch", ENV{ID_INPUT}="1", ENV{ID_INPUT_TOUCHSCREEN}="1"

The WaveShare WS170120 is the device name obtained by querying /sys/dev/char/xx\:xx/device/uevent after the WaveShare touch screen is plugged into USB. It supports hid-multitouch.

Other Fixes

init.cfg

Initialization configuration file, similar to init.rc in Android

vi /base/startup/init_lite/services/etc/init.cfg

To modify:

- "/etc/init.Hi3516DV300.cfg"
+ "/etc/init.rpi4.cfg"

- "mount ext4 /dev/block/platform/soc/10100000.himci.eMMC/by-name/vendor /vendor wait rdonly barrier=1",
- "mount ext4 /dev/block/platform/soc/10100000.himci.eMMC/by-name/userdata /data wait nosuid nodev noatime barrier=1,data=ordered,noauto_da_alloc"
+ "mount ext4 /dev/block/mmcblk0p3 /vendor wait rdonly barrier=1",
+ "mount ext4 /dev/block/mmcblk0p4 /data wait nosuid nodev noatime barrier=1,data=ordered,noauto_da_alloc"

vendor

Although the HDF driver has not been ported, the relevant files are necessary for the kernel compilation process. Create a new file under OpenHarmony/vendor, and the directory structure is as follows:

vendor
└── raspberry
└── rpi4
└── hdf_config
├── hdf.hcs
├── hdf_test
│ ├── hdf.hcs
│ └── Makefile
├── khdf
│ ├── hdf.hcs
│ └── Makefile
├── Makefile
└── uhdf
└── hdf.hcs

Among them, hdf.hcs are:

root {
module = "default";
}

Makefile is copied from OpenHarmony/vendor/hisilicon/Hi3516DV300/hdf_config/khdf/Makefile

camera.rpi4.gni

Although the camera driver has not been ported, it is necessary for compilation, otherwise an error will be reported:

cp drivers/peripheral/camera/hal/adapter/chipset/gni/camera.rpi3.gni drivers/peripheral/camera/hal/adapter/chipset/gni/camera.rpi4.gni

Image size

The image size can be modified in xxx_image_conf.txt under OpenHarmony/build/ohos/images/mkimage/.

Compile

Execute in the root directory OpenHarmony:

bash build/prebuilts_download.sh

The downloaded third-party open source software compressed package is stored in OpenHarmony_2.0_canary_prebuilts in the same directory as OpenHarmony. When the script uses wget to download mingw-w64, it may trigger a Segmentation fault (core dumped) because the latter is too large. There is no better solution yet. You can only use other download tools to manually download clang-mingw.tar.g z from the Huawei mirror and then put it in.

Compile:

./build.sh --product-name rpi4 --ccache --jobs $(nproc)

Before compiling the kernel, the script will print the compilation command in the console, which is convenient for us to manually compile in the kernel source root directory after an error or after modifying the config. When compiling manually, an error may occur that the environment variable PRODUCT_PATH cannot be found. Manually set it:

export PRODUCT_PATH=vendor/raspberry/rpi4

Make an SD card and boot

Partitioning and formatting

Use fdisk to set up sd card partitions:

sudo fdisk /dev/mmcblk0

step:

Possible final effect (p command):

Device Boot Start End Sector Size Id Type
/dev/mmcblk0p1 * 2048 264191 262144 128M c W95 FAT32 (LBA)
/dev/mmcblk0p2 264192 4458495 4194304 2G 83 Linux
/dev/mmcblk0p3 4458496 5507071 1048576 512M 83 Linux /dev/
mmcblk0p4 5507072 62333951 56826880 27.1G 83 Linux

The corresponding fdisk command execution sequence:

n p 1 +128M n p 2 +2G n p 3 +512M n p t 1 c a 1 w

format:

sudo mkfs.msdos /dev/mmcblk0p1 -n boot
sudo mkfs.ext4 /dev/mmcblk0p2
sudo mkfs.ext4 /dev/mmcblk0p3
sudo mkfs.ext4 /dev/mmcblk0p4

Preparation of boot

Based on the official firmware of Raspberry Pi . Assume that the boot partition /dev/mmcblk0p1 has been mounted to /media/username/boot:

cd ../ && git clone git://github.com/raspberrypi/firmware --depth=1
cp firmware/boot/{overlays,bcm2711-rpi-4-b.dtb,bcm2711-rpi-400.dtb,bcm2711-rpi-cm4.dtb,cmdline.txt,config.txt,fixup4.dat,fixup4x.dat,start4.elf,start4x.elf} /media/username/boot -r
cp OpenHarmony/out/ohos-arm-release/packages/phone/images/zImage /media/username/boot

Modify config.txt:

vi /media/username/boot/config.txt

# Kernel
kernel=zImage

# waveshare touchscreen
max_usb_current=1
hdmi_group=2
hdmi_mode=87
hdmi_cvt 800 480 60 6 0 0 0
hdmi_drive=1

# fake KMS
dtoverlay=vc4-fkms-v3d

enable_uart=1

# output diagnostic information
uart_2ndstage=1

# for hardware power button
dtoverlay=gpio-key,gpio=3,keycode=116,label="POWER"

Modify cmdline.txt:

vi /media/username/boot/cmdline.txt

console=serial0,115200 no_console_suspend root=/dev/mmcblk0p2 elevator=deadline rootwait spidev.bufsiz=65536 androidboot.hardware=rpi4 androidboot.selinux=permissive

Flashing the image

cd OpenHarmony/out/ohos-arm-release/packages/phone/images
sudo dd if=system.img of=/dev/mmcblk0p2 bs=1M
sudo dd if=vendor.img of=/dev/mmcblk0p3 bs=1M
sudo dd if=userdata.img of=/dev/mmcblk0p4 bs=1M

start up

In order for the Weixue touch screen to display successfully, the following three conditions must be met:

Button shutdown

When configuring the kernel to compile defconfig, we enabled CONFIG_KEYBOARD_GPIO to compile gpio-key into the kernel, which is an architecture-independent GPIO key driver. You only need to add the required key child node to the gpio-key node in the device tree to convert the GPIO state change into a key event.

The official Raspberry Pi has already implemented it (see rpi-kernel/linux/arch/arm/boot/dts/overlays/README for details ). You only need to enable it in config.txt:

dtoverlay=gpio-key,gpio=3,keycode=116,label="POWER"

In this way, GPIO3 will be pulled high by default, and when it is grounded, gpio-key will convert it into a key event with a key code value of 116 and output it to /dev/input/event0.

On mainstream Linux distributions (such as Raspbian OS based on Debian), systemd comes with a key event monitoring process. You only need to uncomment HandlePowerKey = ignore in /etc/systemd/logind.conf to achieve physical key (or F5) shutdown.

Although Android and OpenHarmony do not use systemd, they can run services. Therefore, we write a simple daemon program ourselves:

mkdir ../event0reader && cd $_
vi event0reader.c

#include <stdio.h>
#include <linux/input.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>

#define DEV_PATH "/dev/input/event0"

int main()
{
int keys_fd;
int ret=0;
struct input_event t;
keys_fd=open(DEV_PATH, O_RDONLY);
if(keys_fd <= 0)
{
printf("open /dev/input/event0 device error!\n");
return -1;
}
while(1)
{
if(read(keys_fd, &t, sizeof(t)) == sizeof(t))
{
if(t.type==EV_KEY && t.code==116 && t.value==1)
{
ret=system("/bin/reboot shutdown");
if (ret == -1)
{
printf("failed to shutdown!\n");
return -1;
}
}
}
usleep(100000);
}
close(keys_fd);
return 0;
}

/bin/reboot is the restart/shutdown program that comes with OHOS, and its source code is located in OpenHarmony/base/startup/init_lite/services/cmds/reboot/init_cmd_reboot.c.

Compile with static link library to ensure the successful operation of the program. Assume that the system partition /dev/mmcblk0p2 has been mounted to /media/username/_:

arm-linux-gnueabihf-gcc event0reader.c -o myservice -static
sudo cp myservice /media/username/_/system/bin/
sudo chmod 777 /media/username/_/system/bin/myservice
sudo chgrp 2000 /media/username/_/system/bin/myservice

When OHOS is initialized, the kernel will traverse all initialization configurations under /system/etc/init/. We write a corresponding myservice.cfg in this directory:

sudo vi /media/username/_/system/etc/init/myservice.cfg

{
"jobs" : [{
"name" : "post-fs",
"cmds" : [
"start myservice_shutdown"
]
}
],
"services" : [{
"name" : "myservice_shutdown",
"path" : ["/system/bin/myservice"],
"uid" : "root",
"gid" : ["system", "shell"]
}
]
}

When we start the kernel we observe the following information:

# dmesg |grep myservice
[ 3.722287] [pid=1][init_read_cfg.c:110][Init][INFO] ReadCfgs :/system/etc/init/myservice.cfg from /system/etc/init success.
[ 7.558109] [pid=1][param_service.c:263][Init][INFO] SystemWriteParam name init.svc.myservice_shutdown value: running
[ 7.558618] [pid=116][init_service.c:200][Init][INFO] service->name is myservice_shutdown
[ 7.569011] [pid=1][trigger_processor.c:165][Init][INFO] PostParamTrigger init.svc.myservice_shutdown success

This means that myservice has been successfully started and can be shut down using the physical button. Wiring diagram:

poweroff_bb

This post is from Linux and Android

Latest reply

It looks very complicated.   Details Published on 2021-12-29 16:10

7422

Posts

2

Resources
2
 

It looks very complicated.

This post is from Linux and Android
 
Personal signature

默认摸鱼,再摸鱼。2022、9、28

 

Guess Your Favourite
Just looking around
Find a datasheet?

EEWorld Datasheet Technical Support

EEWorld
subscription
account

EEWorld
service
account

Automotive
development
circle

Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号
快速回复 返回顶部 Return list