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