I2C-Keypad mit TCA8418

Vor einiger Zeit ist mir ein interessanter Chip über den Weg gelaufen mit dem man eine Tastatur mit I2C Schnittstelle realisieren kann. Ich habe ihn mir in Februar bestellt und seitdem lag das Teil auf meinem Tisch rum. Ich spielte mit den Gedanken, sowas Ähnliches wie Pocket C.H.I.P zu bauen. Die Kosten für den ersten Prototypen haben mich etwas abgeschreckt (bzw. tun es immer noch). Außerdem hatte ich zu der damaligen Zeit noch kein Ersatz für EAGLE gefunden. Vor einigen Wochen fand ich die ESD-Tüte mit den Keypad ICs. Ich setzte mich hin und fing an ein Schaltplan zu entwerfen.

Wichtiger Hinweis

Dieser Artikel ist eine reine Beschreibung, wie ich das zum Laufen gebracht habe und keine Anleitung! D.h. einige Sachen könnten fehlen, fehlerhaft oder nach einiger Zeit einfach nicht mehr aktuell sein.

TCA8418 I2C Keypad Scanner

Zuerst einige Daten zum IC. Das Gehäuse ist in meinem Fall ein WQFN24 (es gibt auch eine Ausführung als BGA) und ist 4x4mm groß. Es verfügt über 18 GPIOs (ESD geschützt) und bietet die Möglichkeit bis zu 80 Tasten anzuschließen. Spannungsversorgung 1,65V – 3,6V. Ein Output-Pin für den Interrupt ist auch vorhanden. I2C Clock bis zu 1MHz (Fast Mode Plus). Die Typischen Anwendungen sind Smartphones, Tablets, HMI, GPS Geräte, MP3 Player und Digitalkameras.

Tastenbelegung

Bei der Tastenbelegung habe ich versucht, mich an das Beispiel von Pocket C.H.I.P zu halten, Als ich mir auch die Schaltpläne angeschaut habe, war ich etwas überrascht. Auch hier wurde ein TCA8418 verbaut. Also habe ich die Anbindung und Anordnung der Tasten fast identisch gehalten. Einige Tasten habe ich weggelassen. Die Anzahl der Taster liegt bei 55 Stück. Als Layout habe ich die US Version gewählt.

Schaltplan

Die Beschattung ist recht überschaubar. Die Anordnung der Tasten erinnert stark an die übliche Matrix-Tastaturen. Die I/O sind auch in zwei Gruppen unterteilt: 8 Zeilen (Row) und 10 Spalten (Column). Die unbenutzten I/Os werden über Pull-Ups mit der Versorgungsspannung verbunden. Die restlichen I/Os (I2C, INT, RST) habe ich auch mit Pull-Ups versehen und dazu noch einige Platzhalter für Tiefpassfilter, die ich aber zum Glück nicht gebraucht habe.

TCA8418 I2C Keyboard Schaltplan

PCB Layout

Zuerst die Frage klären, wie sich die Form des Boards ergeben hat. Die Antwort ist einfach: aus reiner Langeweile 😉 Ich habe mir nichts dabei gedacht, sondern einfach nur fast willkürlich die Linien gezogen.

Die Platine besteht aus zwei Lagen. Die Tastenbeschriftung ist leider nicht so fancy, wie bei dem PocketCHIP, aber für den ersten Prototypen ausreichend. Die Platine habe ich mit CircuitStudio entworfen. CS ist momentan das Tool, was ich für die Entwicklung von Schaltplänen und PCB Layouts verwende. Routing ist relativ einfach, da langsame Signale, kaum Strom und genug Platz. Das Einzige, worauf ich geachtet habe, dass kein Signal von einem Taster, unter einem anderen verläuft. Wenn es notwendig war, habe ich auf andere Lage gewechselt. Der innere Aufbau des Tasters ist mir unbekannt. Es kann passieren, dass beim Betätigen von einem Taster ein Übersprechen auf die darunter liegende Leiterbahn stattfindet. Das Risiko ist minimal, aber ich wollte auf Nummer sicher gehen. Die Platine wollte ich manuell löten, daher habe ich die Masseflächen um den IC, die Widerstände und Kondensatoren herum etwas weiter weg platziert und die GND Pins mit Leiterbaahnen an diese Massefläche gezogen. Das macht das Löten etwas bequemer. Das Layout war übrigens angelehnt and das von PocketCHIP

Software

I2C Test

Pinbelegung

Pin Keypad Pin Raspberry Pi Zero
3,3V 3,3V (Pin 1)
SCL SCL (Pin 3)
SDA SDA (Pin 5)
GND GND (Pin 6)
INT GPIO18 (Pin 12)
Reset Braucht man nicht

I2C Tools installieren und testen, ob ein Busteilnehmer mit der Adresse 34 gefunden wird.

sudo apt update
sudo apt upgrade
sudo apt install i2c-tools
i2c-detect -y 1

Der Chip wurde sauber erkannt

pi@raspberrypi:~/linux/drivers/input/keyboard $ i2cdetect -y 1
     0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f
00:          -- -- -- -- -- -- -- -- -- -- -- -- -- 
10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
30: -- -- -- -- 34 -- -- -- -- -- -- -- -- -- -- -- 
40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
70: -- -- -- -- -- -- -- --

Treiber/Kernel bauen

Eigentlich wollte ich das nicht machen. Ich bin auf diesem Gebiet noch etwas unerfahren und bei meinem letzten Projekt, bei dem ich Bootloader etc. bauen musste,  hat es etwas Zeit und Nerven gekostet, die passenden Sources etc. zu finden und es fehlerfrei zu kompilieren. Und als ich vor einigen Jahren was für den Pi bauen musste, ging’s mir ähnlich.

Ich habe für dieses Projekt nach fertigen Treibern und nach einem einfacheren Weg gesucht, doch nichts gefunden. Gut! Bringt alles nix. Musste ich selber bauen. An dieser Stelle muss ich aber die Devs hinter dem Pi echt loben. Die „Kompiliererei“ ist gut und übersichtlich dokumentiert und der ganze Vorgang, den neuen Kernel zu kompilieren ist tadellos durchgelaufen und hat am Ende sogar funktioniert und warf mir in der Konsole keine Kernel Panic raus 🙂 Das Kompilieren auf dem Zero hat übrigens so um die 20 Stunden gedauert.

Übrigens! Damit ich gleich nach dem Flachen der SD-Karte für den Pi alles über SSH machen konnte, habe ich mir direkt eine WLAN Verbindung konfiguriert und zwar nach dieser Anleitung

Ich werfe an dieser Stelle noch die Kernel Version mit rein

pi@raspberrypi:~ $ uname -a
Linux raspberrypi 4.14.77+ #1 Sun Oct 21 08:44:24 UTC 2018 armv6l GNU/Linux

Beim Bauen bin ich nach diesen zwei Anleitungen vorgegangen. Die erste, wie man allgemein ein Kernel für den Pi baut. Irgendwo in der Mitte wird dann auf die zweite Anleitung verwiesen, falls man ihn anders konfigurieren möchte.

https://www.raspberrypi.org/documentation/linux/kernel/building.md

https://www.raspberrypi.org/documentation/linux/kernel/configuring.md

Als es dann um die Kernel-Config ging, das Modul TCA8418 mit „Y“ gesetzt.

Device Tree Overlay

Beim erstellen des DT-Overlays war mir der Blog von Mozzwald eine große Hilfe. Im Prinzip macht er mit diesem Projekt das, wofür ich noch zu geizig bin 😉

Overlay in /boot/overlays einfügen. Overlay ist noch aus einem frühen Stadium, könnte also Fehler beinhalten 😉

/dts-v1/;
/plugin/;


/{

compatible = "brcm,bcm2708";

fragment@0 {
	target = <&i2c1>;
	__overlay__{
		tca8418@34 {
	        compatible = "ti,tca8418";    
			
	        reg = <0x34>;

		/* the interrupt is specified as:
		 * The first cell is the GPIO number.
		 * The second cell is used to specify flags:
		 * bits[3:0] trigger type and level flags:
		 * 1 = low-to-high edge triggered.
		 * 2 = high-to-low edge triggered.
		 * 4 = active high level-sensitive.
		 * 8 = active low level-sensitive.
		*/

		irq-gpio = <&gpio 18 0x2>; /* IRQF_TRIGGER_FALLING */
		interrupts = <18 2>; /* high-to-low edge triggered */
		interrupt-parent = <&gpio>;
		interrupt-controller;
	        
		keypad,num-rows = <8>;
	        keypad,num-columns = <10>;

		/* row | column | key-code  ex: 04,08,0010 q key */
	        linux,keymap = <
				0x0000000d	//EQUAL
				0x00010002	//1
				0x00020003	//2
				0x00030004	//3
				0x00040005	//4
				0x00050006	//5
				0x00060007	//6
				0x00070008	//7
				0x00080009	//8
				0x0009000a	//9

				0x01000010	//Q
				0x01010011	//W
				0x01020012	//E
				0x01030013	//R
				0x01040014	//T
				0x01050015	//Y
				0x01060016	//U
				0x01070017	//I
				0x01080018	//O
				0x01090019	//P

				0x0200001e	//A	
				0x0201001f	//S
				0x02020020	//D
				0x02030021	//F
				0x02040022	//G
				0x02050023	//H
				0x02060024	//H
				0x02070025	//J
				0x02080026	//K
				0x0209001C	//ENTER

				0x0300000f	//TAB
				0x0301002c	//Z
				0x0302002d	//X
				0x0303002e	//C	
				0x0304002f	//V
				0x03050030	//B
				0x03060031	//N
				0x03070032	//M
				0x03080067	//UP
				0x0309006c	//DOWN

				0x04000001	//ESC
				0x04010038	//ALT right
				0x04020064	//ALT left
				0x04030039	//SPACE
				0x0404001d	//CTRL
				0x04050035	//SLASH
				0x04060036	//RIGHTSHIFT
				0x04080069	//LEFT
				0x0409006a	//RIGHT

				0x0500002a	//LEFTSHIFT
				0x0501000b	//0
				0x0502000c	//MINUS	
				0x0503000e	//BACKSPACE
				0x05040034	//DOT

				>;
			};
		};
	};

};

DT-Overlay kompilieren

sudo dtc -@ -I dts -O dtb -o tca8418.dtbo tca8418.dts

Der Vorgang spuckte einige Fehler / Warnungen aus, die ich erstmal ignoriert habe.

tca8418.dtbo: Warning (reg_format): "reg" property in /fragment@0/__overlay__/tca8418@34 has invalid length (4 bytes) (#address-cells == 2, #size-cells == 1)
tca8418.dtbo: Warning (unit_address_vs_reg): Node /fragment@0 has a unit name, but no reg property
tca8418.dtbo: Warning (avoid_default_addr_size): Relying on default #address-cells value for /fragment@0/__overlay__/tca8418@34
tca8418.dtbo: Warning (avoid_default_addr_size): Relying on default #size-cells value for /fragment@0/__overlay__/tca8418@34

Außerdem muss noch die Datei /boot/config.txt um folgenden Eintrag ergänzt werden.

dtoverlay=tca8418

Rebootet und geschaut, ob das Keypad sich irgendwie sichtbar macht.

pi@raspberrypi:~ $ dmesg | grep i2c
[    4.069592] i2c /dev entries driver
[    8.843265] input: tca8418 as /devices/platform/soc/20804000.i2c/i2c-1/1-0034/input/input0
pi@raspberrypi:~ $

Checken, ob das Eingabegerät bei Tastendruck etwas ausspuckt

pi@raspberrypi:/boot/overlays $ cat /dev/input/event0 
V?[??QV?[??
           V?[??V?[??QV?[??
                           V?[??V?[2F
QV?[2F

V?[2F
V?[Y?

Immer wenn man ich Taste betätigt habe, wurde eine „Buchstabensuppe“ ausgegeben. Damit man das auch in Klartext lesen kann, habe ich mir das Programm evtest installiert.

pi@raspberrypi:/boot/overlays $ sudo evtest /dev/input/event0 | grep EV_KEY
  Event type 1 (EV_KEY)
Event: time 1540314435.416024, type 1 (EV_KEY), code 16 (KEY_Q), value 1
Event: time 1540314435.540462, type 1 (EV_KEY), code 16 (KEY_Q), value 0
Event: time 1540314436.610922, type 1 (EV_KEY), code 17 (KEY_W), value 1
Event: time 1540314436.685645, type 1 (EV_KEY), code 17 (KEY_W), value 0
Event: time 1540314437.562458, type 1 (EV_KEY), code 18 (KEY_E), value 1
Event: time 1540314437.662112, type 1 (EV_KEY), code 18 (KEY_E), value 0
Event: time 1540314438.414409, type 1 (EV_KEY), code 19 (KEY_R), value 1
Event: time 1540314438.588845, type 1 (EV_KEY), code 19 (KEY_R), value 0
Event: time 1540314439.239903, type 1 (EV_KEY), code 20 (KEY_T), value 1
Event: time 1540314439.364442, type 1 (EV_KEY), code 20 (KEY_T), value 0
Event: time 1540314443.615618, type 1 (EV_KEY), code 21 (KEY_Y), value 1
Event: time 1540314443.665419, type 1 (EV_KEY), code 21 (KEY_Y), value 0

Keymap anpassen / erweitern

Jede Taste ist mit mehr als nur einer Funktion belegt. Deswegen benötigt man eine angepasste Keymap. Zuerst eine Datei z.b. im home Verzeichnis anlegen i2c-keypad.map

Dann folgt ein leichtes Umdenken. Wenn bei der Tastenzuweisung im Overlay mit Hexadezimal gearbeitet wurde, arbeitet man hier mit dezimalen Zahlen. Auch hier hat mir die Webseite von Mozzwald sehr geholfen. So sah meine keymap anschließend aus.

keymaps 0-2,3-5,8-9,12
keycode   1 = Escape
	shift altgr	keycode 1 = Break
keycode   2 = one
	shift keycode 2 = exclam
	altgr keycode 2 = F1
keycode   3 = two
	shift keycode 3 = at
	altgr keycode 3 = F2
keycode   4 = three
	shift keycode 4 = numbersign
	altgr keycode 5 = F3
keycode   5 = four
	shift keycode 5 = dollar
	altgr keycode 5 = F4
keycode   6 = five
	shift keycode 6 = percent
	altgr keycode 6 = F5
keycode   7 = six
	shift keycode 7 = asciicircum
	altgr keycode 7 = F6
keycode   8 = seven
	shift keycode 8 = ampersand
	altgr keycode 8 = F7
keycode   9 = eight
	shift keycode 9 = asterisk
	altgr keycode 9 = F8
keycode  10 = nine
	shift keycode 10 = parenleft
	altgr keycode 10 = F9
keycode  11 = zero
	shift keycode 11 = parenright
	altgr keycode 11 = F10
keycode  12 = minus
	shift keycode 12 = underscore
keycode  13 = plus
	shift keycode 13 = equal
keycode  14 = BackSpace
	altgr	keycode  14 = Remove
keycode  15 = Tab
keycode  16 = +q
	shift	keycode  16 = +Q
	control	keycode  16 = Control_q
keycode  17 = +w
	shift	keycode  17 = +W
	altgr	keycode  17 = asciitilde
	control	keycode  17 = Control_w
keycode  18 = +e
	shift	keycode  18 = +E
	control	keycode  18 = Control_e
keycode  19 = +r
	shift	keycode  19 = +R
	control	keycode  19 = Control_r
keycode  20 = +t
	shift	keycode  20 = +T
	control	keycode  20 = Control_t
keycode  21 = +y
	shift	keycode  21 = +Y
	altgr	keycode  21 = braceleft
	control	keycode  21 = Control_y
keycode  22 = +u
	shift	keycode  22 = +U
	altgr	keycode  22 = braceright
	control	keycode  22 = Control_u
keycode  23 = +i
	shift	keycode  23 = +I
	altgr	keycode  23 = bracketleft
	control	keycode  23 = Control_i
keycode  24 = +o
	shift	keycode  24 = +O
	altgr	keycode  24 = bracketright
	control	keycode  24 = Control_o
	shift	altgr	keycode  24 = degree
keycode  25 = +p
	shift	keycode  25 = +P
	altgr	keycode  25 = bar
	control	keycode  25 = Control_p
keycode  26 =
keycode  27 =
keycode  28 = Return
keycode  29 = SControl
keycode  30 = +a
	shift	keycode  30 = +A
	control	keycode  30 = Control_a
keycode  31 = +s
	shift	keycode  31 = +S
	control	keycode  31 = Control_s
	shift	control	keycode  31 = Control_s
keycode  32 = +d
	shift	keycode  32 = +D
	control	keycode  32 = Control_d
keycode  33 = +f
	shift	keycode  33 = +F
	control	keycode  33 = Control_f
keycode  34 = +g
	shift	keycode  34 = +G
	control	keycode  34 = Control_g
keycode  35 = +h
	shift	keycode  35 = +H
	control	keycode  35 = BackSpace
	altgr	keycode  35 = less
keycode  36 = +j
	shift	keycode  36 = +J
	control	keycode  36 = Control_j
	altgr	keycode  36 = greater
keycode  37 = +k
	shift	keycode  37 = +K
	control	keycode  37 = Control_k
	altgr	keycode  37 = apostrophe
keycode  38 = +l
	shift	keycode  38 = +L
	control	keycode  38 = Control_l
	altgr	keycode  38 = quotedbl
keycode  39 =
keycode  40 =  
keycode  41 =       
keycode  42 = SShift
keycode  43 = backslash
	shift	keycode  43 = bar
keycode  44 = +z
	shift	keycode  44 = +Z
	control	keycode  44 = Control_z
keycode  45 = +x
	shift	keycode  45 = +X
	control	keycode  45 = Control_x
keycode  46 = +c
	shift	keycode  46 = +C
	control	keycode  46 = Control_c
keycode  47 = +v
	shift	keycode  47 = +V
	control	keycode  47 = Control_v
keycode  48 = +b
	shift	keycode  48 = +B
	altgr   keycode  48 = grave
	control	keycode  48 = Control_b
keycode  49 = +n
	shift	keycode  49 = +N
	control	keycode  49 = Control_n
	altgr	keycode  49 = asciitilde
keycode  50 = +m
	shift	keycode  50 = +M
	control	keycode  50 = Control_m
	altgr	keycode  50 = colon
keycode  51 =
keycode  52 = period
	shift	keycode  52 = comma
	altgr	keycode  52 = semicolon
keycode  53 = slash
	shift keycode  53 = question
	altgr keycode  53 = backslash
keycode  54 = SShift            
keycode  55 =       
keycode  56 = SAltGr
keycode  57 = space
	control	keycode  57 = nul
keycode  58 =
keycode  59 =
keycode  60 =
keycode  61 =
keycode  62 =
keycode  63 =
keycode  64 =
keycode  65 =
keycode  66 =
keycode  67 =
keycode  68 =
keycode  69 =
keycode  70 =
keycode  71 =
keycode  72 =
keycode  73 =
keycode  74 =
keycode  75 =
keycode  76 =
keycode  77 =
keycode  78 =
keycode  79 =
keycode  80 =
keycode  81 =
keycode  82 =
keycode  83 =
keycode  84 =
keycode  85 =
keycode  86 =
keycode  87 =
keycode  88 =
keycode  89 =
keycode  90 =
keycode  91 =
keycode  92 =
keycode  93 =
keycode  94 =
keycode  95 =
keycode  96 =
keycode  97 =
keycode  98 =
keycode  99 =
keycode 100 =
keycode 101 =
keycode 102 =
keycode 103 = Up
keycode 104 =
keycode 105 = Left
keycode 106 = Right
keycode 107 = 
keycode 108 = Down
keycode 109 =
keycode 110 =
keycode 111 =
keycode 112 =
keycode 113 =
keycode 114 =
keycode 115 =
keycode 116 =
keycode 117 =
keycode 118 =
keycode 119 =
keycode 120 =
keycode 121 =
keycode 122 =
keycode 123 =
keycode 124 =
keycode 125 =
keycode 126 =
keycode 127 =
keycode 128 =
keycode 129 =
keycode 130 =
keycode 131 =
keycode 132 =
keycode 133 =
keycode 134 =
keycode 135 =
keycode 136 =
keycode 137 =
keycode 138 =
keycode 139 =
keycode 140 =
keycode 141 =
keycode 142 =
keycode 143 =
keycode 144 =
keycode 145 =
keycode 146 =
keycode 147 =
keycode 148 =
keycode 149 =
keycode 150 =
keycode 151 =
keycode 152 =
keycode 153 =
keycode 154 =
keycode 155 =
keycode 156 =
keycode 157 =
keycode 158 =
keycode 159 =
keycode 160 =
keycode 161 =
keycode 162 =
keycode 163 =
keycode 164 =
keycode 165 =
keycode 166 =
keycode 167 =
keycode 168 =
keycode 169 =
keycode 170 =
keycode 171 =
keycode 172 =
keycode 173 =
keycode 174 =
keycode 175 =
keycode 176 =
keycode 177 =
keycode 178 =
keycode 179 =
keycode 180 =
keycode 181 =
keycode 182 =
keycode 183 =
keycode 184 =
keycode 185 =
keycode 186 =
keycode 187 =
keycode 188 =
keycode 189 =
keycode 190 =
keycode 191 =
keycode 192 =
keycode 193 =
keycode 194 =
keycode 195 =
keycode 196 =
keycode 197 =
keycode 198 =
keycode 199 =
keycode 200 =
keycode 201 =
keycode 202 =
keycode 203 =
keycode 204 =
keycode 205 =
keycode 206 =
keycode 207 =
keycode 208 =
keycode 209 =
keycode 210 =
keycode 211 =
keycode 212 =
keycode 213 =
keycode 214 =
keycode 215 =
keycode 216 =
keycode 217 =
keycode 218 =
keycode 219 =
keycode 220 =
keycode 221 =
keycode 222 =
keycode 223 =
keycode 224 =
keycode 225 =
keycode 226 =
keycode 227 =
keycode 228 =
keycode 229 =
keycode 230 =
keycode 231 =
keycode 232 =
keycode 233 =
keycode 234 =
keycode 235 =
keycode 236 =
keycode 237 =
keycode 238 =
keycode 239 =
keycode 240 =
keycode 241 =
keycode 242 =
keycode 243 =
keycode 244 =
keycode 245 =
keycode 246 =
keycode 247 =
keycode 248 =
keycode 249 =
keycode 250 =
keycode 251 =
keycode 252 =
keycode 253 =
keycode 254 =
keycode 255 =

Damit diese keymap nach dem Boot verwendet wird, lade ich sie über /etc/rc.local

pi@raspberrypi:~ $ cat /etc/rc.local 
#!/bin/sh -e
#
# rc.local
#
# This script is executed at the end of each multiuser runlevel.
# Make sure that the script will "exit 0" on success or any other
# value on error.
#
# In order to enable or disable this script just change the execution
# bits.
#
# By default this script does nothing.

# Print the IP address
_IP=$(hostname -I) || true
if [ "$_IP" ]; then
  printf "My IP address is %s\n" "$_IP"
fi

/bin/loadkeys /home/pi/i2c-keypad.map
exit 0

Und dann hat es auch schon funktioniert. Dazu sei noch gesagt, dass ich das Light Image des Raspbians nutze. Wenn man auch Desktop benutzen will, muss man noch weitere Konfigurationen machen.

Hier noch ein ganz kurzes Demo-Video

One Reply to “I2C-Keypad mit TCA8418”

  1. Pingback: Keyboard Mapping – Blak_RPI

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert

*

Bitte löse folgende Rechenaufgabe * Time limit is exhausted. Please reload CAPTCHA.