Картинка для привлечения внимания
Картинка для привлечения внимания

По итогам 2023 года ролики о старых цифровых камерах набрали суммарно более 1 миллиарда просмотров в TikTok. В свою очередь на YouTube блогеры актино обозревают цифромыльницы с призывом приобщиться к тренду. На фоне становления Y2K эстетики и смещения интересов в области фотографии в прошлое я предлагаю заглянуть немного подальше и посмотреть, как всё начиналось.

Если вам интересно, как связаны между собой зарождение цифровой эпохи в фотографии, странная самоделка, и причём здесь вынесенная в название оперативная память – добро пожаловать под кат!

Введение

Как это часто бывает, тут не обойтись без личной истории. Для меня в фотографии сам процесс и его технические аспекты важны не меньше, чем результат. Рано или поздно такой подход приводит к мысли о создании самодельного устройства для захвата мгновений ради удовлетворения внутреннего ребёнка. Не я первый – не я последний, например, в интернете можно найти работы энтузиастов, воссоздавших старинные форматные камеры и снимающих на них же с использованием коллоидного процесса.
К сожалению, плотник из меня неважный и я совсем не силён в химии, но мало-мальски разбираюсь в цифровой технике.

Первыми в голову приходят следующие мысли:

  • Попробовать сделать что-нибудь на базе имеющихся в продаже датчиков, например, от OmniVision, но радости такая самоделка принесёт немного. По сути это маленькая готовая камера, порой даже с поддержкой автофокуса и оптикой в комплекте.

  • Однажды я узнал про сканирующие задники для больших форматных камер – можно попробовать раздобыть ПЗС-линейку или похожий контактный датчик и сделать что-то подобное. К сожалению, зачастую необходимые детали существуют только в каталоге производителя – найти и купить их в наших реалиях сложно. Также из принципа действия следует не столько недостаток, сколько особенность – снимать такой камерой можно только статичные сюжеты.

Изготовить фотодатчик самому, конечно, невозможно, однако даже с готовыми компонентами есть место творчеству.

Циклоп и радиолюбители

Та самая камера. Источник: Wikipedia
Та самая камера. Источник: Wikipedia

В далёком 1975 году американская компания Cromemco внезапно представила полностью твердотельную камеру под названием Cyclops c возможностью подключения к микро-ЭВМ, таким как Altair 8800. Применённое инженерами решение находилось где-то на грани наглости и накуренности – вместо электронной передающей трубки прибор смотрел на мир с помощью чипа динамической памяти. За 50 долларов можно было заказать необходимые детали для самостоятельной сборки камеры (версию для подключению к осциллографу), включая тот самый датчик; схема устройства в свою очередь публиковалась в журнале Popular Electronics.

Страница из журнала
Страница из журнала

Анализ принципа действия

В микросхемах памяти динамического типа функции запоминающей ячейки выполняет конденсатор, образованный внутри МОП-структуры. Информация представляется в виде наличия или отсутствия заряда. Согласно книге «Микросхемы памяти и их применение» из серии «Массовая радиобиблиотека» логическому нулю соответствует наличие заряда, единице – его отсутствие (об этом мы ещё обязательно поговорим). Из-за несовершенства нашего мира время сохранения заряда ячейкой ограничено, поэтому такой памяти требуется регулярная перезапись – регенерация.

Мы воспользуемся тем обстоятельством, что под действием света ячейка начинает разряжаться быстрее и в конечном итоге меняет своё состояние. Объяснения этому явлению ни в сети, ни в литературе я так и не нашёл, однако рискну предположить, что паразитный p-n переход между стоком и истоком n-МОП транзистора в составе ячейки ведёт себя подобно фотодиоду, позволяя конденсатору разряжаться на шину данных.

Подбор компонентов

Выбираем память

Ради справедливости стоит сказать, что та самая микросхема была заказной – ячейки памяти были расположены в виде массива из 32 строк и 32 колонок не только логически. Также я видел в сети упоминания похожих микросхем на 64К ячеек от компании Micron, шедших с прозрачным окошком в корпусе с завода и созданных для тех же целей. Оба варианта давно не найти, но можно попробовать перепрофилировать под эти цели серийную память. Опыт Германа Курца с зарубежной памятью типа 4164 очень вдохновляет.

Для получения картинки, очевидно, нужно подвергнуть кристалл воздействию света, а это значит, что нужно как-то вскрыть корпус микросхемы, не повредив сам кристалл и приваренную к нему золотую проволоку, ведущую к выводам корпуса. @BarsMonster травил пластиковые корпуса дымящей азотной кислотой, но у меня нет доступа ни к кислоте, ни к хорошей вытяжке, зато есть паяльник и доступ к гравёру с алмазным диском – самое время обратить внимание на память в металлокерамических корпусах.

Первое, что приходит в голову – это отечественная серия К565, и я полез на известный сайт объявлений. Шутки-шутками, но среди интересующих меня объявлений не было ни одного из Default City – всё в других городах. Было несколько предложений К565РУ3 в больших количествах, чудом не доставшихся варварам-аффинажникам, но выбор пал на более современные К565РУ5 (тот же продавец, у которого я заказал комплект из вожделенных микросхем, предлагал ещё и РУ7, но уже по какой-то совсем заоблачной цене). Дело тут не в большей ёмкости – РУ5 менее капризна в плане питания и её намного сложнее убить по невнимательности. Более старые РУ1 и РУ3 требуют сразу три напряжения питания: +12, +5 и -5 В, причём подавать и снимать их нужно в корректной последовательности во избежание теплового пробоя и выхода кристалла из строя. С современной элементной базой организовать всё это несложно, порой в даташитах к DC-DC преобразователям можно найти даже пример разводки платы, но от неправильного аварийного отключения это не спасает, особенно когда процесс разработки итеративный, ну или рядом попросту бегают котики.

Есть решение – мне поможет микроконтроллер!

Времена MS-DOS и параллельного порта давно прошли, а это значит, что от использования микроконтроллера с целью подружить память с современными машинами не отвертеться. Поначалу среди всего многообразия, предоставляемого рынком, мой взгляд достаточно быстро упал на старый-добрый ATmega328P в составе китайского клона Arduino Nano. Не спешите кидаться камнями и тухлыми яйцами – я прекрасно понимаю тех, кто презирает платформу, но считаю, что в моём случае выбор вполне оправдан. Главным критерием выбора были питание от 5В и как следствие – пятивольтовые уровни, память гарантированно можно подключить напрямую к микроконтроллеру без усложнений в виде сопряжения логических уровней. Как писал @aronsky, для моргания светодиодом это слишком мощно, а для обработки изображений – слишком слабо, но для того, чтобы устроить ногодрыг и отправить результаты большому брату по UART её более чем достаточно. Более того, на плате уже есть вся необходимая для экспериментов обвязка в лице стабилизатора и USB-UART преобразователя, а в сам камень уже зашит загрузчик – шей сколько влезет, не доставая программатор.

Схема
Схема

Изначальный вариант схемы предполагал наличие триггера-защёлки на выходе микросхемы памяти, но в процессе выяснилось, что необходимость в нём отсутствует.

Пишем прошивку и клиентскую программу

Программируем микроконтроллер

Временные диаграммы
Временные диаграммы

Процесс работы с памятью хорошо описан в вышеупомянутой книге. Временные диаграммы могут выглядеть немного пугающе, но на самом деле в обращении к памяти нет ничего сложного. Для чтения и записи нам нужно:

  1. Подать сигнал чтения (1)/разрешения записи (0);

  2. Подать на адресную шину код адреса строки и вместе с ним стробирующий сигнал ~RAS;

  3. После небольшой задержки, которая зависит от типа микросхемы, подать адрес столбца и стробирующий сигнал ~CAS;

  4. В случае записи – подать записываемое значение на вход DI, иначе – прочитать значение с выхода DO;

  5. По окончании снять стробирующие сигналы в обратном порядке и выдержать нормированную задержку.

Страничная запись
Страничная запись

Но читать и писать по одному биту это слишком медленно – микросхема может работать в страничном режиме, когда мы пишем или читаем сразу несколько ячеек. Процесс очень похож на обычные чтение и запись, только адрес столбца и сигнал ~CAS подаются несколько раз. В книге не было временных диаграмм для этих режимов, но их можно подсмотреть в документации на зарубежную память типа 4164. Понятно, что задержки будут другими, но лишним не будет.

Ещё один необходимый режим – принудительная регенерация. В нашем случае мы по сути специально портим данные, чтобы получить изображение, и он нам не особо нужен, но перед началом работы память нужно инициализировать. К565РУ5 выходит в рабочий режим спустя 2 мс и 16 циклов регенерации после подачи питания. Для этого мы просто перебираем строки с сигналом ~CAS.

Поначалу при написании программы для микроконтроллера я допустил одну досадную ошибку, которую заметил не сразу. При скорости UART 57600 бод попытка считать память целиком и передать её содержимое на компьютер занимала около 25 секунд, при этом записанные данные практически не портились (несколько битых ячеек всё-таки было). Проблема крылась в функции формирования задержек – по ошибке я вбил в калькулятор несколько лишних нулей и вместо 62,5 нс на такт получил 0,625. Я как можно быстрее стёр это позорище; по сути мне требовались задержки в единицы тактов – издевательство над таймером в итоге превратилось во что-то такое:

// Задержка в N тактов
template <uint8_t N = 1>
void delay_cycles() {
	__asm__ __volatile__ ("nop");
	delay_cycles<N - 1>();
}

// База рекурсивного шаблона задержки
template <>
inline void delay_cycles<0>() {}

С другой стороны теперь я на практике убедился в том, что память может хранить данные на порядки дольше, чем написано в паспорте (в теории РУ5 требует принудительной регенерации каждые 2 мс, иначе сохранность данных не гарантирована). Эта возможность может пригодиться как для формирования более длинных выдержек, так и для передачи данных. Напомню, что у микроконтроллера всего 2 Кб оперативной памяти, в то время как ёмкость РУ5 – все 8, поэтому мы вынуждены прочитать порцию данных, отправить её и дальше читать следующую. В моём случае считывание происходит построчно – 256 посылок по 32 байта.

Пишем клиент

Одно дело смотреть на то, как байты бегут в окошке терминальной программы, другое – превратить этот поток в картинку и сохранить её в файл. Нужна клиентская программа которая будет на стороне «большого» компьютера принимать и обрабатывать данные.

Предварительная версия клиента
Предварительная версия клиента

Вообще моей «первой любовью» в мире разработки была Java, однако по превратности судьбы мне приходилось работать преимущественно с .NET и C#, поэтому с выбором инструментов долго думать не пришлось.

Microsoft любезно предоставляет класс System.IO.Ports.SerialPort для работы с UART, поэтому больших сложностей не возникло. Наверное, основное, на что стоит обратить внимание, это асинхронный метод получения данных – мы ждём завершения приёма в буфер в отдельном потоке, не блокируя UI.

var progressHandler = new Progress<int>(value => progressBar.Value = value);
var progress = progressHandler as IProgress<int>;

byte[] buffer = new byte[8192];

await Task.Run(() =>
{
    // Пишем и читаем память по команде с компьютера
    // Ждём 4 байта: мнемонику 0xBADBEE и число - как долго экспонируем кристалл
    byte[] command = { 0xBA, 0xDB, 0xEE, (byte)shutterSpeed };
    _serialPort.Write(command, 0, 4);

    for (int i = 0; i < 8192; i++)
    {
        buffer[i] = (byte)_serialPort.ReadByte();
        if (progress != null)
        {
            progress.Report(i);
        }
    }
});

Самый душный этап и беда, откуда не ждали

Вскрываем кристалл

Теоретические выкладки и написание ПО – это хорошо, но рано или поздно приходит пора проверить жизнеспособность всего этого на практике.

Пора. Вскрывать. Корпус.

Одна из вскрытых микросхем
Одна из вскрытых микросхем

Сначала я думал срезать крышку скальпелем или отпаять её. В процессе выяснилось, что запаян корпус на совесть, и просто так срезать крышку не выйдет. Отпаять крышку мне удалось только с добавлением сплава Розе (не делайте так, это очень плохая практика), причём в обоих случаях кристаллы были испорчены – первый я заляпал припоем, второй перегрел. Более здравой оказалась идея срезать крышку гравёром – тут всё получилось; для защиты от механических повреждений вместо металлической крышки было приклеено предметное стекло для оптического микроскопа (прошу прощения за качество фото, макрообъектива под рукой нет).

Геометрия и паттерны

Сначала я даже подумал, что повредил и этот кристалл – независимо от того, что я в него записывал, всё время считывался паттерн, который можно увидеть на скриншоте (чёрные ячейки соответствуют нулю). Однако стоило мне уйти в тёмную комнату или прикрыть окошко плотным картоном, как память начинала отдавать ровно то, что в неё записывали.

Читаем засвеченный кристалл
Читаем засвеченный кристалл

На этом же этапе в процессе экспериментов с режимом записи и частичным прикрытием окошка выяснилось несколько вещей:

  1. Память необязательно забивать нулями – под действием света единички превращаются в нолики точно так же, как и нолики в единички. Как это соотносится с тем, что написано в книге по поводу соответствия наличия заряда нулю – хороший вопрос. Ну и похоже, что моё предположение оказалось неверным. Ждём знающих людей в комментариях.

  2. В зависимости от того, чем была инициализирована память, на свет реагировали либо тёмные участки паттерна, либо светлые.

  3. В считанном паттерне явно прослеживаются блоки 64 на 64 ячейки, это пригодится нам в дальнейшем.

Первые два пункта позволяют ввести компенсацию: инициализировать память инверсным паттерном и интерпретировать цвет ячейки в зависимости от её расположения на стороне клиента.

С точки зрения программиста память представляет собой массив 256 на 256 ячеек, но никто не говорил нам, что в реальности ячейки будут расположены так же.

Микрофотография кристалла. Источник: Zeptobars
Микрофотография кристалла. Источник: Zeptobars

Задача ясна с порога: найти соответствия между логическими адресами и положением ячеек на кристалле. Если посмотреть на кристалл внимательнее, то можно выделить 16 отдельных зон, на которых расположены ячейки.

We need to go deeper

То, что получилось на данном этапе – уже неплохо, но для дальнейших опытов было бы неплохо наблюдать за изменениями в реальном времени, а не получать изображение по запросу вручную.

Кроме платки с 328-й Мегой у меня также есть «Синяя таблетка» на базе STM32F103C8T6, у которого на борту не просто значительно больше ресурсов, но ещё есть аппаратный USB со скоростью до 12 Мб/с – то, что нужно! Даже не пришлось заниматься сопряжением уровней – у камня оказалось достаточно толерантных к высоким уровням выводов.

В прошивке нет ничего сверхъестественного: микроконтроллер в бесконечном цикле очищает память, вычитывает содержимое и отправляет по USB.
USB и GPIO сконфигурированы с помощью CubeIDE. Я, к сожалению, не прожжённый эмбеддер, поэтому сделать USB на чистом CMSIS для меня пока сложновато, хотя наверное это могло бы улушить производительность по сравнению с использованием HAL.

Я использую USB Communication Device Class, но не в режиме виртуального COM-порта, а в связке с libusb согласно этому руководству от ST.

Также я написал небольшой класс-обёртку, чтобы заменить громоздкие обращения к регистрам и вызовы функций HAL на более читаемые конструкции вида Pin.set(); Pin.reset();

#ifndef PIN_H_
#define PIN_H_

#include "stm32f1xx_hal.h"

class Pin {

    GPIO_TypeDef *port_;
    uint16_t pin_;

public:

    Pin(GPIO_TypeDef *port_, uint16_t pin_) :
    port_(port_), pin_(pin_) {
    }
    
    void mode(uint32_t mode) {
    	GPIO_InitTypeDef GPIO_InitStruct;
    	GPIO_InitStruct.Pin = pin_;
    	GPIO_InitStruct.Mode = mode;
    	GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
    	GPIO_InitStruct.Pull = GPIO_NOPULL;
    	HAL_GPIO_Init(port_, &GPIO_InitStruct);
    }
    
    inline bool read() const {
    	return ((port_->IDR >> pin_) & 1U) != 0;
    }
    
    inline void set() const {
    	port_->BSRR = (1UL << pin_);
    }
    
    inline void reset() const {
    	port_->BRR = (1UL << pin_);
    }
    
    inline void set(bool value) const {
    	if (value) {
    		this->set(); // Установить высокое напряжение
    	} else {
    		this->reset(); // Установить низкое напряжение
    	}
    }

    inline void toggle() const {
    	port_->ODR ^= (1UL << pin_);
    }
};

#endif

В результате функции чтения/записи заметно упростились:

// Адресная шина
Pin A0(GPIOB, 12);
Pin A1(GPIOB, 13);
Pin A2(GPIOB, 14);
Pin A3(GPIOB, 15);
Pin A4(GPIOA, 8);
Pin A5(GPIOA, 9);
Pin A6(GPIOA, 10);
Pin A7(GPIOB, 7);

// RAS, CAS, WR
Pin RAS(GPIOB, 8);
Pin CAS(GPIOA, 15);
Pin WR(GPIOB, 3);

// DIN, DOUT
Pin DIN(GPIOB, 6);
Pin DOUT(GPIOB, 4);

//***

void write(uint8_t row, uint8_t column, uint8_t value) {
	set_address(row);
	RAS.reset();
	WR.reset();
	delay_cycles<4>();

	set_address(column);
	CAS.reset();
	DIN.set(value);
	// Задержка 80 нс
	delay_cycles<6>();

	WR.set();
	RAS.set();
	CAS.set();
	// После окончания цикла нужно выдержать паузу в 150 нс
	delay_cycles<11>();
}

uint8_t read(uint8_t row, uint8_t column) {
	set_address(row);
	RAS.reset();
	WR.set();
	delay_cycles<4>();

	set_address(column);
	CAS.reset();
	// Задержка 175 нс; TA_CAS + TSU_(RAS-CAS)
	delay_cycles<13>();

	uint8_t ret = DOUT.read();

	RAS.set();
	CAS.set();
	// После окончания цикла нужно выдержать паузу в 150 нс
	delay_cycles<11>();
	return ret;
}

Для отправки данных используется простой кольцевой буфер на 64 байта (по размеру пакета USB). К сожалению, нельзя сказать, что полуившееся решение достаточно эффективно. На каждый кадр имеем 256 вызовов очистки (нельзя очистить более одной строки за раз), аналогично 256 вызовов чтения и 128 посылок. При использовании inline-функций, прямом обращении к регистрам вместо HAL-вызовов там, где это возможно и включенной оптимизации -O3 полчается примерно 9-10 кадров в секунду.

Обработка данных и демонстрация работы

На стороне клиента из принятого массива формируется объект типа Bitmap.

var src = new Bitmap(128, 512, PixelFormat.Format1bppIndexed);
BitmapData data = src.LockBits(new Rectangle(0, 0, src.Width, src.Height),
ImageLockMode.WriteOnly, src.PixelFormat);

Marshal.Copy(buffer, 0, data.Scan0, buffer.Length);
src.UnlockBits(data);

Значения ширины и высоты подобраны экспериментально, исходя из геометрии кристалла и реакции отдельных участков изображения на засветку или затенение. Далее происходит разделение чётных и нечётных строк и столбцов (нечётные в одну половину региона, чётные – в другую):

private void SeparateRows(Bitmap bitmap, int startRow, int endRow)
{
    List<int> evenRows = new List<int>();
    List<int> oddRows = new List<int>();

    for (int i = startRow; i < endRow; i++)
    {
        if ((i % 2) == 0)
            evenRows.Add(i);
        else
            oddRows.Add(i);
    }

    List<int> reorderedRows = new List<int>(evenRows.Count + oddRows.Count);
    reorderedRows.AddRange(evenRows);
    reorderedRows.AddRange(oddRows);

    Dictionary<int, int> newPositions = new Dictionary<int, int>();
    for (int i = 0; i < reorderedRows.Count; i++)
        newPositions[reorderedRows[i]] = i + startRow;

    using (var src = bitmap.Clone(new RectangleF(0, 0, bitmap.Width, bitmap.Height), bitmap.PixelFormat))
    using (Graphics g = Graphics.FromImage(bitmap))
    {
        for (int current = startRow; current < endRow; current++)
        {
            int target = newPositions[current];
            g.DrawImage(src, new Rectangle(0, target, bitmap.Width, 1), new Rectangle(0, current, bitmap.Width, 1), GraphicsUnit.Pixel);
        }     
    }
}

Здесь производительность временно принесена в жертву читаемости, я планирую переписать этот фрагмент с использованием прямого доступа к памяти вместо рисования с помощью объекта Graphics по аналогии с созданием исходного Bitmap.

Процесс повторяется несколько раз как для всего изображения, так и для разных регионов:

var workingCopy = src.Clone(new RectangleF(0, 0, src.Width, src.Height), PixelFormat.Format24bppRgb);
SeparateRows(workingCopy, 0, workingCopy.Height);

for (int i = 0; i < 8; i++)
{
    SeparateRows(workingCopy, i * 64, ((i + 1) * 64 - 1));
}

Заключение

Причины появления паттерна при засветке кристалла выяснить так и не удалось. Его можно компенсировать, но ценой серьёзной потери производительности, т.к. заранее посчитанный буфер не влезает в память. Финальное изображение по-прежнему идёт блоками как из-за малого размера кристалла, так и несовершенства обработки и деления его на зоны.

Меня как будто преследует проклятие незавершённости – начинание доходит до стадии демонстрации концепции, но дальше начинает сказываться нехватка знаний и навыков. Так или иначе, это было интересно; надеюсь, что не только мне одному.

P.S. Вместо рекламы телеграм-канала: никому часом не нужен младший шарпист?

Комментарии (25)


  1. BarsMonster
    29.10.2025 17:19

    Хехе, не раз думал сделать что-то подобное, и даже пытался запилить на EEPROM - но пока неудачно.

    По паттерну - нужно калибровать по черному и белому кадру (т.е. для каждого пикселя - нужно помнить уровень черного и белого), без этого никак... Эти калибровочные данные будут зависить от напряжения питания и температуры.

    Разброс транзисторов большой, так что без этого никуда. В МК памяти не хватит - а вот в настольнике вполне должно получится.


    1. Lizdroz
      29.10.2025 17:19

      EEPROM совсем другой уровень сложности, там ячейка заряд держит годами, заставить ее реагировать на свет за адекватное время наверное почти нереально. DRAM тут куда более подходящий кандидат из-за своей забывчивости


      1. BarsMonster
        29.10.2025 17:19

        Там свои хитрости, можно программировать ячейки "на половину", и потом в зависимости от напряжения питания измерять освещенность, что-то такое. Годами ждать конечно бесполезно, но EEPROM у всех много, можно попробовать и так )


  1. Javian
    29.10.2025 17:19

    Off для сравнения кристалл 1Мбит DRAM тех времён

    U61000
    U61000



  1. dimao79
    29.10.2025 17:19

    Если не стоит задача использовать именно память - то народ делает самодельные фотики на оптических сенсорах из мышей.


    1. fhunter
      29.10.2025 17:19

      Вроде не все подходят - часть отдают уже обработанные данные, без самой картинки.

      Плюсом у всех таких датчиков есть "улучшение" картинки, типа усиления краёв и т.д.


      1. MaFrance351
        29.10.2025 17:19

        Нужно искать древние мыши, где стоит отдельно чип и отдельно контроллер интерфейса. В новых внутри один-единственный чип, который сразу и датчик, и обработчик сигнала, и контроллер USB или PS/2. Из него картинку уже не вытащить.


    1. Lizdroz
      29.10.2025 17:19

      Поди найди нынче правильную древнюю мышь, где сенсор отдает сырые пиксели, а не готовый вектор смещения) Современные мыши для этого уже не годятся


      1. fhunter
        29.10.2025 17:19

        Даташиты на сенсоры в помощь, в некоторых описано. Но по-моему я ещё не видел мышей, где в одном корпусе была и логика PS/2 или USB и сенсор.


    1. AKudinov
      29.10.2025 17:19

      Я, видимо, настолько стар, что при словах "оптический сенсор из мышей" представляю сдвоенный фототранзистор. Внутри механических мышей шарик вращал два перпендикулярных вала, на концах которых находились диски с прорезями. И вращение этих дисков считывалось с помощью оптопар, где с одной стороны диска находился светодиод, а с другой -- сдвоенный фототранзистор.

      Но как из этого можно сделать фотоаппарат? Надо раскурочить очень много мышей...


      1. dimao79
        29.10.2025 17:19

        Я солнечную батарею из МП35 делал, так что все возможно.


      1. Blackbird_shadow
        29.10.2025 17:19

        ну это было в механических - потом уже стали делать банально камеру правда низкого разрешения ибо большое не требовалось . Народ даже писал проги чтобы вытянуть с неё картинку - более того можно было проехавшись по листу бумаги его сосканировать . А сейчас уже пишут что все мозги уже с камерой интегрированы и только перемещения сразу выдают - скучно :)


  1. Lizdroz
    29.10.2025 17:19

    Наглядное пособие о том, почему документация на чип важна


    1. Coppermine Автор
      29.10.2025 17:19

      Есть такое. Вменяемую информацию про 565-ю серию нашёл только в упомянутом в статье справочнике.


  1. Fox_Alex
    29.10.2025 17:19

    Надо над чипом (уже после объектива) поместить очень тонкую апертуру или точечный источник света. И его перемещением откалибровать истинное положение пикселей на кристалле.


    1. Blackbird_shadow
      29.10.2025 17:19

      слишком замороченно . Я когда хотел нечто такое запилить еще в начале 2000х когда все цеплялось еще к LPT порту . Вскрывал ру5 и обнаружил что там все блоками 32x32 идет - удобно отбраковки делать видимо (были половинные ру5 насколько я помню где часть памяти которая "не удалась" просто блокировалась ) . А делать можно просто поставив объектив и снимая прямую наклоную линию нарисрованную на бумаге например


      1. Coppermine Автор
        29.10.2025 17:19

        Мне показалось, что скорее блоками 64 на 64, причём эти области на кристалле не квадратные :)

        Я пытался закрывать кристалл плотным картоном и играться с объективом от камеры видеонаблюдения (фокусное 8мм), но сфокусированное пятно света получается слишком большим и как раз закрывает один или несколько блоков.


  1. Blackbird_shadow
    29.10.2025 17:19

    А почему бы оригинальный циклоп не собрать ? номер журнала легко качается - она там совсем несложная схема то . Правда Mostek MK4008P-9 или AMI S4008-9 который со снятой крышкой используется как сенсор уже аналогофф не имеет - наша к565ру1 уже имела 4 килобита


    1. Coppermine Автор
      29.10.2025 17:19

      Я думал об этом, но как уже выяснилось, в той памяти, которую можно достать, физическое расположение ячейки и её логический адрес отличаются. Поэтому пришлось городить огород из перестановки строк и столбцов программно, чтобы получить мало-мальски вменяемые результаты.


  1. volkahowl
    29.10.2025 17:19

    Автор, а что у вас за планшет на последнем видео?


    1. Coppermine Автор
      29.10.2025 17:19

      Surface Go 3. i3-10100Y, 8/128. В своё время искал компактную машинку, которую можно постоянно носить с собой. По иронии судьбы сейчас это мой основной компьютер, у настольной машины похоже накрылась видеокарта и я временно не могу приобрести замену.


  1. GidraVydra
    29.10.2025 17:19

    Так а превращение единицы в ноль и ноля в единицу происходят при одних и тех же уровнях шин? Просто если одно из них можно объяснить фотодинамикой мосфета (фотогейтинг, фотопроводимость), то второе?


    1. fhunter
      29.10.2025 17:19

      https://www.righto.com/2020/11/reverse-engineering-classic-mk4116-16.html вот тут в статье описано (правда для другого чипа, но примерно того же периода), что одна половинка массива используется для чтения, а во второй половинке стоит опорная ячейка с меньшим конденсатором. (искать по dummy cell). И она определяет порог перехода.
      (и при смене половинок - они меняются местами)


  1. tormozedison
    29.10.2025 17:19

    Помню похожий по назначению проект Kuckuck (кукушка, по аналогии с «сейчас вылетит птичка») с программой для DOS.