• 17
  • 8月

在KeilC的选项中,C51这一项里有一项叫做“Don't use absolute register accesses”。我们已经因为这一项出了三次Bug了。

那么这一项有什么作用呢?

在KeilC默认中,这一项并没有选上,表示KeilC将使用寄存器的绝对定位来优化程序。什么意思呢?我们知道,51中有四组通用寄存器。在寄存器组0的时候,R0-R7实际上就映射到了0x01-0x07这段地址。也就是说有时候为了优化,KeilC将会使用0x01-0x07这样的绝对地址。举个简单的例子吧,比如说我们需要将寄存器R5的值存入R7,正常我们会这样写:
MOV A, R5
MOV R7, A
但是如果使用寄存器的绝对定位呢?我们就可以这样写了:
MOV R7, 0x05
节省了一条指令的执行时间!
当然,正常时候这样使用当然没有任何问题。然而,如果有一个中断的服务程序,我们使用了寄存器组1呢?这时候,R5就不再是0x05了,而是0x0D!因此,Bug就出来了。
当然,我们可以在这个中断服务程序上所调用的所有子程序中加在using 1的关键字来解决这个问题。不过这样还是带来了一些不便,更有一些时候,一些子函数是多处调用了。因此,有时我们一般都直接勾选了这个选项来取消KeilC的这项优化。

  • 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模式。

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

就先简单记到这了。