I2C从驱动到应用(下篇)

简介:

I2C的应用实例一: 利用i2c读取SPD的信息 

下面以龙芯BIOS为例,介绍如何利用I2C读取内存条上的SPD信息。
1. 硬件连接
龙芯内部的i2c控制器包括时钟发生器、字节命令控制器、状态寄存器、发送寄存器、接收寄存器,结构如下图:
 wKiom1YqED3zY94zAADMVttYhXI379.jpg

主要的寄存器介绍如下:
 wKioL1YqEIOAkQPCAAEo34do7rE662.jpg

wKiom1YqEGbSowk8AAEFu-W3Xxg957.jpg

2. 利用i2c读取内存SPD信息
以读取芯片类型(DDR2,DDR3,DDR4)为例子,根据SPD规范,SPD偏移为2的寄存器表示DIMM Type,如果它的值是0x08,就表示DDR2,如果值为0xb则表示DDR3。
通过上面的寄存器说明,结合i2c读写的时序河代码,我们可以写出如下进行i2c读写的流程:
1.初始化控制寄存器;
2.查询状态寄存器,直至TIP=0(表示i2c控制器空闲);
3.发送地址或者偏移到TX寄存器;
4.设置命令寄存器的START bit和读bit,启动传输;
5.查询状态寄存器直到TIP 和busy bit 都为0,读取接收寄存器。
实现的过程如下:

    dli     a1, 2
    GET_I2C_NODE_ID_a2
   

*i2c_send_b*/              
    /* load device address to write reg offset */
    andi    v1, a0, 0xfe        
    li  v0, H2LS_I2C0_TXR_REG   
    sb  v1, 0x0(v0)     

    /* send start frame */
    li  v1, CR_START | CR_WRITE 
    li  v0, H2LS_I2C0_CR_REG        
    sb  v1, 0x0(v0)     

    /* waite send finished */
//  i2c_wait_tip            
    li  v0, H2LS_I2C0_SR_REG    
1:                      
    lb  v1, 0x0(v0)     
    andi    v1, v1, SR_TIP      
    bnez    v1, 1b          
    nop 
    
    /* send data to be written */
    move    v1, a1          
    li  v0, H2LS_I2C0_TXR_REG   
    sb  v1, 0x0(v0)     

    /* send data frame */
    li  v1, CR_WRITE        
    li  v0, H2LS_I2C0_CR_REG        
    sb  v1, 0x0(v0)     

    /* waite send finished */
//  i2c_wait_tip            
    li  v0, H2LS_I2C0_SR_REG    
1:                      
    lb  v1, 0x0(v0)     
    andi    v1, v1, SR_TIP      
    bnez    v1, 1b           
  nop 

/* i2c_read_b */                   
    /* load device address */
    ori v1, a0, 0x1
    li  v0, H2LS_I2C0_TXR_REG   
    sb  v1, 0x0(v0)     
    
    /* send start frame */
    li  v1, CR_START | CR_WRITE 
    li  v0, H2LS_I2C0_CR_REG        
    sb  v1, 0x0(v0)     

    /* waite send finished */
//  i2c_wait_tip            
    li  v0, H2LS_I2C0_SR_REG    
1:                      
    lb  v1, 0x0(v0)     
    andi    v1, v1, SR_TIP      
    bnez    v1, 1b          
    nop 
    
    /* receive data to fifo */
    li  v1, CR_READ | CR_ACK    
    li  v0, H2LS_I2C0_CR_REG        
    sb  v1, 0x0(v0)     

//  i2c_wait_tip            
    li  v0, H2LS_I2C0_SR_REG    
1:                      
    lb  v1, 0x0(v0)     
    andi    v1, v1, SR_TIP      
    bnez    v1, 1b          
    nop 

    /* read data from fifo */
    li  v0, H2LS_I2C0_RXR_REG                                                                                                                                          
                                 
   lb  a1, 0x0(v0)

/* i2c_stop */              
    /* free i2c bus */
    li  v0, H2LS_I2C0_CR_REG        
    li  v1, CR_STOP     
    sb  v1, 0x0(v0)     
1:                  
    li  v0, H2LS_I2C0_SR_REG        
    lb  v1, 0x0(v0)     
    andi    v1, v1, SR_BUSY     
    bnez    v1, 1b          
    nop             
    
    move    v0, a1

    jr  ra
    nop
END(i2cread)


( 1.写寄存器偏移到SPD;2.读指定偏移的SPD。其中上面的每个步骤都可以再分解成两步:1.写地址到TX 寄存器,start,直到TIP变成0;2.用要读或者写的寄存器偏移填充TX,start,直到TIP变成0 。当然最后是通过清除状态寄存器的busy bit来设置当前控制器从busy状态转移到free状态)。


实现了基本的i2cread读写函数之后,就可以利用它来读取SPD上任意偏移寄存器的信息了,下面摘取了一部分代码:
 bal     i2cread
    nop  
    //only bit[7:0] used
    andi    v0, v0, 0xff 
    /* v0 should be 0xb or 0x8,else error DIMM type */
    dli     a1, 0x08 
    beq     v0, a1, DDR2 
    nop  
    dli     a1, 0x0B 
    beq     v0, a1, DDR3 
    nop  
================
上面的代码主要是调用i2cread函数去访问SPD.

I2C的应用实例二: 利用Integrated SMBus 读取HasWell SPD
和龙芯利用自己的i2c控制器读取SPD信息类似,Intel的HasWell处理器芯片系列也提供了SMBus来访问SPD。 HasWell芯片提供了下面的几个寄存器来专门读取SPD和TSOD的信息:
smb_stat: 重要的位段有
smb_rdo:表示在一次SMBus Read命令执行完成后,这个寄存器的接收数据位段保存读到的数据是有效的
smb_wod:写操作完成
smb_busy:表示当前有i2c或者SMBus的命令正在总线上执行
tsod_sa:保存有上次执行的读取TSOD指令的从地址
smb_rdata:当smb_rdo为1时,这些位段表示接收到的有效数据
smb_cmd: 重要的位段有
smb_cmd_trigger:设置这个bit为1之后,才来出发smbus发送命令
smb_word_access:控制是按照byte还是word来访问device
smb_wrt_cmd:smbus读写控制选择控制的位段
smb_sa:slave address,这个位段决定要访问的SPD或者TSOD
smb_ba:要访问的设备的bus地址
smb_wdata:缓存要通过SPDW指令写入的数据
smb_cntl:重要的位段有
smb_dti (bit31~bit28):指定访问的是SPD还是TSOD,如果访问的是SPD,需要把这个位段设置成2'b1010
smb_ckovrd: 以防任何等待的事务出现,或者使SMbus芯片从hang状态中解放出来
smb_soft_rst: 软件重启smb 控制器,用来终止所有之前还有待进行的传输事务,软件需要,和smb_ckovrd结合通过设置smb_ckovrd=0 且smb_soft_rst=1,维持35ms,来使得smb 控制器恢复空闲状态。
smb_rst_on_forcest: 控制是否让force self reset 信号重启smb 控制器。
了解了上述的寄存器的功能和 用法之后,我们就不难整理出基于HasWell处理器的读取SPD的步骤:
初始化SMbus控制器:利用smb_cntl寄存器中的smb_soft_rst和smb_ckovrd字段来重启smbus控制器;
设置要读取的SPD的i2c 总线地址和从地址、设置按照byte访问、访问模式是写入,往smb_wdata里写入要访问SPD上的寄存器的偏移;
把smb_cmd_trigger设置成1,发送smbus command;
查询状态寄存器的smb_wod 和smb_busy bit,直至它们表示写操作已经完成;
设置要读取的SPD的i2c 总线地址和从地址、设置按照byte访问、访问模式是读出;
把smb_cmd_trigger设置成1,发送smbus command;
查询状态寄存器的smb_rdo 和smb_busy bit,直至它们表示读操作已经完成;
读取状态寄存器中的smb_rdata字段,返回给上层程序。

通过总结HasWell和龙芯访问SPD信息的步骤,我们可以发现控制的流程是相同的,区别就在于不同的Smbus/i2c控制器里相关寄存器的实现不一样,这就要求工程师一定要根据具体的芯片手册,结合I2C/Smubus读写的流程来处理这些差异。












本文转自存储之厨51CTO博客,原文链接:http://blog.51cto.com/xiamachao/1705631 ,如需转载请自行联系原作者







相关实践学习
部署高可用架构
本场景主要介绍如何使用云服务器ECS、负载均衡SLB、云数据库RDS和数据传输服务产品来部署多可用区高可用架构。
负载均衡入门与产品使用指南
负载均衡(Server Load Balancer)是对多台云服务器进行流量分发的负载均衡服务,可以通过流量分发扩展应用系统对外的服务能力,通过消除单点故障提升应用系统的可用性。 本课程主要介绍负载均衡的相关技术以及阿里云负载均衡产品的使用方法。
相关文章
|
8月前
|
传感器 Linux 芯片
嵌入式Linux系列第20篇:驱动编写入门
嵌入式Linux系列第20篇:驱动编写入门
|
物联网 Linux 开发者
驱动简介 | 学习笔记
快速学习驱动简介
88 0
驱动简介 | 学习笔记
|
Java 数据库连接 mybatis
【SSM框架解析】——前篇:详解动态代理【案例驱动】(案例源码自取)
今天开始要学习SSM框架了,新的开始我决定用博客来记录自己的学习过程,和CSDN上的大佬们一同进步。
【SSM框架解析】——前篇:详解动态代理【案例驱动】(案例源码自取)
|
编解码 Ubuntu Linux
树莓派4b入手 (下篇)
系统选择 推荐普通用户使用官方镜像即可. 该系统对树莓派设备适配优化的最为成熟. Download Raspberry Pi OS for Raspberry Pi https://www.raspberrypi.org/downloads/raspberry-pi-os/ 如果直接下载系统包过慢,可以选择下载torrent. 或者去清华 tuna下载站 https://mirrors.tuna.tsinghua.edu.cn/raspberry-pi-os-images/ 去进行下载. 这里推荐使用官方 Raspberry Pi Imager 去安装系统
211 0
树莓派4b入手 (下篇)
领域驱动DDD原理简介与实践(下)
领域驱动DDD原理简介与实践(下)
221 0
领域驱动DDD原理简介与实践(下)
领域驱动DDD原理简介与实践(中)
领域驱动DDD原理简介与实践(中)
128 0
领域驱动DDD原理简介与实践(中)
|
Dubbo 测试技术 应用服务中间件
领域驱动DDD原理简介与实践(上)
领域驱动DDD原理简介与实践(上)
259 0
领域驱动DDD原理简介与实践(上)