// See RAM chip pinout here: https://www.digchip.com/datasheets/parts/datasheet/922/MK4116-pdf.php const PinName kAddressPins[] = { PA_7, PC_7, PB_6, PB_10, PA_8, PA_9, PB_4, }; const PinName kRasPin = PA_6; const PinName kWritePin = PB_9; const PinName kDinPin = PB_8; const PinName kDoutPin = PA_10; const PinName kCasPin = PB_3; void Timer1Isr(); void setup() { pinMode(LED_BUILTIN, OUTPUT); Serial.begin(115200); for (int i = 0; i < 7; i++) { pinMode(pinNametoDigitalPin(kAddressPins[i]), OUTPUT); } pinMode(pinNametoDigitalPin(kRasPin), OUTPUT); pinMode(pinNametoDigitalPin(kCasPin), OUTPUT); pinMode(pinNametoDigitalPin(kWritePin), OUTPUT); pinMode(pinNametoDigitalPin(kDoutPin), INPUT); pinMode(pinNametoDigitalPin(kDinPin), OUTPUT); digitalWrite(pinNametoDigitalPin(kRasPin), HIGH); digitalWrite(pinNametoDigitalPin(kCasPin), HIGH); digitalWrite(pinNametoDigitalPin(kWritePin), HIGH); // Instantiate HardwareTimer object. Thanks to 'new' instanciation, HardwareTimer is not destructed when setup() function is finished. HardwareTimer *MyTim = new HardwareTimer(TIM1); MyTim->setOverflow(1400, MICROSEC_FORMAT); MyTim->attachInterrupt(Timer1Isr); MyTim->resume(); } #define LV(x) ((x) ? HIGH : LOW) void writeAddress(int address) { for (int i = 0; i < 7; i++) { digitalWriteFast(kAddressPins[i], LV(address & (1 << i))); } } int read(int address) { int row = address >> 7; int col = address & 0x7f; noInterrupts(); writeAddress(row); digitalWriteFast(kRasPin, LOW); writeAddress(col); digitalWriteFast(kCasPin, LOW); delayMicroseconds(1); // tCAS ish int out = digitalReadFast(kDoutPin); digitalWriteFast(kCasPin, HIGH); digitalWriteFast(kRasPin, HIGH); interrupts(); return out; } void write(int address, int data) { int row = address >> 7; int col = address & 0x7f; noInterrupts(); writeAddress(row); digitalWriteFast(kRasPin, LOW); digitalWriteFast(kWritePin, LOW); digitalWriteFast(kDinPin, LV(data)); writeAddress(col); digitalWriteFast(kCasPin, LOW); for (int i = 0; i < 10; i++) asm volatile(""); // extra delay digitalWriteFast(kWritePin, HIGH); delayMicroseconds(1); // tCAS ish digitalWriteFast(kCasPin, HIGH); digitalWriteFast(kRasPin, HIGH); interrupts(); } void writepage(int address, const uint8_t data[16]) { int row = address >> 7; noInterrupts(); writeAddress(row); digitalWriteFast(kRasPin, LOW); for (int col = 0; col < 128; col++) { int b = data[col >> 3] & (1 << (col % 8)); digitalWriteFast(kDinPin, LV(b)); digitalWriteFast(kWritePin, LOW); writeAddress(col); digitalWriteFast(kCasPin, LOW); for (int i = 0; i < 10; i++) asm volatile(""); // extra delay digitalWriteFast(kWritePin, HIGH); delayMicroseconds(1); // tCAS ish digitalWriteFast(kCasPin, HIGH); } digitalWriteFast(kRasPin, HIGH); interrupts(); } void readpage(int address, uint8_t data[16]) { int row = address >> 7; noInterrupts(); writeAddress(row); digitalWriteFast(kRasPin, LOW); for (int col = 0; col < 128; col++) { uint8_t& out = data[col >> 3]; writeAddress(col); digitalWriteFast(kCasPin, LOW); delayMicroseconds(1); // tCAS ish int b = digitalReadFast(kDoutPin); out >>= 1; if (b == HIGH) out |= 0x80; digitalWriteFast(kCasPin, HIGH); } digitalWriteFast(kRasPin, HIGH); interrupts(); } int writeread(int address, int value) { write(address, value); return read(address); } void refreshrow(int row) { writeAddress(row); digitalWriteFast(kRasPin, LOW); delayMicroseconds(1); digitalWriteFast(kRasPin, HIGH); } void refreshall() { for (int row = 0; row < 128; row++) { refreshrow(row); } } void Timer1Isr() { refreshall(); } int check01(int address) { if (writeread(address, 0) != 0) return -1; if (writeread(address, 1) != 1) return -2; return 0; } int checkrow(int row) { int row_address = row << 7; for (int i = 0; i < 128; i++) { int ret = check01(row_address + i); if (ret != 0) { Serial.printf("failure at 0x%04x: %d\n", row_address + i, ret); return ret; } } return 0; } int address = 0x007f; int led_count = 0; int led = 0; char cmd = '\0'; const int kLedInterval = 1000000; const uint8_t kSampleData[16] = { 'b', 'l', 'a', 'r', 'g', ',', ' ', 'c', 'e', 'c', 'i', ' ', 'e', 's', 't', '!', }; void dump16(int address) { address &= 0x3f80; uint8_t data[16]; readpage(address, data); Serial.printf("%04x:", address); for (int i = 0; i < 16; i++) { Serial.printf(" %02x", data[i]); } Serial.print(" "); for (int i = 0; i < 16; i++) { if (data[i] < 33 || data[i] > 126) { Serial.print("."); } else { Serial.printf("%c", data[i]); } } Serial.println(""); } void filltest() { uint8_t data[16]; for (int row = 0; row < 128; row++) { snprintf(reinterpret_cast(data), 16, "testing row %03d", row); writepage(row << 7, data); } for (int row = 0; row < 128; row++) { readpage(row << 7, data); if (atoi(reinterpret_cast(&data[12])) != row) { Serial.printf("error in row %d\n", row); return; } } Serial.println("fill test ok."); } void runcmd(char cmd) { uint8_t dat[16]; if (cmd == 'p') { writepage(address, kSampleData); dump16(address); } else if (cmd == '\0') { address += 128; dump16(address); } else if (cmd == '0') { address = 0; dump16(address); } else if (cmd == 'f') { filltest(); } else if (cmd == 't') { for (int row = 0; row < 128; row++) { Serial.printf("row %d... ", row); int ret = checkrow(row); if (ret != 0) { break; } Serial.println("ok!"); } } } void loop() { // put your main code here, to run repeatedly: if (led_count > kLedInterval) { digitalWrite(LED_BUILTIN, LV(led % 2)); led += 1; led_count = 0; } led_count += 1; if (Serial.available()) { char c = Serial.read(); if (c == '\n') { runcmd(cmd); cmd = '\0'; } else { cmd = c; } } }