Skip to content

Instantly share code, notes, and snippets.

@wdevore
Created November 2, 2019 15:30
Show Gist options
  • Save wdevore/e0e3ed91d42d701bff7fb8b83d49d98b to your computer and use it in GitHub Desktop.
Save wdevore/e0e3ed91d42d701bff7fb8b83d49d98b to your computer and use it in GitHub Desktop.
A simple Arduino sketch for the TTGO T-Display.
/*
Sketch for TTGO T-Display:
This sketch generates signals on 2 or 3 pins according the memory cycle specs
of the FM1808 NVRam chip from RamTron (now "Cypress Semi")
Read cycle: |----- 2us ----------|
/CE _____/''''''''\____________________/''''''''\________
ADR xxxxxxx0101010101010xxxxxxxxxxxxxxxxxxx
/OE ''''''''''''''''''\______________________/'''''''''''
Write cycle: CE controlled
/CE _____/''''''''\____________________/''''''''\________
ADR xxxxxxx0101010101010xxxxxxxxxxxxxxxxxxx
/WE ''''''''''\_____________________________/'''''''''''
/OE '''''''''''''''''''''''''''''''''''''''''''''''''''''
DAT xxxxxxxxxxxxxxxxxx01010101010101010101010101xxxxxxxxxx
*/
// --------------------------------------------------------------------
// Pins
// --------------------------------------------------------------------
// Pin definitions can't be "const int" as that would mapped them to
// inaccessible location causing a crash dump.
uint8_t CE_Pin = 2; // Active low Chip Enable
uint8_t WE_Pin = 15; // Active low Write Enable
uint8_t OE_Pin = 13; // Active low Output Enable
uint8_t pulseActive_Pin = 21; // Flashes when sequence being generated
// Note: The buttons exist on the TTGO itself.
// TTGO's schematics show buttons pulled high which means they are Active Low.
uint8_t buttonRC_Pin = 0; // Button to generate Read cycle
uint8_t buttonWC_Pin = 35; // Button to generate Write cycle
// This is only used for the Read cycle to give slower external processes
// time to capture the data.
uint8_t cycleCompelete_Pin = 22; // External process indicator
// --------------------------------------------------------------------
// States
// --------------------------------------------------------------------
const int CYCLE_IDLE = 0;
const int ENTER = 1;
const int IN = 2;
const int WAIT = 3;
const int WAIT_COMPLETE = 4;
const int EXIT = 5;
int cycleState = CYCLE_IDLE;
int buttonRCState = LOW;
int buttonWCState = LOW;
int cycleCompleteState = LOW;
// Simple debouncer flag
bool buttonTriggeredState = false;
int cnt = 0;
void setup() {
Serial.begin(1000000);
Serial.println("Initializing");
// initialize the LED pin as an output:
pinMode(pulseActive_Pin, OUTPUT);
pinMode(CE_Pin, OUTPUT);
pinMode(WE_Pin, OUTPUT);
pinMode(OE_Pin, OUTPUT);
// Default controls to in-active.
digitalWrite(CE_Pin, HIGH);
digitalWrite(WE_Pin, HIGH);
digitalWrite(OE_Pin, HIGH);
// initialize the push button pins as an input:
pinMode(buttonRC_Pin, INPUT);
pinMode(buttonWC_Pin, INPUT);
pinMode(cycleCompelete_Pin, INPUT);
cycleCompleteState == HIGH;
Serial.println("Initialization complete.");
}
// TTGO's pins can be bit-banged at ~3MHz which is fast enough
// meet the NVRam's timing requirements.
// Note: The address and data values will already be present
// and supplied by another process. This sketch simply generates
// the control signals for a memory cycle.
void loop() {
// Scan the buttons
buttonRCState = digitalRead(buttonRC_Pin);
buttonWCState = digitalRead(buttonWC_Pin);
cycleCompleteState = digitalRead(cycleCompelete_Pin);
switch (cycleState) {
case CYCLE_IDLE:
if (buttonTriggeredState && cycleCompleteState == LOW) {
cnt = 0;
cycleState = WAIT;
break;
}
if (buttonRCState == LOW || buttonWCState == LOW) {
cycleState = ENTER;
break;
}
// Serial.printf("Idling %d\n", cnt);
// cnt++;
// delay(250);
break;
case WAIT:
if (cycleCompleteState == HIGH) {
Serial.println("Memory cycle ended");
buttonTriggeredState = false;
cycleCompleteState = LOW;
cnt = 0;
cycleState = CYCLE_IDLE;
break;
}
Serial.printf("Waiting %d\n", cnt);
cnt++;
delay(250);
break;
case ENTER:
Serial.println("Memory cycle starting");
buttonTriggeredState = true;
digitalWrite(pulseActive_Pin, HIGH);
cycleState = IN;
break;
case IN:
if (buttonRCState == LOW) {
Serial.println("Generating Read sequence");
// First activate /CE to start the cycle. All the code below
// can't take more than 2 microseconds according to the memory specs (Tca)
digitalWrite(CE_Pin, LOW);
digitalWrite(CE_Pin, LOW);
// Use LED pin as a fast delay
// digitalWrite(pulseActive_Pin, LOW);
// Next activate the memory's output
digitalWrite(OE_Pin, LOW);
// Complete the cycle by deactivating CE
digitalWrite(CE_Pin, HIGH);
// Now we wait for a response from the external process to capture the data.
// The response arrives on the cycleCompelete_Pin.
// ##Simulate## response from external process.
// Normally the next state would be WAIT
cycleState = EXIT;
// Instead we wait for ~700us which is plenty of time.
// A delay of 1ms is actually about 700us because of hardware.
delay(1);
digitalWrite(OE_Pin, HIGH);
} else if (buttonWCState == LOW) {
Serial.println("Generating Write sequence");
// Note: This is a CE controlled write cycle which means WE is active first.
digitalWrite(WE_Pin, LOW);
// Next activate /CE to start the cycle. All the code below
// can't take more than 2 microseconds according to the memory specs (Tca)
digitalWrite(CE_Pin, LOW); // About 150ns
digitalWrite(CE_Pin, LOW); // Stretch out a bit
// Complete the cycle by deactivating CE
digitalWrite(CE_Pin, HIGH);
digitalWrite(WE_Pin, HIGH);
buttonTriggeredState = false;
cycleState = EXIT;
}
break;
case EXIT:
buttonTriggeredState = true;
digitalWrite(pulseActive_Pin, HIGH);
cycleState = CYCLE_IDLE;
delay(100);
break;
}
digitalWrite(pulseActive_Pin, LOW);
}
@wdevore
Copy link
Author

wdevore commented Nov 2, 2019

This sketch is a simple memory cycle sequencer for reading and writing from a RamTron NV Ram 32Kx8 chip.
This is the test version where buttons are used to trigger each sequence. A Logic Analyser was used to verify the timing specs.
The release version of the sketch eliminates the buttons and instead reads addition pins to initiate a read or write sequence.

@wdevore
Copy link
Author

wdevore commented Nov 2, 2019

A simple test circuit with 1 button to end memory cycle.
ttgo sequencer

@wdevore
Copy link
Author

wdevore commented Nov 2, 2019

This is a manual programmer than kind of works, meaning it can't meet the timing specs and thus sporadically fails to read or write. But it is useful to understand the NVRam the big chip in the middle. It is a 32Kx8. If you sequence the buttons quickly enough you can successfully write to the chip. You need to be even faster to perform a read.
ramtron manual programmer

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment