系统移植&驱动开发试题
系统移植
1.Makefile/.config/Kconfig的区别
- Kconfig:定义配置项
- Makefile:说明配置项的编译方法
- .config:控制配置项编译进内核、编译成模块还是不编译
2.make menuconfig/make <board_name>_defconfig/make all的关系
- make <board_name>_defconfig:默认板子缺省配置文件
- make menuconfig:基于图形化界面信息配置
- make all:根据.config文件,决定哪些文件被编译到uboot镜像文件中,哪些文件不被编译到镜像文件中
3.开发板如何部署Linux操作系统的,写出bootcmd和bootargs的参数设置
- 1.设置好开发板的IP以及虚拟机的IP,让开发板可以ping通ubuntu
- 2.通过tftp服务将设备树的镜像和内核镜像下载到开发板内存
- 3.设置bootargs,当u-boot引|导内核启动后按照bootargs的设置给操作系统远程挂载一个文件系统
bootcmd环境变量的设置方式:
- 方式1: setenv bootcmd u-boot命令1\;u-boot命令2\;...
- 方式2: setenv bootcmd "u-boot命令1;u-boot命令2;..."
setenv bootcmd "tftp 0xc2000000 uImage; \
tftp 0xc4000000 \
stm32mp157a-fsmp1a.dtb;\
bootm 0xc2000000 - 0xc4000000"
setenv bootargs root=/dev/nfs nfsroot=192.168.1.250:\
/home/ubuntu/nfs/rootfs,tcp,v4 rw \
console=ttySTM0,115200 init=/linuxrc \
ip=192.168.1.10
4.uboot环境变量中mmc read,mmc write命令如何使用
mmc read addr blk# cnt
addr
: 表示保存从mmc读出数据的内存地址
blk#
: 表示要读取的mmc的sector地址
cnt
: 表示要读取多少个sector的数据
mmc write addr blk# cnt
addr
: 表示要写入mmc设备的原始数据的内存地址
blk#
: 表示要写入的mmc的sector地址
cnt
: 表示要写取多少个sector的数据
5.配置内核和编译内核镜像的命令
配置内核:make menuconfig
编译内核镜像:make uImage LOADADDR=0xC2000000 单独编译linux内核
make uImage dtbs LOADADDR=0xC2000000 编译内核和设备树
6.第一次配置内核时,应使用的缺省内核配置文件是什么
make <board_name>_defconfig生成.config文件
7.如何添加自己的 LED 灯驱动程序,采用模块化方式编译,并且进行测试
备注:需要写出 makefile/.config/kconfig 这三个文件添加哪些内容
8.如何制作ramdisk.img 镜像文件
- 1.进入到nfs目录下
- 2.使用dd命令制作一个64M大小的文件
- 3.使用mkfs.ext4对ramdisk进行格式化,格式化为ext4格式
- 4.将ramdisk 挂载到/mnt目录
- 5. 使用strip命令压缩文件的体积
- 6.将~/nfs/rootfs中的内容拷贝到/mnt目录下
- 7.解除挂载
- 8.使用gzip对ramdisk进行压缩
- 9.使用mkimage命令给ramdisk.gz文件添加64字节的文件头得到ramdisk.img镜像文件
- 10.拷贝ramdisk.img到~/tftpboot目录下
- 11.设置内核通过ram挂载根文件系统的大小
- 12.对ramdisk.img的镜像文件进行测试
9.请写出如何将uboot镜像文件烧写到EMMC设备中
- 1. tf卡通过读卡器被ubuntu识别
- 2. 使用ls /dev/sd*命令查看tf卡是否被ubuntu识别成功
- 3. 拷贝sdtools.sh脚本文件到u-boot源码目录下
- 4. 执行脚本文件,将镜像文件烧录到tf卡中
驱动开发
1.请描述printk和printf使用的区别
- printk允许通过指定一个标志来设置优先级,从而决定这条打印是否需要打印出来
- printk函数运行环境在内核态,printf函数在用户态
- printf是不能设置优先级的,printk函数可以设置优先级
- 当优先级确定时,printk可以通过修改控制台输出的优先级来决定是否输出某条打印
- 不指定优先级时,printk会有一个默认的优先级
2.编写一个设备树节点,要求编写出五种不同键值对内容
mynode@0x12345678{
compatible = "hqyj,mynode";
astring="hello 24051";
uint =<0xaabbccdd 0x11223344>;
binarry=[00 0c 29 7b f9 be];
mixed ="hello",[11 22],<0x12345678>;
};
3. 编写对linux内核模块编译的Makefile 文件,需要写完整
arch ?= arm
modname ?= demo
ifeq ($(arch),arm)
KERNELDIR:=/home/ubuntu/linux-5.10.61
else
KERNELDIR := /lib/modules/$(shell uname -r)/build
endif
PWD:= $(shell pwd)
all:
make -C $(KERNELDIR) M=$(PWD) modules
clean:
make -C $(KERNELDIR) M=$(PWD) clean
obj-m := $(modname).o
4.编程实现使用iic子系统,采集温湿度传感器值,请大家按照以下需求编写
需要1:头文件(5分)
需要2:驱动代码(10分)
需求 3:应用层代码(5分)
读取温度寄存器地址为:0xE3
读取湿度寄存器地址为:0xE5
head.h
#ifndef __HEAD_H__
#define __HEAD_H__
//功能码构建例子不传递第三个参数:
#define GET_HUM _IOR('m',1,int)
#define GET_TEM _IOR('m',0,int)
#endif
iic.c
#include <linux/init.h>
#include <linux/module.h>
#include <linux/i2c.h>
#include <linux/fs.h>
#include <linux/io.h>
#include <linux/device.h>
#include "head.h"
int major;
char kbuf[128] = {0};
struct class *cls;
struct device *dev;
struct i2c_client *client1;
// 封装一个读取温湿度数据的函数
// reg:寄存器地址
short si7006_read_hum_tem(char reg)
{
int ret;
char r_buf = reg;
short value; // 保存从机发送的数据
// 消息封装
struct i2c_msg r_msg[] = {
[0] = {
.addr = client1->addr,
.flags = 0,
.len = 1,
.buf = &r_buf,
},
[1] = {
.addr = client1->addr,
.flags = 1,
.len = 2,
.buf = (u8 *)&value,
},
};
//进行消息传输
ret = i2c_transfer(client1->adapter, r_msg, 2);
if (ret != 2)
{
printk("消息传输失败\n");
return ret;
}
//将获取到的消息返回
return value;
}
// 封装操作方法
int mycdev_open(struct inode *inode, struct file *file)
{
printk("%s:%s:%d\n", __FILE__, __func__, __LINE__);
return 0;
}
ssize_t mycdev_read(struct file *file, char *ubuf, size_t size, loff_t *lof)
{
unsigned long ret;
printk("%s:%s:%d\n", __FILE__, __func__, __LINE__);
// 向用户空间读取拷贝
if (size > sizeof(kbuf)) // 用户空间期待读取的大小内核满足不了,那就给内核支持的最大大小
size = sizeof(kbuf);
ret = copy_to_user(ubuf, kbuf, size);
if (ret) // 拷贝失败
{
printk("copy_to_user filed\n");
return ret;
}
return 0;
}
ssize_t mycdev_write(struct file *file, const char *ubuf, size_t size, loff_t *lof)
{
unsigned long ret;
// 从用户空间读取数据
if (size > sizeof(kbuf)) // 用户空间期待读取的大小内核满足不了,那就给内核支持的最大大小
size = sizeof(kbuf);
ret = copy_from_user(kbuf, ubuf, size);
if (ret) // 拷贝失败
{
printk("copy_to_user filed\n");
return ret;
}
return 0;
}
long mycdev_ioctl(struct file *file, unsigned int cmd, unsigned long argp)
{
int tem, hum, ret; // 保存读取到的温湿度数据
switch (cmd)
{
case GET_HUM:
hum = si7006_read_hum_tem(0XE5);
ret = copy_to_user((unsigned int *)argp, &hum, 4); // 将读取到的温湿度数据传递到应用程序
if (ret) // 拷贝失败
{
printk("copy_to_user filed\n");
return ret;
}
break;
case GET_TEM:
tem = si7006_read_hum_tem(0XE3);
ret = copy_to_user((unsigned int *)argp, &tem, 4);
if (ret) // 拷贝失败
{
printk("copy_to_user filed\n");
return ret;
}
break;
}
return 0;
}
int mycdev_close(struct inode *inode, struct file *file)
{
printk("%s:%s:%d\n", __FILE__, __func__, __LINE__);
return 0;
}
// 定义操作方法结构体变量并赋值
struct file_operations fops = {
.open = mycdev_open,
.read = mycdev_read,
.write = mycdev_write,
.unlocked_ioctl = mycdev_ioctl,
.release = mycdev_close,
};
// 给对象分配空间并且初始化
int i2c_probe(struct i2c_client *client, const struct i2c_device_id *id)
{
client1 = client;
// 字符设备驱动注册
major = register_chrdev(0, "mychrdev", &fops);
if (major < 0)
{
printk("字符设备驱动注册失败\n");
return major;
}
printk("字符设备驱动注册成功:major=%d\n", major);
// 向上提交设备类
cls = class_create(THIS_MODULE, "si7006");
if (IS_ERR(cls))
{
printk("向上提交设备类失败\n");
return PTR_ERR(cls);
}
printk("向上提交设备类成功\n");
dev = device_create(cls, NULL, MKDEV(major, 0), NULL, "si7006");
if (IS_ERR(dev))
{
printk("向上提交设备信息失败\n");
return PTR_ERR(dev);
}
printk("向上提交设备信息成功\n");
return 0;
}
int i2c_remove(struct i2c_client *client)
{
// 设备信息的注销
device_destroy(cls, MKDEV(major, 0));
// 销毁设备类
class_destroy(cls);
// 注销字符设备驱动
unregister_chrdev(major, "mychrdev");
return 0;
}
// 定义设备树匹配的表
struct of_device_id oftable[] = {
{
.compatible = "hqyj,si7006",
},
{},
};
struct i2c_driver i2c_drv = {
.probe = i2c_probe,
.remove = i2c_remove,
.driver = {
.name = "si7006",
.of_match_table = oftable,
},
};
module_i2c_driver(i2c_drv);
MODULE_LICENSE("GPL");
test.c
#include <stdlib.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <sys/ioctl.h>
#include<arpa/inet.h>
#include "head.h"
int main(int argc, char const *argv[])
{
int tem, hum;
float tem1,hum1;
int fd = open("/dev/si7006", O_RDWR);
if (fd < 0)
{
printf("打开设备文件失败\n");
exit(-1);
}
while(1)
{
ioctl(fd,GET_HUM,&hum);//获取湿度
ioctl(fd,GET_TEM,&tem);//获取湿度
//进行数据的字节序转换
hum=ntohs(hum);
tem=ntohs(tem);
//计算湿度
hum1=(float)125*hum/65536-6;
//计算温度
tem1=175.72*tem/65536-46.85;
printf("温度tem=%.3f\t湿度hum=%.3f\n",tem1,hum1);
sleep(1);
}
close(fd);
return 0;
}
原文地址:https://blog.csdn.net/2301_80922669/article/details/142823692
免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!