• 23
  • 5月

这个东西老是忘,在这里记录一下吧。

USB设备是DP上有1.5K的上拉,DM悬空。

USB主机是DP和DM上都有15K的下拉。

一个是1.5K,另一个是15K;

一个是上拉,另一个是下拉。嗯,记清楚了。

  • 16
  • 5月

CMD6是SD卡用来扩展功能的一条重要命令。在SD协议1.00和2.00的版本是,该命令主要用于切换卡进入高速模式。而在3.00的协议中,该命令被赋予了更多的功能。

首先来说说功能模块的基本结构吧。SD卡协议中定义了6组功能,每组功能相当于是一组单框,我们可以根据自己不同的需要,来对每一组功能进行不同的选择。

这里以SD协议2.00版本为例,共定义了两种功能:Group1该组功能的名称叫AccessMode,主要就是用于速度上的选择了。默认选项为0x0,即25MHz的总线速度。我们可以将其选为0x1 High-Speed,即可进入到50MHz的总线速度模式了。Group2功能的名称叫Commandsystem,看样子是做一些命令上的扩展。怀疑可能会与加密卡有关,这里没有进行进一步的研究。

因此,简单的说,CMD6我们主要就是用于SD卡高速模式的切换了。下面说说该命令切换高速模式的用法。

CMD6命令共有查询模式和设置模式两种。查询模式主要用于查询是否支持该功能,而设置模式主要用于对该功能的设置。我们采取的流程是先查询,后设置。根据SPEC,因此,我们第一次发送的命令参数应该为:0x00, 0xff, 0xff, 0xf1。该命令的作用是查询AccessMode是否支持High-Speed。命令发送完毕,这里需要注意的是,CMD6并不是用命令总线,而是用数据总线来进行应答。在命令发送完毕时,我们会从数据总线上接收到64Byte的数据。根据SPEC,我们判断第17Byte的低4Bit(data_buf[16]&0x0f)是否等于1。是则继续,否则表示不支持高速模式。

确认SD卡支持高速模式后,我们第二次发送CMD6的参数为:0x80, 0xff, 0xff, 0xf1。该命令的作用是设置AccessMode为High-Speed。命令发送完毕,我们再一次查询接快收数据第17Byte的低4Bit (data_buf[16]&0x0f)是否等于1。如果是,则表明切换成功,接下来就可以调整SD主机模块的时钟和边沿控制了。

  • 7
  • 3月

做SD/MMC卡驱动的项目也有大半年了,总觉得该总结些什么了。在这里,主要就是记录一些比较常见的问题及解决方法,以免再一次遇到。

首先就是SD/MMC卡的初始化错误问题。在找错误之前,先确认:1.用读卡器确认这张SD卡是否损坏;2.用另一套环境(一样的程序)读取同一张卡,是否正常;3.用相同的环境读取另外一张SD卡是否正常。如果是1,那么就直接退出本文章了;如果是2,那么就是该环境上出现虚焊短路或芯片损坏,问题也比较好办;如果是3,那么就说明程序和环境问题不大,可能是一些细节上的问题,可以参考以下内容的其中一部分;如果都不是,那么就要开始排查了。

寻找这类错误的原因,首先要检查的就是硬件。我想,第一步,我会确认原理图,看IO的连接是否正确,用万用表确认IO没有虚焊、短路。接下来,用示波器(如果没有,只能用万用表了),测量SD卡座的电源脚。一般来说,电压值应该在3.3V左右,如果相差过大,可能就是电路错误,或者LDO的供电能力不足了。

如果确认完以上两步,那么,硬件方面问题就不大了。接下来要确认的是固件上驱动程序的问题了。一般来说,如果这时候有个逻辑分析仪,那么问题就简化了。如果没有,只能按经验来一步一步排查了。首先要检查的是上电顺序,还记得在血的教训一文中提到这个问题。简单地说,就是先开电,再上拉。上电OK了?那么就看看初始化程序了。确认刚上电时的时序控制在100KHz到400KHz之间(一般采用240KHz左右,这里最好能用示波器确认),在发送第一条命令之前,确认主机已经发送足够的时钟(好像是74个时钟以上)。

然后,正式进入初始化程序。这里需要说一下SD/MMC卡的区分,浅谈SD卡和MMC卡的异同一文中也稍微讲了下这些。一般来说刚上电时,SD卡不支持CMD1而支持CMD55,MMC卡不支持CMD55而支持CMD1,这样就可以区分这两种卡。然后SD1.1和SD2.0卡主要通过CMD8来区分,总之,就是按照SPEC上的要求了。还要注意的是:上电时CMD55的参数为全0,ACMD41在SD1.1和SD2.0上的参数会有所不同。发送CMD0的时候,注意IO口电平,以防误入SD卡的SPI模式。

到了这一步,如果能够激活成功,后面的问题也就不大了。具体问题还需要具体分析。

就先简单记到这了。

  • 26
  • 11月

这几天一直被一个叫Global Offset Table的东西困扰着。

在uboot的程序上看到一个叫_GLOBAL_OFFSET_TABLE_的东东,却到处找不到。经过一番Google,才明白这东东叫全局变量偏移表,用来做与位置无关的程序编译时使用的。并且编译选项要加上-mabicalls。另:与程序位置无关的编译选项是:-fpic和-fPIC。

Global Offset Table里,存得是一些函数地址,放在.got段。一般是使用gp来访问。

不过在资料中还看到,这个主要用于一些动态库。如果没用到动态库的话,应该也不是十分太需要吧,毕竟使用GOT会影响small data的使用,同时会增加每个函数调用所需的指令。

  • 25
  • 11月

费了好大的劲,终于知道gp寄存器的用法了。

首先说说gp寄存器出现的原因吧,由于RISC体系的CPU,每条指令都是32Bit,而地址总线也是32Bit,这样,就不可能通过一条指令来实现Memory的访问。

MIPS中,访问Memory的指令格式为:

lw r1, offset(r2)

其中,offset为16Bit,也就是说,最多能访问以r2为基地址,前后32K的空间。

于是这个时候,gp就闪亮登场了。

我们知道,GCC在编译过程,会将变量分别放在data,bss,common等段。而编译mips程序时,会将小变量放入sdata,sbss,scommon等段。这个大小由编译选项-G来决定。-G0则表示不使用小数据段。默认是-G8,表示小于或等于8 byte的数据将放入小变量区。

这样的话,在上电时给gp初始化一个值,那么,所有小变量区的变量就可以通过

lw r1, offset(gp)

来访问了。

那么,GCC怎么知道gp初始化的值呢?只要在link文件中添加_gp符号,连接器就会认为这是gp的值。我们在上电时,将_gp的值赋给gp寄存器就行了。