记录最近一年调试hisilicon 平台的相关经验,现已经转到互联网云存储方面的。话说嵌入领域,智能硬件领域,无非就是CPU,外设;但鉴于现在芯片原厂SDK 中基本都封装好啊! 改动的比较少,差不多就是按部就班的过程; 处于自己对互联网行业的向往, 现总结自己关于嵌入开发,特别是海思平台的开发; 鉴于自己的前期不重视,总结出三个字,“精,深,面”;精则为精通某一领域,深则为深挖其中的精髓,面则为逐步扩宽自己的知识面;
前面的纯属扯淡,欢迎调侃!
1. 3518EV200之Liteos
1.1 uboot篇
编译配置:make ARCH=arm CROSS_COMPILE=arm-hisiv300-linux- hi3518ev200_config
编译:make ARCH=arm CROSS_COMPILE=arm-hisiv300-linux-
生成bin档:./mkboot.sh reg_info_hi3518ev200.bin u-boot-hi3518ev200.bin
注意,reg_info_hi3518ev200.bin 为SDK中uboot_tools 目录生成的xls文件生成的io配置文件。
1.2 Liteos系统篇
编译Liteos系统:make CHIP=hi3518ev200
编译liteos APP程序:make CHIP=hi3518ev200 (原SDK Sample目录中会生成sample.bin程序,该程序主要实现驱动的初始化,文件系统的初始化,挂载文件系统,以及应用业务)
1.2.1 uboot 引导Liteos系统的启动CMD参数:
nand flash:
setenv bootcmd 'nand read 0x800080000x100000 0x700000; go 0x80008000’; saveenv
spi flash:
setenv bootcmd 'sf probe 0;sf read0x82000000 0x100000 0x700000;go 0x80008000'
注意,0x80008000 为Liteos 固定的启动地址,它是在编译时指定的连接启动地址,可在board.ld中修改。
1.3 Liteos 文件系统篇
1.3.1 Jffs2
JFFS2 (日志文件系统):管理在设备上实现的日志型文件系统;它主要应用与NOR型闪存,特点是可读写、支持数据压缩,并提供崩溃/掉电安全保护,提供写平衡支持。
初始化步骤:
(1)初始化头结点
init_head()
(2)添加JFFS2 分区
add_mtd_parttion(类型,分区起始地址,分区长度,分区号)
(3)挂载JFFS2
mount()实现设备节点和挂载点的挂载
shell 挂载命令 mount/dev/spinorblk1 /jffs1 jffs
判断是否挂载成功:在文件系统的根目录是否可以正常查看到挂载目录
将从串口得到如下回应信息,表明挂载成功。
HuaweiLite OS# mount /dev/spinorblk1/jffs1 jffs
挂载成功后,用户就能对norflash进行读写操作。
(4)卸载JFFS2
umount()
(5)删除JFFS2 分区
delete_mtd_partition 删除已经卸载的分区
jffspar 查看挂载分区的情况,如显示下列log 则说明挂载ok
jffs_partition num:0, devname:/dev/spinorblk0, mountpt:/jffs0, startaddr:0x0100000, length:0x0300000
1.3.2 FAT文件系统
它是File Alloction Table(文件配置表)的简称;它将硬盘分区为MBR、DBR、FAT、FDT、FADT区等5个区域;
ffconf.h FAT文件系统配置文件,可设置文件读写的相关属性
初始化步骤:
(1) 设备识别
(2) 文件系统挂载与卸载 mount /dev/mmcblk0p0 /sd0p0 vfat ;umount /sd0p0
1.4 Liteos NAND/NOR Flash 篇
初始化步骤:
(1) 初始化nand flash控制
Nand_init() /spinor_init() 初始化主控
(2)分区,flash 控制器初始化后,即可对其进行分区操作。
int add_mtd_partition( char *type, uint32_tstart_addr, uint32_t length, uint32_t partition_num)
[type]:存储介质类型,指定字符串为"nand"与"spinor"。分别代表两类存储介质。
[start_addr]:分区操作flash的物理开始地址。
[length]:分区操作Nand flash的分区大小。
[partition_num]:分区盘符。
eg:
add_mtd_partition("nand", 0x900000,16*0x100000, 0);
(3)挂载分区
int mount(FAR const char *source, FAR constchar *target,FAR const char *filesystemtype, unsigned long mountflags,FAR constvoid *data)
[source]: 挂载源设备。参数意义指需要挂载的设备结点。
[target]: 挂载点目录。
[filesystemtype]: 挂载文件系统类型。
[mountflags]: 挂载标志。在此例挂载暂时无义,可传入0 参数。后续版本会进行
扩展。
[data]:挂载追加参数。此例挂载暂时无义。可传入参数0。
eg:
mount("/dev/nandblk0","/yaffs0", "yaffs", 0, NULL);
1.5 Liteos MMC/SD/EMMC篇
初始化步骤:
#1 初始化SD/MMC/SDIO模块 SD_MMC_Host_init()
#2 挂载设备 mount()
#3 格式化设备 format(const char *dev, int sectors) 格式化FAT32 文件系统
#4 分区设备
int add_mmc_partition(structdisk_divide_info *info, size_t sector_start,size_t sector_count);
参数说明:
*info:必须指定为extern structdisk_divide_info emmc;
sector_start:分区的起始扇区位置,目前版本以512kbyte为一个扇区。
sector_count:分区的扇区数量,目前版本以512kbyte为一个扇区。
1.6 Liteos 其他驱动篇
1.6.1 I2C
功能:完成CPU 对I2C 总线上连接的从设备的读写
#1 i2c初始化
i2c_dev_init()
#2 i2c 读写
i2c_read 命令对I2C 外围设备进行读操作:
i2c_read
i2c_write 命令对I2C 外围设备进行写操作:
i2c_write
1.6.2 SPI
功能:完成对SPI 总线上连接的从设备的读写
#1 初始化
hi_spi_init()
1.6.3 USB Host Controller
初始化函数:usb_init()
1.6.4 DDR 内存管理
#1 所有DDR内存中,一部分由操作系统管理,称为OS内存;另一部分由MMZ模块管理,供媒体业务单独使用,称为MMZ内存。
#2 OS内存起始地址为0x80008000,MMZ内存起始地址默认为(Hi3518EV200: 0x82000000;Hi3518EV201:0x81000000;Hi3516CV200:0x84000000),OS内存起始地址固定,不能修改。MMZ内存起始地址可以根据客户的场景业务修改。
#3 MMZ内存由MMZ内核模块管理,MMZ模块初始化时,通过参数指定其大小。
#4 请注意MMZ内存地址范围不能与OS内存重叠。
1.7 Liteos Shell指令篇
1.7.1 注册命令函数:
UINT32 osCmdReg( UINT32 uwCmdType, CHAR *pscCmdKey,UINT32
uiParaNum,CMD_CBK_FUNC pfnCmdProc );
– uwCmdType:命令类型,对外提供的命令类型为CMD_TYPE_EX。
– pscCmdKey:命令关键字,函数在Shell中访问的名称。
– uiParaNum:调用的执行函数的入参个数。
– pfnCmdProc:函数地址,即执行函数。
这个函数可以将一个函数链接到Shell中,可以在Shell命令行中使用。
1.7.2 常见shell 指令
#1 starthapd 用于启动AP 模式
startapd [channel][ssid][encryptionscheme][encryptionalgorithm][pwd]
信道 名字 加密方式 加密算法 密码
参数总结:
channel 信道 0~11
encryptionscheme 加密方式 none,wep-shared,wep-open,wpa,wpa2,wpa+wpa2
encryptionalgorithm 加密算法 tkip,aes,tkip+aes
注意:当加密方式为none 时,后面的参数就不需要再加
eg:
startapd3 ddpai_liteos wpa2 aes 1234567890
startapd3 ddpai_liteos none
#2 stopapd 关闭AP模式
#3 startwpa 开启WiFi的station
#4 setwpamode 设置WiFi station模式各项参数
命名格式:setwpamode [name] [encryptionscheme][encryptionalgorithm] [pwd]
#5 stowpa 关闭station模式
#6 iperf 测试网络传输速度
命令格式: iperf[-c] [ipaddrss]
#7 memcheck 检查动态申请的内存块释放完整,释放存在内存踩踏
2 Hi3559 Liteos/Linux 系统篇
2.1 uboot篇
它主要完成引导liteos/linux 系统的功能;
配置指令:make ARCH=arm CROSS_COMPILE=arm-hisiv500-linux- hi3519_config
编译指令:make ARCH=arm CROSS_COMPILE=arm-hisiv500-linux-
镜像生成指令:./mkboot.sh reg_info.bin hi3519_uboot.bin
2.2 Liteos/linux 系统篇
Liteos |
Linux |
||||
NDK |
MAPI |
Local |
HisysLink |
HisysLink |
MAPIClient |
ndk 提供媒体相关的采集、处理、编解码等驱动和库,对外以MAPI接口形式呈现
#1 编译osdrv:
make osdrv -C ndk 或者 进入到ndk子目录,执行makeosdrv
#2 编译ndk:
make mapi -C ndk 或者 进入ndk子目录,执行makemapi
#3 编译Middleware:
make middleware 或者 进入middleware子目录,执行makemiddleware
#4 Uboot 编译:
make ARCH=arm CROSS_COMPILE=arm-hisiv500-linux-hi3559_config
make ARCH=armCROSS_COMPILE=arm-hisiv500-linux-
./mkboot.sh reg_info.bin hi3519_uboot.bin
#5 kernel 编译:
cp arch/arm/config/hi3559_xxx_defconfig.config
make ARCH=armCROSS_COMPILE=arm-hisiv500-linux- menuconfig
make ARCH=armCROSS_COMPILE=arm-hisiv500-linux- uImage
#6 LITEOS 编译
cd platform/liteos/liteos/
make menuconfig
make
#7 IPCM(Inter-Processor CommunictionModule) 多核通信模块,实现Liteos与linux 之间的通信
./build.sh
注意:当拿到3559 SDK时,需要进入到ndk文件夹。执行一次make all,对整个SDK进行编译;以后如要编译进入每个模块内执行makefile,详见个模块内部的makefile;
如编译出现部分错误,请参照Hi3559_编译环境note.txt 文件;
切记:3559 SDK 开发环境需用64位系统!!!!!
2.3 Liteos /Linux 内存布局
Hisilion 默认参考:
Linux Sys Mem |
Liteos sys Mem |
IPCM |
Parameter |
Linux MMZ |
Liteos MMZ |
96M |
80M |
4M |
1M |
8M |
220M |
切记:必须先加载liteos,再加载linux
Liteos 内存配置文件 :platform/bsp/hi3559/cortex-a17/board.h
/* sample.bin should be loaded atSYS_MEM_BASE */
#define SYS_MEM_BASE 0x86000000 /*起始基地址*/
#define SYS_MEM_SIZE_DEFAULT 0x5000000 /*分配的内存长度*/
#define DDR_MEM_SIZE 0x100000000
2.4 uboot引导双系统启动篇
2.4.1 Flash 分区
2.4.2 uboot引导
Linux 系统启动参数:
bootargs=mem=96M console=ttyAMA0clk_ignore_unused rw root=/dev/mtdblock2 rootfstype=jffs2mtdparts=hi_sfc:1M(boot),4M(kernel),19M(rootfs)
uboot 引导双系统启动参数:
bootcmd=sf probe 0; sf read 0x860080000x1800000 0x100000; go_a17 0x86008000; sf read0x82000000 0x100000 0x400000; bootm 0x82000000
Linux系统的启动大致分为:
#1 uboot 引导uimage,解压uimage,并调用start_kernel来初始化内核镜像;
#2 内核初始化
#3 挂载root文件系统(由于jffs2 挂载时会扫描flash)
3 .linux 文件系统浅谈篇
文件系统
系统有一个file_system_type类型的全局变量file_systems,用来保存系统已经支持的文件系统;在挂载(mount)文件系统时,会判断系统是否支持挂载的文件系统。
struct file_system_type {
const char *name; /*文件系统名*/
int fs_flags;
struct dentry *(*mount) (structfile_system_type *, int,const char *, void *);
void (*kill_sb) (struct super_block *);
struct module *owner;
struct file_system_type * next; /*所有已经注册的文件系统连接到file_systems*/
struct hlist_head fs_supers; /*mount文件系统,系统都会为它创建一super_block,保存文件系统本身以及挂载点相关信息。*/
struct lock_class_key s_lock_key;
struct lock_class_key s_umount_key;
struct lock_class_key s_vfs_rename_key;
struct lock_class_key i_lock_key;
struct lock_class_key i_mutex_key;
struct lock_class_key i_mutex_dir_key;
};
文件件系统4大金刚:super_block,inode,file,dentry;
#1 super_block (超级块)
存储文件系统相关信息。
#2 inode 包含文件系统中的一个文件的所有信息,inode与文件系统中的文件是一一对应的。
主要组成部分:
#1 描述文件状态的元数据,文件元数据包括文件大小,权限,类型,时间;
#2 文件数据描述,则用来定义文件数据再磁盘上的存放位置;
#3 file
它与进程相关的,file代表一个打开的文件,file与inode 之间是多对一的关系;因为多进程可以同时
打开一个文件,系统就会为每一个打开的文件都创建file结构。
#4 dentry
它主要是用来加快目录遍历
struct dentry {
/*RCU lookup touched fields */
unsignedint d_flags; /* protectedby d_lock */
seqcount_td_seq; /* per dentry seqlock */
structhlist_bl_node d_hash; /* 保存在hash表中;为了处理hash冲突 */
structdentry *d_parent; /* parentdirectory */
structqstr d_name; /* 文件的名称*/
structinode *d_inode; /* dentry 所对应的inode,它主要就是通过路径名查找inode*/
unsignedint d_count; /*dentry引用计数*/
conststruct dentry_operations *d_op;
structsuper_block *d_sb; /* 该目录项所在文件系统实例的超级块*/
};
文件系统mount 流程(内核函数调用关系):
SYSCALL_DEFINE5(mount,xxxx) 系统调用
do_mount
do_remount_sb 通知文件系统改变挂载属性
do_new_mount
do_kern_mount
mount_fs
type->mount(type,flags, name, data); 调用到file_system_type 文件系统的xxx_mount
read/write 流程:
#1 VFS 层
它主要屏蔽下层具体文件系统操作的差异。
#2 具体文件系统层
#3 cache 层(page cache层)
它主要是为了提高linux操作系统对磁盘访问的性能
#4 通用块层(generic blocklayer)
它主要为接收上层发出的磁盘请求,并最终发出IO请求。
#5 IO 调度层
它主要接收通用块层发出的IO请求,缓存请求。
#6 块设备驱动层
#7 物理块设备层
Read 函数调用栈关系:
sys_read
do_sync_read
filp->f_op->aio_read(&kiocb,&iov, 1, kiocb.ki_pos);
generic_file_aio_read(xxx_file_operations)
do_generic_file_read
BIO 层调用关系:
block 层调用:
submit_bio
generic_make_request
__generic_make_request
q->make_request_fn(q,bio); 该make_request_fn 函数指针为__make_request
4 hisilion MMC Host/Block 初始化及req调用关系浅谈
4.1 /driver/mmc/host/himciv100/himci.c 主控初始文件
hi_mci_probe 初始化内核定时器,并启动是否有卡接入到卡槽;
mmc_alloc_host 初始化延时队列mmc_rescan
mmc_rescan 延时队列,用于扫描SD卡
hi_mci_detect_card 定时器,用于SD卡热插拔
hi_mci_init_card 初始化SD/MMC/SDIO Host
mmc_add_host
mmc_start_host
mmc_detect_change 检测SD是否接入到卡槽,原理为:sd_detect管脚拉低,则表示有sdcard 接入
4.2 Block
mmc io的读写从mmc_queue_thread()的获取queue里面的request开始;
主要调用函数流程(从下到上),如下:
host->ops->request
mmc_start_request
mmc_start_req
mmc_blk_issue_rw_rq
mmc_blk_part_switch(选择读写分区)
mmc_blk_issue_rq
md->queue.issue_fn= mmc_blk_issue_rq;
mmc_queue_thread-->blk_fetch_request(从块设备队列提取存储的req)
5 调试篇
主要记录调试uboot,linux,liteos,rootfs 相关经验;
烧录uboot:
sf probe 0
mw.b 82000000 ff 100000;
tftp 0x82000000 u-boot-hi3518ev200.bin; 通过tftp将uboot文件下载到内存8200000
sf probe 0;
sf erase 0 100000;
sf write 82000000 0 100000;
烧录镜像:
mw.b 82000000 ff 300000
tftp 82000000 uImage
sf probe 0
sf erase 100000 300000
sf write 82000000 100000 300000
烧录rootfs:
mw.b 82000000 ff C00000
tftp 0x82000000 jffs2-root.img
tftp 0x82000000rootfs_hi3516cv200_64k.jffs2
sf probe 0
sf erase 400000 C00000
sf write 82000000 400000 C00000
上传镜像:hi3516cV200_flash_16M.bin
mw.b82000000 ff 1000000
sfprobe 0
sfread 0x82000000 0x0 0x1000000
tftp0x82000000 hi3516cV200_flash.bin 0x1000000
LiteOS 调试记录:
tftp 0x80008000 sample.bin;go 0x80008000 通过tftp将sample.bin 下载到内存,并从0x80008000启动;
挂载SD卡命令:
mount /dev/mmcblk0p0 /sd0p0 vfat
umount /sd0p0
有什么问题或者错误的情况,请各位指正!
工作在于总结,在于交流,在于深入,在于理解,在于运用!请做一个善于思索,善于总结的工程师;每天进步一点点,日积月累就有可能成为专家!