前言
STM32MP1是意法半导体推出的第一款MPU,它家的STM32系列MCU搞的不错,资料什么挺多,所以平时用的也蛮多,所以它家出的MPU也想体验下。
这篇文章将以官方的STM32MP157F-DK2套件为基础,参考官方的wiki,进行体验使用,并对相关过程做个记录。
https://wiki.stmicroelectronics.cn/stm32mpu/wiki/Getting_started/STM32MP1_boards/STM32MP157x-DK2
基础准备
系统环境
下载安装Ubuntu Desktop(这里使用版本为20.04.4):
https://ubuntu.com/download/desktop
安装完成后进行基础环境安装与设置:
sudo apt update
sudo apt install -y build-essential
以下为应用与内核开发需要的环境安装与设置:
sudo apt install -y gawk git-core diffstat texinfo gcc-multilib chrpath socat cpio python3-pip python3-pexpect xz-utils debianutils iputils-ping python3-git python3-jinja2 libegl1-mesa libsdl1.2-dev pylint3 pylint xterm
sudo apt install -y xsltproc docbook-utils fop dblatex xmlto
sudo apt install -y libmpc-dev libgmp-dev
sudo apt install -y libncurses5 libncurses5-dev libncursesw5-dev libssl-dev linux-headers-generic u-boot-tools device-tree-compiler bison flex libyaml-dev libmpc-dev libgmp-dev
sudo apt install -y python-is-python3
# 设置使MMC支持分为16个分区
echo 'options mmc_block perdev_minors=16' > /tmp/mmc_block.conf
sudo mv /tmp/mmc_block.conf /etc/modprobe.d/mmc_block.conf
硬件连接
硬件连接如下图所示:
特别需要注意的是使用的电源(5V3A)、供电的USB线、通讯的USB线品质不能太差,不然可能系统镜像烧录过程中会出错。
系统镜像烧录测试
ST官方提供了测试用的系统镜像,使用ST的烧录工具可以烧录镜像到存储器中。烧录工具有Linux、Windows、Mac版本的,选择合适的平台进行即可。
烧录是通过 USB OTG 那个口进行的(DFU模式)。需要注意的是烧录过程中设备会断开重新连接,如果使用虚拟机的话需要把这个USB设备设置为自动转到虚拟机或是在重新连接的过程中手动转到虚拟机。
下面是Linux下系统镜像烧录测试过程:
STM32CubeProgrammer安装
STM32CubeProgrammer用来将系统二进制文件烧录到TF卡或eMMC中,可以从下面选择合适的版本下载:
https://www.st.com/en/development-tools/stm32cubeprog.html
我这里通过Ubuntu自带的浏览器下载,得到的 en.stm32cubeprg-lin_v2-10-0.zip
文件位于 ~/Downloads/
目录下。
接下来进行安装:
# 建立STM32CubeProgrammer安装目录
mkdir -p ~/mp157/tools/prog
# 解压与安装
cd ~/Downloads/
unzip en.stm32cubeprg-lin_v2-10-0.zip
./SetupSTM32CubeProgrammer-2.10.0.linux
# 安装时选择上面建立的安装目录,其它默认即可
允许USB相关功能:
# sudo apt install libusb-1.0-0
cd ~/mp157/tools/prog/Drivers/rules/
sudo cp *.* /etc/udev/rules.d/
导出到环境变量方便使用:
# 下面方式是临时的,每次打开终端都需要重新设置
export PATH=$HOME/mp157/tools/prog/bin:$PATH
# 设置成功的话使用 STM32_Programmer_CLI --h 可以看到软件信息
系统镜像烧录
从下面地址下载ST官方提供的系统镜像:
https://www.st.com/content/st_com/en/products/embedded-software/mcu-mpu-embedded-software/stm32-embedded-software/stm32-mpu-openstlinux-distribution/stm32mp1starter.html
我这里通过Ubuntu自带的浏览器下载,得到的 en.FLASH-stm32mp1-openstlinux-5-10-dunfell-mp1-21-11-17_tar.xz
文件位于 ~/Downloads/
目录下。
mkdir -p ~/mp157/ecosystem/starter
cd ~/mp157/ecosystem/starter
mv ~/Downloads/en.FLASH-stm32mp1-openstlinux-5-10-dunfell-mp1-21-11-17_tar.xz ./
tar xvf en.FLASH-stm32mp1-openstlinux-5-10-dunfell-mp1-21-11-17_tar.xz
# 官方的系统固件与烧录配置等都在解压得到的目录中
烧录前将开发板背面的两个拨码开关都拨到OFF位置,然后按正面的RESET按钮进行复位。接着启动烧录工具:
STM32CubeProgrammer
连接设备,打开下面目录中对应的烧录配置文件(.tsv):
~/mp157/ecosystem/starter/stm32mp1-openstlinux-5.10-dunfell-mp1-21-11-17/images/stm32mp1/flashlayout_st-image-weston/
然后二进制文件路径选择下面这个:
~/mp157/ecosystem/starter/stm32mp1-openstlinux-5.10-dunfell-mp1-21-11-17/images/stm32mp1/
最后点击 Download
进行烧录即可:
烧录过程比较漫长,请耐心等待。
烧录完成后将开发板背面的两个拨码开关都拨回ON位置,然后按正面的RESET按钮进行复位。
系统将正常启动显示开机画面,初次启动时接着将黑屏几分钟进行初始化,完成后会在屏幕上显示文章开头图片中画面。
如果STLink那个USB口使用数据线连接到电脑的话会在电脑上有一个串口,使用终端工具进行连接的话会在这里打印出启动日志。也可以通过这里与系统进行交互:
应用与内核开发
SDK安装
从下面地址下载ST官方提供的SDK(SDK中包含编译工具链和库文件):
https://www.st.com/content/st_com/en/products/embedded-software/mcu-mpu-embedded-software/stm32-embedded-software/stm32-mpu-openstlinux-distribution/stm32mp1dev.html
我这里通过Ubuntu自带的浏览器下载,得到的 en.SDK-x86_64-stm32mp1-openstlinux-5.10-dunfell-mp1-21-11-17.tar.xz
文件位于 ~/Downloads/
目录下。
cd ~/Downloads/
tar xvf en.SDK-x86_64-stm32mp1-openstlinux-5.10-dunfell-mp1-21-11-17.tar.xz
# 建立SDK安装目录
mkdir -p ~/mp157/ecosystem/developer/SDK
# 执行脚本安装SDK
chmod +x stm32mp1-openstlinux-5.10-dunfell-mp1-21-11-17/sdk/st-image-weston-openstlinux-weston-stm32mp1-x86_64-toolchain-3.1.11-openstlinux-5.10-dunfell-mp1-21-11-17.sh
./stm32mp1-openstlinux-5.10-dunfell-mp1-21-11-17/sdk/st-image-weston-openstlinux-weston-stm32mp1-x86_64-toolchain-3.1.11-openstlinux-5.10-dunfell-mp1-21-11-17.sh -d $HOME/mp157/ecosystem/developer/SDK
# 设置SDK
# 下面方式是临时的,每次打开终端都需要重新设置
cd ~/mp157/ecosystem/developer/
source SDK/environment-setup-cortexa7t2hf-neon-vfpv4-ostl-linux-gnueabi
# echo $ARCH
# echo $CROSS_COMPILE
# $CC --version
# echo $OECORE_SDK_VERSION
应用开发
# 建立并进入工程目录
mkdir -p ~/mp157/ecosystem/developer/application/gtk_hello_world_example
cd ~/mp157/ecosystem/developer/application/gtk_hello_world_example/
建立 gtk_hello_world.c
文件(gedit gtk_hello_world.c),内容如下:
#include <gtk/gtk.h>
static void
print_hello (GtkWidget *widget,
gpointer data)
{
g_print ("Hello World\n");
}
static void
activate (GtkApplication *app,
gpointer user_data)
{
GtkWidget *window;
GtkWidget *button;
GtkWidget *button_box;
window = gtk_application_window_new (app);
gtk_window_set_title (GTK_WINDOW (window), "Window");
gtk_window_set_default_size (GTK_WINDOW (window), 200, 200);
button_box = gtk_button_box_new (GTK_ORIENTATION_HORIZONTAL);
gtk_container_add (GTK_CONTAINER (window), button_box);
button = gtk_button_new_with_label ("Hello World");
g_signal_connect (button, "clicked", G_CALLBACK (print_hello), NULL);
g_signal_connect_swapped (button, "clicked", G_CALLBACK (gtk_widget_destroy), window);
gtk_container_add (GTK_CONTAINER (button_box), button);
gtk_widget_show_all (window);
}
int
main (int argc,
char **argv)
{
GtkApplication *app;
int status;
app = gtk_application_new ("org.gtk.example", G_APPLICATION_FLAGS_NONE);
g_signal_connect (app, "activate", G_CALLBACK (activate), NULL);
status = g_application_run (G_APPLICATION (app), argc, argv);
g_object_unref (app);
return status;
}
建立 Makefile
文件(gedit Makefile),内容如下:
PROG = gtk_hello_world
SRCS = gtk_hello_world.c
CLEANFILES = $(PROG)
# Add / change option in CFLAGS and LDFLAGS
CFLAGS += -Wall $(shell pkg-config --cflags gtk+-3.0)
LDFLAGS += $(shell pkg-config --libs gtk+-3.0)
all: $(PROG)
$(PROG): $(SRCS)
$(CC) -o $@ $^ $(CFLAGS) $(LDFLAGS)
clean:
rm -f $(CLEANFILES) $(patsubst %.c,%.o, $(SRCS))
使用 make
进行编译。编译得到的二进制文件可以通过网络传输到开发板中(比如使用 scp gtk_hello_world root@<board ip address>:/usr/local 方式),然后在开发板中运行(比如通过串口终端来运行)。运行运行上面程序会在开发板的屏幕上出现一个带有按钮的窗体:
内核编译
从下面地址下载ST官方提供的Linux内核源码开发包:
https://st.com/content/ccc/resource/technical/sw-updater/firmware2/group0/78/11/85/59/c4/22/46/41/STM32cube_Standard_A7_BSP_components_kernel/files/SOURCES-kernel-stm32mp1-openstlinux-5.10-dunfell-mp1-21-11-17.tar.xz/_jcr_content/translations/en.SOURCES-kernel-stm32mp1-openstlinux-5.10-dunfell-mp1-21-11-17.tar.xz
我这里通过Ubuntu自带的浏览器下载,得到的 en.SOURCES-kernel-stm32mp1-openstlinux-5.10-dunfell-mp1-21-11-17.tar.xz
文件位于 ~/Downloads/
目录下。
# 解压开发包内容
cd ~/mp157/ecosystem/developer/
cp ~/Downloads/en.SOURCES-kernel-stm32mp1-openstlinux-5.10-dunfell-mp1-21-11-17.tar.xz ./
tar xvf en.SOURCES-kernel-stm32mp1-openstlinux-5.10-dunfell-mp1-21-11-17.tar.xz
# 解压内核,打上MP157补丁
cd stm32mp1-openstlinux-5.10-dunfell-mp1-21-11-17/sources/arm-ostl-linux-gnueabi/linux-stm32mp-5.10.61-stm32mp-r2-r0/
tar xvf linux-5.10.61.tar.xz
cd linux-5.10.61
for p in `ls -1 ../*.patch`; do patch -p1 < $p; done
# source $HOME/mp157/ecosystem/developer/SDK/environment-setup-cortexa7t2hf-neon-vfpv4-ostl-linux-gnueabi
# 进行相关设置
make ARCH=arm multi_v7_defconfig "fragment*.config"
for f in `ls -1 ../fragment*.config`; do scripts/kconfig/merge_config.sh -m -r .config $f; done
yes '' | make ARCH=arm oldconfig
# 编译内核和设备树
make ARCH=arm uImage vmlinux dtbs LOADADDR=0xC2000040
# 编译内核模块
make ARCH=arm modules
mkdir -p $PWD/install_artifact/
make ARCH=arm INSTALL_MOD_PATH="$PWD/install_artifact" modules_install
编译完成后后可以使用网络将生成的内容更新到开发板上:
# 更新内核
# scp arch/arm/boot/uImage root@<board ip address>:/boot
# 更新设备树
# scp arch/arm/boot/dts/stm32mp157*.dtb root@<board ip address>:/boot
# 更新内核模块
# rm install_artifact/lib/modules/5.10.61/build install_artifact/lib/modules/5.10.61/source
# find install_artifact/ -name "*.ko" | xargs $STRIP --strip-debug --remove-section=.comment --remove-section=.note --preserve-dates
# scp -r install_artifact/lib/modules/* root@<ip of board>:/lib/modules
以下操作在开发板终端中进行:
# /sbin/depmod -a
# sync
# 重启使所有更改生效
# reboot
内核修改测试
# cd $HOME/mp157/ecosystem/developer/stm32mp1-openstlinux-5.10-dunfell-mp1-21-11-17/sources/arm-ostl-linux-gnueabi/linux-stm32mp-5.10.61-stm32mp-r2-r0/linux-5.10.61/
# 打开内核一个源码进行修改
gedit ./drivers/gpu/drm/stm/drv.c
在打开的文件中添加红框中一条语句:
修改完成后保存推出,然后重新编译内核:
make uImage LOADADDR=0xC2000040
# 编译完成后重新传输内核到开发板
scp arch/arm/boot/uImage root@<board ip address>:/boot
以下操作在开发板终端中进行:
reboot
# 等待重启完成查看刚才修改的打印信息
dmesg | grep -i stm_drm_platform_probe
------END------