This is the low level flash driver. It has some stuff at the top of the cpp file that lets me see the pins states. I originally planned to use the Arduino LED blinking to know what was going on. The use of the serial port is much better.
Right now the diagnostic code is made of functions living in the file aren't part of the class. I'll change that going forward, or I'll remove it.
But, for now, the code seems to work.
#ifndef INCLUDE_FLASHLOW
#define INCLUDE_FLASHLOW
#include <Arduino.h>
class FlashLow
{
public:
FlashLow();
// Setsw the input/output pin mode
void EnablePins(bool enable);
// Resets the CPLD
bool Reset();
// Write data to *ptr.
// NOTE: This is a NOT toggle bit operation, just sends data to *ptr
// returns true if successful
void Write(long ptr, byte data);
// Read data at *ptr into *pData
// returns true if successful
void Read(long, byte* pData);
// Force update of all address bits
void UpdateAddress(long addr);
// Update address bits only on parts that are different
void UpdateAddressDiff(long addr);
// Update address bits 3:0
void UpdateAddress_3_0(long addr);
// Update address bits 7:4
void UpdateAddress_7_4(long addr);
// Update address bits 17:8
void UpdateAddress_17_8(long addr);
// Update chip control where bits 3-0 are drive, CS*, WR*, and RD*
void UpdateChip(int chip);
// Update the CTRL register that tells which register to pulse data in and out
void UpdateCtrl(int ctrl);
// Swaps a data byte on Din/Dout
byte ReadWrite(byte data);
// Pulse CLK high and low
void PulseClk();
// Pulse nCTRL low and high
void PulseCtrl();
// Control pins directly
void DirectWrite(bool enable, bool clk, bool din, bool ctrl);
void DirectRead(bool* enable, bool* clk, bool* din, bool* dout, bool* ctrl);
// Reads until the toggle bits stop toggling
// Returns true if the read data matches expected
// Use expected of 0xff for erase operations
bool Toggle(byte expected);
// Send CPLD reset sequence
void ResetSequence();
private:
// Update an arbitrary part of the address bits
void UpdateAddress_start_end(long addr, int startBit, int endBit);
int m_lastAddr;
public:
static const int PIN_nCTRL =
static const int PIN_Dout = 3;
static const int PIN_Din = 4;
static const int PIN_CLK = 5;
static const int PIN_ENABLE = 6;
};
#endif
Here is the cpp part:
#include "flashLow.h"
//#define SUPER_SLO_MO() delay(1000)
#define SUPER_SLO_MO() SendOutPins()
void SendOutPins()
{
byte progress[10] = { 0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
progress[1] =
(digitalRead(FlashLow::PIN_ENABLE) ? 0x01 : 0) |
(digitalRead(FlashLow::PIN_nCTRL) ? 0x02 : 0) |
(digitalRead(FlashLow::PIN_CLK) ? 0x04 : 0) |
(digitalRead(FlashLow::PIN_Din) ? 0x08 : 0) |
(digitalRead(FlashLow::PIN_Dout) ? 0x10 : 0);
Serial.write(progress, 10);
delay(250);
}
void BlinkOutPins()
{
digitalWrite(13, HIGH);
delay(1000);
digitalWrite(13, LOW);
delay(1000);
if (digitalRead(FlashLow::PIN_ENABLE))
{
digitalWrite(13, HIGH);
delay(500);
digitalWrite(13, LOW);
delay(500);
}
else
{
digitalWrite(13, HIGH);
delay(250);
digitalWrite(13, LOW);
delay(250);
digitalWrite(13, HIGH);
delay(250);
digitalWrite(13, LOW);
delay(250);
}
delay(1000);
if (digitalRead(FlashLow::PIN_nCTRL))
{
digitalWrite(13, HIGH);
delay(500);
digitalWrite(13, LOW);
delay(500);
}
else
{
digitalWrite(13, HIGH);
delay(250);
digitalWrite(13, LOW);
delay(250);
digitalWrite(13, HIGH);
delay(250);
digitalWrite(13, LOW);
delay(250);
}
delay(1000);
if (digitalRead(FlashLow::PIN_CLK))
{
digitalWrite(13, HIGH);
delay(500);
digitalWrite(13, LOW);
delay(500);
}
else
{
digitalWrite(13, HIGH);
delay(250);
digitalWrite(13, LOW);
delay(250);
digitalWrite(13, HIGH);
delay(250);
digitalWrite(13, LOW);
delay(250);
}
delay(1000);
if (digitalRead(FlashLow::PIN_Din))
{
digitalWrite(13, HIGH);
delay(500);
digitalWrite(13, LOW);
delay(500);
}
else
{
digitalWrite(13, HIGH);
delay(250);
digitalWrite(13, LOW);
delay(250);
digitalWrite(13, HIGH);
delay(250);
digitalWrite(13, LOW);
delay(250);
}
delay(1000);
if (digitalRead(FlashLow::PIN_Dout))
{
digitalWrite(13, HIGH);
delay(500);
digitalWrite(13, LOW);
delay(500);
}
else
{
digitalWrite(13, HIGH);
delay(250);
digitalWrite(13, LOW);
delay(250);
digitalWrite(13, HIGH);
delay(250);
digitalWrite(13, LOW);
delay(250);
}
delay(1000);
}
FlashLow::FlashLow()
{
m_lastAddr = -1;
}
void FlashLow::EnablePins(bool enable)
{
if (enable)
{
pinMode(PIN_ENABLE, OUTPUT);
pinMode(PIN_nCTRL, OUTPUT);
pinMode(PIN_Dout, INPUT);
pinMode(PIN_Din, OUTPUT);
pinMode(PIN_CLK, OUTPUT);
}
else
{
pinMode(PIN_ENABLE, INPUT_PULLUP);
pinMode(PIN_nCTRL, INPUT_PULLUP);
pinMode(PIN_Dout, INPUT);
pinMode(PIN_Din, INPUT_PULLUP);
pinMode(PIN_CLK, INPUT_PULLUP);
}
}
void FlashLow::Write(long addr, byte data)
{
UpdateAddressDiff(addr);
ReadWrite(data);
UpdateChip(0x1); // drive, CS, WR
UpdateChip(0x3); // drive, CS
UpdateChip(0xf); // done
}
void FlashLow::Read(long addr, byte* pData)
{
UpdateAddressDiff(addr);
*pData = ReadWrite(0);
}
void FlashLow::UpdateAddressDiff(long addr)
{
if (m_lastAddr == -1)
{
UpdateAddress(addr);
}
else
{
long diffs = (addr ^ m_lastAddr);
if ((diffs & 0x0000f) != 0)
{
UpdateAddress_3_0(addr);
}
if ((diffs & 0x000f0) != 0)
{
UpdateAddress_7_4(addr);
}
if ((diffs & 0xfff00) != 0)
{
UpdateAddress_17_8(addr);
}
m_lastAddr = addr;
}
}
void FlashLow::UpdateAddress(long addr)
{
UpdateAddress_3_0(addr);
UpdateAddress_7_4(addr);
UpdateAddress_17_8(addr);
m_lastAddr = addr;
}
void FlashLow::UpdateAddress_start_end(long addr, int endBit, int startBit)
{
int i;
for (i = startBit; i <= endBit; ++i)
{
long mask = 1L << i;
m_lastAddr &= ~mask;
m_lastAddr |= (mask & addr);
digitalWrite(PIN_Din, (addr & (1L << i)) ? HIGH : LOW);
SUPER_SLO_MO();
PulseClk();
}
}
void FlashLow::UpdateAddress_3_0(long addr)
{
UpdateCtrl(0x01);
UpdateAddress_start_end(addr, 3, 0);
}
void FlashLow::UpdateAddress_7_4(long addr)
{
UpdateCtrl(0x02);
UpdateAddress_start_end(addr, 7, 4);
}
void FlashLow::UpdateAddress_17_8(long addr)
{
UpdateCtrl(0x03);
UpdateAddress_start_end(addr, 17, 8);
}
void FlashLow::UpdateChip(int chip)
{
int i;
UpdateCtrl(0x07);
for (i = 0; i < 4; ++i)
{
digitalWrite(PIN_Din, (chip & 1) ? HIGH : LOW);
SUPER_SLO_MO();
PulseClk();
chip >>= 1;
}
PulseCtrl();
}
void FlashLow::UpdateCtrl(int ctrl)
{
int i;
digitalWrite(PIN_nCTRL, LOW);
SUPER_SLO_MO();
for (i = 0; i < 3; ++i)
{
int bit = ctrl & 1;
ctrl = ctrl >> 1;
digitalWrite(PIN_Din, bit ? HIGH : LOW);
SUPER_SLO_MO();
PulseClk();
}
digitalWrite(PIN_nCTRL, HIGH);
SUPER_SLO_MO();
}
byte FlashLow::ReadWrite(byte data)
{
int i;
byte outData = 0;
UpdateCtrl(0x00);
for (i = 0; i < 8; ++i)
{
if (digitalRead(PIN_Dout) == HIGH)
{
outData |= 0x80;
}
digitalWrite(PIN_Din, (data & 1) ? HIGH : LOW);
SUPER_SLO_MO();
PulseClk();
outData >>= 1;
data >>= 1;
}
return outData;
}
bool FlashLow::Toggle(byte expected)
{
bool toggling = true;
byte data0;
byte data1;
Read(m_lastAddr, &data0);
while (toggling)
{
Read(m_lastAddr, &data1);
if ((data1 ^ data0) & 0x40)
{
// toggle bit toggling
data0 = data1; // set up for next toggle check
}
else
{
toggling = false;
}
}
return data1 == expected;
}
void FlashLow::PulseClk()
{
digitalWrite(PIN_CLK, HIGH);
SUPER_SLO_MO();
digitalWrite(PIN_CLK, LOW);
SUPER_SLO_MO();
}
void FlashLow::PulseCtrl()
{
digitalWrite(PIN_nCTRL, LOW);
SUPER_SLO_MO();
digitalWrite(PIN_nCTRL, HIGH);
SUPER_SLO_MO();
}
void FlashLow::ResetSequence()
{
m_lastAddr = -1;
// initialize pins before setting output mode
digitalWrite(PIN_ENABLE, HIGH);
digitalWrite(PIN_CLK, HIGH);
digitalWrite(PIN_nCTRL, HIGH);
digitalWrite(PIN_Din, HIGH);
// set pin modes
pinMode(PIN_ENABLE, OUTPUT);
pinMode(PIN_nCTRL, OUTPUT);
pinMode(PIN_Dout, INPUT);
pinMode(PIN_Din, OUTPUT);
pinMode(PIN_CLK, OUTPUT);
// Execute reset sequence
PulseClk();
PulseClk();
digitalWrite(PIN_nCTRL, LOW);
PulseClk();
PulseClk();
PulseClk();
digitalWrite(PIN_nCTRL, HIGH);
SUPER_SLO_MO();
digitalWrite(PIN_ENABLE, LOW);
SUPER_SLO_MO();
}
void FlashLow::DirectWrite(bool enable, bool clk, bool din, bool ctrl)
{
digitalWrite(PIN_ENABLE, enable ? (HIGH) : (LOW));
digitalWrite(PIN_CLK, clk ? (HIGH) : (LOW));
digitalWrite(PIN_Din, din ? (HIGH) : (LOW));
digitalWrite(PIN_nCTRL, ctrl ? (HIGH) : (LOW));
}
void FlashLow::DirectRead(bool* enable, bool* clk, bool* din, bool* dout, bool* ctrl)
{
*enable = digitalRead(PIN_ENABLE) == HIGH;
*clk = digitalRead(PIN_CLK) == HIGH;
*din = digitalRead(PIN_Din) == HIGH;
*dout = digitalRead(PIN_Dout) == HIGH;
*ctrl = digitalRead(PIN_nCTRL) == HIGH;
}
And just to refresh, here is the code part of the Verilog for the CPLD:
`define ACTIVELOW 1'b0
`define ACTIVEHIGH 1'b1
module flashProgrammer(
input pin_ENABLE,
input pin_CLK,
input pin_Din,
input pin_nCTRL,
output reg pin_Dout,
output [17:0] pins_A,
output pin_nWR,
output pin_nRD,
output pin_nCS,
inout [7:0] pins_D
);
reg [2:0] ctrlReg;
reg [7:0] dataReg;
reg [17:0] addrReg;
reg [3:0] chipReg;
wire nOE;
reg nRDint;
reg nWRint;
reg nCSint;
reg nOEint;
assign pin_nRD = !pin_ENABLE ? nRDint : 1'bz;
assign pin_nWR = !pin_ENABLE ? nWRint : 1'bz;
assign pin_nCS = !pin_ENABLE ? nCSint : 1'bz;
assign nOE = nOEint | pin_ENABLE;
assign pins_D = (nOE==`ACTIVELOW && pin_ENABLE==`ACTIVELOW && pin_nRD==1'b1) ? dataReg : 8'bzzzzzzzz;
assign pins_A = (pin_ENABLE == `ACTIVELOW) ? addrReg : 18'bzzzzzzzzzzzzzzzzzz;
always @(posedge pin_nCTRL) begin
// Strobe out of the chip
nRDint <= chipReg[0];
nWRint <= chipReg[1];
nCSint <= chipReg[2];
nOEint <= chipReg[3];
end
always @(posedge pin_CLK) begin
if (pin_nCTRL == `ACTIVELOW) begin
// clocking in control
pin_Dout <= ctrlReg[0];
ctrlReg <= {pin_Din, ctrlReg[2:1]};
if (pin_ENABLE == 1'b1) begin
chipReg <= 4'b1111;
end
end
else begin
case (ctrlReg)
3'b000 : begin
pin_Dout <= dataReg[0];
dataReg <= { pin_Din, dataReg[7:1]};
end
3'b001 : begin
pin_Dout <= addrReg[0];
addrReg[3:0] <= { pin_Din, addrReg[3:1]};
end
3'b010 : begin
pin_Dout <= addrReg[4];
addrReg[7:4] <= { pin_Din, addrReg[7:5]};
end
3'b011 : begin
pin_Dout <= addrReg[8];
addrReg[17:8] <= { pin_Din, addrReg[17:9]};
end
3'b100 : begin
end
3'b101 : begin
end
3'b110 : begin
end
3'b111 : begin
pin_Dout <= chipReg[0];
chipReg <= { pin_Din, chipReg[3:1]};
// If reading, read now
if ((pin_nRD | nOE) == `ACTIVELOW) begin
dataReg <= pins_D;
end
end
endcase
end
end
endmodule
BTW, this has the bug fix described in the previous post. The actual CPLD I have doesn't update Dout properly while shifting ctrlReg.