中断调试
断点
嵌入式系统的中断程序一般处理的是实时性非常高的任务,断点对中断调试几乎没有用处。
中断调试准则
- 降低ISR的复杂度(10-20行)
- 充分利用前后台架构
- 进行肉眼调试
可重入性
在中断执行后例程没有变化,可以安全的并行执行,可重入的代码需满足以下条件
- 原子性使用所有共享变量,除非都被特别分配
- 不调用不可重入函数
- 不进行IO调用
递归函数一定是可重入的。
原子变量
对原子变量的操作是不可分割(中断)的。
- mov ax,bx
- temp=foobar; temp+=1; foobar=temp;
- foobar+=1
以上三种操作中第一句是原子的,第二句不是。
第三句需要看对应的汇编指令:
- mov ax,[foobar]; inc ax; mov [foobar] ax
- inc [foobar]
- lock inc [foobar]
其中第三种是原子式的
保持可重入性
保持可重入性有以下的手段
- 去除共享变量,使用局部变量或动态分配的变量
- 屏蔽中断(临界区)
- 信号量
异步
int timer_hi;
interrupt timer(){
++timer_hi;
}
long timer_read(void){
unsigned int low, high;
low=inword(hardware_reg); //通过硬件获取低16位时间
high=timer_hi; //通过软件获取高16位时间
return (high<<16+low);
}
以上代码存在问题。
假设高位为0,低位为0xffff,在计算完low(0xffff)后时钟触发ISR操作,硬件存储的部分+1溢出触发timer(),导致high变为1,得到0x1ffff的错误结果。
解决方案:
- 屏蔽计时器中断,可能导致时钟的延迟与准确性
- 采取验证:首先读取高位,再读取硬件,再读取高位。如果高位值不变则可以返回;否则重新执行上述三步。
- 优点:保证准确性
- 缺点:高实时环境下可能需要反复很长时间,具有不确定的执行时间
- 屏蔽中断
long timer_read(void){
unsigned int low, high;
push_interrupt_state;
disable_interrupts;
low=inword(hardware_reg);
high=timer_hi;
if(inword(timer_overflow)){
++high;
low=inword(hardware_reg);
}
pop_interrupt_state;
return ((ulong)high<<16+(ulong)low);
}
总线
总线包含:
- 一系列缆线
- 对应的通信协议
总线协议
- 通过状态机描述
- 包含异步逻辑行为
多总线结构
- 慢设备共用一条总线
- 快设备各自使用总线
- 使用桥接器连接多个总线
- 北桥芯片离CPU较近,连内存、显卡等高速设备
- 南桥芯片离CPU较远,连鼠标、键盘等低速设备
常见的总线协议
UART | CAN | USB | SPI | PC |
---|---|---|---|---|
认知度高、经济有效、简单 | 安全、快速 | 快速、即插即用、简单、低成本 | 快速、广泛接受、低成本、大型系列 | 简单、认知度高、广泛接受、即插即用、大型系列、经济有效 |
功能有限、点对点 | 复杂、固件昂贵 | 需要强大主机、需指定驱动 | 无即插即用硬件、无固定标准 | 有限速率 |