前言
SDK中会做好很多功能,如果对SDK不熟悉那么很可能花很长一段时间进行开发结果发现SDK已经提供了接口。
所以在项目开始前,对SDK进行学习非常有必要。
文档
用户指南
介绍了环境搭建相关内容
本次学习采用的HI3528E开发板主要使用了串口线及网线进行调试。
JTAG虽然也提供了,但是没有用到。一般JTAG用于较为底层(uboot)的功能调试。
uboot是海思官方已经开发好的,在实战和工作当中很少去调试,除非是基于海思的uboot去开发一些更高级的功能。
uboot应用开发指南
提供了uboot移植相关内容指导
SDK中相关脚本学习
目录在Hi3518E V200R001C01SPC030\01.software\board
中
解压开进入文件夹
这两个是脚本文件
scripts中也有一个脚本文件
我们首先需要研究这三个脚本文件
这三个脚本文件的内容是我们整个package中所有内容怎么解压开,怎么去配置编译的,怎么编译uboot,怎么编译内核这些东西的指导,是别人已经做好了的。
我们只要将这三个脚本文件研究清楚,那么我们就能随便玩这个SDK了。
于是我们需要去分析这个脚本文件,然后再根据脚本文件的内容和我们自己的理解去实现一定的功能。
功能方面,从文件名不难看出
- sdk.cleanup——清理
- sdk.unpack——解压
sdk.cleanup阅读
内容如下
#!/bin/sh
source scripts/common.sh
ECHO "Cleanup SDK" COLOR_YELLOW
ECHO ""
WARN "ALL THE SOUCE FILES WILL BE DELETED, FILES YOU MOTIFIED/ADDED WILL BE LOST !!!"
ECHO ""
#ECHO "To continue, type 'Yes' and then press ENTER ..."
#read choice
#[ x$choice != xYes ] && exit 1
set +e
ECHO "cleanup drv"
pushd .
run_command_progress_float "rm drv -frv" 0 "find drv | wc -l"
popd
ECHO "cleanup mpp"
pushd .
run_command_progress_float "rm mpp* -frv" 0 "find mpp* | wc -l"
popd
ECHO "cleanup osdrv"
pushd .
run_command_progress_float "rm osdrv -frv" 0 "find osdrv | wc -l"
popd
第一行的#!/bin/sh
说明这是一个shell脚本
第二行source scripts/common.sh
是将scripts/common.sh
复制到这里,和include的头文件包含类似。
scripts文件夹中的common.sh中定义了很多函数。可以理解为common.sh是库函数,另外两个为main函数。
第三行ECHO "Cleanup SDK" COLOR_YELLOW
先打印一个 Cleanup SDK,颜色为黄色
后面几行一样是打印
WARN “ALL THE SOUCE FILES WILL BE DELETED, FILES YOU MOTIFIED/ADDED WILL BE LOST !!!”
所有源文件将删除,你添加/修改的文件将丢失
这里说的是解压开的文件。我们需要在执行cleanup之前将修改过的文件做备份。
#ECHO "To continue, type 'Yes' and then press ENTER ..."
#read choice
#[ x$choice != xYes ] && exit 1
后面读取输入的指令,不等于yes就退出
最后一部分
pushd . 是保存当前目录
然后执行scripts/common.sh
中run_command_progress_float
函数
执行这个脚本,效果如下
发现./不能执行,但是source可以执行。
具体没有去了解,以结果为导向的话能用就可以了
sdk.unpack阅读
#!/bin/sh
source scripts/common.sh
ECHO "Unpacking SDK" COLOR_YELLOW
WARN "Be sure you have installed the cross-compiler. if not, install it first!"
WARN "ALL THE SOUCE FILES WILL BE OVERWRITED, FILES YOU MOTIFIED WILL BE LOST !!!"
ECHO ""
#ECHO "To continue, type 'Yes' and then press ENTER ..."
#read choice
#[ x$choice != xYes ] && exit 1
set +e
#ECHO "install cross toolchain"
#./tools/toolchains/cross.install
ECHO "unpacking osdrv"
mkdir -p osdrv/
run_command_progress_float "tar -xvzf package/osdrv.tgz" 0 "tar -tzf package/osdrv.tgz | wc -l"
ECHO "unpacking kernel"
mkdir -p osdrv/
run_command_progress_float "tar -xvzf osdrv/opensource/kernel/linux-3.4.y.tgz -C osdrv/opensource/kernel/" 0 "tar -tzf osdrv/opensource/kernel/linux-3.4.y.tgz | wc -l"
if [ "$SDK_CHIP" = "hi3519" ]; then
#ECHO "unpacking mpp_single"
#mkdir -pv mpp_single
#run_command_progress_float "tar -xvzf package/mpp_single.tgz" 0 "tar -tzf package/mpp_single.tgz | wc -l"
ECHO "unpacking mpp_big-little"
mkdir -pv mpp_big-little
run_command_progress_float "tar -xvzf package/mpp_big-little.tgz" 0 "tar -tzf package/mpp_big-little.tgz | wc -l"
else
ECHO "unpacking mpp"
mkdir -pv mpp
run_command_progress_float "tar -xvzf package/mpp.tgz" 0 "tar -tzf package/mpp.tgz | wc -l"
fi
ECHO "unpacking drv"
mkdir -pv drv
run_command_progress_float "tar -xvzf package/drv.tgz" 0 "tar -tzf package/drv.tgz | wc -l"
阅读完上面的cleanup后,这里就粗略的阅读一下
首先打印出来,要求使用者先安装交叉编译工具链。
如果之前解压过修改过,再执行unpack的话,会将原来的文件覆盖掉。
mkdir -p osdrv/
在当前目录下创建osdrv
这个目录
运行run_command_progress_float
这个函数
解压package/osdrv.tgz
下面对芯片的型号进行判断,显然我们使用的不是3519。
于是进入else
解压mpp.tgz
最后解压package/drv.tgz
执行如下
虽然上面的打印让我们先安装交叉编译工具链,但是通过阅读发现,脚本后面的内容都是解压没有编译,所以没有关系。
解压完前后对比如下
- drv——驱动
- mpp——一些库
- osdrv——uboot和kernel
于是我们需要重点研究osdrv中的内容
scripts/common.sh
#!/bin/sh
#set -e
# for debug
DEBUG_LOG_FILE='&2'
DEBUG_LOG_LEVEL=0
# ANSI COLORS
COLOR_CRE="[K"
COLOR_NORMAL="[0;39m"
COLOR_RED="[1;31m"
COLOR_GREEN="[1;32m"
COLOR_YELLOW="[1;33m"
COLOR_BLUE="[1;34m"
COLOR_MAGENTA="[1;35m"
COLOR_CYAN="[1;36m"
COLOR_WHITE="[1;37m"
# Shell command
TAR=tar
CP=/bin/cp
RM=/bin/rm
GREP=grep
SED=sed
MKDIR=mkdir
CHMOD=chmod
MV=mv
CD=cd
LN=ln
MAKE=make
MKNOD=mknod
PUSHD=pushd
POPD=popd
RMDIR=rmdir
DEPMOD=/sbin/depmod
RMDIR=rmdir
MKIMG=mkimage
PATCH=patch
DIFF=diff
TOUCH=touch
CAT=cat
e_blank='[ ][ ]*'
e_year='20[0-9][0-9]'
e_month='([1-9]|0[1-9]|1[0-2])'
e_day='([1-9]|0[1-9]|[12][0-9]|3[0-1])'
e_time='([01][0-9]|2[0-3]):[0-5][0-9]'
e_employid='[a-zA-Z][a-zA-Z]*[0-9]{4,}'
#$1: string
#$2: color
ECHO()
{
[ -n "$2" ] && eval echo -n \"\${${2}}\";
echo "${1}${COLOR_NORMAL}"
}
ERR()
{
echo "${COLOR_RED} ERR: ${1}${COLOR_NORMAL}" >&2
}
WARN()
{
echo "${COLOR_YELLOW}WARN: ${1}${COLOR_NORMAL}" >&2
}
# $1:
LOG()
{
echo "$1"
}
#$1: string
#$2: level
DEBUG()
{
local level=$2
[ -z "$level" ] && { level=0; }
[ $level -lt $DEBUG_LOG_LEVEL ] && return 0;
echo "$COLOR_WHITE$1$COLOR_NORMAL" > $DEBUG_LOG_FILE
}
# $1: command
# $2: LR/CR steps
run_command_progress()
{
local n=0
local steps=$2
local progress_bar=""
local counter=0
local files=0
ECHO "run_command_progress: '$1'"
[ -z "$steps" ] && { steps=1; }
[ -n "$3" ] && [ -d "$3" ] && { steps=`find $3 | wc -l`; steps=`expr $steps / 50`; }
eval $1 | while read line
do
#((n++))
#((files++))
((++n))
((++files))
if [ $n -ge $steps ] ;
then
#((counter++))
((++counter))
if [ $counter -le 50 ] ;
then
progress_bar="$progress_bar#";
printf " --------------------------------------------------|\r[%03d]$progress_bar\r" $steps
else
printf "[%03d#$progress_bar|\r" `expr $files / 50`
fi
n=0
fi
done
echo ""
}
# $1: command
# $2: total
# $3: command to calc totals
run_command_progress_float()
{
local readonly RCP_RANGE=50
local rcp_lines=0
local rcp_nextpos=1
local rcp_total=0
local progress_bar=
local rcp_prog=0
local rcp_tmp=0
local prog_bar_base=
local rcp_percent=0
ECHO "run_command_progress_float: '$1'"
if [ -n "$3" ] ;
then
echo -n "Initializing progress bar ..."
rcp_total=`eval $3`;
echo -n "\r"
[ -z "$rcp_total" ] && rcp_total=1
else
[ -n "$2" ] && rcp_total=$2
fi
[ -z "$rcp_total" ] && rcp_total=1
[ $rcp_total -le 0 ] && rcp_total=1
prog_bar_base="[ ]"
while [ $rcp_tmp -lt $RCP_RANGE ]
do
prog_bar_base="$prog_bar_base-"
#((rcp_tmp++))
((++rcp_tmp))
done
prog_bar_base="${prog_bar_base}|"
printf "\r$prog_bar_base\r"
set +e
eval $1 | while read line
do
#((rcp_lines++))
((++rcp_lines))
if [ $rcp_lines -ge $rcp_nextpos ]
then
rcp_percent=`expr \( $rcp_lines \* 101 - 1 \) / $rcp_total `
rcp_prog=`expr \( $rcp_lines \* \( $RCP_RANGE + 1 \) - 1 \) / $rcp_total `
[ $rcp_prog -gt $RCP_RANGE ] && rcp_prog=$RCP_RANGE
rcp_nextpos=`expr \( \( $rcp_percent + 1 \) \* $rcp_total \) / 100`
[ $rcp_nextpos -gt $rcp_total ] && rcp_nextpos=$rcp_total
rcp_tmp=0
progress_bar=""
while [ $rcp_tmp -lt $rcp_prog ]
do
progress_bar="$progress_bar#"
((rcp_tmp++))
done
printf "\r$prog_bar_base\r[%3d%%]$progress_bar\r" $rcp_percent
fi
done
set -e
echo ""
}
#$1: path
abs_path()
{
pushd "$1" >/dev/null
[ $? -ne 0 ] && return 1;
pwd
popd >/dev/null
}
#$1: $cfg_moddir is multi
prepare_unpacking_cleanup()
{
$CAT >> $HCM_SH_SDKINSTALL << EOF
ECHO "unpacking $cfg_moddir"
mkdir -pv $module_basedir
run_command_progress_float "tar -xvzf `sub_dir $dir_postbuild_srctarball $HCM_DESTDIR`/$module_dirname.tgz -C $module_basedir/" 0 \
"tar -tzf `sub_dir $dir_postbuild_srctarball $HCM_DESTDIR`/$module_dirname.tgz | wc -l"
EOF
if [ -z "$1" ] ;
then
$CAT >> $HCM_SH_SDKCLEANUP << EOF
ECHO "cleanup $cfg_moddir"
run_command_progress_float "rm $cfg_moddir -frv" 0 "find $cfg_moddir | wc -l"
EOF
else
$CAT >> $HCM_SH_SDKCLEANUP << EOF
ECHO "cleanup $cfg_moddir"
pushd $module_basedir
run_command_progress_float "rm $cfg_moddir -frv" 0 "find $cfg_moddir | wc -l"
popd
EOF
fi
}
# $1: prefix
# $2..$n: dirs list
make_dirs()
{
local make_dirs_count=2
local make_dirs_dir=
[ -z "$1" ] && { ERR "make_dirs mast have a prefix dir!"; return 1; }
$MKDIR $1 -p
while true
do
eval make_dirs_dir=\${$make_dirs_count}
[ -z "$make_dirs_dir" ] && break;
$MKDIR $1/$make_dirs_dir -p
#((make_dirs_count++))
((++make_dirs_count))
done
}
check_dir_empty()
{
[ -z "$1" ] && return 0;
! [ -d $1 ] && return 0;
[ -z "`find $1/ -maxdepth 1 -mindepth 1`" ] && return 0;
return 1
}
# $1 - $2
# $3: frefix for '/', like "\\\\/"
sub_dir()
{
local subdir=
local dirA=`dirname $1/stub`
local dirB=`dirname $2/stub`
while [ "$dirA" != "$dirB" ] && [ "$dirA" != "." ] && [ "$dirA" != "/" ]
do
if [ -z "$subdir" ] ; then
subdir=`basename $dirA`
else
subdir=`basename $dirA`$3/$subdir
fi
dirA=`dirname $dirA`
done
[ -z "$subdir" ] && subdir=.
dirname $subdir/stub
}
# $1: base dir
# $2: dest dir
# $3: frefix for '/', like "\\\\/"
base_offset_dir()
{
local ofstdir=`sub_dir $2 $1`
local bodofst=
while [ "$ofstdir" != "." ] && [ "$ofstdir" != "/" ]
do
if [ -z "$bodofst" ] ; then
bodofst=..
else
bodofst=..$3/$bodofst
fi
ofstdir=`dirname $ofstdir`
done
dirname $bodofst/stub
}
#$1: dir
set_drv_kbuild()
{
local cc_file=Makefile
local mbdir=
for mbdir in $1 $1/*
do
if [ -f $mbdir/$cc_file ] ;
then
local kbuild_dir_adj="`base_offset_dir $HCM_DESTDIR $mbdir "\\\\"`\\/`echo "$HCM_SDKDIR_KBUILD" | \
sed -n "s/\//\\\\\\\\\//gp"`"
$SED -i "s/^KERNEL_MAKE[ \t]*:=.*/KERNEL_MAKE := -C $kbuild_dir_adj/" $mbdir/$cc_file
fi
done
}
#$1: name
#$2: level
write_rootfs_level()
{
local rlevel_config=$HCM_DESTDIR/$HCM_SDKDIR_RESOURCE/rlevel.config
$TOUCH $rlevel_config
[ -n "`grep "^\[[0-9A-Za-z][0-9A-Za-z\-]*\] $1$" < $rlevel_config`" ] && { \
WARN "$rlevel_config already have item '$1'"
return 0;
}
echo "[$2] $1" >> $rlevel_config
}
#$1:
remove_all_cvsdir()
{
! [ -d "$1" ] && { WARN "'$1' not found when remove 'CVS' directories."; return ; }
ECHO "Remove: 'CVS' directories in $1"
find $1 -type d -name "CVS" | xargs rm -fr
}
#$1: strip command
#$2: file list
strip_elf()
{
for file in $2
do
[ -z "`file $file | grep "ELF .* executable, .*, not stripped"`" ] && continue
ECHO "$1 $file"
$1 $file
done
}
#$1: strip command
#$2: file list
strip_lib()
{
for file in $2
do
[ -z "`file $file | grep "ELF .* shared object, .*, not stripped"`" ] && continue
ECHO "strip not really done: $file"
done
}
# $1: rootfs base
# $2: modules list
install_extern_kmod()
{
local iek_installed_modules=
local iek_dest_module=
local iek_depend_info=
local iek_install_base=
pushd $1 >/dev/null
iek_install_base=$PWD
popd >/dev/null
for iek_extmod in `find $2`
do
iek_dest_module=/$HCM_INROOTFS_EXTKMOD/`basename $iek_extmod`
[ -f $HCM_DESTDIR/$HCM_KERNEL_INSTALL_RESOURCE/$iek_dest_module ] && \
{ WARN "Extern module $iek_extmod conflict: $iek_dest_module"; sleep 1; }
iek_installed_modules="$iek_installed_modules $iek_dest_module"
$CP -uf $iek_extmod $HCM_DESTDIR/$HCM_KERNEL_INSTALL_RESOURCE/$iek_dest_module
done
pushd $HCM_DESTDIR/$HCM_KERNEL_INSTALL_RESOURCE >/dev/null
ECHO "Generating modules dependency ..."
$DEPMOD -ae -b ./ -r -F $HCM_DESTDIR/$HCM_SDKDIR_KBUILD/System.map $HCM_KERNEL_RELEASE
for iek_extmod in $iek_installed_modules
do
iek_depend_info=`grep "^$iek_extmod:" < $HCM_DESTDIR/$HCM_KERNEL_INSTALL_RESOURCE/$HCM_INROOTFS_DEPKMOD/modules.dep | sed "s/\://"`
for iek_extmod in $iek_depend_info
do
$CP -uf --parents .$iek_extmod $iek_install_base/
[ x$cfg_install_strip == xyes ] && $HCM_CROSS_COMPILE-strip $iek_install_base$ikm_kmod -g -S -d
done
done
popd >/dev/null
}
# $1: dest rootfs based
# $2: module list
install_kernel_module()
{
local ikm_kmod_resdir=$HCM_DESTDIR/$HCM_KERNEL_INSTALL_RESOURCE
local ikm_install_basedir=
local ikm_kmod=
pushd $1 >/dev/null
ikm_install_basedir=$PWD
popd >/dev/null
pushd $ikm_kmod_resdir >/dev/null
$DEPMOD -ae -b ./ -r -F $HCM_DESTDIR/$HCM_SDKDIR_KBUILD/System.map $HCM_KERNEL_RELEASE
while read ikm_kmod
do
ikm_depend_info=`grep "^$ikm_kmod:" < $HCM_DESTDIR/$HCM_KERNEL_INSTALL_RESOURCE/$HCM_INROOTFS_DEPKMOD/modules.dep | sed "s/\://"`
for ikm_kmod in $ikm_depend_info
do
$CP -uf --parents .$ikm_kmod $ikm_install_basedir
[ x$cfg_install_strip == xyes ] && $HCM_CROSS_COMPILE-strip $ikm_install_basedir$ikm_kmod -g -S -d
done
done << EOF
`pushd $HCM_INROOTFS_KERNMOD >/dev/null; \
eval find "$2" -type f -printf \"/$HCM_INROOTFS_KERNMOD/%p\\\n\"; \
popd >/dev/null`
EOF
popd >/dev/null
}
string_to_varname()
{
echo "$1" | sed 's/[^a-zA-Z0-9_]/_/g'
}
patchset_get_param()
{
echo "$1" | cut -d')' -f1 | sed 's/[\(\|]/ /g'
}
patchset_get_name()
{
echo "$file" | cut -d')' -f2
}
内容较长,一部分一部分的看。
这个脚本里边主要定义了一些函数。
这部分是颜色数值,像我们之前在操作linux的时候出现的很多有颜色的字符就是这么来的。
这部分定义了一些命令。
为什么要定义这些命令?
和宏定义类似,这个脚本可能不光在sh里用,将来可能在别的里面用,命令可能需要替换,所以定义。
另外两个脚本都用到的run_command_progress
函数,实际上就是显示解压进度条。
还有另一个进度条相关的函数
# $1: command
# $2: total
# $3: command to calc totals
run_command_progress_float()
有三个参数,一个是命令,一个是总量,一个是计算百分比
这个函数是通过小数点显示
运行的效果如下
关于脚本,只需要能看懂它大概是干什么的就可以,实际工作场景中脚本都是写好的,用就行了
osdrv
上面说的,解压出来的重点就是osdrv
这个文件夹
接下来对uboot
和kernel
进行学习
在osdrv
中有一个readme
和makefile
,先看这两个
makefile中写了
这边做了两个交叉编译选项来选择对应的交叉编译工具链。
- glibc功能全,但是占空间大
- uclibc是glibc的精简版本,保留了必要的功能,体积非常小
实际产品的flash只有8兆,在这种情况下只能使用uclibc
,glibc
光是这个库都放不下就更不用说其他的东西了。
使用glibc
的产品大多为板载的不是SPI Flash,用的是TF卡或者EMMC。所以不用考虑glibc
的两三百兆。
其他内容就是一些命令
执行发现交叉编译工具链没有找到,此时需要查看makefile
可以看到,虽然编译选项中给了交叉编译工具链的选择,但是makefile
中没有绝对路径。
makefile
中的写法就是访问当前目录,所以找不到
继续浏览
发现,需要在当前目录下有一个arm-hisiv300-linux
目录,这个目录下放对应的交叉编译工具链才行。
交叉编译工具链的脚本文件中给出了安装工具链的路径,我们可以改makefile或者这里的路径,再或者直接把压缩包拷贝到相应路径中
我们选择最简单的方式
于是我们需要将交叉编译工具链安装到osdrv
底下
交叉编译工具链在/osdrv/opensource/toolchain/
中
接着,我们将其中的压缩包移动到/osdr
底下并解压
有了这个路径,这样makefile就可以找到它,如下图
然后这样配置了之后还是报错找不到交叉编译工具链
这是由于32位的工具链和64位工具链不同导致的
下一期给出解决方案