振南的PATA IDE硬盘调试记
关于IDE硬盘振南早就有过研究,当然是用圈圈的USB学习板作过一个“USB移动硬盘”,过后就再没有关心了,开始全力转向了SD卡、CF卡以及U盘等存储设备的研究,以至于后来的FAT32文件系统、znFAT,还有书的出版。
最近,有网友跟我说他在用单片机驱动PATA IDE硬盘,已取得成功,并且对ATA协议颇有研究,产生了写书的念头。我鼓励他把研究进行到底,把书的写作**到最后,同时我也告诫他不可三分热情,写书不是一时半会儿的事情,需要一定的毅力。
这又勾起了我对IDE硬盘的兴趣,原因有几点
1、IDE硬盘现在有比较高的性价比,一个40G的硬盘,只需要10几块钱,比各种存储卡要便宜,而且读写速度要快得多;
2、作一套IDE硬盘读写模块,为我的ZN-X系列开发板扩展功能和接口,基于硬盘高速的读写性能,可以作出更多精彩的实验;
3、IDE接口可以衍生出很多设备,比如CF卡、SATA硬盘、SSD固态硬盘等等,同时也可以作为ZN-X的IO扩展。
IDE硬盘的驱动方式其实非常简单,整个驱动程序不过百行代码,但是经过实际的调试,我发现真正要把它作到稳定可靠,也不容易。我一开始觉得硬盘读写模块在设计上应该比较简单,但是历时近1个月,却遇到很多问题。
IDE硬盘采用16位并行数据接口,外加上3个地址线(用于选择8个功能寄存器),还有两个片选,一个复位,一个判忙,读使能与写使能,一共需要25个IO。具体的接口定义如下:
数据传输读写的时序非常简单,就是标准的并行总线时序,如下所示:
最大的问题是如何尽量的减少IDE接口对IO资源的占用,针对这一问题,振南在IDE硬盘读写模块的设计上提出了3种方案,它应对了3种不同的接口和读写方式。
1、使用单片机的IO与硬盘IDE接口相连,这是最浪费IO的方案,但是最直接,也最高效高速。适合于IO比较多的单片机。
2、使用少量的IO扩展出更多的IO,通过它们再比IDE接口相连,间接的实现对硬盘的读写。振南使用了经典的并行IO扩展芯片,82C55(我原以为这种古老的芯片并没什么可说的,但是后来我发现82C55也有很多门道,后面慢慢再说)。它通过一个8位的数据端口和几个控制信号可以扩展出24个IO(PA、PB与PC,其中PC还可以位操作,非常适合作控制信号,比如说作为片选信号;同PA与PB合并起来作为IDE接口的16位数据)。我原以为82C55芯片与IDE接口,可以同时作为单片机的总线设备,把读写使能信号同时接在单片机的WR和RD上,通过不同的地址来操作。我甚至已经把PCB设计出来了,但是后来我发现大错特错了,82C55和IDE的读写使能绝对不能接在一起,“它们在工作的时候,不是独立的,而是嵌套的!!!”(后面详解)。
3、使用极少的IO扩展出更多的IO,比如可以使用SPI。振南为了实现这种方案,一直在寻找一种SPI接口的IO扩展芯片,但并没有找到。不过我倒是找到了PCF8754,一个I2C接口的远程IO扩展芯片,它是8位的。也有16位的,PCF8575。我一度认为我找到了好的方案,但是后来我发现PCF8574无法胜任我的需求,原因是它太慢了。PCF8574的I2C接口,最大速率可以到400kbps,也就是每秒最多50KBps,实际工作时,也就20-30KBps,这样的速度是无法容忍的。IDE硬盘的读写速度动辄几百KBps,上兆KB,几十兆KB,如果使用I2C接口的PCF8674的话,那I2C的速度甚至不能称其为“瓶颈”,只能叫“死喉”!太慢了!
有人给我建议说可以使用74HC595或者74HC165,这确实是一种价格极为低廉,速度可以飙到很高的方法(74系列HC的芯片工作时钟可以到几十MHz),配合单片机的硬件SPI,由它扩展出来的IO速度还是非常快的。但是它们并行端口都是单向的:74HC595是8位串转并,74HC165是8位并转串。只使用其中之一,不能实现双向IO的功能。所以需要一并使用,而且还需要级联。很多人对于595和165的级联使用方法不是很熟悉,其实这种级联的方式,在SPI中有一种好听的名字叫“菊花链”,总让我想起“菊花残”。下图是级联应用的电路图,以供参考。
通过级联,可以由3片74HC595产生24位的输出IO,由2片74HC165产生16位的输入IO。24位输出IO其中16位与16位输入IO短接,成为双向IO,与IDE的16位数据相连。而其余的8个输出IO,用于控制IDE的地址线与片选等信号。
74HC595与74HC165互相协同工作,在实际调试的时候还是有一些细节需要注意的(不要让74HC595的输出干扰了74HC165的输入)。
振南一直的作风都是物尽其用,希望在一个PCB上加上更多的功能,所以我起先的想法是把这三种驱动方案同时作到一个模块上,通过跳线来选择采用哪种驱动方式,这注定就引入了较高的复杂度和难度,以至于后来我才考虑将3种模式单独分开,各出一个模块。
要将上述3种接口方案,作到一块PCB上,最大的问题就是如何灵活的在3种驱动模式之间切换。可以看到,3种方案,IDE接口的信号分别接到了单片机的IO、82C55扩展出来的IO以及595+165扩展出来的IO上。
我需要一种单刀三掷开关。机械开关?不现实,需要要切换的信号线太多了!数据选择器芯片?不行,它是单向的!模拟开关芯片?好像很少有多路而且是单刀三掷的。但是我确实找到了一些多通道的开关芯片(SPDT,SinglePoleDoubleThrow,即单刀双掷,同理单刀单掷是SPST,我所需要的单刀三掷是SP3T),比如SGM5018。
我曾经考虑过使用多个SPDT来组成一个SP3T。但是成本太高了。一个SGM5018有4路单刀双掷开关。IDE信号一共有20几个,大约需要10几片SGM5018,一片SGM5018大约是3块钱,这就需要近40块钱。于是我最终放弃了这种信号切换的方案。
最后我还是用了最坏的办法,使用0欧电阻来跳线。我专门设计了一种封装,形状就像是“核辐射标志”一样。
这样作的坏处就是降低了灵活性,要改变接口方式的时候,必须动用烙铁。
实际上,如果能有一种3档的旋转拨码开关就好了。