Changes for page Front I/O

Last modified by Kevin Wiki on 2024/07/07 22:48

From version 1.2
edited by Kevin Wiki
on 2024/07/04 13:12
Change comment: There is no comment for this version
To version 8.8
edited by Kevin Wiki
on 2024/07/07 22:44
Change comment: There is no comment for this version

Summary

Details

Page properties
Content
... ... @@ -2,34 +2,490 @@
2 2  (((
3 3  (% class="col-xs-12 col-sm-8" %)
4 4  (((
5 += Code =
6 +
7 +Arduino project with utils and script for driving all LEDs, buttons and MLB front I/O headers for driving Xserve front I/O devices: [[https:~~/~~/github.com/KevinMidboe/xserve-io>>https://github.com/KevinMidboe/xserve-io/]].
8 +
5 5  = Pinout =
6 6  
7 7  There is a single cable that controls four parts, each half side of I/O LED and center column of blue LEDs.
8 8  
9 -== Sub-paragraph ==
13 +[[image:xserve io main cable and PCB pinout.drawio.png||alt="xserve io main cable pinout.drawio.png"]]
10 10  
11 -Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
15 +(% class="wikigeneratedid" %)
16 +[[attach:xserve io main cable and PCB pinout.drawio.svg||target="_blank"]]
12 12  
13 -== Sub-paragraph ==
18 +(% class="wikigeneratedid" %)
19 +This cable allows us to communicate with 4 chips using two data lines, audio & service switch, case switch and (yet to be documented) compute LEDs
14 14  
15 -Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
21 += How we got here =
16 16  
17 -=== Sub-sub paragraph ===
23 +Measure out the ground and power signals by comparing with other chips on board. E.g. we find [SAA1064T] datasheet, locate the GND (Vee) and 5V (Vcc) and measure connectivity (0 ohm resistance) between chip pins and cable pins. This gives us pins GND 2 & 8 and PWR 16 & 22.
18 18  
19 -Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
25 +We keep doing this for SCL & SDA pins on SAA1064T chip and find pins 14 & 15 and 20 & 21 are I2C clock and data pins for each chip.
20 20  
27 +== Finding i2c chip address ==
21 21  
22 -= Paragraph 2 =
29 +=== SAA1064T ===
23 23  
24 -Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
31 +Reading the datasheet for SAA1064T chip we find that: "//This results in the corresponding valid addresses HEX 70, 72, 74 and 76 for writing and 71, 73, 75 and 77 for reading. All other addresses cannot be acknowledged by the circuit".// Giving us a clue what we are looking for, i2c addresses 0x70, 0x72 or 0x74.
25 25  
26 -== Sub-paragraph ==
33 +=== PCA9554 ===
27 27  
28 -Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
35 +asdf
29 29  
30 -== Sub-paragraph ==
37 +=== Code example finding i2c addresses ===
31 31  
32 -Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
39 +We can test the following addresses manually or use the following code snippet:
40 +
41 +{{code language="C++"}}
42 +/*I2C_scanner
43 + This sketch tests standard 7-bit addresses.
44 + Devices with higher bit address might not be seen properly.*/
45 +
46 +#include <Wire.h>
47 +
48 +void setup() {
49 + Wire.begin();
50 +
51 + Serial.begin(9600);
52 + while (!Serial);
53 + Serial.println("\nI2C Scanner");
54 +}
55 +
56 +void loop() {
57 + byte error, address;
58 + int nDevices;
59 +
60 + Serial.println("Scanning...");
61 +
62 + nDevices = 0;
63 + for (address = 1; address < 127; address++ ) {
64 + Wire.beginTransmission(address);
65 + error = Wire.endTransmission();
66 +
67 + if (error == 0) {
68 + Serial.print("I2C device found at address 0x");
69 + if (address < 16)
70 + Serial.print("0");
71 + Serial.print(address, HEX);
72 + Serial.println(" !");
73 +
74 + nDevices++;
75 + }
76 + else if (error == 4) {
77 + Serial.print("Unknown error at address 0x");
78 + if (address < 16)
79 + Serial.print("0");
80 + Serial.println(address, HEX);
81 + }
82 + }
83 + if (nDevices == 0)
84 + Serial.println("No I2C devices found\n");
85 + else
86 + Serial.println("done\n");
87 +
88 + delay(5000);
89 +}
90 +{{/code}}
91 +
92 +== i2c multiplexing with TCA9548 ==
93 +
94 +We have two sets of chips, one for left and one for right where we have two different i2c chips on each side for controlling lights. Since the chips controlling their respective parts have the same address for each side, we can't distinguish them from each other. To handle this we use a i2c multiplexer to selectively communicate with one half at a time, switching TCA9548 between two different output ports.
95 +
96 +=== Code example finding i2c ports ===
97 +
98 +To verify wiring, connection, output ports and device addresses run the following script:
99 +
100 +{{code language="c++"}}
101 +/**
102 + * TCA9548 I2CScanner.ino -- I2C bus scanner for Arduino
103 + *
104 + * Based on https://playground.arduino.cc/Main/I2cScanner/
105 + *
106 + */
107 +
108 +#include "Wire.h"
109 +
110 +#define TCAADDR 0x70
111 +
112 +void tcaselect(uint8_t i) {
113 + if (i > 7) return;
114 +
115 + Wire.beginTransmission(TCAADDR);
116 + Wire.write(1 << i);
117 + Wire.endTransmission();
118 +}
119 +
120 +
121 +// standard Arduino setup()
122 +void setup()
123 +{
124 + while (!Serial);
125 + delay(1000);
126 +
127 + Wire.begin();
128 +
129 + Serial.begin(9600);
130 + Serial.println("\nTCAScanner ready!");
131 +
132 + for (uint8_t t=0; t<8; t++) {
133 + tcaselect(t);
134 + Serial.print("TCA Port #"); Serial.println(t);
135 +
136 + for (uint8_t addr = 0; addr<=127; addr++) {
137 + if (addr == TCAADDR) continue;
138 +
139 + Wire.beginTransmission(addr);
140 + if (!Wire.endTransmission()) {
141 + Serial.print("Found I2C 0x"); Serial.println(addr,HEX);
142 + }
143 + }
144 + }
145 + Serial.println("\ndone");
146 +}
147 +
148 +void loop()
149 +{
150 +}
151 +{{/code}}
152 +
153 +== SAA1064T data for driving center IO LED stack ==
154 +
155 +Center IO stack is a stack of 24 LED's, 23 blue and 1 green for ethernet activity. These are duplicated next to each other and driven by each their SAA1064T chips. Earlier we found the i2c address and just by playing around figured out that 4 segments of 1 byte binary values are used to set ship register.
156 +
157 +{{code language="C++"}}
158 +void fillColumns() {
159 + Serial.println("filling columns");
160 + Wire.beginTransmission(saa1064);
161 + Wire.write(1);
162 + Wire.write(0x7F); // 127 - 1111111
163 + Wire.write(0x7F); // 127 - 1111111
164 + Wire.write(0x7F); // 127 - 1111111
165 + Wire.write(0x1F); // 31 - 11111
166 + Wire.endTransmission();
167 +
168 + colsFilled = 1;
169 +}
170 +{{/code}}
171 +
172 +(% class="wikigeneratedid" %)
173 +~-~- Here the last byte we send only is 5 bits since we only have 5 LEDs instead of 6 to address (total of 24). Also note that we start the transmission with a single bit. ~-~-
174 +
175 +== Pinouts voltages from MLB ==
176 +
177 +Powered off:
178 +
179 +* PWR fail LED - 0.00 V
180 +* UID LED - 4.5V
181 +* OH/Fan fail LED - 4.72 V
182 +* NIC1 LED - 0.8 - 2.6 V
183 +* NIC2 LED - 2.95 V
184 +* UID SW - 2.8V
185 +* HDD LED - 0.00 V
186 +* Power LED P3V3 - 0.00V
187 +* Power LED - 0.00 V after unplug grows
188 +
189 +Powered on:
190 +
191 +* PWR tail LED - 3.47 V
192 +* UID LED - 4.85V
193 +* OH/Fan failed LED - 5 V
194 +* NIC 1 LED - 1.2 - 2.9 V
195 +* NIC 2 LED - 3.2 V
196 +* UID SW - 3V
197 +* HDD LED - 3 V
198 +* Power LED P3V3 - 3.30V
199 +* Power LED - 0.87 V
200 +
201 += Controlling top I/O LED =
202 +
203 +On the top row we have the following input/output devices in order from left to right;
204 +
205 +Left side:
206 +
207 +* physical lock
208 +* lock LED
209 +* warning/service button
210 +* warning/service LED
211 +* locate button
212 +* power LED (red & green)
213 +* fan LED (red & green)
214 +* temperature LED (red & green)
215 +* compute LED (unknown)
216 +
217 +Right side:
218 +
219 +* power LED (red & green)
220 +* fan LED (red & green)
221 +* temperature LED (red & green)
222 +* compute LED (unknown)
223 +* lock switch
224 +
225 +Each sides bank of LEDs are driven by each their PCA9554 shift register. The registers represent the following LEDs: (Note that Lock LED is only present for the LEFT side)
226 +
227 +(% border="1" %)
228 +|=(% scope="row" %)Register|1|2|3|4|5|6|7
229 +|=Device|Power LED Green|Power LED Red|Fan LED Green|Fan LED Red|Temperature LED Green|Temperature LED Red|Lock LED
230 +
231 +To control each LED we shift either a 0 to turn off or 1 to turn on. Since each device shares a single red/green LED (power LED green & power LED red) setting both to 1 at the same time will always leave it red. That is when power LED green and power LED red are both enabled, red always takes precedence.
232 +
233 +Use following script to power LEDs one at a time:
234 +
235 +{{code language="c++"}}
236 +#include <PCA9554.h> // Load the PCA9554 Library
237 +
238 +PCA9554 ioCon1(0x24); // Create an object at this address
239 +
240 +uint8_t mapIO = 0b10000000;
241 +
242 +void shiftL() {
243 + mapIO = (mapIO << 1) | ((mapIO & 0x80) >> 7);
244 +}
245 +
246 +void write() {
247 + Serial.println("writing to PCA9554 device");
248 +
249 + for (int i = 0; i < 8; ++i) {
250 + ioCon1.digitalWrite(i, (mapIO & (1 << i)) ? 0 : 1);
251 + }
252 +}
253 +
254 +void setup()
255 +{
256 + Serial.begin(9600);
257 + Serial.println("Setup");
258 +
259 + ioCon1.portMode(ALLOUTPUT);
260 +}
261 +
262 +void loop()
263 +{
264 + write();
265 + shiftL();
266 +
267 + delay(500);
268 +}
269 +{{/code}}
270 +
271 +
272 +Controlling middle IO strip
273 +
274 +0 = 0000
275 +1 (green) = 0001
276 +2 = 0010
277 +1 + 2 = 0011
278 +3 = 0100
279 +
280 +
281 +There are 4 words, each containing 7 data bits. They do not
282 +
283 +
284 += Controlling center LED columns =
285 +
286 +There are a total of 4 banks of addressable LED's 12 each of the total 48.
287 +
288 +
289 +|**Address Range (Binary)**|**Address Range (hex)**|**Size**|**Description**
290 +|0-7|00-07|1 byte|Ethernet indicator and LEDs bank-1
291 +|8-15|08-0F|1 byte|LEDs bank-2
292 +|16-23|10-17|1 byte|LEDs bank-3
293 +|24-31|18-1F|1 byte|LEDs bank-4
294 +
295 +[[attach:Address Ranges-Table 1.csv||target="_blank"]]
296 +
297 +|=**Address Banks**|=**LEDs Controlled**|=**Count**|=**Address Range (hex)**|=**Description**
298 +|=**Bank-1**|1 2 4 6 8 10 12|7|00-07|LED 1 ethernet indicator, even bottom half
299 +|=**Bank-2**|3 5 7 9 11 13|6|08-0F|Odd LED top half
300 +|=**Bank-3**|14 16 18 20 22 23 24|7|10-17|Even LED bottom half
301 +|=**Bank-4**|15 17 19 21|4|18-1F|Odd LED top half
302 +
303 +[[attach:LEDs per bank-Table 1.csv||target="_blank"]]
304 +
305 +
306 +| | |(% colspan="8" %)**bits (1 byte per register)**
307 +|**Controls device**|**Register**|**7**|**6**|**5**|**4**|**3**|**2**|**1**|**0**
308 +|**Ethernet LED**|Register 1|0|0|0|0|0|0|0|1
309 +|**LED 1**|Register 1|0|0|0|0|0|0|1|0
310 +|**LED 2**|Register 2|0|0|0|0|0|0|1|0
311 +|**LED 3**|Register 1|0|0|0|0|0|1|0|0
312 +|**LED 4**|Register 2|0|0|0|0|0|1|0|0
313 +|**LED 5**|Register 1|0|0|0|0|1|0|0|0
314 +|**LED 6**|Register 2|0|0|0|0|1|0|0|0
315 +|**LED 7**|Register 1|0|0|0|1|0|0|0|0
316 +|**LED 8**|Register 2|0|0|0|1|0|0|0|0
317 +|**LED 9**|Register 1|0|0|1|0|0|0|0|0
318 +|**LED 10**|Register 2|0|0|1|0|0|0|0|0
319 +|**LED 11**|Register 1|0|1|0|0|0|0|0|0
320 +|**LED 12**|Register 2|0|1|0|0|0|0|0|0
321 +|**LED 13**|Register 3|0|0|0|0|0|0|0|1
322 +|**LED 14**|Register 4|0|0|0|0|0|0|0|1
323 +|**LED 15**|Register 3|0|0|0|0|0|0|1|0
324 +|**LED 16**|Register 4|0|0|0|0|0|0|1|0
325 +|**LED 17**|Register 3|0|0|0|0|0|1|0|0
326 +|**LED 18**|Register 4|0|0|0|0|0|1|0|0
327 +|**LED 19**|Register 3|0|0|0|0|1|0|0|0
328 +|**LED 20**|Register 4|0|0|0|0|1|0|0|0
329 +|**LED 21**|Register 3|0|0|0|1|0|0|0|0
330 +|**LED 22**|Register 3|0|0|1|0|0|0|0|0
331 +|**LED 23**|Register 3|0|1|0|0|0|0|0|0
332 +
333 +
334 +
335 +Script for writing all permutations to display:
336 +
337 +{{code language="c++"}}
338 +#include "Wire.h" // enable I2C bus
339 +
340 +byte saa1064 = 0x3B; // define the I2C bus address for our SAA1064 (pin 1 to GND) ****
341 +
342 +void setup()
343 +{
344 + Wire.begin(); // start up I2C bus
345 +}
346 +
347 +void write(int value) {
348 + Wire.beginTransmission(saa1064);
349 + Wire.write(1);
350 +
351 + Wire.write(value);
352 + Wire.write(value);
353 + Wire.write(value);
354 + Wire.write(value);
355 +
356 + Wire.endTransmission();
357 +}
358 +
359 +void loop() {
360 + for (int value = 0; value < 127; value++) {
361 + write(value);
362 + delay(300);
363 + }
364 +}
365 +{{/code}}
366 +
367 +Since LED positions don't map sequentially with LED number we can't address them in 10-base form, but we can define each LED in binary and use OR operator to display LEDs we want.
368 +
369 +{{code language="c++"}}
370 +#include "Wire.h" // enable I2C bus
371 +
372 +#define TCAADDR 0x70
373 +byte saa1064 = 0x3B; // define the I2C bus address for our SAA1064
374 +
375 +byte bank1;
376 +byte bank2;
377 +byte bank3;
378 +byte bank4;
379 +
380 +byte activityLED = 0b00000001;
381 +byte leds[23][4] = {
382 + {0b00000010, 0b00000000, 0b00000000, 0b00000000}, // 1
383 + {0b00000000, 0b00000010, 0b00000000, 0b00000000}, // 2
384 + {0b00000100, 0b00000000, 0b00000000, 0b00000000}, // 3
385 + {0b00000000, 0b00000100, 0b00000000, 0b00000000}, // 4
386 + {0b00001000, 0b00000000, 0b00000000, 0b00000000}, // 5
387 + {0b00000000, 0b00001000, 0b00000000, 0b00000000}, // 6
388 + {0b00010000, 0b00000000, 0b00000000, 0b00000000}, // 7
389 + {0b00000000, 0b00010000, 0b00000000, 0b00000000}, // 8
390 + {0b00100000, 0b00000000, 0b00000000, 0b00000000}, // 9
391 + {0b00000000, 0b00100000, 0b00000000, 0b00000000}, // 10
392 + {0b01000000, 0b00000000, 0b00000000, 0b00000000}, // 11
393 + {0b00000000, 0b01000000, 0b00000000, 0b00000000}, // 12
394 + {0b00000000, 0b00000000, 0b00000001, 0b00000000}, // 13
395 + {0b00000000, 0b00000000, 0b00000000, 0b00000001}, // 14
396 + {0b00000000, 0b00000000, 0b00000010, 0b00000000}, // 15
397 + {0b00000000, 0b00000000, 0b00000000, 0b00000010}, // 16
398 + {0b00000000, 0b00000000, 0b00000100, 0b00000000}, // 17
399 + {0b00000000, 0b00000000, 0b00000000, 0b00000100}, // 18
400 + {0b00000000, 0b00000000, 0b00001000, 0b00000000}, // 19
401 + {0b00000000, 0b00000000, 0b00000000, 0b00001000}, // 20
402 + {0b00000000, 0b00000000, 0b00010000, 0b00000000}, // 21
403 + {0b00000000, 0b00000000, 0b00100000, 0b00000000}, // 22
404 + {0b00000000, 0b00000000, 0b01000000, 0b00000000} // 23
405 +};
406 +
407 +void setup()
408 +{
409 + Serial.begin(9600);
410 + Wire.begin(); // start up I2C bus
411 +
412 + Serial.println("setting up ports");
413 +}
414 +
415 +void tcaselect(uint8_t i) {
416 + if (i > 7) return;
417 +
418 + Wire.beginTransmission(TCAADDR);
419 + Wire.write(1 << i);
420 + Wire.endTransmission();
421 +}
422 +
423 +void selectLeft() { tcaselect(2); }
424 +void selectRight() { tcaselect(1); }
425 +
426 +void write() {
427 + Wire.beginTransmission(saa1064);
428 + Wire.write(1);
429 +
430 + Wire.write(bank1);
431 + Wire.write(bank2);
432 + Wire.write(bank3);
433 + Wire.write(bank4);
434 +
435 + Wire.endTransmission();
436 +}
437 +
438 +void resetBanks() {
439 + bank1 = 0;
440 + bank2 = 0;
441 + bank3 = 0;
442 + bank4 = 0;
443 +}
444 +
445 +void displayNumber(int number) {
446 + bank1 = leds[number - 1][0];
447 + bank2 = leds[number - 1][1];
448 + bank3 = leds[number - 1][2];
449 + bank4 = leds[number - 1][3];
450 +}
451 +
452 +void displayUpToNumber(int number) {
453 + for (int i = 0; i < number; i++) {
454 + bank1 = bank1 | leds[i][0];
455 + bank2 = bank2 | leds[i][1];
456 + bank3 = bank3 | leds[i][2];
457 + bank4 = bank4 | leds[i][3];
458 + }
459 +}
460 +
461 +void computeEthernetActivity() {
462 + bank1 = bank1 | activityLED;
463 +}
464 +
465 +void loop() {
466 + resetBanks();
467 + delay(10);
468 +
469 + displayUpToNumber(15);
470 + computeEthernetActivity();
471 +
472 + selectLeft();
473 + write();
474 + delay(2);
475 +
476 + selectRight();
477 + write();
478 + delay(1000);
479 +}
480 +{{/code}}
481 +
482 +
483 += Missing pieces, TODO =
484 +
485 +* how to control compute LED in top IO row
486 +* control warning button LED
487 +
488 +
33 33  )))
34 34  
35 35  
... ... @@ -44,5 +44,12 @@
44 44  
45 45  [[image:[email protected]]]
46 46  //Figure 2: [[Waves>>https://commons.wikimedia.org/wiki/File:Culebra_-_Playa_de_Flamenco.jpg]]//
503 +
504 +
505 +
506 +
507 +
508 +
509 +
47 47  )))
48 48  )))
Address Ranges-Table 1.csv
Author
... ... @@ -1,0 +1,1 @@
1 +XWiki.kevin
Size
... ... @@ -1,0 +1,1 @@
1 +209 bytes
Content
... ... @@ -1,0 +1,6 @@
1 +Address Range (Binary);Address Range (hex);Size;Description
2 +0-7;00-07;1 byte;Ethernet indicator and LEDs bank-1
3 +8-15;08-0F;1 byte;LEDs bank-2
4 +16-23;10-17;1 byte;LEDs bank-3
5 +24-31;18-1F;1 byte;LEDs bank-4
6 +
LEDs per bank-Table 1.csv
Author
... ... @@ -1,0 +1,1 @@
1 +XWiki.kevin
Size
... ... @@ -1,0 +1,1 @@
1 +294 bytes
Content
... ... @@ -1,0 +1,6 @@
1 +Address Banks;LEDs Controlled;Count;Address Range (hex);Description
2 +Bank-1;1 2 4 6 8 10 12;7;00-07;LED 1 ethernet indicator, even bottom half
3 +Bank-2;3 5 7 9 11 13;6;08-0F;Odd LED top half
4 +Bank-3;14 16 18 20 22 23 24;7;10-17;Even LED bottom half
5 +Bank-4;15 17 19 21;4;18-1F;Odd LED top half
6 +
xserve io main cable and PCB pinout.drawio.png
Author
... ... @@ -1,0 +1,1 @@
1 +XWiki.kevin
Size
... ... @@ -1,0 +1,1 @@
1 +88.9 KB
Content
xserve io main cable and PCB pinout.drawio.svg
Author
... ... @@ -1,0 +1,1 @@
1 +XWiki.kevin
Size
... ... @@ -1,0 +1,1 @@
1 +83.3 KB
Content