我的第一篇博客
第一次写博客,记录我学习Linux嵌入式的过程
主要往Linux嵌入式软件应用方向学习。
学习主要用到的工具:
- VMware 15.5.0
- Ubuntu 18.0.4
- MobaXterm_Personal_12.2
- FileZilla Client
- Source Insight 4.0
- notepad++
- NXP I.MX6ULL 开发板
- QT4.8
安装搭建开发环境
学习路线
1. C语言基础
2. Linux基本知识
Linux文件目录与权限
Linux shell 与常用命令
3、Linux C编程编译
熟悉掌握GCC编译器的编译流程:预处理、汇编、编译和链接Makefile的基础以及基础语法和使用
4、ARM汇编基础
熟悉常用汇编指令以及了解寄存器的运行
5、构建系统
U-Boot的编译、使用方法、启动流程以及如何移植
Linux Kernel 的编译、移植。
zImage内核文件、设备树文件更新到开发板上
根文件系统:这里部分暂时不是很懂
6、系统和程序的烧写
使用开发板官方的烧写工具
7、Linux应用开发基础
文件IO;进程与线程的理解;
8、Linux驱动的基础
查看芯片手册(对芯片的使用理解更深入);
掌握基本的电路原理图(能基本看懂和使用就行);
驱动程序的框架、设计思想(分层/分离/总线设备驱动)
设备树的引入与改造
了解GPIO和Pinctrl子系统的基本原理和使用
Linux异常与中断的概念以及处理流程
9、ARM裸机的操作与使用
中断实验;LCD显示;
I2C协议的编程;SPI编程(目前还未深入掌握)
主要关注传感器模块的使用(注重使用,不必纠结原理)
10、QT的开发以及移植到开发板上
实现通过GUI达到人机交互的功能(还未学习QT移植的具体操作与方法)
第一个Linux App,实现简单的文本读写
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
int main()
{
//用open去创建一个文件
int fd=open("./2.txt", O_RDWR|O_CREAT|O_TRUNC,0777);
if(fd==-1)
{
printf("-1文件创建失败");
return -1;
}
else {
printf("创建成功\n\r");
}
//定义写入Buf数组
char writBuf[100]="my ID is 315\n\r my name is wss";
//对文件进行数据写入
int writNum=write(fd,writBuf,strlen(writBuf));
printf("writenum:写入成功%d\n\r",writNum);
//将光标从末尾移到开头
int lseekNum=lseek(fd,0,SEEK_SET);
//定义读取Buf数组并进型数据初始化
char readBuf[100] = {};
//对文件进行数据读取
int num=read(fd,readBuf,100);
printf("readBuf:%s\n\r",readBuf);
printf("num:%d\n\r",num);
close(fd);
return 0;
}
第一个驱动程序
韦东山老师的程序
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/errno.h>
#include <linux/miscdevice.h>
#include <linux/kernel.h>
#include <linux/major.h>
#include <linux/mutex.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <linux/stat.h>
#include <linux/init.h>
#include <linux/device.h>
#include <linux/tty.h>
#include <linux/kmod.h>
#include <linux/gfp.h>
/* 1. 确定主设备号 */
static int major = 0;
static char kernel_buf[1024];
static struct class *hello_class;
#define MIN(a, b) (a < b ? a : b)
/* 3. 实现对应的open/read/write等函数,填入file_operations结构体 */
static ssize_t hello_drv_read (struct file *file, char __user *buf, size_t size, loff_t *offset)
{
int err;
printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);
err = copy_to_user(buf, kernel_buf, MIN(1024, size));
return MIN(1024, size);
}
static ssize_t hello_drv_write (struct file *file, const char __user *buf, size_t size, loff_t *offset)
{
int err;
printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);
err = copy_from_user(kernel_buf, buf, MIN(1024, size));
return MIN(1024, size);
}
static int hello_drv_open (struct inode *node, struct file *file)
{
printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);
return 0;
}
static int hello_drv_close (struct inode *node, struct file *file)
{
printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);
return 0;
}
/* 2. 定义自己的file_operations结构体 */
static struct file_operations hello_drv = {
.owner = THIS_MODULE,
.open = hello_drv_open,
.read = hello_drv_read,
.write = hello_drv_write,
.release = hello_drv_close,
};
/* 4. 把file_operations结构体告诉内核:注册驱动程序 */
/* 5. 谁来注册驱动程序啊?得有一个入口函数:安装驱动程序时,就会去调用这个入口函数 */
static int __init hello_init(void)
{
int err;
printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);
major = register_chrdev(0, "hello", &hello_drv); /* /dev/hello */
hello_class = class_create(THIS_MODULE, "hello_class");
err = PTR_ERR(hello_class);
if (IS_ERR(hello_class)) {
printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);
unregister_chrdev(major, "hello");
return -1;
}
device_create(hello_class, NULL, MKDEV(major, 0), NULL, "hello"); /* /dev/hello */
return 0;
}
/* 6. 有入口函数就应该有出口函数:卸载驱动程序时,就会去调用这个出口函数 */
static void __exit hello_exit(void)
{
printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);
device_destroy(hello_class, MKDEV(major, 0));
class_destroy(hello_class);
unregister_chrdev(major, "hello");
}
/* 7. 其他完善:提供设备信息,自动创建设备节点 */
module_init(hello_init);
module_exit(hello_exit);
MODULE_LICENSE("GPL");
使用Source Insight 进行代码的编写,事先导入对应的Linux源码文件,方便查看内核源码
先分析的是入口函数:
register_chrdev函数注册字符设备驱动
第一个参数是主设备号,0代表由系统动态分配。
第二个参数是设备的名字
第三个参数是文件操作指针,file_operations结构体。
class_create动态创建设备的逻辑类,并完成部分字段的初始化,然后将其添加到Linux内核中
device_create函数,创建一个设备节点,并注册它到sysfs中
file_operations结构体。
对应的各个函数open,read,write,close;
read使用copy_to_user,从内核空间到用户空间
write使用copy_from_user,从用户空间到内核空间
第一篇完结,2020/6/8 10:00