struct machine_desc以及i2c的学习
struct machine_desc {
unsigned int nr; /* architecture number */
const char *name; /* architecture name */
unsigned long atag_offset; /* tagged list (relative) */
const char *const *dt_compat; /* array of device tree
* 'compatible' strings */
unsigned int nr_irqs; /* number of IRQs */
#ifdef CONFIG_ZONE_DMA
unsigned long dma_zone_size; /* size of DMA-able area */
#endif
unsigned int video_start; /* start of video RAM */
unsigned int video_end; /* end of video RAM */
unsigned char reserve_lp0 :1; /* never has lp0 */
unsigned char reserve_lp1 :1; /* never has lp1 */
unsigned char reserve_lp2 :1; /* never has lp2 */
char restart_mode; /* default restart mode */
struct smp_operations *smp; /* SMP operations */
bool (*smp_init)(void);
void (*fixup)(struct tag *, char **,
struct meminfo *);
void (*reserve)(void);/* reserve mem blocks */
void (*map_io)(void);/* IO mapping function */
void (*init_early)(void);
void (*init_irq)(void);
void (*init_time)(void);
void (*init_machine)(void);
void (*init_late)(void);
#ifdef CONFIG_MULTI_IRQ_HANDLER
void (*handle_irq)(struct pt_regs *);
#endif
void (*restart)(char, const char *);
};
这个结构体定义在mach/arch.h,在内核移植中起着相当重要的作用,内核通过struct machine_desc来控制系统体系架构相关部分的初始化,这个结构体内包含了体系相关的初始化函数:
map_io(),init_irq(),init_machine()等。
用户可以在具体的板卡设备文件中初始化该结构体,一般初始化形式为:
MACHINE_START(GSIA18S, "GS_IA18_S")
.init_time = at91sam926x_pit_init,
.map_io = at91_map_io,
.handle_irq = at91_aic_handle_irq,
.init_early = gsia18s_init_early,
.init_irq = at91_init_irq_default,
.init_machine = gsia18s_board_init,
MACHINE_END
MACHINE_START是一个宏,作用是定义一个struct machine_desc的实例并初始化,放在section(.arch.info.init),是初始化数据,内核启动完成后其所占用的内存会被释放。
struct machine_desc的各个成员会在内核启动的不同时期被调用。
map_io:用于对I/O端口的静态映射,会在系统初始化过程中被调用,流程为:start_kernel()->setup_arch()->paging_init()
inti_machine:会在arch/arm/kernel/setup.c中调用,放在arch_init段里面,会自动按照顺序被调用。
init_irq:调用顺序:start_kernel()->init_IRQ()->init_arch_irq()中被调用
I2C:
I2c通信是适用于小数据量的一种片间低速同步通信协议,速率一般在几百kb,标准模式为100kb/s,快速模式为400kb/s,同时也是一种带有冲突检测和仲裁机制的多主机总线,但是同一时刻只会有一个主机。
连接在总线上的每个器件都会有唯一地址。在嵌入式领域,一般都是以soc上的i2c控制器作为主机,连接在总线上的i2c外设做从机。常见的设备由:e2prom、传感器等。
在主机与从机的通信中,“start”信号是必须的,结束信号和应答信号可以没有。起始信号后面必须发送一个8bit的数据,其中7bit从机地址+1bit标志位。
标志位分为:“write”表示数据的流向是从主机到从机,“read”表示数据流向是从机到主机。
应答信号:ACK表示收到数据。NACK表示未收到数据(发送放接收到这个数据后会停止发数据)
i2c的通信方式为:
一、主机向从机写数据:
1、主机获取SDA的控制权,将其在SCL处于高电平的状态下拉低,发出“start”信号,
2、主机通过广播的方式发出自己想要与之通信的从机地址(8bit数据,最低为为write,表示数据的传输方向是:主机---->从机)
3、从机发出“ack”,告知主机收到
4、主机接收到响应后,发出自己要操作的从机内部寄存器的地址(8bit数据)
5、从机接收到寄存器地址后发出“ack”信号
6、主机发出8bit数据
7、从机接收到数据后向主机发出应答信号。
8、主机发出“stop”
二、主机从主机读数据:
1、主机获取SDA的控制权,在SCL高电平状态下将其拉低,发出“start”信号
2、主机发出8bit数据(7bit是从机地址,1bit表示数据的传输方向:主机---->从机)
3、主机发出8bit数据(从机中的寄存器地址)
主机会再次发送start信号
4、主机发出8bit数据(7bit是从机地址,1bit表示数据的传输方向:从机---->主机)
5、从机向主机发出应答后,主机释放SDA,从机获得控制权,并向主机发出8bit数据
6、主机接收数据后,向从机发出应答信号
7、主机重新获得SDA控制权,发出“stop”
总结:i2c通信是一种半双工通信,同一时刻总线上的数据传输方向是单一的。读写操作的步骤虽然分为好记步,但可以这样理解:
1、不管是写还是读,都需要先将从机地址和从机中需要进行操作的寄存器地址发送给从机,让其做好准备,所以这里的操作标志位应当是write。
2、如果是写操作,那么不需要修改数据的传输方向,执行完步骤1后,从机向主机发出应答,主机便进行写数据。
3、如果是读操作,那么执行完步骤1以后,需要主机再次发出start信号,并且发出从机地址和操作标志位组成的8bit数据,将数据传输方向变更为从机--->主机。
主机在收到从机的应答信号后,就会释放掉SDA,从机获取SDA控制权,向主机发出数据,直到主机发出非应答信号,传输结束。
如何使用示波器测量i2c信号:
1、使用双通道示波器,将SDA与SCL信号接入示波器。成功接入的标志是两个表笔的电平都是高电平。
2、设置示波器:trigger menu中,将触发方式设置为边沿触发(下降沿),信源选择SDA所接的通道。触发模式选择auto,如果需要单次则将触发模式设置为signal。
建议先整体看一下,再单次触发。
波形分析关键点:
如果在第九个时钟周期SDA信号出现异常的尖峰,应该是因为从机将SDA控制权交还给主机造成的。