一、复习进线程
进程间通信:无名管道、有名管道、共享内存、信号(信号量/消息队列)、套接字。
共享内存不自带同步互斥机制:
- 多个进程同时读写会造成数据混乱
- 必须配合 信号量 / 互斥锁 来控制访问顺序
线程:互斥锁、读写锁、自旋锁(忙 等待)、信号量(同步)
cs
读写锁
// 共享数据
int shared_data = 0;
// 读写锁
pthread_rwlock_t rwlock;
// 写线程函数:写者互斥,与读者也互斥
void* writer(void* arg) {
int id = *(int*)arg;
// 加写锁
pthread_rwlock_wrlock(&rwlock);
printf("写线程 %d 获取写锁,开始修改数据...\n", id);
shared_data++;
sleep(1); // 模拟写操作耗时
printf("写线程 %d 修改完成,shared_data = %d,释放写锁\n", id, shared_data);
// 释放写锁
pthread_rwlock_unlock(&rwlock);
return NULL;
}
// 读线程函数:读者之间共享,与写者互斥
void* reader(void* arg) {
int id = *(int*)arg;
// 加读锁
pthread_rwlock_rdlock(&rwlock);
printf("读线程 %d 获取读锁,读取数据:shared_data = %d\n", id, shared_data);
sleep(1); // 模拟读操作耗时
printf("读线程 %d 读取完成,释放读锁\n", id);
// 释放读锁
pthread_rwlock_unlock(&rwlock);
return NULL;
}
自旋锁 :轻量级锁 ,比互斥锁更快,适合锁内操作极短的场景,也是共享内存同步常用的高性能锁。
cpp
pthread_spinlock_t spin_lock;
网络编程:
ISO七层模型:应用、表示、会话、传输、网络、链路、物理
四层模型:应用、传输、网络、链路接口
MAC地址(网卡硬件地址) IP地址(区分主机) 端口(区分进程)
TTL = 数据包最多跳多少个路由器,到 0 就死。
DHCP(动态主机配置协议)
- IP 地址
- 子网掩码
- 默认网关
- DNS 服务器地址
Static:静态 IP 配置。
网段:A、B、C、D、E子网掩码:255.255.255.0
把 IP 地址 切成两段:
- 网络位 → 标识这个网段
- 主机位 → 标识这个网段里的某台设备
然后判断:两台设备的网络位是否相同 → 相同 = 同一局域网;不同 = 跨网段。
划分网段为1的位必须一致才属于同一局域网。
网络号(子网掩码中为1的位)主机号(子网掩码中为0的位)。
同一网段指的是网络号相同的IP(相互连通)。
二、ARM中断
1、设置异常向量表地址为0(为0则可以重映射) //start.S
中断初始化:
1.重映射异常向量表基地址
2.初始化GIC
中断源:key_init()引脚相关:配置引脚功能及方向 GPIODIR
设置中断触发方式、使能中断 GPIO_ICR GPIO_IMR
GIC中断使能 GIC_EnableIRQ(IRQn_Type IRQn)
GIC中断优先级设置 GIC_SetPriority(IRQn Type IRQn, uint32_t priority)
清中断标志:GPIO_ISR**(GPIO_IMR |= (1<<pin)**;


cs
get GIC--IAR // 读取 GIC 的 IAR 寄存器,获取当前中断号
deal irq // 根据中断号调用对应的 C 语言处理函数
set GIC--EOIR // 向 GIC 的 EOIR 寄存器写入,告知中断处理完成
| 数组名 | 用途 | 对应中断类型 |
|---|---|---|
irq_handler_array |
通用中断处理函数表 | 普通外设中断(UART、Timer、I2C、IOMUXC 等独立中断号) |
irq_gpio_handler_array |
GPIO 专用中断处理函数表 | GPIO 分组中断(如 GPIO1_IO18_IRQ 这类引脚级中断号) |
ARM 中断处理汇编(IRQ 入口)
cs
_irq_handler:
sub lr, lr, #4 修正返回地址:IRQ 异常返回时LR多4,必须减 4 才能正确返回 */
stmfd sp!, {r0-r12, lr} 保存通用寄存器r0~r12和lr到IRQ 模式栈(满减栈) */
mrc p15, 4, r1, c15, c0, 0 从 CP15 协处理器读取 GIC 基地址 → r1 */
add r1, r1, #0x2000 计算 GIC CPU 接口基地址 = GIC 基 + 0x2000 */
ldr r0, [r1, #0xc] 读取 GIC_IAR(中断确认寄存器)→ r0,获取中断号 */
stmfd sp!, {r0,r1} 保存 r0(中断号)、r1(GIC 地址)到栈 */
cps #0x1f /* 切换到系统模式(System Mode),允许嵌套中断 / 运行 C 函数 */
stmfd sp!, {r0-r12, lr} 保存系统模式下的寄存器环境 */
bl system_irq_handler 调用 C 语言中断处理函数(真正业务逻辑) */
ldmfd sp!, {r0-r12, lr} 恢复寄存器,从 C 函数返回 */
cps #0x12 切回 IRQ 模式,继续完成硬件中断收尾 */
ldmfd sp!, {r0, r1} 恢复之前保存的 GIC 地址 r1、中断号 r0 */
str r0, [r1, #0x10] 写GIC_EOIR(中断结束寄存器),通知中断控制器:处理完成*/
ldmfd sp!, {r0-r12, pc}^
恢复所有寄存器,^ 表示同时恢复SPSR→CPSR,真正返回被中断的程序 */
ARM 处理器的复位初始化代码
cs
_reset_handler:
/* DDR 地址范围:0x80000000 ~ 0xA0000000(512MB 内存空间)*/
cpsid i 关闭全局中断 IRQ,防止初始化阶段被打断 */
ldr sp, =0x81000000 初始化【系统模式】栈指针,栈顶地址 0x81000000
栈空间大小:16MB,用于系统模式运行 */
配置 CP15 协处理器 c1 寄存器(开启/关闭缓存相关)*/
mrc p15, 0, r1, c1, c0, 0 读取 CP15 控制寄存器 c1 → r1 */
orr r1, r1, #(1 << 12) /* 置位第12位:使能 I-Cache 指令缓存 */
bic r1, r1, #(1 << 13) /* 清零第13位:禁止 D-Cache 数据缓存 */
mcr p15, 0, r1, c1, c0, 0 将配置写回 CP15 寄存器生效 */
cps #0x12 切换 CPU 工作模式 → IRQ 中断模式 */
ldr sp, =0x82000000 初始化【IRQ 中断模式】栈指针,栈顶 0x82000000
栈空间大小:16MB,专门给中断服务程序使用 */
cps #0x1f 切换 CPU 工作模式 → 系统模式(System Mode)*/
ldr sp, =0x83000000 再次初始化【系统模式】栈指针,栈顶 0x83000000
栈空间大小:16MB,给 C 语言 main 函数运行 */
cpsie i 开启全局中断 IRQ,允许中断触发 */
bl main
IMX6ULL 按键中断初始化
cs
按键中断初始化函数:配置GPIO为下降沿/上升沿中断输入
void key_irq_init(void)
{
1. 设置引脚复用:将 UART1_CTS_B 复用为 GPIO1_IO18 功能
0 表示复用功能为普通GPIO(无其他复用)
IOMUXC_SetPinMux(IOMUXC_UART1_CTS_B_GPIO1_IO18, 0);
2. 配置引脚电气属性:上拉、禁止开路输出、速度中等、驱动能力等
0x10b0 是IMX官方推荐的按键输入配置值
IOMUXC_SetPinConfig(IOMUXC_UART1_CTS_B_GPIO1_IO18, 0x10b0);
3. 配置GPIO1_IO18为输入模式
GDIR:方向寄存器,0=输入,1=输出
~(1<<18) 把第18位清零 → 输入
GPIO1->GDIR &= ~(1 << 18);
4. 配置中断触发方式:ICR2 控制 GPIO16~31
(0x3 << 4):GPIO1_IO18 对应第4位开始,设置为 11 = 双边沿触发(上升+下降沿)
00=低电平 01=高电平 10=下降沿 11=上升沿
GPIO1->ICR2 |= (0x3 << 4);
5. 使能GPIO1_IO18中断
IMR:中断屏蔽寄存器,1=使能中断,0=屏蔽中断
GPIO1->IMR |= (1 << 18);
}