打印
[51单片机]

【振南的PATA IDE硬盘调试记】★★

[复制链接]
1196|5
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
znmcu|  楼主 | 2015-10-29 17:43 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
本帖最后由 znmcu 于 2015-10-30 08:42 编辑

http://www.znmcu.cn/zn_ide_debug.html



振南的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-XIO扩展。
IDE硬盘的驱动方式其实非常简单,整个驱动程序不过百行代码,但是经过实际的调试,我发现真正要把它作到稳定可靠,也不容易。我一开始觉得硬盘读写模块在设计上应该比较简单,但是历时近1个月,却遇到很多问题。
IDE硬盘采用16位并行数据接口,外加上3个地址线(用于选择8个功能寄存器),还有两个片选,一个复位,一个判忙,读使能与写使能,一共需要25IO。具体的接口定义如下:
数据传输读写的时序非常简单,就是标准的并行总线时序,如下所示:
最大的问题是如何尽量的减少IDE接口对IO资源的占用,针对这一问题,振南在IDE硬盘读写模块的设计上提出了3种方案,它应对了3种不同的接口和读写方式。
1、使用单片机的IO与硬盘IDE接口相连,这是最浪费IO的方案,但是最直接,也最高效高速。适合于IO比较多的单片机。
2、使用少量的IO扩展出更多的IO,通过它们再比IDE接口相连,间接的实现对硬盘的读写。振南使用了经典的并行IO扩展芯片,82C55(我原以为这种古老的芯片并没什么可说的,但是后来我发现82C55也有很多门道,后面慢慢再说)。它通过一个8位的数据端口和几个控制信号可以扩展出24IOPAPBPC,其中PC还可以位操作,非常适合作控制信号,比如说作为片选信号;同PAPB合并起来作为IDE接口的16位数据)。我原以为82C55芯片与IDE接口,可以同时作为单片机的总线设备,把读写使能信号同时接在单片机的WRRD上,通过不同的地址来操作。我甚至已经把PCB设计出来了,但是后来我发现大错特错了,82C55IDE的读写使能绝对不能接在一起,“它们在工作的时候,不是独立的,而是嵌套的!!!”(后面详解)。
3、使用极少的IO扩展出更多的IO,比如可以使用SPI。振南为了实现这种方案,一直在寻找一种SPI接口的IO扩展芯片,但并没有找到。不过我倒是找到了PCF8754,一个I2C接口的远程IO扩展芯片,它是8位的。也有16位的,PCF8575。我一度认为我找到了好的方案,但是后来我发现PCF8574无法胜任我的需求,原因是它太慢了。PCF8574I2C接口,最大速率可以到400kbps,也就是每秒最多50KBps,实际工作时,也就20-30KBps,这样的速度是无法容忍的。IDE硬盘的读写速度动辄几百KBps,上兆KB,几十兆KB,如果使用I2C接口的PCF8674的话,那I2C的速度甚至不能称其为“瓶颈”,只能叫“死喉”!太慢了!
有人给我建议说可以使用74HC595或者74HC165,这确实是一种价格极为低廉,速度可以飙到很高的方法(74系列HC的芯片工作时钟可以到几十MHz),配合单片机的硬件SPI,由它扩展出来的IO速度还是非常快的。但是它们并行端口都是单向的:74HC5958位串转并,74HC1658位并转串。只使用其中之一,不能实现双向IO的功能。所以需要一并使用,而且还需要级联。很多人对于595165的级联使用方法不是很熟悉,其实这种级联的方式,在SPI中有一种好听的名字叫“菊花链”,总让我想起“菊花残”。下图是级联应用的电路图,以供参考。
通过级联,可以由374HC595产生24位的输出IO,由274HC165产生16位的输入IO24位输出IO其中16位与16位输入IO短接,成为双向IO,与IDE16位数据相连。而其余的8个输出IO,用于控制IDE的地址线与片选等信号。
74HC59574HC165互相协同工作,在实际调试的时候还是有一些细节需要注意的(不要让74HC595的输出干扰了74HC165的输入)。
振南一直的作风都是物尽其用,希望在一个PCB上加上更多的功能,所以我起先的想法是把这三种驱动方案同时作到一个模块上,通过跳线来选择采用哪种驱动方式,这注定就引入了较高的复杂度和难度,以至于后来我才考虑将3种模式单独分开,各出一个模块
要将上述3种接口方案,作到一块PCB上,最大的问题就是如何灵活的在3种驱动模式之间切换。可以看到,3种方案,IDE接口的信号分别接到了单片机的IO82C55扩展出来的IO以及595+165扩展出来的IO上。
我需要一种单刀三掷开关。机械开关?不现实,需要要切换的信号线太多了!数据选择器芯片?不行,它是单向的!模拟开关芯片?好像很少有多路而且是单刀三掷的。但是我确实找到了一些多通道的开关芯片(SPDTSinglePoleDoubleThrow,即单刀双掷,同理单刀单掷是SPST,我所需要的单刀三掷是SP3T),比如SGM5018
我曾经考虑过使用多个SPDT来组成一个SP3T。但是成本太高了。一个SGM50184单刀双掷开关。IDE信号一共有20几个,大约需要10几片SGM5018,一片SGM5018大约是3块钱,这就需要近40块钱。于是我最终放弃了这种信号切换的方案。
后来,我确实找到了SP3T芯片,ADI生产的,而且不光有SP3T,还有SP4TSPNT。不过这些芯片大多是用于高端设备的,非常贵。而且大多都是单路的。有需要的童鞋可以参考这个链接:http://www.analog.com/cn/products/switches-multiplexers/rf-switches/spst-spdt-sp3t-sp4t-sp6t-sp8t.html
最后我还是用了最坏的办法,使用0欧电阻来跳线。我专门设计了一种封装,形状就像是“核辐射标志”一样。
这样作的坏处就是降低了灵活性,要改变接口方式的时候,必须动用烙铁。
实际上,如果能有一种3档的旋转拨码开关就好了。


三种模式共处一板,更大的问题是电路和元件的冗余,还有不够美观。当使用某一个模式时,另两种模式的相关电路和元件都将闲置,虽然我使用了芯片座,以便不使用时可以将芯片拆下来。但是光秃秃的芯片座以及没有焊接的空焊盘,给人一种很糟糕的感觉。所以,这致使我最终放弃把三种模式作在一起,而是分成了独立的3个模块。


硬盘读写模块上还有一部分,其实算是纯电路的东西,我研究了比较长的一段时间,它就是电平转换电路。IDE接口的工作电压是5V,但是单片机的IO却不一定是5V,现在更多情况下IO3.3V,比如STM32LPC17XX等,就连一些51芯片也都是3.3V5V的芯片越来越少,所以需要3.3-5电平转换。虽然在很多情况下,5V器件是可以识别3.3V为高电平的,IDE接口标准里也确实指明它可接受的高电平最低电压是2.V,但是我认为用3.3V仍然是存在隐患的,最根本的办法还是加入电压转换。
电平转换是个老声长谈的问题。如果是单向的电平转换,比较好解决,比如3.3V转到5V,最简单可以用上拉,或者三极管电路;5V3.3V,可以用钳制二极管、电阻分压等。最简单的方法是用74HC244作缓冲器。但是对于IDE硬盘接口电路来说,比这个要麻烦,因为它是双向的。单片机在向硬盘写数据的时候,需要3.3V->5V;而读取数据的时候,需要5V->3.3V,它存在一个转换方向的问题。
最简单的办法是直接在单片机的IO上加5V上拉,直接拉成5V,去驱动IDE。而IDE输出的5V信号也直接进入单片机的IO,前提是单片机的IO如果能承受5V的话!这种方法是不可靠的。这种情况下,可以使用专用的双向电平转换芯片,比如74LVC4245。它是8位双向3.3-5V电平转换芯片。它带有一个DIR端,即方向控制。问题就在于这个DIR,我需要专门从单片机上分配出一个IO给它。而对于IO资源比较紧张的应用场合,能省掉这个IO当然是最好的。问题就是:是否能够让电平转换芯片能够自动地、智能地判断电平转换的方向。单片机在与IDE读写数据的过程,不需要去关心电平转换方向的问题,这有三点好处
1、节省了IO资源
2、电平转换对于使用者透明
3、提高了单片机与IDE接口之间的数据读写效率
但是如何实现呢?我开始寻找是否有芯片具有这种自动判断电平转换方向的功能,结果确实有!TXB0108。它可以通过检测电平双方的电流和电压变化情况自动切换电平转换方向。但是最终我没有用它,因为它比较贵。一片TXB01089块钱,而74LVC4245只需要2块钱(另一个原因是,后者还有16位的型号,74LVC16T245,也只需要6块钱)。
后来,我想通了,74LVC4245在并行总线通信中,是有办法实现电平方向自动转换的。方法就是:DIR直接接在单片机的WR
    74LVC4245的电平转换时间大约为4ns。可以说,在并行总线读写使能信号出现之后,74LVC4245就在瞬间完成了电平转换的工作,使得数据在转换的终端得以迅速的呈现。它的速度远快于绝大部分单片机或处理器的总线速度,所以这种使用WR作为方向信号的方法是绝对可行,而且可靠的。从某种意义上说,74LVC4245对我们透明了,我们面对的就是一条可以完成电平转换工作的“导线”!!
另外,我还把74LVC4245OE信号连接到了WR&RD(单片机的WRRD经过74HC1G08,即两输入与门后输出的信号),在总线没有动作的情况下,74LVC4245两端呈现高阴态,它就如同没有接入电路一样,不会产生任何影响。而总线动作时,只要有WRRD拉低,它随即被使能,起到电平转换的作用。这是一种“绝妙”的设计。我想这种方法适用于所有的并行双向通信场合,因为一定会有一个信号去表示读或者写。不过这种方法不适用于串行总线,比如I2C
在第2版的电路中,我实际使用的电平转换芯片是74LVC16T245,因为它是16位的。而对于IDEDIOWDIOR、地址线、片选等信号,只需要使用74HC244即可,因为它们是单向的。


上述电平转换的问题,是模式1的主要问题,也就是单片机IO直接与IDE相连的方式。而模式2不光涉及电平转换的问题(单片机IO 3.382C555V),还涉及到“总线时序嵌套”!
先来考虑一个关于总线的问题:
模式2使用82C55来扩展IO,它与单片机之间通过8位并行总线来连接和通信,扩展出PAPBPC,其它PAPB合并为16位数据,接到IDE,而PC因为可以位操作,所以接到IDE的控制信号上。问题在于我们是否可以把IDE作为一个总线设备,把它的DIOWDIOR,即读写使能信号直接接在单片机的RDWR上(即和82C55共用)。同时将IDECS1CS082C55CS以及地址线分配到单片机并行总线的地址线上(比如51单片机的P2,即A15~18),用编址来区分82C55IDE,对它们进行独立的读写。这样作的好处是可以使用并行总线的硬件优势,提高读写速度和效率。
这种连接方式,在单片机向IDE16位数据的时候,过程如下:
1、拉低CS(即选通82C55),配置PAPBPC均为输出模式,通过8位总线向PA口输出16位数据低8
2、再向PB输出16位数据高8
3、向PC输出IDE寄存器地址(即DA2~DA0,它们指定16位数据被写到IDE的某个寄存器中),在此过程中,因为IDECS1CS0均未被选中,所以IDE不会响应WR信号,即不会对IDE产生误操作。
4、拉高CS(即失选82C55),依情况选通CS1CS0,配以WR信号,数据被写入到IDE82C55PAPBPC具有锁存功能,原来写入的数据不会消失)
5、拉高CS1CS0,一次向IDE写入16位数据的过程完成。
上述过程均通过编址方式通过硬件总线完成,所以速度很快(如果是IO模拟时序那就慢了)
上述的写入过程是没有问题的,我们再来看看如何从IDE读取16位数据到单片机,过程如下:
1、拉低CS,配置PAPB为输入,PC为输出,向PC输出DA2~DA0,拉高CS
2、依情况选通CS1CS0,拉低RDIDERD低电平期间把16位数据送到16位数据端(接下来我们需要使用82C55PAPB来读取它)。
3、拉高CS1CS0RD,拉低CS,把单片机8位总线转让给82C55问题出现了!!!一旦CS1CS0RD拉高,IDE16位数据将会消失。
这是一种窘境!!16位数据就在PAPB上,但是因为总线无法转让给82C55,所以眼睁睁的无法去读!!
如何解决?振南想过一些方法。可以在IDE16位端口处加一个8位锁存芯片,比如74HC37374HC573
问题在于,在CS1CS0RD为低电平的期间,谁来给74HC573一个锁存时钟?(锁存器锁存数据,是需要一个LATCH CLOCK的,即锁存时钟)。还需要额外的一个IO?就算有一个IO为它提供锁存时钟,在硬件总线读写的过程中,它也根本插不进来(单片机在读写外部并行总线的过程中,难道还能同时操作IO吗?它又不是多核!!)。
有一种办法是可行的,但可行不可靠。可以把锁存器的锁存时钟接到RD上,利用RD的上升沿来锁存IDE16位数据(RD上升沿意味着总线读取操作结束)。问题在于,RD上升沿,16位数据端口上的数据还能稳定的存在吗?一般来说,数据总线上在RD释放(所谓释放就是指拉为高电平)之后,会浮动一小段时间(一般是10ns左右),数据手册上称之后“Floating Data”,浮动数据。只要锁存器足够快,确实是可以截获到正确的16IDE数据的。然后再把总线转让给82C55,去读取锁存到的数据。
不过,这是个非常冒险的时序!!因为Floating Data是不被明确保护的,说白了它可有可无


振南在使用82C55读取IDE硬盘的过程中,没有采用上述方案。而是把IDEDIOWDIORCS1CS0全部放在了82C55PC口上。
82C55独享总线,对于IDE的一切时序都通过PAPBPC三个扩展端口来完成。样作更加节省IO,同时对82C55PC端口利用率也比较高。唯一不足就是速度上有些损失。但由于82C55由硬件总线操作,操作一次82C55只需要几个机器周期,因此实际读写IDE的速度尚可接受。


以上介绍了电路设计、时序上的一些问题,下面要说的问题才是真正困扰我调试全程的问题,它导致了读写硬盘的不稳定。
为了节省PCB的面积,能尽量把模块作得小一些,我几乎没有使用电容,对电源进行退耦处理。我认为模块只是一些纯数字电路,退耦应该起不到多少作用。但我发现不对5V3.3V退耦,会导致硬盘读取不稳定。我初步分析是因为硬盘中电机的机械动作对电路产生了冲击。因为同样一个没有加退耦电容的模块,对硬盘读写会出现停顿现象,而对于CF卡(其接口兼容IDE,但其存储介质是NandFlash,没有机械运作)读写就非常流畅。而且在我加了几个退耦电容之后,硬盘读写的情况了有改观。
通过查阅相关资料,我开始对“退耦”有了新的认识。退耦的目的是为了给频繁开关的芯片提供一个电源储备。一些数字芯片在工作的时候,因高低电平的频繁变化,可能会产生对电源短暂的电流需求,如果电源供电能力不好,则可能造成工作不正常。退耦电容就是在此时为芯片提供应急电荷的,它使数字芯片工作更加稳定。而我们通常认为对电源产生滤波作用的电容,并不是退耦电容,而是放置在电源入口位置上的“旁路”电容。它为电源的交流分量提供一个阻抗较小的通路,从而使电源更加平稳。
旁路电容一般取值为220UF~10UF、而芯片的退耦电容通常取值为10UF~0.01UF。受此教训,在第二版的硬盘模块上,我放置了一些旁路电容和退耦电容。


对于硬盘模块的模式3,即使用74HC595+165通过SPI扩展IO驱动硬盘,我没有使用电平转换芯片。595165直接用5V供电,而3.3V对于它们来说是稳定可识别的(主要原因是它是串行的,信号线很少,所以敢用3.3V驱动5V)。
另外,这种IO扩展方法,在74HC165读取数据的时候,在数据线上与之并连的74HC595必须输出高电平,即0XFF,而不能有0,这样会导致165读取的那一位永远为0我们知道一个低电平和一个高电平相遇的时候,通常高电平会被低电平拉低。所以在总线通信中,当某个器件不再占用总线,即释放总线之后,它所有的信号线应该都是高电平,否则它会影响到其它器件的总线通信。但是,一个高电平一定会被低电平拉下来吗?不一定,如果一个高电平的驱动能力很强,而一个低电平很弱,则可能根本拉不下来。此时,总线上可能产生2.5V这种中间的混沌电压,导致系统出现严重错误!  
如何保证自己不去干扰别人操作总线?1、不要输出太强的高电平 2、直接脱离电路。后者即所谓的“高阻态”。这就是所有芯片为什么要有OE端的原因。
我在第一版的模式3中,直接把74HC595OE接地了,即一直输出使能。在74HC165读取数据的时候,我把74HC595输出0XFF,但我发现165读不到正确的总线数据。最后我发现,IDE接口输出的数据中的0,没有把74HC595输出高电平有效的拉为低电平。其原因就是74HC595的输出太强了,因为它的输出端口集成了锁存电路。所以我在第二版中把74HC595OE单独拿出来由单片机IO来控制,使它在165读取数据的时候呈现高阻态。
以上就是振南近10天调试IDE硬盘的一些总结,希望对您有所启发!!

相关帖子

沙发
huangqi412| | 2015-10-29 19:23 | 只看该作者
沙发?

使用特权

评论回复
板凳
znmcu|  楼主 | 2015-10-30 20:37 | 只看该作者
接下来基于硬盘,可以做硬盘mp3,视频播放、录像实验

使用特权

评论回复
地板
armxu| | 2015-10-31 20:30 | 只看该作者
很好!有资料?最好出书。

使用特权

评论回复
5
dirtwillfly| | 2015-10-31 22:14 | 只看该作者
学习

使用特权

评论回复
6
znmcu|  楼主 | 2015-11-1 20:01 | 只看该作者
出书,哪方面的书?

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

个人签名:振南的znFAT -- 单片机上上的FAT32文件系统 www.znmcu.cn

4474

主题

5195

帖子

33

粉丝