99134acadd76ad6c9e848c9e975c6f9f1a6c5694
[linux-gpio-pinout] / gpio.pl
1 #!/usr/bin/perl
2 use warnings;
3 use strict;
4 use autodie;
5 use Data::Dump qw(dump);
6 use Getopt::Long;
7
8 my $opt_svg = 0;
9 my $opt_alt = 0;
10 my $opt_invert = 0;
11 my $opt_vertical = 0;
12 my $opt_horizontal = 0;
13 my $opt_edge = 0;
14 my $opt_middle = 0;
15 my $opt_zebra = 0;
16 my $opt_lines = 0;
17 my $opt_read = '';
18 my $opt_pins = '';
19 my $opt_color = 0;
20 GetOptions(
21         'svg!' => \$opt_svg,
22         'alt!' => \$opt_alt,
23         'invert!' => \$opt_invert,
24         'vertical-flip!' => \$opt_vertical,
25         'horizontal-flip!' => \$opt_horizontal,
26         'edge-pins!' => \$opt_edge,
27         'middle-pins!' => \$opt_middle,
28         'zebra!' => \$opt_zebra,
29         'lines!' => \$opt_lines,
30         'read=s' => \$opt_read,
31         'pins=s' => \$opt_pins,
32         'color' => \$opt_color,
33 );
34
35 # svg font hints
36 my $font_w = 1.67; # < 2.54, font is not perfect square
37 my $font_b = 2.10; # font baseline position
38
39 $opt_read .= '/' unless $opt_read =~ m/\/$/;
40
41 sub slurp {
42         open(my $fh, '<', $opt_read . shift);
43         local $/ = undef;
44         <$fh>;
45 }
46
47 my $pins;
48
49 my $model = slurp('/proc/device-tree/model');
50 $model =~ s/\x00$//; # strip kernel NULL
51 warn "# model [$model]";
52
53 open(DATA, '<', $opt_pins) if $opt_pins;
54
55 my @lines;
56 my $line_i = 0;
57
58 my $include = 0;
59 while(<DATA>) {
60         chomp;
61         if ( m/^#\s(.+)/ ) {
62                 warn "MODEL [$1] == [$model] ?\n";
63                 if ( $model =~ m/$1/ ) {
64                         $include = 1;
65                 } else {
66                         $include = 0;
67                 }
68         } elsif ( $include || $opt_pins ) {
69                 push @{ $pins->{$1} }, $line_i while ( m/\t(\w+\d+)/g );
70
71                 push @lines, $_;
72
73                 $line_i++;
74         } else {
75                 warn "IGNORE: [$_]\n";
76         }
77 }
78
79 die "add pin definition for # $model" unless $pins;
80
81 #warn "# lines ",dump( \@lines );
82 warn "# pins ",dump($pins);
83
84 my $serial_tty;
85 foreach (
86         glob($opt_read . '/sys/devices/platform/soc*/*.serial/tty/tty*'),       # 4.x
87         glob(            '/sys/devices/soc.*/*.uart/tty/tty*')                  # 3.10
88 ) {
89         my @v = split(/\//, $_);
90         $serial_tty->{ $v[-3] } = $v[-1];
91 }
92 warn "# serial_tty = ",dump($serial_tty);
93
94
95 my $pin_function;
96 my $device;
97 my $pin;
98 my $function;
99
100 open(my $fh, '<', $opt_read . '/sys/kernel/debug/pinctrl/pinctrl-maps');
101 while(<$fh>) {
102         chomp;
103         if ( m/^device (\S+)/ ) {
104                 $device = $1;
105                 if ( my $replace = $serial_tty->{$device} ) {
106                         $device = $replace; # replace serial hex with kernel name
107                 } else {
108                         $device =~ s/^[0-9a-f]*\.//; # remove hex address
109                 }
110         } elsif ( m/^group (\w+\d+)/ ) {
111                 $pin = $1;
112
113         } elsif ( m/^function (\S+)/ ) {
114                 $function = $1;
115         } elsif ( m/^$/ ) {
116                 if ( $device && $pin && $function ) {
117                         push @{ $pin_function->{$pin} }, "$device $function";
118
119                         if ( $pins->{$pin} ) {
120                                 foreach my $line ( @{$pins->{$pin}} ) {
121                                         my $t = $lines[$line];
122                                         if ( $opt_svg ) {
123                                                 $t =~ s/$pin/[$device $function]/;
124                                         } else {
125                                                 $t =~ s/$pin/$pin [$device $function]/ || warn "can't find $pin in [$t]";
126                                         }
127                                         $lines[$line] = $t;
128                                         warn "# $line: $lines[$line]\n";
129                                 }
130                         } else {
131                                 warn "IGNORED: pin $pin function $function\n";
132                         }
133
134                 } else {
135                         warn "missing one of ",dump( $device, $pin, $function );
136                 }
137
138                 $device = undef;
139                 $pin = undef;
140                 $function = undef;
141
142         }
143 }
144
145 warn "# pin_function = ",dump($pin_function);
146
147 my @max_len = ( 0,0,0,0 );
148 my @line_parts;
149
150 shift(@lines) while ( ! $lines[0] );    # remove empty at beginning
151 pop(@lines) while ( ! $lines[-1] );     # remove empty at end
152
153 foreach my $line (@lines) {
154         if ( $line =~ m/^#/ ) {
155                 push @line_parts, [ $line ] unless $opt_svg && $line =~ m/^###+/; # SVG doesn't display 3rd level comments
156                 next;
157         }
158         $line =~ s/\[(\w+)\s+(\w+)\] \[\1\s+(\w+)\]/[$1 $2 $3]/g; # compress kernel annotation with same prefix
159         $line =~ s/(\[(?:uart\d*|serial|tty\w+))([^\t]*\]\s[^\t]*(rx|tx)d?)/$1 $3$2/gi;
160         $line =~ s/(\[i2c)([^\t]*\]\s[^\t]*(scl?k?|sda))/$1 $3$2/gi;
161         $line =~ s/(\[spi)([^\t]*\]\s[^\t]*(miso|mosi|s?clk|c[se]\d*))/$1 $3$2/gi;
162         $line =~ s/\s*\([^\)]+\)//g if ! $opt_alt;
163
164         # shorten duplicate kernel device/function
165         $line =~ s/\[serial (\w+) (uart\d+)\]/[$2 $1]/g;
166         $line =~ s/\[(\w+) (\w+) \1(\d+)\]/[$1$3 $2]/g;
167
168         $line =~ s/\[(\w+)\s+([^\]]+)\s+\1\]/[$1 $2]/g; # duplicate
169
170         my @v = split(/\s*\t+\s*/,$line,4);
171         @v = ( $v[2], $v[3], $v[0], $v[1] ) if $opt_horizontal && $v[2];
172
173         push @line_parts, [ @v ];
174         foreach my $i ( 0 .. 3 ) {
175                 next unless exists $v[$i];
176                 next if $v[$i] =~ m/^#/; # don't calculate comments into max length
177                 my $l = length($v[$i]);
178                 $max_len[$i] = $l if $l > $max_len[$i];
179         }
180 }
181
182 warn "# max_len = ",dump( \@max_len );
183 warn "# line_parts = ",dump( \@line_parts );
184
185 #print "$_\n" foreach @lines;
186
187 my $x = 20.00; # mm
188 my $y = 20.00; # mm
189
190 if ( $opt_svg ) {
191         print qq{<?xml version="1.0" encoding="UTF-8" standalone="no"?>
192 <svg
193    xmlns:dc="http://purl.org/dc/elements/1.1/"
194    xmlns:cc="http://creativecommons.org/ns#"
195    xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
196    xmlns:svg="http://www.w3.org/2000/svg"
197    xmlns="http://www.w3.org/2000/svg"
198    xmlns:xlink="http://www.w3.org/1999/xlink"
199    id="svg8"
200    version="1.1"
201    viewBox="0 0 210 297"
202    height="297mm"
203    width="210mm">
204
205
206 <g id="layer1">
207
208         }; # svg, insert rest of rect
209
210         print qq{<rect x="0" y="0" width="210" height="297" style="fill:#000000" id="high-contrast"/>} if $opt_invert;
211 }
212
213 my @later;
214
215 my $cols = {    # foreground background
216         txt  => [ '#000000', '#ffffff' ],
217         pins => [ '#ffffff', '#ff00ff' ],
218         vcc  => [ '#ff0000', '#ffff00' ],
219         gnd  => [ '#000000', '#00ffff' ],
220         i2c  => [ '#008800', '#ffcccc' ],
221         serial=>[ '#000088', '#ccffcc' ],
222         spi  => [ '#880000', '#ccccff' ],
223 };
224
225 sub swap_cols {
226         my $swap = shift;
227         die "$swap not found in ",dump($cols) unless $cols->{$swap};
228         my ( $c1, $c2 ) = @{ $cols->{$swap} };
229         $cols->{$swap} = [ $c2, $c1 ];
230 }
231
232 swap_cols 'txt' if $opt_invert;
233         
234
235 sub svg_style {
236         my ($name,$x,$y,$col) = @_;
237
238         return '' unless $opt_color;
239
240         $y -= $font_b; # shift box overlay to right vertical position based on font baseline
241
242         sub rect {
243                 my ($x,$y,$col,$fill) = @_;
244                 print qq{<rect x="$x" y="$y" height="2.54" width="}, $max_len[$col] * $font_w, qq{" style="fill:$fill;stroke:#ffffff;stroke-width:0.10" />\n};
245
246         }
247
248         if ( $name =~ m/^(\d+)$/ ) { # pins
249                 my $pin = $1;
250                 my ( $fg, $bg ) = @{ $cols->{pins} };
251                 if ( $pin == 1 ) {
252                         my $w  = $max_len[$col]*$font_w - 0.1;
253                         my $cx = $x + $w;
254                         my $cy = $y + 2.54;
255                         #print qq{<polygon points="$x,$y $cx,$y $x,$cy $x,$y" stroke="$fg" stroke-width="0.25" fill="$bg" />};
256                         #print qq{<polygon points="$x,$cy $cx,$cy $cx,$y $x,$cy" stroke="$bg" stroke-width="0.25" fill="$fg" />};
257                         print qq{<rect x="$x" y="$y" width="$w" height="2.54" stroke="$fg" stroke-width="0.3" fill="$bg" />};
258                         my ( $fg, $bg ) = @{ $cols->{txt} };
259                         print qq{<rect x="$x" y="$y" width="$w" height="2.54" rx="1" ry="1" stroke="$fg" stroke-width="0.3" fill="$bg" />};
260                 } else {
261                         rect $x,$y,$col,$fg;
262                 }
263                 return qq{ style="fill:$bg"};
264         }
265
266         if ( $name =~ m/(VCC|3V3|3.3V|5v)/i ) {
267                 my ($fg,$bg) = @{ $cols->{vcc} };
268                 rect $x,$y,$col,$bg;
269                 return qq{ style="fill:$fg"};
270         } elsif ( $name =~ m/(G(ND|Round)|VSS|0v)/i ) {
271                 my ($fg,$bg) = @{ $cols->{gnd} };
272                 rect $x,$y,$col,$bg;
273                 return qq{ style="fill:$fg"};
274         } elsif ( $name =~ m/\[(\w+)/ ) { # kernel
275                 my $dev = $1;
276                 my ($fg,$bg) = @{ $cols->{txt} };
277                 $dev = 'serial' if $dev =~ m/^tty/;
278                 ($fg,$bg) = @{ $cols->{$dev} } if exists $cols->{$dev};
279                 rect $x,$y,$col,$bg;
280                 return qq{ style="fill:$fg"};
281         } else {
282                 my ( $fg, $bg ) = @{ $cols->{txt} };
283                 rect $x,$y,$col,$bg;
284                 #return qq{ style="fill:$fg"};
285                 return '';
286         }
287 }
288
289 my $alt_col = 0;
290
291 my @cols_order = ( 0,1,2,3 );
292 my @cols_align = ( '','-','','-' ); # sprintf prefix
293
294 my @cols_shuffle = @cols_order;
295
296 if ( $opt_edge ) {
297         # pins outside on the right
298         @cols_shuffle = ( 0,1,3,2 ) if $opt_edge;
299         @cols_align = ( '-','-','','' );
300 } elsif ( $opt_middle ) {
301         # pins in middle
302         @cols_shuffle = ( 1,0,2,3 );
303         @cols_align = ( '','','-','-' );
304 }
305
306 sub cols_shuffle {
307         my ( $what, $order ) = @_;
308         my $new = [];
309         foreach my $i ( 0 .. $#$what ) {
310                 $new->[$i] = $what->[ $order->[$i] ];
311         }
312         warn "# cols_shuffle what=",dump($what)," order=",dump($order)," new=",dump($new);
313         return @$new;
314 }
315
316 @cols_order = cols_shuffle( \@cols_order, \@cols_shuffle );
317 @max_len    = cols_shuffle( \@max_len,    \@cols_shuffle );
318
319 warn "# cols_order = ",dump( \@cols_order );
320 warn "# cols_align = ",dump( \@cols_align );
321
322 my $fmt = "%$cols_align[0]$max_len[0]s %$cols_align[1]$max_len[1]s %$cols_align[2]$max_len[2]s %$cols_align[3]$max_len[3]s\n";
323
324
325 # cut marks
326 my ($fg,$bg) = @{ $cols->{txt} };
327 my $line_fmt = qq{<line x1="%s" y1="%s" x2="%s" y2="%s" style="stroke:$fg;stroke-width:0.10;fill:$bg" />\n};
328
329 my @cut_marks;
330 sub cut_mark {
331         my ($x,$y) = @_;
332         return unless $opt_svg;
333         push @cut_marks, sprintf($line_fmt, $x-5, $y-$font_b,   $x+5, $y-$font_b);
334         push @cut_marks, sprintf($line_fmt, $x,   $y-$font_b-5, $x,   $y-$font_b+5);
335 }
336 #cut_mark $x, $y;
337 my $max_x = $x;
338 $max_x += $max_len[$_] * $font_w foreach ( 0 .. 3 );
339 #cut_mark $max_x, $y;
340
341 sub line {
342         my ($x,$y,$max_x) = @_;
343         push @cut_marks, sprintf($line_fmt, $x, $y-$font_b, $max_x, $y-$font_b);
344 }
345
346
347 my $last_cut_mark = 0;
348
349 foreach my $i ( 0 .. $#line_parts ) {
350         $i = $#line_parts - $i if $opt_vertical;
351         my $line = $line_parts[$i];
352
353         if ( $opt_svg ) {
354
355                 # not a minimal two column pin description
356                 if ( ! exists $line->[1] ) {
357                         $last_cut_mark = 1 if $line->[0] =~ m/^##/; # skip comments
358
359                         # before first empty line
360                         if ( $last_cut_mark == 0 ) {
361                                 cut_mark $x, $y;
362                                 cut_mark $max_x, $y;
363                                 $last_cut_mark = 1;
364                                 line $x, $y, $max_x if $opt_lines;
365                                 $y += 15; # make spacing between pinouts
366                         }
367                 } elsif ( $last_cut_mark ) {
368                         # first full line
369                         cut_mark $x, $y;
370                         cut_mark $max_x, $y;
371                         $last_cut_mark = 0;
372                 } else {
373                         #warn "CUTMARK no magic";
374                 }
375
376                 line $x, $y, $max_x if $opt_lines && exists $line->[1];
377
378                 my ($fg,$bg) = @{ $cols->{txt} };
379                 my $tspan = qq{<tspan x="$x" y="$y" style="line-height:2.54;fill:$fg;stroke:none;">\n};
380
381                 my $x_pos = $x;
382                 foreach my $i ( 0 .. $#cols_order ) {
383                         my $order = $cols_order[$i];
384                         next unless $line->[$order];
385
386                         my $text_anchor = 'middle';
387                         my $len = $max_len[$i];
388                         my $x2 = $x_pos + ( $len * $font_w ) / 2;
389                         # is this comment?
390                         if ( $#$line == 0 && $line->[$order] =~ s/^#+s*// ) {
391                                 # comment, center over whole width
392                                 $len = length($line->[$order]);
393                                 $x2 = $x + (($max_x-$x)/2); # middle
394                                 $tspan .= qq{\t<tspan x="$x2" text-anchor="$text_anchor"}.sprintf( '>%' . $cols_align[$i] . $len . 's</tspan>', $line->[0]);
395                         } else {
396                                 $tspan .= qq{\t<tspan x="$x2" text-anchor="$text_anchor"}.svg_style($line->[$order],$x_pos,$y,$i).sprintf( '>%' . $cols_align[$i] . $len . 's</tspan>', $line->[$order]);
397                         }
398                         $x_pos += $len * $font_w;
399                 }
400
401                 $tspan .= qq{\n</tspan>\n};
402                 push @later,sprintf $tspan, @$line;
403                 $y += 2.54;
404
405                 # swap pin colors for line stripe
406                 if ( $opt_zebra ) {
407                         swap_cols $_ foreach qw( pins txt );
408                 } else {
409                         swap_cols 'pins';
410                 }
411
412         } else {
413
414                 if ( $#$line == 0 ) {
415                         print $line->[0], "\n";
416                 } else {
417                         push @$line, '' while ($#$line < 3); # fill-in single row header
418                         printf $fmt, map { $line->[$_] } @cols_order;
419                 }
420
421         }
422 }
423
424 if ( $opt_svg ) {
425         cut_mark $x,$y;
426         cut_mark $max_x,$y;
427         line $x, $y, $max_x if $opt_lines;
428
429         print qq{
430     <text
431        id="text4506"
432        y="$x"
433        x="$y"
434        style="font-size:2.34px;line-height:2.54px;font-family:'Andale Mono';stroke:none"
435        xml:space="preserve">
436
437         }; #svg
438
439         print @later, qq{</text>\n}, @cut_marks, qq{</g>\n</svg>};
440
441 }
442
443 __DATA__
444 # Cubietech Cubieboard
445 ## U14 (Next to SATA connector)
446 ###     SPI0
447 48      PI13 (SPI0-MISO/UART6-RX/EINT25)        47      PI11 (SPI0-CLK/UART5-RX/EINT23)
448 46      PI12 (SPI0-MOSI/UART6-TX/EINT24)        45      PI10 (SPI0-CS/UART5-TX/EINT22)
449 ###     LCD
450 44      3.3V (nc in 2012-08-08)                 43      VCC-5V
451 42      Ground                                  41      SPDIF
452 40      PB10 (LCD0-SCK/LCD-PIO1)                39      PB11 (LCD0-SDA/LCD-PIO2)
453 38      Ground                                  37      PH7 (LCD0-BL-EN/LCD-PIO0/UART5-RX/EINT7)
454 36      XN_TP (TP-X2)                           35      YN_TP (TP-Y2)
455 34      XP_TP (TP-X1)                           33      YP_TP (TP-Y1)
456 32      PD25 (LCDDE)                            31      PB2 (PWM0)
457 30      PD26 (LCDHSYNC/VGA-HSYNC)               29      PD24 (LCDCLK)
458 28      PD23 (LCDD23)                           27      PD27 (LCDVSYNC/VGA-VSYNC)
459 26      PD21 (LCDD21)                           25      PD22 (LCDD22)
460 24      PD19 (LCDD19/LVDS1N3)                   23      PD20 (LCDD20)
461 22      PD17 (LCDD17/LVDS1NC)                   21      PD18 (LCDD18/LVDS1P3)
462 20      Ground                                  19      PD16 (LCDD16/LVDS1PC)
463 18      PD14 (LCDD14/LVDS1P2)                   17      PD15 (LCDD15/LVDS1N2)
464 16      PD12 (LCDD12/LVDS1P1)                   15      PD13 (LCDD13/LVDS1N1)
465 14      PD10 (LCDD10/LVDS1P0)                   13      PD11 (LCDD11/LVDS1N0)
466 12      PD8 (LCDD8/LVDS0P3)                     11      PD9 (LCDD9/LVDS0N3)
467 10      PD7 (LCDD7/LVDS0NC)                     9       Ground
468 8       PD5 (LCDD5/LVDS0N2)                     7       PD6 (LCDD6/LVDS0PC)
469 6       PD3 (LCDD3/LVDS0N1)                     5       PD4 (LCDD4/LNVS0P2)
470 4       PD1 (LCDD1/LVDS0N0)                     3       PD2 (LCDD2/LVDS0P1)
471 2       Ground                                  1       PD0 (LCDD0/LVDSP0)
472
473 ## U15 (Between Ethernet port and USB ports)
474 ### CSI1/TS
475 1       VCC-5V                                  2       PH15 (CSI1-PWR/EINT15)
476 3       CSI1-IO-2V8                             4       PH14 (CSI1-RST#/EINT14)
477 5       PG0 (CSI1-PCLK/SDC1-CMD)                6       PB18 (TWI1-SCK)
478 7       PB19 (TWI1-SDA)                         8       PG3 (CSI1-VSYNC/SDC1-D1)
479 9       PG2 (CSI1-HSYNC/SDC1-D0)                10      PG1 (CSI1-MCLK/SDC1-CLK)
480 11      PG4 (CSI1-D0/SDC1-D2)                   12      PG5 (CSI1-D1/SDC1-D3)
481 13      PG6 (CSI1-D2/UART3-TX)                  14      PG7 (CSI1-D3/UART3-RX)
482 15      PG8 (CSI1-D4/UART3-RTS)                 16      PG9 (CSI1-D5/UART3-CTS)
483 17      PG10 (CSI1-D6/UART4-TX)                 18      PG11 (CSI1-D7/UART4-RX)
484 19      Ground                                  20      Ground
485 ###     Analog SDIO3
486 21      FMINL                                   22      PI4 (SDC3-CMD)
487 23      FMINR                                   24      PI5 (SDC3-CLK)
488 25      Ground                                  26      PI6 (SDC3-D0)
489 27      VGA-R                                   28      PI7 (SDC3-D1)
490 29      VGA-G                                   30      PI8 (SDC3-D2)
491 31      VGA-B                                   32      PI9 (SDC3-D3)
492 ###     CSI0/TS
493 33      LCD1-VSYNC                              34      PE4 (CSI0-D0)
494 35      LCD1-HSYNC                              36      PE5 (CSI0-D1)
495 37      Ground                                  38      PE6 (CSI0-D2)
496 39      AVCC                                    40      PE7 (CSI0-D3)
497 41      LRADC0                                  42      PE8 (CSI0-D4)
498 43      CVBS                                    44      PE9 (CSI0-D5)
499 45      HPL                                     46      PE10 (CSI0-D6)
500 47      HPR                                     48      PE11 (CSI0-D7)
501
502 ## DEBUG serial (middle of board)
503 4       PB22 (UART0-TX)
504 3       PB23 (UART0-RX)
505 2       VCC-3V3
506 1       GND
507
508
509 # Lamobo R1
510 ## CON3 rpi DIP26-254
511 1       3.3v                    2       5v     
512 3       PB20 SDA.1              4       5V     
513 5       PB21 SCL.1              6       0v     
514 7       PI3 PWM1                8       PH0 UART3_TX
515 9       0v                      10      PH1 UART3_RX
516 11      PI19 UART2_RX           12      PH2
517 13      PI18 UART2_TX           14      0v     
518 15      PI17 UART2_CTS          16      PH21 CAN_RX 
519 17      3.3v                    18      PH20 CAN_TX 
520 19      PI12 SPI0_MOSI          20      0v     
521 21      PI13 SPI0_MISO          22      PI16 UART2_RTS   
522 23      PI11 SPI0_SCLK          24      PI10 SPI0_CS0    
523 25      0v                      26      PI14 SPI0_CS1
524
525 ## J13 DIP2-254
526 2       PB22 UART0_TX
527 1       PB23 UART0_RX
528
529 ## J12 DIP8-254
530 8       GND                     7       GND
531 6       PI20 UART7_TX           5       PH3
532 4       PI21 UART7_RX           3       PH5
533 2       3V3                     1       SATA-5V
534
535 # Raspberry Pi
536 1       3.3v                    2       5v
537 3       gpio2 (SDA.1)           4       5v
538 5       gpio3 (SCL.1)           6       0v
539 7       gpio4 (WPi 7)           8       gpio14  (TxD)
540 9       0v                      10      gpio15  (RxD)
541 11      gpio17 (WPi 0)          12      gpio18  (WPi 1)
542 13      gpio27 (WPi 2)          14      0v
543 15      gpio22 (WPi 3)          16      gpio23  (WPi 4)
544 17      3.3v                    18      gpio24  (WPi 5)
545 19      gpio10 (MOSI)           20      0v
546 21      gpio9 (MISO)            22      gpio25  (WPi 6) 
547 23      gpio11 (SCLK)           24      gpio8   (CE0)
548 25      0v                      26      gpio7   (CE1)
549 # Raspberry Pi 3 Model B Rev 1.2
550 27      gpio0 (SDA.0)           28      gpio1   (SCL.0)
551 29      gpio5 (WPi 21)          30      0v
552 31      gpio6 (WPi 22)          32      gpio12  (WPi 26)
553 33      gpio13 (WPi 23)         34      0v
554 35      gpio19 (WPi 24)         36      gpio16  (WPi 27)
555 37      gpio26 (WPi 25)         38      gpio20  (WPi 28)
556 39      0v                      40      gpio21  (WPi 29)
557