Newtank

个人站

欢迎来到我的个人站~


嵌入式设备的IO(二)

目录

中断调试

断点

嵌入式系统的中断程序一般处理的是实时性非常高的任务,断点对中断调试几乎没有用处。

中断调试准则

  • 降低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
认知度高、经济有效、简单 安全、快速 快速、即插即用、简单、低成本 快速、广泛接受、低成本、大型系列 简单、认知度高、广泛接受、即插即用、大型系列、经济有效
功能有限、点对点 复杂、固件昂贵 需要强大主机、需指定驱动 无即插即用硬件、无固定标准 有限速率