Микроша. Глава первая. Контроллер SD карты

cca980ea41411f353a4f448bb6c6bf4f.jpg
Многие помнят эту замечательную ПЭВМ. У меня такая появилась, когда мне было 11. Прошло 28 лет и сейчас я решил в порядке хобби сделать устройства расширения, которых мне так не хватало тогда.
В сети я видел несколько вариантов SD загрузчиков для подобных ПЭВМок, мне не нравилось наличие в них микроконтроллеров, хотелось сделать по «винтажной, теплой DIPовой» схемотехнике, именно поэтому я решил делать на отечественной логике «КР1533».
В качестве доп. ОЗУ я применил UT62256. Это единственная импортная микросхема в проекте. Конечно, можно было поставить КР537РУ10 или КР537РУ25А, но во-первых, их бы пришлось ставить не одну, а две (я планировал 4 кБ доп. ОЗУ), а во-вторых UT62256 у меня была, а КР537 не было, и заказывать не хотелось. Поэтому я позволил себе вольность поставить импорт, и тогда пришла идея использовать все 32кБ доп.ОЗУ, со страничным переключением.
bshqhoyuqbckntjlxyd73v88gb8.jpeg
Для ПЗУ выбрал КР573РФ5, как раз было две чистых.
Посидев за чашкой чая, я нарисовал вот такую блок-схему.
d70cffce259c82278a736bf08817c893.jpg
Здесь микросхема ОЗУ, микросхема ПЗУ, и блок «ПОРТ». Блок «ПОРТ» есть параллельный интерфейс, имеющий 8 входов и 8 выходов. При записи по адресу EFFF, записываемый код выставляется на выходах, а при чтении из этого-же адреса, прочитанное значение соответствует состоянию входов. Три из выходов и один из входов подключены к SD карте через преобразователь уровней.
ОЗУ представлено микросхемой UT62256 и имеет 32кБ памяти. Поскольку диапазон адресов E000-EFFE есть почти 4кБ (4095 байт), то получается 8 страниц, которые выбираются блоком «ПОРТ», битами 1,2 и 3. То есть запись по адресу EFFF приводит к установке страницы в соответствии с этими тремя битами. Также чтение из этого порта показывает какая страница сейчас выбрана (в этих же битах). Итого, мы имеем 32760 байт дополнительного ОЗУ (4095×8стр).
Микросхема ПЗУ есть КР573РФ5. Она подключена в адресное пространство F000-F7FF, и содержит код БСВВ (BIOS), задача этого кода инициализировать SD карту, загрузить с нее OS и передать ей управление.
Соответственно после включения ПЭВМ, набираем в Системном Мониторе GF000 и нажимаем ВК.
В дальнейшем есть идея доработать родное ПЗУ Системного Монитора, для автоматической загрузки OS с SD карты, и ПЭВМ выходит в стандартное приглашение Монитора если загрузка не удалась или была прервана, например, нажатием какой-то клавиши.
Об этом еще подумаю.
Примерно 2–3 часа за компьютером, и я нарисовал в EAGLE следующую схему.
67090be572d225a008cd2d370da819e2.jpg
Увеличить
Рисовал опираясь на те микросхемы, которые у меня были. Возможно, что число микросхем логики можно сократить, если использовать другие вентили, но у меня были только такие. И в дальнейшем, я скорее всего оптимизирую схему.

Низкоуровневый разбор схемы…

…убрал под спойлер, думаю мало кому интересны эти дебри.

Посмотрим на ячейку И V3/1, к ней подключены линии A14 и A15 шины адреса, значит на выводе N3 появится логическая единица, когда эти оба сигнала адреса находятся в лог.1. Через инвертор V1/2 формируется сигнал с условным названием G, который приходит на дешифратор IC2. Входы этого дешифратора A и B, подключены к линиям A12 и A13 соответственно. Значит, получается, что дешифратор активируется от наличия единиц на A14 и A15, а его выходы показывают код на линиях A12 и A13. Нас интересует только один вариант — 1110,
то есть A15–1; A14–1; A13–1; A12–0. Такой сигнал получается на выходе дешифратора N2. Поскольку ячеек дешифратора две, то этот сигнал должен появляться на выводах 5 и 11, но из-за того, что каждая из ячеек имеет еще один вход С, то от состояния этого входа будет зависеть какая из ячеек будет активна. Вход 1С активирует выход 5, а вход 2С активирует выход 11. Эти входы спаралелены, но вход 1C прямой, а вход 2C инверсный, значит при наличии лог.1 на них активируется вывод 5, а при лог.0 — вывод 11.
Подытожим: При наличии на шине адреса кода Exxx и С=1, формируется сигнал «PORT», а при наличии на шине адреса кода Exxx и C=0, формируется сигнал «RAM».
Сигнал «C» образуется за счет функции логического И, из всех младших адресов (A0-A11). Когда на шине выставлен код xFFF, то С=1, а иначе С=0. Итого: сигнал «PORT» вызывается адресом EFFF, а сигнал «RAM» адресами E000-EFFE.
Сигнал «RAM» приходит на вход CS микросхемы IC3, это микросхема ОЗУ, и значит, что запись по адресам E000-EFFE приведет к записи в эту микросхему. Также чтение по адресам E000-EFFE приведет к чтению из этой микросхемы. При записи по адресу EFFF код будет записан в регистр IC4, и защелкнется на его выходах. Сигнал записи формируется из сигналов «PORT» и «WR» c помощью элементов V1/5, V1/6 и V3/4.
Чтение по адресу EFFF приведет к считыванию данных из буфера IC5, и код будет зависеть
от состояния входов B0-B7.
Микросхема ПЗУ включена в адресное пространство ПЭВМ с помощью штатного адресного дешифратора. Для этого из порта «Внутренний Интерфейс» берется сигнал CS3 и он подключен к линии CS микросхемы ПЗУ.


Сейчас травить плату в домашних условиях у меня возможности нет, и я, взяв кусок фольгированного двухстороннего текстолита, выпилил из него необходимый прямоугольник.
Этот прямоугольник плотно вставлялся в слот «внутренний интерфейс» ПЭВМ, не болтался и не сдвигался. Далее я процарапал контактные площадки с задней и передней сторон. Получилось неплохо. Затем грубая расстановка микросхем и сверлежка отверстий. С лицевой стороны рассверлил крупным сверлом, чтобы выводы микросхем не контактировали с лицевой фольгой. С обратной стороны отцарапал периметр каждого контактного ряда и разделил на контактные площадки.
Следующим этапом поставил все микросхемы (и панельку) и пропаял с обратной стороны. Много времени отнял монтаж, который я вел тонким МГТФом. Вел проводки с обоих сторон, с лицевой подпаивал прямо к ножкам микросхем, с обратной к площадкам.
7509e4d4e80b18f13e256c81782968f9.jpg
Когда процесс пайки был окончен, я решил уделить внимание преобразователю уровней сигналов. Дело в том, что SD карта работает с напряжением 3,3в., а микросхемы КР1533АП6 и КР1533ИР22 ТТЛ 5в. Поэтому пришлось сделать небольшую платку переходника, на котором уровни ограничивались стабилитронами.
Сигнал идущий от SD карты к контроллеру я просто подтянул к источнику 3,3в. резистором 10к. Как показала практика, этот сигнал в преобразовании не нуждается.
992d76c5ea76c42abe70872fc511cdbc.jpg
Хотя в конечном варианте я, наверное, сделаю обратный преобразователь на основе компаратора.
В качестве держателя карты использовал переходник microSD в SD.
В общем, проблем особых в сборке макета не возникло, хотя я боялся, что некоторые из микросхем могут быть неисправны.
Первым делом я проверил работу ОЗУ, записал в область E000-EFFE с помощью директивы «F» Системного Монитора паттерны «AA»,»55», «F0» и »0F» и проверил их с помощью директивы «D». Все оказалось в норме.
Далее директивой «M» начал записывать в адрес EFFF разные значения, и смотреть мультиметром изменения на ножках регистра КР1533ИР22, состояния соответствовали записаным кодам. Также при чтении из этого порта в коде содержалась выбранная страница, в соответствии с задуманным, и еще при замыкании MISO сигнала на землю в младшем бите оказывался 0, а при размыкании 1.
Даже было как-то подозрительно, что все микросхемы исправны и монтаж удался без ошибок.
Конечно никаких специальных инструментов для написания программ под КР580ВМ80А у меня не было. Пришлось писать программу в блокноте (notepad), затем переводить в коды вручную.
Создал файл в редакторе под DOS «HIEW» и начал заполнять кодами. Для основы взял свой проект под AVR, в котором имелась стандартная инициализация SD карты. Проект был старый, и в нем не использовалось никакой файловой системы, просто логгер.
Сначала написал низкоуровневую функцию программного интерфейса SPI, а потом высокоуровневую подпрограмму инициализации SD карты.

Получился примерно такой алгоритм…

…который убран под спойлер, думаю, он и так всем известен.

1. Взвести счетчик попыток (СП) на 90;
2. Выставить CS в лог.1 и отправить 10 раз FF;
3. Выставить CS в лог.0;
4. Отправить CMD0;
5. Если читается 01, тогда переход на 7;
6. Уменьшить СП. Если СП=0, то выход с ошибкой, иначе переход на 2;
7. Отправить CMD8;
8. Отправить ACMD41;
9. Если читается 00, тогда переход 11
10. Уменьшить СП. Если СП=0, то выход с ошибкой, иначе переход на 8;
11. Отправить CMD58.
12. Прочитать 2й байт ответа и записать по адресу EFFE.
13. Инициализация закончена.


В подпрограмме инициализации также читался регистр OCR карты, и 2й байт в нем записывался по адресу EFFE. Это было нужно для определения типа карты.
В случае SDSC — 80h, а в случае SDHC — C0h.
Если инициализация не проходила, то выводилось сообщение «ОШИБКА SD КАРТЫ» и затем происходил выход в Монитор без сброса.
Такую БСВВ я конвертировал в WAV и загружал в ПЭВМ через магнитофонный вход, затем отлаживал, правил исходник и снова загружал.
Теперь у меня есть дополнительное ОЗУ, размером 32760 байт, разделенное на 8 страниц. Но как осуществлять переход между страницами? Как программа, выполняющаяся в первой странице, может вызвать подпрограмму, находящуюся в четвертой?
Для решения этой задачи я предусмотрел программные мосты. Мост — это небольшая область в ПЗУ, которая является посредником при передаче управления.
Например, выполняющийся код должен передать управление на страницу номер 3, в адрес E4B5. Тогда, выполняющийся код помещает младшие 12 бит (4B5) в регистровую пару HL процессора, а в старшие четыре бита помещает значение 3 — номер страницы. Теперь в регистровой паре HL записано значение 34B5. И код делает прыжок (JMP) в область ПЗУ, которая называется JMP-Bridge, это просто переход по фиксированному адресу в ПЗУ. Код в этой области извлекает номер страницы из старших битов регистровой пары HL и записывает их в регистр блока «ПОРТ» по адресу EFFF. Теперь в область E000-EFFE отображается третья страница ОЗУ. Программа JMP-Bridge обнуляет четыре старших бита регистровой пары HL и записывает туда «E». Теперь в регистровой паре HL находится уже физический адрес E4B5, и вот на него программа JMP-Bridge передает управление.
Таким образом передается управление между страницами.
Есть мост CALL-Bridge, он нужен для вызова подпрограммы с возвратом, и отличается от JMP-Bridge сохранением текущей страницы в стеке, и обратной процедуры для возврата.
Следующие два моста STA-Bridge и LDA-Bridge. Как следует из названий, первый записывает регистр Аккумулятор по логическому адресу (в HL), а второй читает в этот регистр данные из логического адреса.
Благодаря этим двум мостам, программа исполняющаяся из какой-то страницы, может хранить данные в другой.
Если взглянуть на загрузочный сектор SD карты, то можно заметить, что по адресам 1AC-1D4 расположен текст «Disk error, press any key to restart».
8ca9885d6912ec982bac57e87d3ec9b8.jpg
Да, так странно как на фото он выглядит, потому-что кодировка символов Микроши не совпадает с ASCII.
Я решил использовать эту область, что-бы расположить там данные для загрузки ПЭВМ.
Первым делом я поставил код 00 в позицию 1BA, и тем самым урезал запись. Теперь, должно выводиться просто «Disk error» и все. Остальные байты мои. Принцип простой, 6 байт сигнатура «MicrOS», и 4 байта адрес на SD карте начала файла с OS. В БСВВ я записал, после получения загрузочного сектора с SD карты, проверяется сигнатура, и если она есть, то взять 4 следующих байта и использовать в качестве адреса сектора для загрузки OS.
Если сигнатура отсутствует, то выводится сообщение «ОШИБКА ЗАГРУЗКИ OS» и происходит выход в Системный Монитор без сброса.
И вот, наконец-то все, работает. БСВВ написана, но мне еще требуется записать ее в ПЗУ.
a83d9150582d6a02fac7ac5477e4163a.jpg
А для этого мне нужно отредактировать все адреса вызовов подпрограмм и переходов, так-как в этом процессоре абсолютная адресация. А я писал БСВВ для области 6000–67FF, чтобы грузить в ОЗУ. Но теперь надо поменять все 6xxx на Fxxx.
Кроме того, я в «попаданецких» условиях. Программатор ПЗУ у меня есть, но он старенький, под LPT порт. И нет ни одного компьютера с LPT. Но есть пара Atmega32A, в PDIP40 корпусе и макетная плата. Возможно придется эмулировать LPT с помощью AVR. Но может все обойдется…

На этом, пока, все. Спасибо за внимание! Продолжение следует…

© Habrahabr.ru