struct与union:
最大的区别在于内存利用。 struct各成员各自拥有自己的内存,各自使用互不干涉,同时存在的,遵循内存对齐原则。一个struct变量的总长度等于所有成员的长度之和。union 各成员共用一块内存空间,并且同时只有一个成员可以得到这块内存的使用权(对该内存的读写),各变量共用一个内存首地址。因而,联合体比结构体更节约内存。一个union变量的总长度至少能容纳最大的成员变量,而且要满足是所有成员变量类型大小的整数倍。不允许对联合体变量名U2直接赋值或其他操作。
struct与class:
C++中struct与class关键字一般可以通用,只有一个很小的差别。struct成员默认属性是public,而class成员为private。
struct 结构名
{
类型 变量名;
类型 变量名;
...
} 结构变量;
在使用结构变量时要先对其定义; 结构名是结构的标识符不是变量名;结构是按变量名字来访问成员的;结构体指针采用“->”访问成员,结构体变量采用“.”访问。
需要字节对齐的根本原因在于CPU访问数据的效率问题。假设整型变量不是内存对齐,比如地址在0x00000002,则取值需要2次操作,先取0x00000002-0x00000003的short数据,再取0x00000003-0x00000004的short数据,再合并起来组成整型数据。
带参宏 | 函数 | |
---|---|---|
处理时间 | 编译时 | 程序运行时 |
参数类型 | 没有参数类型问题 | 定义实参、形参类型 |
处理过程 | 不分配内存 | 分配内存 |
程序长度 | 变长 | 不变 |
运行速度 | 不占运行时间 | 调用和返回占用时间 |
引发的问题:
①此函数不是一个可重入函数,而当此函数已经在执行时它可能被另一个ISR所调用。这样就会导致结果是可变的而且很可能会导致一些参数的错误。
②另一个问题就是本地变量和参数所使用的内存可能被其他函数的内存覆盖。如果函数是由中断所调用的,则此函数的内存就会被使用。这会引起其它函数的内存错误。
解决办法:
①如果你100%确认这个函数的两个副本都不会同时执行(如果此函数是被main调用并且中断是未被使能的)并且此函数没有使用内存(只使用的寄存器),那么你就可以忽略此警告。
②如果此函数使用了内存,你就要使用OVERLAY directive来将此函数从覆盖分析(overlay anaysis)中移除。
③无论何时当从main中调用此函数时,需要关闭中断。你可能需要对被调用的函数使用#pragma disable。你也必须使用OVERLAY directive将此函数从overlay analysis中移除。
④为此函数创建两个副本。
⑤使此函数可重入。
https://blog.csdn.net/u011123091/article/details/81748686
优化器在用到使用该关键字定义的变量时需要小心地去内存中取值,而不是取寄存器的备份。
例子:
① 并行设备的硬件寄存器
② 一个中断服务子程序会访问到的非自动变量
③ 多线程应用中被几个任务共享的变量
可以同时使用,例如只读的状态寄存器。
(1)静态存储区分配。内存在程序编译时已分配好,在整个运行器件都存在。
(2)栈上创建。在执行函数时,函数内局部变量的存储单元都可以在栈上创建,函数执行结束时这些存储单元自动释放。
(3)堆上分配。动态内存分配生存期由程序员决定。
设两个栈A、B,一开始为空。
入队:
将新元素push入栈A
出队:
(1)判断栈B是否为空
(2)若不为空,则将栈A中所有元素一次pop出并push到栈B
(3)将栈B的栈顶元素pop出
在计算机中,有些信息存储时并不需要占用一个完整的字节,而只需占用一个或几个二进制位。比如在存放一个只有0和1两种状态的开关量时,用一位二进制位即可表示。因此,为了节省存储空间,C语言提供了一种称为“位域”的数据结构来充分利用存储空间。
① 定义只读常量
② 修饰函数参数表示在函数体内不希望改变参数的值
③ 修饰函数返回值表示返回值不可变,多用于返回指针
const int p; //p是一个常整数型
int const p; //p是一个常整数型
<左数右指>
const int* p; //p可变,p指向的内容不可变
int* const p; //p不可变,p指向的内容可变
int const* p; //p可变,p指向的内容不可变
const int* const p; // p和p指向的内容都不可变
数组要么在静态存储区被创建(如全局数组),要么在栈上被创建。指针可以随时指向任意类型的内存块。
创建两个指针指向链表头结点,然后让其中的一个指针每次移动一个结点,另一个每次移动两个结点,判断两个指针指向的结点是否相同
https://blog.csdn.net/m0_37631322/article/details/81777855
https://www.cnblogs.com/electronic/p/10896510.html
https://blog.csdn.net/qq_33243189/article/details/80222629
系统启动RomBoot --> SPL --> u-boot --> Linux kernel --> file system --> start application
SPL是单板上电后,硬件主动读取Nandflash等存储器读取前4k/8k数据到内存的0地址上,例如S3C2440在上电后就会读取前4k到内存上
第一阶段:
① 设置CPU工作模式svc管理者模式
② 关闭MMU和cache
③ 关看门狗
④ 屏蔽中断(防止程序跑飞)
⑤ 初始化时钟
⑥ 初始化SDRAM
⑦ 设置栈
⑧ 代码重定位
⑨ 清bss段
⑩ 调用start_armboot
第二阶段:
主要是环境参数设置
cache主要用来加快cpu读取内存中指令的速度,但在cpu初始化时,内存起始并未准备就绪,这样直接进行数据读取,势必导致指令取址异常。
简单的讲,uboot利用函数指针及传参规范,它将
R0: 0x0
R1: 机器号
R2: 参数地址
三个参数传递给内核。
其中,R2寄存器传递的是一个指针,这个指针指向一个TAG区域。
参考:https://blog.csdn.net/MoLiYw/article/details/101104184
参考:https://blog.csdn.net/MoLiYw/article/details/101104184
应用程序通过系统调用进入内核,具体执行了swi val,引发一个异常,进入内核的异常处理函数中,根据传入的值调用sys_read函数,再根据打开文件的属性,去找到相应的驱动程序,从而调用驱动程序的read函数来实现功能。
参考:https://www.cnblogs.com/lifexy/p/7542989.html
参考:https://www.cnblogs.com/lifexy/p/7569371.html
参考:https://www.cnblogs.com/MrYuan/p/5245191.html
因为在内核中操作的都是虚拟地址,内核访问不到物理地址,只能通过ioremap映射为虚拟地址,内核才能访问此内存空间。
中断分成上半部分和下班部分的原因主要是因为内核要保证内核中进程的正常调度和运行,中断程序所以需要短小精悍,但是有些驱动在中断处理程序需要完成大量的工作,所以就很耗时。为了解决这个问题就Linux 将中断处理程序分解为两个半部:顶半部(top half)和底半部(bottom half)。顶半部完成尽可能少的比较紧急的功能,底半部就由tasklet或者工作队列的方法实现 。
使用自旋锁的进程不能睡眠,使用信号量的进程可以睡眠。
中断服务例程中的互斥使用的是自旋锁,原因是在中断处理例程中,硬中断是关闭的;但是要注意这样会丢失可能到来的中断。
原子操作指的是无法被打断的操作
insmod调用init函数,rmmod调用exit函数。设计时需要严格记住相关内存的操作后必须在exit中进行释放,避免内存泄漏。如存储,ioremap,定时器,工作队列等等。
卸载失败原因是因为有进程正在使用该模块,这跟我们在windows下拔出正在使用的U盘类似。
(1)void cdev_init(struct cdev *cdev, struct file_operations *fops)
该注册函数可以将cdev结构嵌入到自己的设备特定的结构中。cdev是一个指向结构体cdev的指针,而fops是指向一个类似于file_operations结构(可以是file_operations结构,但不限于该结构)的指针.
(2) int register_chrdev(unsigned int major, const char *name , struct file_operations *fopen);
该注册函数是早期的注册函数,major是设备的主设备号,name是驱动程序的名称,而fops是默认的file_operations结构(这是只限于file_operations结构)。对于register_chrdev的调用将为给定的主设备号注册0-255作为次设备号,
并为每个设备建立一个对应的默认cdev结构。
字符设备:
字符设备是个能够像字节流(类似文件)一样被访问的设备,由字符设备驱动程序来实现这种特性。字符设备驱动程序通常至少实现open,close,read和write系统调用。字符终端、串口、鼠标、键盘、摄像头、声卡和显卡等就是典型的字符设备。
块设备:
和字符设备类似,块设备也是通过/dev目录下的文件系统节点来访问。块设备上能够容纳文件系统,如:u盘,SD卡,磁盘等。
字符设备和块设备的区别仅仅在于内核内部管理数据的方式,也就是内核及驱动程序之间的软件接口,而这些不同对用户来讲是透明的。在内核中,和字符驱动程序相比,块驱动程序具有完全不同的接口。
(1) 应用程序在退出时,可以不管资源的释放或者其他的清除工作,但是模块的退出函数却必须仔细此撤销初始化函数所作的一切。
(2)该机制有助于缩短模块的开发周期。即:注册和卸载都很灵活方便。
由于内核空间和用户空间是不能互相访问的,如果需要访问就必须借助内核函数进行数据读写。
copy_to_user():完成内核空间到用户空间的复制
copy_from_user():是完成用户空间到内核空间的复制
一般用于file_operations结构里的read,write,ioctl等内存数据交换作用的函数。当然,如果ioctl没有用到内存数据复制,那么就不会用到这两个函数。
DMA:
是一种无须CPU的参与就可以让外设与系统内存之间进行双向数据传输的硬件机制,使用DMA可以使系统CPU从实际的I/O数据传输过程中摆脱出来,从而大大提高系统的吞吐率.
中断:
是指CPU在执行程序的过程中,出现了某些突发事件时CPU必须暂停执行当前的程序,转去处理突发事件,处理完毕后CPU又返回源程序被中断的位置并继续执行。
所以中断和DMA的区别就是DMA不需CPU参与而中断是需要CPU参与的。
注册中断:
int request_irq(unsigned int irq, irqreturn_t (*handler)(int, void *, struct pt_regs *), unsigned long flags, const char *dev_name, void *dev_id);
参数意义依次是:中断号,中断处理函数,中断管理有关的掩码,中断请求设备名,中断信号线。
过程是:dev_name设备请求中断->cpu分配中断号->设置中断管理的掩码->分配中断信号线->处理中断函数->完成之后再根据设置情况返回原处理程序处继续处理程序。
注销中断:
Void free_irq(unsigned int irq, void *dev_id);
释放中断和中断信号线
mmap函数实现把一个文件映射到一个内存区域,从而我们可以像读写内存一样读写文件,他比单纯调用read/write也要快上许多。在某些时候我们可以把内存的内容拷贝到一个文件中实现内存备份,当然,也可以把文件的内容映射到内存来恢复某些服务。
另外,mmap实现共享内存也是其主要应用之一,mmap系统调用使得进程之间通过映射同一个普通文件实现共享内存。
参考:https://blog.csdn.net/janneoevans/article/details/8125106
并发(concurrency)指的是多个执行单元同时、并行被执行,而并发的执行单元对共 享资源(硬件资源和软件上的全局变量、静态变量等)的访问则很容易导致竞态(race conditions)。
解决竞态问题的途径是保证对共享资源的互斥访问,所谓互斥访问就是指一个执行单元 在访问共享资源的时候,其他的执行单元都被禁止访问。
访问共享资源的代码区域被称为临界区,临界区需要以某种互斥机 制加以保护,中断屏蔽,原子操作,自旋锁,和信号量都是linux设备驱动中可采用的互斥途径。
https://www.cnblogs.com/guochaoxxl/p/6970090.html
https://www.cnblogs.com/haofei2haojie/p/8466881.html
示波器;抓包
拆分发送,接收端组合;采用共用体;
(1)在数据位的两端添加了起始位,奇偶校验位,停止位等用于进行数据的同步和纠错
(2)接收端用16倍波特率对数据进行采样,取采样中间点的值,这样可以很大程度上确保采样数据的正确性
(3)通过流控制信号(如上面的uart_rts,uart_cts信号)确保数据传输的正确性,不会发生underrun和overrun
考虑大小端问题
串口两端利用union判断大小端,不一致需要逐位调换顺序,组合后数据即正确。
常问时序图、同步与仲裁
参考:https://blog.csdn.net/MoLiYw/article/details/101103224
常问时序图、与UART及IIC区别
参考:https://blog.csdn.net/MoLiYw/article/details/101106543
参考:https://blog.csdn.net/sinat_20265495/article/details/72417137
参考:https://blog.csdn.net/MoLiYw/article/details/101108969
题目来源:
由于时间比较赶,部分答案直接摘取了相关文章的内容,可以通过链接直接进去看,对此向这些博主表示感谢!
[1] https://www.nowcoder.com/discuss/16963
[2] http://news.eeworld.com.cn/mcu/2018/ic-news121942596.html
[3] https://blog.csdn.net/weixin_42832780/article/details/93626215
[4] https://blog.csdn.net/qq_31505483/article/details/75012661
[5] https://blog.csdn.net/zqixiao_09/article/details/50937907
[6] https://blog.csdn.net/kai_zone/article/details/82021233