├── README.md └── atf22v10c.ino /README.md: -------------------------------------------------------------------------------- 1 | # atf22v10c 2 | Programming algorithm for ATF22V10C Generic Array Logic chip. 3 | 4 | I used an Arduino Due for this. Since you have to be able to switch 12V to the PREN pin, you can use any of a number of logic-level switches, such as a combination of an NPN and PNP transistor, or an NMOS and a PMOS. 5 | -------------------------------------------------------------------------------- /atf22v10c.ino: -------------------------------------------------------------------------------- 1 | #define MOSI 53 // ATF22V10 pin 11 2 | #define MISO 52 // ATF22V10 pin 14 3 | #define SCK 50 // ATF22V10 pin 10 4 | #define PREN 51 // 12V switch for ATF22V10 pin 2 5 | #define nSTR 49 // ATF22V10 pin 13 6 | #define OLMC 48 // ATF22V10 pin 8 7 | #define WRITE 46 // ATF22V10 pin 3 8 | #define ERASE 47 // ATF22V10 pins 4, 6, 7, 9 9 | 10 | void enable_programming() { 11 | digitalWrite(nSTR, HIGH); 12 | delayMicroseconds(20); 13 | digitalWrite(PREN, HIGH); 14 | delay(50); 15 | } 16 | 17 | void disable_programming() { 18 | digitalWrite(PREN, LOW); 19 | delayMicroseconds(20); 20 | } 21 | 22 | // For reading 23 | void short_pulse_strobe() { 24 | digitalWrite(nSTR, LOW); 25 | delayMicroseconds(1); 26 | digitalWrite(nSTR, HIGH); 27 | } 28 | 29 | // For writing 30 | void long_pulse_strobe() { 31 | digitalWrite(nSTR, LOW); 32 | delay(20); 33 | digitalWrite(nSTR, HIGH); 34 | } 35 | 36 | // For erasing 37 | void very_long_pulse_strobe() { 38 | digitalWrite(nSTR, LOW); 39 | delay(200); 40 | digitalWrite(nSTR, HIGH); 41 | } 42 | 43 | // Data is written msb first. 44 | void _write_data(uint8_t* buffer, uint8_t bits, bool end) { 45 | uint8_t* ptr = buffer; 46 | uint8_t bytes = (bits+7)/8; 47 | uint8_t nbits = 0; 48 | for (int i = 0; i < bytes; i++, ptr++) { 49 | for (int j = 7; j >= 0; j--, nbits++) { 50 | if (nbits >= bits) return; 51 | int c = (*ptr & (1 << j)) ? HIGH : LOW; 52 | digitalWrite(MOSI, c); 53 | // The last bit gets clocked in not by SCK, but by nSTR, 54 | // so we leave MOSI set for the next strobe. 55 | if (nbits == bits - 1 && end) return; 56 | digitalWrite(SCK, HIGH); 57 | delayMicroseconds(1); 58 | digitalWrite(SCK, LOW); 59 | delayMicroseconds(1); 60 | } 61 | } 62 | } 63 | 64 | void write_data(uint8_t* buffer, uint8_t bits) { 65 | _write_data(buffer, bits, false); 66 | } 67 | 68 | void write_data_end(uint8_t* buffer, uint8_t bits) { 69 | _write_data(buffer, bits, true); 70 | } 71 | 72 | void send_column(uint8_t column) { 73 | column <<= 2; 74 | write_data_end(&column, 6); 75 | } 76 | 77 | void set_column(uint8_t column) { 78 | send_column(column); 79 | short_pulse_strobe(); 80 | digitalWrite(MOSI, LOW); 81 | delayMicroseconds(1); 82 | } 83 | 84 | // Data is read msb first 85 | void read_data(uint8_t* buffer, uint8_t bits) { 86 | uint8_t* ptr = buffer; 87 | uint8_t bytes = (bits+7)/8; 88 | uint8_t nbits = 0; 89 | for (int i = 0; i < bytes; i++, ptr++) { 90 | *ptr = 0; 91 | for (int j = 0; j < 8; j++, nbits++) { 92 | *ptr <<= 1; 93 | if (nbits >= bits) continue; // zero-fills the rest 94 | int c = digitalRead(MISO); 95 | if (c == HIGH) *ptr |= 1; 96 | // Don't have to clock after the last bit 97 | if (nbits != bits - 1) { 98 | digitalWrite(SCK, HIGH); 99 | delayMicroseconds(1); 100 | digitalWrite(SCK, LOW); 101 | delayMicroseconds(1); 102 | } 103 | } 104 | } 105 | } 106 | 107 | // Buffer must be at least 17 bytes 108 | void read_column(uint8_t* buffer, uint8_t column) { 109 | set_column(column); 110 | read_data(buffer, 132); 111 | } 112 | 113 | // Buffer must be at least 17 bytes 114 | void write_column(uint8_t* buffer, uint8_t column) { 115 | write_data(buffer, 132); 116 | send_column(column); // yes, the column comes last 117 | digitalWrite(WRITE, HIGH); 118 | long_pulse_strobe(); 119 | digitalWrite(WRITE, LOW); 120 | } 121 | 122 | // Buffer must be at least 9 bytes 123 | void read_id(uint8_t* buffer) { 124 | set_column(0x3A); // 0x1D, 0 125 | read_data(buffer, 72); 126 | } 127 | 128 | // Buffer must be at least 3 bytes 129 | void read_olmc(uint8_t* buffer) { 130 | digitalWrite(OLMC, HIGH); 131 | short_pulse_strobe(); 132 | read_data(buffer, 20); 133 | digitalWrite(OLMC, LOW); 134 | } 135 | 136 | // Buffer must be at least 3 bytes 137 | void write_olmc(uint8_t* buffer) { 138 | digitalWrite(OLMC, HIGH); 139 | write_data_end(buffer, 20); 140 | digitalWrite(WRITE, HIGH); 141 | long_pulse_strobe(); 142 | digitalWrite(WRITE, LOW); 143 | digitalWrite(OLMC, LOW); 144 | } 145 | 146 | // powerdown bit not working yet 147 | 148 | // Buffer must be at least 1 byte 149 | void read_powerdown(uint8_t* buffer) { 150 | set_column(0x3B); 151 | read_data(buffer, 1); 152 | } 153 | 154 | void write_powerdown(uint8_t* buffer) { 155 | write_data(buffer, 1); 156 | send_column(0x3B); // yes, the column comes last 157 | digitalWrite(WRITE, HIGH); 158 | long_pulse_strobe(); 159 | digitalWrite(WRITE, LOW); 160 | } 161 | 162 | void erase() { 163 | digitalWrite(WRITE, HIGH); 164 | digitalWrite(ERASE, HIGH); 165 | digitalWrite(OLMC, HIGH); 166 | very_long_pulse_strobe(); 167 | digitalWrite(OLMC, LOW); 168 | digitalWrite(ERASE, LOW); 169 | digitalWrite(WRITE, LOW); 170 | } 171 | 172 | void serial_out_data(uint8_t* buffer, uint8_t bytes) { 173 | for (int i = 0; i < bytes; i++) { 174 | char tmp[3]; 175 | sprintf(tmp, "%02X", buffer[i]); 176 | Serial.print(tmp); 177 | Serial.print(" "); 178 | } 179 | Serial.print("\n"); 180 | } 181 | 182 | void setup_pins() { 183 | digitalWrite(PREN, LOW); 184 | digitalWrite(MOSI, LOW); 185 | digitalWrite(SCK, LOW); 186 | digitalWrite(nSTR, HIGH); 187 | digitalWrite(OLMC, LOW); 188 | digitalWrite(ERASE, LOW); 189 | digitalWrite(WRITE, LOW); 190 | pinMode(PREN, OUTPUT); 191 | pinMode(MOSI, OUTPUT); 192 | pinMode(MISO, INPUT); 193 | pinMode(SCK, OUTPUT); 194 | pinMode(nSTR, OUTPUT); 195 | pinMode(OLMC, OUTPUT); 196 | pinMode(WRITE, OUTPUT); 197 | pinMode(ERASE, OUTPUT); 198 | } 199 | 200 | void setup() { 201 | Serial.begin(115200); 202 | while (!Serial) { 203 | ; // wait for serial port to connect. Needed for Leonardo only 204 | } 205 | 206 | setup_pins(); 207 | 208 | enable_programming(); 209 | 210 | erase(); 211 | 212 | uint8_t wdata[17] = { 213 | 0x21, 0x43, 0x65, 0x87, 0xA9, 0xCB, 0xDE, 0x00, 214 | 0x11, 0x22, 0x33, 0x44, 0x55, 0x55, 0x66, 0x77, 215 | 0x88 216 | }; 217 | write_column(wdata, 0x2C); 218 | uint8_t wolmc_data[3] = {0xF1, 0x35, 0x79}; 219 | write_olmc(wolmc_data); 220 | 221 | // powerdown bit not working yet 222 | //uint8_t wpowerdown_data[1] = {0x00}; 223 | //write_powerdown(wpowerdown_data); 224 | 225 | uint8_t id[9]; 226 | uint8_t olmc[3]; 227 | uint8_t data[17]; 228 | 229 | // read 72 bit ID 230 | read_id(id); 231 | serial_out_data(id, sizeof(id)); 232 | 233 | // read 132 bits per column. The last column is 234 | // the user data column. 235 | for (uint8_t column = 0; column < 0x2D; column++) { 236 | read_column(data, column); 237 | serial_out_data(data, sizeof(data)); 238 | } 239 | 240 | // read 20 bits of OLMC settings 241 | read_olmc(olmc); 242 | serial_out_data(olmc, sizeof(olmc)); 243 | 244 | // read powerdown bit (not working yet) 245 | uint8_t powerdown[1]; 246 | read_powerdown(powerdown); 247 | serial_out_data(powerdown, sizeof(powerdown)); 248 | 249 | disable_programming(); 250 | } 251 | 252 | void loop() { 253 | } 254 | --------------------------------------------------------------------------------