380 lines
9.4 KiB
C++
380 lines
9.4 KiB
C++
#define TRUE 1
|
|
#define FALSE 0
|
|
|
|
/* 74HC595 control (address lines) */
|
|
#define shiftLatchPin A1
|
|
#define shiftClockPin A2
|
|
#define shiftDataPin A0
|
|
#define addressPinA10 13
|
|
|
|
/* Data pins */
|
|
#define dataB0 2
|
|
#define dataB1 3
|
|
#define dataB2 4
|
|
#define dataB3 5
|
|
#define dataB4 6
|
|
#define dataB5 7
|
|
#define dataB6 8
|
|
#define dataB7 10
|
|
|
|
/* Chip control */
|
|
#define chipEnable A3
|
|
#define outputEnable A4
|
|
#define powerEnable A5 // For 27C16 and 27C32
|
|
#define readVoltageEnable 13 // For 27C16
|
|
#define programVoltageEnableC16 9 // For 27C16
|
|
#define programVoltageEnableC32 12 // For 27C32 and 27C512
|
|
#define programVoltageEnableOther 11 // For other
|
|
|
|
/* Voltage control (for programming chips) */
|
|
#define voltageControl A6
|
|
#define rTop 10000.0
|
|
#define rBottom 1500.0
|
|
|
|
//#define MESSAGES
|
|
|
|
typedef enum chipType {
|
|
NONE = 0,
|
|
C16 = 1,
|
|
C32 = 2,
|
|
C64 = 3,
|
|
C128 = 4,
|
|
C256 = 5,
|
|
C512 = 6
|
|
} Chip;
|
|
|
|
typedef enum mode {
|
|
WAIT,
|
|
READ,
|
|
WRITE,
|
|
VOLTAGE
|
|
} Modes;
|
|
|
|
|
|
void write_mode (void);
|
|
void read_mode (void);
|
|
void set_address (uint16_t address);
|
|
uint8_t get_data (void);
|
|
void set_data (uint8_t data);
|
|
uint8_t read_byte (uint16_t address);
|
|
void write_byte (uint16_t address, uint8_t data);
|
|
float get_voltage (void);
|
|
void program_voltage_set (bool state);
|
|
uint16_t gen_address (uint16_t address);
|
|
void select_chip (chipType new_chip);
|
|
|
|
chipType chip = NONE;
|
|
Modes mode = WAIT;
|
|
uint8_t log_enable = FALSE;
|
|
uint16_t start_address = 0x0000;
|
|
uint16_t end_address = 0x0000;
|
|
#define BUF_LEN 16
|
|
uint8_t buf[BUF_LEN];
|
|
|
|
void message(const char* mes){
|
|
if (log_enable)
|
|
Serial.println(mes);
|
|
}
|
|
|
|
void setup() {
|
|
// 74HC595 (*2)
|
|
pinMode(shiftLatchPin, OUTPUT);
|
|
pinMode(shiftClockPin, OUTPUT);
|
|
pinMode(shiftDataPin, OUTPUT);
|
|
pinMode(addressPinA10, OUTPUT);
|
|
|
|
// Chip control
|
|
pinMode(chipEnable, OUTPUT);
|
|
pinMode(outputEnable, OUTPUT);
|
|
pinMode(powerEnable, OUTPUT);
|
|
pinMode(readVoltageEnable, OUTPUT);
|
|
pinMode(programVoltageEnableC16, OUTPUT);
|
|
pinMode(programVoltageEnableC32, OUTPUT);
|
|
pinMode(programVoltageEnableOther, OUTPUT);
|
|
digitalWrite(outputEnable, HIGH);
|
|
digitalWrite(powerEnable, HIGH);
|
|
digitalWrite(readVoltageEnable, HIGH);
|
|
digitalWrite(programVoltageEnableC16, LOW);
|
|
digitalWrite(programVoltageEnableC32, LOW);
|
|
digitalWrite(programVoltageEnableOther, LOW);
|
|
digitalWrite(chipEnable, LOW);
|
|
|
|
// Data pins
|
|
read_mode();
|
|
|
|
Serial.begin(115200);
|
|
Serial.println("Arduino 27 Series programmer");
|
|
}
|
|
|
|
void loop() {
|
|
switch (mode) {
|
|
case READ:
|
|
if (chip == NONE) {
|
|
mode = WAIT;
|
|
break;
|
|
}
|
|
message("Read mode.");
|
|
read_mode();
|
|
if (chip == C16) digitalWrite(readVoltageEnable, LOW);
|
|
digitalWrite(chipEnable, LOW);
|
|
digitalWrite(outputEnable, LOW);
|
|
for (uint16_t i = start_address; i <= end_address; i++) {
|
|
uint8_t data = read_byte(i);
|
|
Serial.write(&data, sizeof(data));
|
|
if (i == end_address) break; // Защита от переполнения uint16
|
|
}
|
|
digitalWrite(outputEnable, HIGH);
|
|
digitalWrite(chipEnable, HIGH);
|
|
if (chip == C16) digitalWrite(readVoltageEnable, HIGH);
|
|
mode = WAIT;
|
|
break;
|
|
case WRITE:
|
|
if (chip == NONE) {
|
|
mode = WAIT;
|
|
break;
|
|
}
|
|
message("Write mode");
|
|
/*for (int i = start_address; i <= end_address; i++) {
|
|
Serial.println(i, HEX);
|
|
write_byte(i, 0x89);
|
|
}*/
|
|
for (uint16_t i = start_address; i <= end_address; i += BUF_LEN) {
|
|
Serial.print("Write block ");
|
|
Serial.println(i);
|
|
uint8_t count = Serial.readBytes((char*)buf, BUF_LEN);
|
|
if (count != BUF_LEN) {
|
|
Serial.print("Error on block");
|
|
Serial.println(i);
|
|
Serial.print("Received ");
|
|
Serial.println(count);
|
|
break;
|
|
}
|
|
for (uint16_t j = 0; j < BUF_LEN; j++) {
|
|
// Write byte
|
|
write_mode();
|
|
program_voltage_set(true);
|
|
write_byte((i + j), buf[j]);
|
|
program_voltage_set(false);
|
|
|
|
// Verify byte
|
|
read_mode();
|
|
if (chip == C16) digitalWrite(readVoltageEnable, LOW);
|
|
digitalWrite(chipEnable, LOW);
|
|
digitalWrite(outputEnable, LOW);
|
|
uint8_t verify = get_data();
|
|
digitalWrite(outputEnable, HIGH);
|
|
digitalWrite(chipEnable, HIGH);
|
|
if (chip == C16) digitalWrite(readVoltageEnable, HIGH);
|
|
if (buf[j] != virify){
|
|
Serial.print("Error on address ");
|
|
Serial.println(i + j);
|
|
mode = WAIT;
|
|
}
|
|
}
|
|
Serial.print("Complete block ");
|
|
Serial.println(i);
|
|
if (i == end_address) break;
|
|
}
|
|
message("Write success.");
|
|
mode = WAIT;
|
|
break;
|
|
case VOLTAGE:
|
|
Serial.print("Programming voltage: ");
|
|
Serial.println(get_voltage(), 1);
|
|
mode = WAIT;
|
|
break;
|
|
default:
|
|
if (chip == NONE) message("Chip not selected!");
|
|
message("Wait commands...");
|
|
while (Serial.available()) Serial.read();
|
|
do {} while (Serial.available() == 0);
|
|
char incomingByte = Serial.read();
|
|
while (Serial.available()) Serial.read();
|
|
switch (incomingByte) {
|
|
case 'r': mode = READ; break;
|
|
case 'w': mode = WRITE; break;
|
|
case 'v': mode = VOLTAGE; break;
|
|
case 'a': select_chip(C16); break;
|
|
case 'b': select_chip(C32); break;
|
|
case 'c': select_chip(C64); break;
|
|
case 'd': select_chip(C128); break;
|
|
case 'e': select_chip(C256); break;
|
|
case 'f': select_chip(C512); break;
|
|
}
|
|
}
|
|
}
|
|
|
|
void select_chip (chipType new_chip) {
|
|
digitalWrite(powerEnable, HIGH);
|
|
switch (new_chip) {
|
|
case C16:
|
|
digitalWrite(powerEnable, LOW);
|
|
chip = new_chip;
|
|
end_address = 0x07ff;
|
|
message("Select 27C16 chip.");
|
|
break;
|
|
case C32:
|
|
digitalWrite(powerEnable, LOW);
|
|
chip = new_chip;
|
|
end_address = 0x0fff;
|
|
message("Select 27C32 chip.");
|
|
break;
|
|
case C64:
|
|
chip = new_chip;
|
|
end_address = 0x1fff;
|
|
message("Select 27C64 chip.");
|
|
break;
|
|
case C128:
|
|
chip = new_chip;
|
|
end_address = 0x3fff;
|
|
message("Select 27C128 chip.");
|
|
break;
|
|
case C256:
|
|
chip = new_chip;
|
|
end_address = 0x7fff;
|
|
message("Select 27C256 chip.");
|
|
break;
|
|
case C512:
|
|
chip = C512;
|
|
end_address = 0xffff;
|
|
message("Select 27C512 chip.");
|
|
break;
|
|
default:
|
|
chip = NONE;
|
|
end_address = 0x0000;
|
|
message("Chip not selected!");
|
|
}
|
|
}
|
|
|
|
|
|
void program_voltage_set (bool state) {
|
|
switch (chip) {
|
|
case C16:
|
|
digitalWrite(programVoltageEnableC16, state);
|
|
break;
|
|
case C32:
|
|
case C512:
|
|
digitalWrite(programVoltageEnableC32, state);
|
|
break;
|
|
case C64:
|
|
case C128:
|
|
case C256:
|
|
default:
|
|
digitalWrite(programVoltageEnableOther, state);
|
|
}
|
|
}
|
|
|
|
void write_mode (void) {
|
|
pinMode(dataB0, OUTPUT);
|
|
pinMode(dataB1, OUTPUT);
|
|
pinMode(dataB2, OUTPUT);
|
|
pinMode(dataB3, OUTPUT);
|
|
pinMode(dataB4, OUTPUT);
|
|
pinMode(dataB5, OUTPUT);
|
|
pinMode(dataB6, OUTPUT);
|
|
pinMode(dataB7, OUTPUT);
|
|
}
|
|
|
|
void read_mode (void) {
|
|
pinMode(dataB0, INPUT_PULLUP);
|
|
pinMode(dataB1, INPUT_PULLUP);
|
|
pinMode(dataB2, INPUT_PULLUP);
|
|
pinMode(dataB3, INPUT_PULLUP);
|
|
pinMode(dataB4, INPUT_PULLUP);
|
|
pinMode(dataB5, INPUT_PULLUP);
|
|
pinMode(dataB6, INPUT_PULLUP);
|
|
pinMode(dataB7, INPUT_PULLUP);
|
|
}
|
|
|
|
uint16_t gen_address (uint16_t address) {
|
|
byte high = highByte(address);
|
|
byte low = lowByte(address);
|
|
switch (chip) {
|
|
case C16:
|
|
break;
|
|
if (mode == READ) {
|
|
high |= 1 << 3; // A11 (C32+) is Vpp for C16 (5v for read)
|
|
}
|
|
break;
|
|
case C64:
|
|
case C128:
|
|
if (mode == READ) {
|
|
high |= 1 << 6; // A14 (C256 and C512) is ~PGM for C64 and C128
|
|
}
|
|
break;
|
|
case C32:
|
|
case C256:
|
|
case C512:
|
|
default:
|
|
break;
|
|
}
|
|
return (high << 8) | low;
|
|
}
|
|
|
|
void set_address (uint16_t address) {
|
|
address = gen_address(address);
|
|
digitalWrite(shiftLatchPin, LOW);
|
|
byte registerTwo = highByte(address);
|
|
byte registerOne = lowByte(address);
|
|
shiftOut(shiftDataPin, shiftClockPin, MSBFIRST, registerTwo);
|
|
shiftOut(shiftDataPin, shiftClockPin, MSBFIRST, registerOne);
|
|
digitalWrite(shiftLatchPin, HIGH);
|
|
}
|
|
|
|
uint8_t get_data (void) {
|
|
uint8_t data = 0;
|
|
data |= digitalRead(dataB0) << 0;
|
|
data |= digitalRead(dataB1) << 1;
|
|
data |= digitalRead(dataB2) << 2;
|
|
data |= digitalRead(dataB3) << 3;
|
|
data |= digitalRead(dataB4) << 4;
|
|
data |= digitalRead(dataB5) << 5;
|
|
data |= digitalRead(dataB6) << 6;
|
|
data |= digitalRead(dataB7) << 7;
|
|
return data;
|
|
}
|
|
|
|
void set_data (uint8_t data) {
|
|
digitalWrite(dataB0, (data & (1 << 0)));
|
|
digitalWrite(dataB1, (data & (1 << 1)));
|
|
digitalWrite(dataB2, (data & (1 << 2)));
|
|
digitalWrite(dataB3, (data & (1 << 3)));
|
|
digitalWrite(dataB4, (data & (1 << 4)));
|
|
digitalWrite(dataB5, (data & (1 << 5)));
|
|
digitalWrite(dataB6, (data & (1 << 6)));
|
|
digitalWrite(dataB7, (data & (1 << 7)));
|
|
}
|
|
|
|
uint8_t read_byte (uint16_t address) {
|
|
set_address(address);
|
|
return get_data();
|
|
}
|
|
|
|
void write_byte (uint16_t address, uint8_t data) {
|
|
set_address(address);
|
|
set_data(data);
|
|
switch (chip) {
|
|
case C16:
|
|
digitalWrite(chipEnable, HIGH);
|
|
delay(15);
|
|
digitalWrite(chipEnable, LOW);
|
|
break;
|
|
case C32:
|
|
case C64:
|
|
case C128:
|
|
case C256:
|
|
case C512:
|
|
default:
|
|
digitalWrite(chipEnable, LOW);
|
|
delayMicroseconds(110);
|
|
digitalWrite(chipEnable, HIGH);
|
|
break;
|
|
}
|
|
}
|
|
|
|
float get_voltage (void) {
|
|
float vADC = (analogRead(voltageControl) / 1024.) * 5.;
|
|
float current = vADC / rBottom;
|
|
return (current * (rTop + rBottom));
|
|
}
|