Из-за того, что в будущем шедевре дисплей неизбежно будет подключаться шлейфом, я предусмотрел наличие мощных шинных формирователей 74LVC8T245, способных изолировать процессорную шину памяти от нагрузки и выдать при этом достаточно большой ток. Я ещё немного опасаюсь за "звон" сигналов (особенно если вспомнить, что "земля" в шлейфе всего ОДНА и это никак не изменить, ибо таков разъём в дисплейной панели), но пока осцилл показывает, что всё ок. В конце концов, шлейф можно дополнить ферритовой нахлобучкой, чтобы она "съела" весь высокочастотный дребезг.
Параноидально вычистил всю схему и даже где-то просчитал тайминги. Особые сомнения вызывала конструкция из двух NAND-вентилей, формирующая сигнал DIR (для переключения направления буферов) из ~WR и ~RD, но всё обошлось.
Собственно, к чему это. У чипа SSD1963 есть команда, позволяющая прочитать некий "дескриптор" заранее известной структуры. Я решил, что это будет достаточно хорошей проверкой работоспособности схемы и вот что я уже получаю в терминале (да, USART тоже заработал, но в будущем планирую реализовать CDC-устройство на USB, просто не всё сразу):
Device Descriptor Block:
0: 01
1: 57
2: 61
3: 01
4: FF
Вот что сказано в документации:
SSL[15:8] : Supplier ID of Solomon Systech Limited high byte, always 01h (POR = 00000001)
SSL[7:0] : Supplier ID of Solomon Systech Limited low byte, always 57h (POR = 010101110)
PROD[7:0] : Product ID, always 61h (POR = 01100001)
REV[2:0] : Revision code, always 01h (POR = 001)
Exit code, always FFh (POR = 11111111)
Работа продолжает кипеть!
Пока непонятно, как заставить FSMC делать паузу между записью команды и чтением её результата (по документации на SSD1963, надо ждать некоторое время; при этом запись команды с параметрами никаких особых пауз, кроме отдельных случаев, не предусматривает). Пока что эту паузу вбил просто тупым пустым циклом, но это бяка.
Добился того, что дисплей показывает мне современное искусство:
Не хуже Майкла Ротко какого-нибудь, тащемта.
Теперь надо настроить тайминги... а где их взять, неведомое сие. "Документация" на дисплей молчит, а вбитые наугад приводят к изменению вот этой вот картины на аналогичную, но уже от Поллака.
Upd Большая (бОльшая) часть времени уходит на попытки осознать, что китайцы хотели сказать по-китайски, но написали по-английски. Понемногу продираюсь сквозь даташит, безжалостно кромсая найденные в сети примеры кода. Получилось вот что:
Не понимаю ещё, почему адресная линия A16 то работает, то не работает (два часа назад всё работало, потом перестало... но когда дёргаю её вручную, через GPIO - пашет!).
Осциллографом увидел, что на одно обращение к внешней памяти идёт ДВА цикла шины вместо одного. Долго думал, пришёл к выводу, что дело в 32-битности процессора: когда он читает по указателю, то не может не прочитать 32-битное число. С другой стороны, где-то там, в глубинах, наверняка есть команды чтения отдельных байтов. Поэтому такой вот забавный код работает:
typedef struct { volatile uint16_t Cmd; volatile uint16_t Data; } SSD1963_t; #define SSD1963 (*(volatile SSD1963_t *)(0x60020000 - 2))
Чтобы записать 16-битное слово в регистр команды, пишем
SSD1932.Cmd = Somethingsomething;
а в регистр данных, соответственно,
SSD1932.Data = Somethingsomething;
Хитрожопое размещение заставляет контроллер памяти сгенерировать правильные адреса, которые правильно преобразуются в правильные управляющие сигналы для правильной внешней схемы. И всё работает. Жаль, что Си не позволяет использовать описание структуры вместо задания типа переменной, было бы ещё лаконичнее (или позволяет, а я не знаю?).
P.S. volatile понатыкал для того, чтобы компилятор ни-ни, никаких оптимизаций тут!