flashLow.cpp/h
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.
1 #ifndef INCLUDE_FLASHLOW
2 #define INCLUDE_FLASHLOW
3 #include <Arduino.h>
4
5 class FlashLow
6 {
7 public:
8 FlashLow();
9
10 // Setsw the input/output pin mode
11 void EnablePins(bool enable);
12
13 // Resets the CPLD
14 bool Reset();
15
16 // Write data to *ptr.
17 // NOTE: This is a NOT toggle bit operation, just sends data to *ptr
18 // returns true if successful
19 void Write(long ptr, byte data);
20
21 // Read data at *ptr into *pData
22 // returns true if successful
23 void Read(long, byte* pData);
24
25 // Force update of all address bits
26 void UpdateAddress(long addr);
27
28 // Update address bits only on parts that are different
29 void UpdateAddressDiff(long addr);
30
31 // Update address bits 3:0
32 void UpdateAddress_3_0(long addr);
33
34 // Update address bits 7:4
35 void UpdateAddress_7_4(long addr);
36
37 // Update address bits 17:8
38 void UpdateAddress_17_8(long addr);
39
40 // Update chip control where bits 3-0 are drive, CS*, WR*, and RD*
41 void UpdateChip(int chip);
42
43 // Update the CTRL register that tells which register to pulse data in and out
44 void UpdateCtrl(int ctrl);
45
46 // Swaps a data byte on Din/Dout
47 byte ReadWrite(byte data);
48
49 // Pulse CLK high and low
50 void PulseClk();
51
52 // Pulse nCTRL low and high
53 void PulseCtrl();
54
55 // Control pins directly
56 void DirectWrite(bool enable, bool clk, bool din, bool ctrl);
57 void DirectRead(bool* enable, bool* clk, bool* din, bool* dout, bool* ctrl);
58
59 // Reads until the toggle bits stop toggling
60 // Returns true if the read data matches expected
61 // Use expected of 0xff for erase operations
62 bool Toggle(byte expected);
63
64 // Send CPLD reset sequence
65 void ResetSequence();
66
67 private:
68 // Update an arbitrary part of the address bits
69 void UpdateAddress_start_end(long addr, int startBit, int endBit);
70
71 int m_lastAddr;
72
73 public:
74 static const int PIN_nCTRL =
75 static const int PIN_Dout = 3;
76 static const int PIN_Din = 4;
77 static const int PIN_CLK = 5;
78 static const int PIN_ENABLE = 6;
79 };
80
81 #endif
Here is the cpp part:
1 #include "flashLow.h"
2
3 //#define SUPER_SLO_MO() delay(1000)
4 #define SUPER_SLO_MO() SendOutPins()
5
6 void SendOutPins()
7 {
8 byte progress[10] = { 0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
9
10 progress[1] =
11 (digitalRead(FlashLow::PIN_ENABLE) ? 0x01 : 0) |
12 (digitalRead(FlashLow::PIN_nCTRL) ? 0x02 : 0) |
13 (digitalRead(FlashLow::PIN_CLK) ? 0x04 : 0) |
14 (digitalRead(FlashLow::PIN_Din) ? 0x08 : 0) |
15 (digitalRead(FlashLow::PIN_Dout) ? 0x10 : 0);
16 Serial.write(progress, 10);
17
18 delay(250);
19 }
20
21 void BlinkOutPins()
22 {
23 digitalWrite(13, HIGH);
24 delay(1000);
25 digitalWrite(13, LOW);
26 delay(1000);
27
28 if (digitalRead(FlashLow::PIN_ENABLE))
29 {
30 digitalWrite(13, HIGH);
31 delay(500);
32 digitalWrite(13, LOW);
33 delay(500);
34 }
35 else
36 {
37 digitalWrite(13, HIGH);
38 delay(250);
39 digitalWrite(13, LOW);
40 delay(250);
41 digitalWrite(13, HIGH);
42 delay(250);
43 digitalWrite(13, LOW);
44 delay(250);
45 }
46
47 delay(1000);
48 if (digitalRead(FlashLow::PIN_nCTRL))
49 {
50 digitalWrite(13, HIGH);
51 delay(500);
52 digitalWrite(13, LOW);
53 delay(500);
54 }
55 else
56 {
57 digitalWrite(13, HIGH);
58 delay(250);
59 digitalWrite(13, LOW);
60 delay(250);
61 digitalWrite(13, HIGH);
62 delay(250);
63 digitalWrite(13, LOW);
64 delay(250);
65 }
66
67 delay(1000);
68 if (digitalRead(FlashLow::PIN_CLK))
69 {
70 digitalWrite(13, HIGH);
71 delay(500);
72 digitalWrite(13, LOW);
73 delay(500);
74 }
75 else
76 {
77 digitalWrite(13, HIGH);
78 delay(250);
79 digitalWrite(13, LOW);
80 delay(250);
81 digitalWrite(13, HIGH);
82 delay(250);
83 digitalWrite(13, LOW);
84 delay(250);
85 }
86
87 delay(1000);
88 if (digitalRead(FlashLow::PIN_Din))
89 {
90 digitalWrite(13, HIGH);
91 delay(500);
92 digitalWrite(13, LOW);
93 delay(500);
94 }
95 else
96 {
97 digitalWrite(13, HIGH);
98 delay(250);
99 digitalWrite(13, LOW);
100 delay(250);
101 digitalWrite(13, HIGH);
102 delay(250);
103 digitalWrite(13, LOW);
104 delay(250);
105 }
106
107 delay(1000);
108 if (digitalRead(FlashLow::PIN_Dout))
109 {
110 digitalWrite(13, HIGH);
111 delay(500);
112 digitalWrite(13, LOW);
113 delay(500);
114 }
115 else
116 {
117 digitalWrite(13, HIGH);
118 delay(250);
119 digitalWrite(13, LOW);
120 delay(250);
121 digitalWrite(13, HIGH);
122 delay(250);
123 digitalWrite(13, LOW);
124 delay(250);
125 }
126
127 delay(1000);
128 }
129
130 FlashLow::FlashLow()
131 {
132 m_lastAddr = -1;
133 }
134
135 void FlashLow::EnablePins(bool enable)
136 {
137 if (enable)
138 {
139 pinMode(PIN_ENABLE, OUTPUT);
140 pinMode(PIN_nCTRL, OUTPUT);
141 pinMode(PIN_Dout, INPUT);
142 pinMode(PIN_Din, OUTPUT);
143 pinMode(PIN_CLK, OUTPUT);
144 }
145 else
146 {
147 pinMode(PIN_ENABLE, INPUT_PULLUP);
148 pinMode(PIN_nCTRL, INPUT_PULLUP);
149 pinMode(PIN_Dout, INPUT);
150 pinMode(PIN_Din, INPUT_PULLUP);
151 pinMode(PIN_CLK, INPUT_PULLUP);
152 }
153
154 }
155
156 void FlashLow::Write(long addr, byte data)
157 {
158 UpdateAddressDiff(addr);
159 ReadWrite(data);
160
161 UpdateChip(0x1); // drive, CS, WR
162 UpdateChip(0x3); // drive, CS
163 UpdateChip(0xf); // done
164 }
165
166 void FlashLow::Read(long addr, byte* pData)
167 {
168 UpdateAddressDiff(addr);
169 *pData = ReadWrite(0);
170 }
171
172 void FlashLow::UpdateAddressDiff(long addr)
173 {
174 if (m_lastAddr == -1)
175 {
176 UpdateAddress(addr);
177 }
178 else
179 {
180 long diffs = (addr ^ m_lastAddr);
181 if ((diffs & 0x0000f) != 0)
182 {
183 UpdateAddress_3_0(addr);
184 }
185 if ((diffs & 0x000f0) != 0)
186 {
187 UpdateAddress_7_4(addr);
188 }
189 if ((diffs & 0xfff00) != 0)
190 {
191 UpdateAddress_17_8(addr);
192 }
193
194 m_lastAddr = addr;
195 }
196 }
197
198 void FlashLow::UpdateAddress(long addr)
199 {
200 UpdateAddress_3_0(addr);
201 UpdateAddress_7_4(addr);
202 UpdateAddress_17_8(addr);
203 m_lastAddr = addr;
204 }
205
206 void FlashLow::UpdateAddress_start_end(long addr, int endBit, int startBit)
207 {
208 int i;
209 for (i = startBit; i <= endBit; ++i)
210 {
211 long mask = 1L << i;
212 m_lastAddr &= ~mask;
213 m_lastAddr |= (mask & addr);
214 digitalWrite(PIN_Din, (addr & (1L << i)) ? HIGH : LOW);
215 SUPER_SLO_MO();
216 PulseClk();
217 }
218 }
219
220 void FlashLow::UpdateAddress_3_0(long addr)
221 {
222 UpdateCtrl(0x01);
223 UpdateAddress_start_end(addr, 3, 0);
224 }
225
226 void FlashLow::UpdateAddress_7_4(long addr)
227 {
228 UpdateCtrl(0x02);
229 UpdateAddress_start_end(addr, 7, 4);
230 }
231
232 void FlashLow::UpdateAddress_17_8(long addr)
233 {
234 UpdateCtrl(0x03);
235 UpdateAddress_start_end(addr, 17, 8);
236 }
237
238 void FlashLow::UpdateChip(int chip)
239 {
240 int i;
241 UpdateCtrl(0x07);
242 for (i = 0; i < 4; ++i)
243 {
244 digitalWrite(PIN_Din, (chip & 1) ? HIGH : LOW);
245 SUPER_SLO_MO();
246 PulseClk();
247 chip >>= 1;
248 }
249 PulseCtrl();
250 }
251
252 void FlashLow::UpdateCtrl(int ctrl)
253 {
254 int i;
255 digitalWrite(PIN_nCTRL, LOW);
256 SUPER_SLO_MO();
257 for (i = 0; i < 3; ++i)
258 {
259 int bit = ctrl & 1;
260 ctrl = ctrl >> 1;
261 digitalWrite(PIN_Din, bit ? HIGH : LOW);
262 SUPER_SLO_MO();
263 PulseClk();
264 }
265 digitalWrite(PIN_nCTRL, HIGH);
266 SUPER_SLO_MO();
267 }
268
269 byte FlashLow::ReadWrite(byte data)
270 {
271 int i;
272 byte outData = 0;
273 UpdateCtrl(0x00);
274 for (i = 0; i < 8; ++i)
275 {
276 if (digitalRead(PIN_Dout) == HIGH)
277 {
278 outData |= 0x80;
279 }
280 digitalWrite(PIN_Din, (data & 1) ? HIGH : LOW);
281 SUPER_SLO_MO();
282 PulseClk();
283 outData >>= 1;
284 data >>= 1;
285 }
286 return outData;
287 }
288
289 bool FlashLow::Toggle(byte expected)
290 {
291 bool toggling = true;
292 byte data0;
293 byte data1;
294 Read(m_lastAddr, &data0);
295 while (toggling)
296 {
297 Read(m_lastAddr, &data1);
298 if ((data1 ^ data0) & 0x40)
299 {
300 // toggle bit toggling
301 data0 = data1; // set up for next toggle check
302 }
303 else
304 {
305 toggling = false;
306 }
307 }
308 return data1 == expected;
309 }
310
311 void FlashLow::PulseClk()
312 {
313 digitalWrite(PIN_CLK, HIGH);
314 SUPER_SLO_MO();
315 digitalWrite(PIN_CLK, LOW);
316 SUPER_SLO_MO();
317 }
318
319 void FlashLow::PulseCtrl()
320 {
321 digitalWrite(PIN_nCTRL, LOW);
322 SUPER_SLO_MO();
323 digitalWrite(PIN_nCTRL, HIGH);
324 SUPER_SLO_MO();
325 }
326
327 void FlashLow::ResetSequence()
328 {
329 m_lastAddr = -1;
330
331 // initialize pins before setting output mode
332 digitalWrite(PIN_ENABLE, HIGH);
333 digitalWrite(PIN_CLK, HIGH);
334 digitalWrite(PIN_nCTRL, HIGH);
335 digitalWrite(PIN_Din, HIGH);
336
337 // set pin modes
338 pinMode(PIN_ENABLE, OUTPUT);
339 pinMode(PIN_nCTRL, OUTPUT);
340 pinMode(PIN_Dout, INPUT);
341 pinMode(PIN_Din, OUTPUT);
342 pinMode(PIN_CLK, OUTPUT);
343
344 // Execute reset sequence
345 PulseClk();
346 PulseClk();
347 digitalWrite(PIN_nCTRL, LOW);
348 PulseClk();
349 PulseClk();
350 PulseClk();
351 digitalWrite(PIN_nCTRL, HIGH);
352 SUPER_SLO_MO();
353 digitalWrite(PIN_ENABLE, LOW);
354 SUPER_SLO_MO();
355 }
356
357 void FlashLow::DirectWrite(bool enable, bool clk, bool din, bool ctrl)
358 {
359 digitalWrite(PIN_ENABLE, enable ? (HIGH) : (LOW));
360 digitalWrite(PIN_CLK, clk ? (HIGH) : (LOW));
361 digitalWrite(PIN_Din, din ? (HIGH) : (LOW));
362 digitalWrite(PIN_nCTRL, ctrl ? (HIGH) : (LOW));
363 }
364
365 void FlashLow::DirectRead(bool* enable, bool* clk, bool* din, bool* dout, bool* ctrl)
366 {
367 *enable = digitalRead(PIN_ENABLE) == HIGH;
368 *clk = digitalRead(PIN_CLK) == HIGH;
369 *din = digitalRead(PIN_Din) == HIGH;
370 *dout = digitalRead(PIN_Dout) == HIGH;
371 *ctrl = digitalRead(PIN_nCTRL) == HIGH;
372 }
And just to refresh, here is the code part of the Verilog for the CPLD:
1 `define ACTIVELOW 1'b0
2 `define ACTIVEHIGH 1'b1
3
4 module flashProgrammer(
5 input pin_ENABLE,
6 input pin_CLK,
7 input pin_Din,
8 input pin_nCTRL,
9 output reg pin_Dout,
10
11 output [17:0] pins_A,
12 output pin_nWR,
13 output pin_nRD,
14 output pin_nCS,
15 inout [7:0] pins_D
16 );
17
18 reg [2:0] ctrlReg;
19 reg [7:0] dataReg;
20 reg [17:0] addrReg;
21 reg [3:0] chipReg;
22 wire nOE;
23
24 reg nRDint;
25 reg nWRint;
26 reg nCSint;
27 reg nOEint;
28
29 assign pin_nRD = !pin_ENABLE ? nRDint : 1'bz;
30 assign pin_nWR = !pin_ENABLE ? nWRint : 1'bz;
31 assign pin_nCS = !pin_ENABLE ? nCSint : 1'bz;
32 assign nOE = nOEint | pin_ENABLE;
33
34 assign pins_D = (nOE==`ACTIVELOW && pin_ENABLE==`ACTIVELOW && pin_nRD==1'b1) ? dataReg : 8'bzzzzzzzz;
35 assign pins_A = (pin_ENABLE == `ACTIVELOW) ? addrReg : 18'bzzzzzzzzzzzzzzzzzz;
36
37 always @(posedge pin_nCTRL) begin
38 // Strobe out of the chip
39 nRDint <= chipReg[0];
40 nWRint <= chipReg[1];
41 nCSint <= chipReg[2];
42 nOEint <= chipReg[3];
43 end
44
45 always @(posedge pin_CLK) begin
46
47 if (pin_nCTRL == `ACTIVELOW) begin
48
49 // clocking in control
50 pin_Dout <= ctrlReg[0];
51 ctrlReg <= {pin_Din, ctrlReg[2:1]};
52
53 if (pin_ENABLE == 1'b1) begin
54 chipReg <= 4'b1111;
55 end
56 end
57 else begin
58 case (ctrlReg)
59 3'b000 : begin
60 pin_Dout <= dataReg[0];
61 dataReg <= { pin_Din, dataReg[7:1]};
62 end
63 3'b001 : begin
64 pin_Dout <= addrReg[0];
65 addrReg[3:0] <= { pin_Din, addrReg[3:1]};
66 end
67 3'b010 : begin
68 pin_Dout <= addrReg[4];
69 addrReg[7:4] <= { pin_Din, addrReg[7:5]};
70 end
71 3'b011 : begin
72 pin_Dout <= addrReg[8];
73 addrReg[17:8] <= { pin_Din, addrReg[17:9]};
74 end
75 3'b100 : begin
76 end
77 3'b101 : begin
78 end
79 3'b110 : begin
80 end
81 3'b111 : begin
82 pin_Dout <= chipReg[0];
83 chipReg <= { pin_Din, chipReg[3:1]};
84 // If reading, read now
85 if ((pin_nRD | nOE) == `ACTIVELOW) begin
86 dataReg <= pins_D;
87 end
88 end
89 endcase
90 end
91 end
92
93 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.