Prise en main de la carte Banana Pi avec U-Boot et Linux

Introduction

Ce document rassemble quelques notes sur l'installation de la carte Banana Pi avec U-Boot et Linux. Ces notes sont inspirées par le site linux-sunxi.org qui est sans doute la référence dans ce domaine.

Ce site préconise l'utilisation des branches principales de U-Boot et du kernel Linux et c'est ce que l'on va faire.

Le process de boot de la carte

A la mise sous tension, Le processeur Allwinner A20 commence par exécuter le code embarqué dans sa rom dans un mode déterminé par la pin BOOTSEL du A20. Cette pin est connectée au bouton K3 de la carte. Il y a donc 2 modes:

Dans le mode eGON, le code cherche un SPL (Secondary Program Loader) dans l'ordre suivant :

  1. sur la carte SD 0.
  2. sur la mémoire NAND interne, qui n'existe pas.
  3. sur la carte SD 2, qui n'existe pas.
  4. sur une mémoire NOR connectée au SPI, qui n'existe pas.
  5. exécute le FEL mode.

Le FEL mode est un mode USB et nécessite un HOST (votre PC) pour charger le SPL puis le u-boot, puis ... C'est un mode qui peut être intéressant pour le développement, mais présente moins d'intérêt pour l'exploitation.

En conséquence, on constate que la carte ne peut booter que sur la carte SD correctement préparée, pour charger u-boot. U-boot étant chargé, il est possible de faire ce que u-boot sait faire : SD, SATA, USB, NFS, PXE, ...

Pour continuer, il nous faudra les binaires u-boot, du noyau Linux et un filesystem root. Sur la machine de développement (mon pc), on dispose d'un compilateur croisé appelé armv7-rpi2-linux-musleabihf- et accessible par le path. Pour éviter de trainer notre préfixe de compilateur partout, on l'exporte par une variable d'environnement:

export CC=armv7-rpi2-linux-musleabihf-

Ne prenez pas forcément les versions que j'indique, prenez les plus récentes...

Compilation de U-boot

Téléchargemnt du code source de U-boot et sélection de la version:

git clone git://git.denx.de/u-boot.git
cd u-boot
git checkout v2016.11

Maintenant on peut configurer u-boot pour le Banana PI:

make CROSS_COMPILE=${CC} Bananapi_defconfig

Vous pouvez personnaliser votre u-boot:

make CROSS_COMPILE=${CC} menuconfig

Compiler u-boot:

make CROSS_COMPILE=${CC}

Compilation du noyau Linux

La compilation du noyau est similaire à celle de u-boot et on commence par télécharger le source :

wget https://cdn.kernel.org/pub/linux/kernel/v4.x/linux-4.8.13.tar.xz
tar Jxvf linux-4.8.13.tar.xz
cd linux-4.8.13

On configure le noyau avec la configuration sunxi:

make ARCH=arm CROSS_COMPILE=${CC} sunxi_defconfig

Cette commande permet la personnalisation de la configuration. On va le faire pour configurer CONFIG_CPUSETS. Il faudra revenir ici plus tard, pour créer les modules dont on aura besoin.

make ARCH=arm CROSS_COMPILE=${CC} menuconfig

Le processeur Allwinner A20 a en fait 2 cores, mais un seul est visible avec le sunxi_defconfig. Avec la configuration suivante, on va activer CONFIG_CPUSETS=y:

General setup
  Control Group support
    Cpuset controller 

On peut maintenant compiler le noyau, le dts et les modules qui seront installés dans le répertoire indiqué. Ces commandes devront être exécutées pour prendre en compte les modifications ultérieures de la configuration

ARCH=arm CROSS_COMPILE=${CC} make zImage dtbs
ARCH=arm CROSS_COMPILE=${CC} INSTALL_MOD_PATH=../modules make modules modules_install

Si vous utilisez le noyau 4.8.13, il vous faudra un patch PATCHv4-net.git-1-2-Revert-stmmac-Fix-eth0-No-PHY-found-regression.patch, sinon ethernet ne fonctionnera pas sur le Banana Pi.

Root fs d'une distribution

A moins de vouloir tout compiler, ce qui prend beaucoup de temps, il semble préférable de prendre les binaires précompilés d'une distributions. Donc arrivé à ce point chacun prendra sa distribution préférée. Les distributions sont en général disponibles sous forme d'images d'une clé USB qu'il suffit de copier sur une carte SD, cela fait à la fois le partionnement, le formatage et l'installation d'un système minimal. Cela ne coute rien d'essayer et si ça ne fonctionne pas il sera toujours temps de revenir à cette page, en conservant votre système et en remplacant u-boot et le noyau.

Personnellement, je me suis dirigé vers la distribution Void Linux qui semble allier simplicité et performance. De plus elle fournit une archive d'un root fs minimal qu'il suffira d'extraire. Ensuite, une fois le système démarré, on pourra utiliser le gestionnaire de paquets pour installer les paquets que l'on souhaite ou même, si nécessaire, les compiler. Mais tout cela est complémentaire à l'objet de cette page.

Le root fs téléchargé sur le site http://repo.voidlinux.eu/live/current s'appelle void-cubieboard2-musl-rootfs-20160316.tar.xz. Il est destiné à la carte cubieboard2 qui utilise le même processeur Allwinner A20.

Préparation de la carte SD

Pour résumer, après les étapes précédentes, on se retrouve dans un répertoire de travail contenant un répertoire u-boot, un répertoire linux-4.8.13, un répertoire modules. On dispose d'une carte SD de 4 Go minimum et de classe 10 de préférence. La notre fait 16 Go et comportera une partition de 4 Go pour le système et une partition home qui contiendra le volume restant.

Il est conseillé de mettre à zéro le premier Mo de la carte, surtout si la carte a auparavant contenu un iso. La commande suivante copie 1023 blocs de 1024 octets à 0, en commencant après les 1024 premiers octets, donc en sautant le MBR. Remplacer sdX, par le nom du volume que vous utilisez, par exemple sdb.

dd if=/dev/zero of=/dev/sdX bs=1k count=1023 seek=1

On peut ensuite partitionner la carte, si ce n'est déja fait. La commande fdisk permet de la faire. La séquence de caractères à taper est la suivante, représente un appui sur la touche entrée.

fdisk /dev/sdX
o
n+4G
n
w

Après la séquence précédente, La commande p dans fdisk montre ceci:

Disk /dev/sdb: 14.6 GiB, 15707668480 bytes, 30679040 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disklabel type: dos
Disk identifier: 0xc6a382f1

Device     Boot   Start      End  Sectors  Size Id Type
/dev/sdb1          2048  8390655  8388608    4G 83 Linux
/dev/sdb2       8390656 30679039 22288384 10.6G 83 Linux

Pour formatter les partitions linux:

  mkfs.ext4 -L BPIROOT /dev/sdb1
  mkfs.ext4 -L BPIHOME /dev/sdb2

On peut installer le SPL u-boot en un endroit où le bootloader du micro saura le trouver:

dd if=u-boot/u-boot-sunxi-with-spl.bin of=/dev/sdX bs=1024 seek=8

Si la machine est opérationnelle, la copie de u-boot peut être effectué sur la machine elle-même, pour une mise à jour:

cd /boot
dd if=u-boot-sunxi-with-spl.bin of=/dev/mmcblk0 bs=1024 seek=8

Maintenant, il est temps d'extraire le filesystem root de notre distribution que l'on a préalablement téléchargé qui s'appelle void-cubieboard2-musl-rootfs-20160316.tar.xz.

mount /dev/sdb1 /mnt
tar -C /mnt -Jxvf void-cubieboard2-musl-rootfs-20160316.tar.xz

Ce filesystem contient bien un noyau et un u-boot destiné à une autre carte, le cubieboard2. On va donc écraser ces binaires par ceux que l'on a généré pour le Banana Pi. Les autres fichiers sont conservés, car ils sont de la même architecture et ils caractérisent la distribution.

On a besoin d'un fichier binaire boot.scr pour donner des instructions à u-boot. Ce fichier est issu d'un fichier source boot.cmd:

ext4load mmc 0 0x46000000 /boot/zImage
ext4load mmc 0 0x49000000 /boot/dtbs/sun7i-a20-bananapi.dtb
setenv bootargs console=ttyS0,115200 root=/dev/mmcblk0p1 ro rootwait panic=10 ${extra}
bootz 0x46000000 - 0x49000000

La commande suivante crée le fichier boot.scr à partir de boot.cmd et la commande mkimage a été généré pour notre host, lorsque l'on acompilé u-boot. Il suffit de la copier dans un endroit accessible par le path.

cp u-boot/tools/mkimage /usr/local
mkimage -C none -A arm -T script -d boot.cmd boot.scr

Pour finir, on peut copier nos fichiers vers la carte SD. Notez que les fichiers boot.cmd et u-boot-sunxi-with-spl.bin ne sont pas nécessaires.

cp boot.cmd boot.scr /mnt/boot
cp u-boot/u-boot.bin u-boot/u-boot-sunxi-with-spl.bin /mnt/boot
cp linux-4.8.13/arch/arm/boot/zImage  /mnt/boot
mkdir -p /mnt/boot/dtbs
cp linux-4.8.13/arch/arm/boot/dts/sun7i-a20-bananapi.dtb /mnt/boot/dtbs

mkdir -p /mnt/lib/modules/4.8.13
tar -C modules/lib/modules/4.8.13 -cvf - . | tar -C /mnt/lib/modules/4.8.13 -xf -

Comme on aura à le faire plusieurs fois, lorsque l'on rajoutera des modules, un Makefile peut être utile.

# Void Linux banana pi sd cart generation Makefile

# sd card mounted on /mnt

VERSION = 4.8.13
LINUX = linux-$(VERSION)
LINUXIMG = $(LINUX)/arch/arm/boot
LINUXDTB = $(LINUX)/arch/arm/boot/dts
DTB = sun7i-a20-bananapi.dtb 
UBOOT = u-boot
BOOT = /mnt/boot
MODULES = /mnt/lib/modules/$(VERSION)
REMMODULES = /lib/modules/$(VERSION)
SMODULES = modules/lib/modules/$(VERSION)

bpi: boot.scr
        tar -C $(SMODULES) -cvf modules.tar .
        scp boot.scr boot.cmd $(LINUXIMG)/zImage $(UBOOT)/u-boot.bin bpi:/boot
        scp $(LINUXDTB)/$(DTB) bpi:/boot/dtbs
        scp modules.tar bpi:/
        ssh bpi "tar -C $(REMMODULES) -xf /modules.tar"
        
sd: $(BOOT)/boot.scr $(BOOT)/zImage $(BOOT)/dtbs/$(DTB) \
         $(BOOT)/u-boot.bin $(MODULES)/modules.alias

boot.scr: boot.cmd
        mkimage -C none -A arm -T script -d boot.cmd boot.scr
$(BOOT)/boot.scr : boot.scr
        cp boot.scr boot.cmd $(BOOT)

$(BOOT)/u-boot.bin : $(UBOOT)/u-boot.bin
        cp $(UBOOT)/u-boot.bin $(UBOOT)/u-boot-sunxi-with-spl.bin $(BOOT)

$(BOOT)/zImage : $(LINUXIMG)/zImage
        cp $(LINUXIMG)/zImage $(BOOT)/zImage

$(BOOT)/dtbs/$(DTB): $(LINUXDTB)/$(DTB)
        mkdir -p $(BOOT)/dtbs
        cp $(LINUXDTB)/$(DTB) $(BOOT)/dtbs/$(DTB)

$(MODULES)/modules.alias : $(SMODULES)/modules.alias
        mkdir -p $(MODULES)
        tar -C $(SMODULES) -cvf - . | tar -C $(MODULES) -xf -
        touch $@

clean:
        rm -f *~

Il comporte 2 cibles bpi et sd. La première bpi suppose que la carte SD est opérationnelle sur la carte Banana PI. La seconde sd suppose que la partition root de la carte SD est montée sur /mnt sur la machine de développement.

make bpi

ou

make sd

On n'oubliera pas de démonter la partition root, lorsqu'elle est montée avant de récupérer la carte SD.

umount /mnt

Liaison série de la carte Banana Pi

Si on souhaite consulter les messages générés pendant la phase de boot et éventuellemnt intervenir en cas de problème, il est pratiquement nécessaire de connecter son PC à la carte Banana Pi par la liaison série.

Mon PC dispose d'une liaison série (j'avais choisi la carte mère pour cela). Le cable se branche donc sur un connecteur à l'arrière et se termine sur une petite carte d'interface, cablée depuis longtemps et servant pour toute connexion série, son rôle étant l'adaptation des niveaux rs232 <-> 3.3 Volts (Voir Rs232 serial adaptor). Il est alors nécessaire de se faire un cable connectant:

Connexions Uart
carte bpi carte rsadapt
J11 Pin1 TXD de l'UART0-TX TXD
J11 Pin2 RXD de l'UART0-RX RXD
J12 Pin2 3.3V 5v
J12 Pin8 GND gnd

L'alimentation de l'adaptateur est fournie par la carte BPI et en général par le montage auquel il est connecté afin de fonctionner avec l'alimentation fournie 5V ou 3.3V. Le 5 ième point non connecté sert de détrompeur.

Si votre PC n'a pas de liaison série, un convertisseur USB série 3.3V fera l'affaire. Il faudra cependant raccorder les points TXD, RXD et GND à votre adaptateur.

Sur le PC un programme comme gtkterm permet de piloter la liaison série /dev/ttyS0 ou la liaison par usb /dev/ttyUSB0.

Photo du cable série pour Banana Pi.

Photo du cable série pour Banana Pi

Pour pouvoir l'utiliser en point de logging, il faut en activer le démarrage et sous Void Linux, c'est:

cd /var/service
ln -s /etc/sv/agetty-console

Cette commande suppose la machine en fonctionnement, ce qui n'est pas toujours le cas. Pour préparer l'opération sur la carte SD montée sur /mnt sur votre machine de développement, exécuter les commandes suivantes:

# cd /mnt/etc/runit/runsvdir/default/
# ln -s /etc/sv/agetty-console

Modifier le fichier /etc/sv/agetty-console/conf, en effet le noyau démarre à 11520 bps alors pourquoi pas continuer, ce qui évite de changer dans le terminal.

BAUD_RATE=115200
TERM_NAME=linux

Installation réseau

L'accès naturel à la machine se fait par ssh. Il faut donc que le réseau soit configuré. Pour cela, une solution simple est d'utiliser dhcpcd et voici son fichier de configuration /etc/dhcpcd.conf qui utilise des ip statiques:

interface eth0
static ip_address=192.168.1.85/24       
static routers=192.168.1.1
static domain_name_servers=192.168.1.1
interface wlan0
static ip_address=192.168.1.86/24       
static routers=192.168.1.1
static domain_name_servers=192.168.1.1

Ce fichier contient déja la configuration pour la wifi que l'on peut commenter ou enlever si on n'a pas l'intention de l'utiliser. La commande suivante permet de démarrer le démon dhcpcd.

# ln -s /etc/sv/dhcpcd /var/service/

ou si la carte sd est montée sur /mnt sur la machine de développement:

# cd /mnt/etc/runit/runsvdir/default/
# ln -s /etc/sv/dhcpcd dhcpcd

Installation wifi

Il ne faut pas se priver d'une installation wifi qui demande seulement l'acquisition d'une clé wifi du point de vue matériel. Elle coute moins cher qu'un cordon rj45 (moins de 2 euros)!. Du point de vue logiciel, il faut le paquet wpa_supplicant et bien sûr, le module du noyau corespondant à la clé installée et éventuellemnt un firmware pour cette clé.

L'essai se fait sucessivement sur 2 clés RTL8188ETV puis MT7601U. La commande lsusb donne des indications sur la clé wifi insérée. Une recherche internet indique que la clé RTL8188ETV est gérée par le module rtl8188eu (staging). Il faut donc activer ce module dans la configuration du noyau.

# lsusb
...
Bus 002 Device 002: ID 0bda:0179 Realtek Semiconductor Corp. RTL8188ETV Wireless LAN 802.11n Network Adapter
...
Bus 002 Device 002: ID 148f:7601 Ralink Technology, Corp. MT7601U Wireless Adapter
...

L'insertion de la RTL8188ETV se passe bien. L'insertion de MT7601U produit les messages suivants qui indique qu' un firmware mt7601u.bin est absent. On va donc l'installer:

[  367.319719] mt7601u 2-1:1.0: ASIC revision: 76010001 MAC revision: 76010500
[  367.328253] mt7601u 2-1:1.0: Direct firmware load for mt7601u.bin failed with error -2
[  367.336918] mt7601u: probe of 2-1:1.0 failed with error -2

Une fois la clé connectée et le module chargé, la commande suivante donne la liste des interfaces net:

# ls /sys/class/net
eth0  lo  wlan0

Maintenant avec notre interface wifi wlan0, on peut créer le fichier de configuration wpa_supplicant, puis le modifier avec wpa_passphrase. La commande wifi fait "echo <Mon-ssid> <Ma-passphrase>" car c'est juste fatiguant de se rappeler et de taper sans erreur ces infos.

# cp /etc/wpa_supplicant/wpa_supplicant.conf  /etc/wpa_supplicant/wpa_supplicant-wlan0.conf 
wpa_passphrase `wifi` >> /etc/wpa_supplicant/wpa_suplicant-wlan0.con

Le fichier résultant est à peu près ceci avec des vraies valeurs pour MY-SSID et MY-WPA-KEY :

$ cat /etc/wpa_supplicant/wpa_supplicant-wlan0.conf
# Default configuration file for wpa_supplicant.conf(5).

ctrl_interface=/run/wpa_supplicant
ctrl_interface_group=wheel
eapol_version=1
ap_scan=1
fast_reauth=1
update_config=1

# Add here your networks.
network={
	ssid="MY-SSID"
	#psk="MY-WPA-KEY"
	psk=3e187b29ae183052c6900244df85b546dce324902938aa486e9063391fd7c77b
}

Il faut ensuite créer un fichier /etc/sv/wpa_supplicant/conf pour donner les paramètres adéquats. Et il arriva ce qui devait arriver: les paramètres de wpa_supplicant sont différents pour chacune des clés. On teste donc si r8188eu est chargé, et si oui on modifie la variable OPTS.

CONF_FILE=/etc/wpa_supplicant/wpa_supplicant-wlan0.conf
if ! modprobe -q -n --first-time -v "r8188eu" ; then
     echo $m is loaded
     OPTS="-Dwext -s"
fi

Il ne reste plus qu'à démarrer wpa_supplicant en tant que service:

# ln -s /etc/sv/wpa_supplicant /var/service/

ou si la carte sd est montée sur /mnt sur la machine de développement:

# cd /mnt/etc/runit/runsvdir/default/
# ln -s /etc/sv/wpa_supplicant

Tout cela est très bien, l'adresse ip est affectée à l'interface mais le modem routeur n'en sait rien. On va donc faire un script /root/bin/netping et activé par /etc/rc.local pour pinguer le routeur.

#!/bin/bash

# when bpi start the ip are set up, but the router is not aware, 
# so send a ping to modem when the interface is up
# /etc/hosts must be up to date

IP=192.168.1.1
HOST=bpi
MODULES="r8188eu mt7601u"

for m in $MODULES ; do
#  echo $m
  if ! modprobe -q -n --first-time -v $m ; then
     echo $m is loaded
     HOST=bpiw
  fi
done
#echo $HOST

# for lazy net card
until $(ping -q -W 1 -c 1 $HOST > /dev/null); do
  echo "Waiting $HOST interface to be up"
  sleep 1
done
#ping the router
ping -q -W 1 -c 1 $IP > /dev/null

Ceci n'est qu'une solution. Si on installe un desktop et NetworkManager les opérations précédentes ne sont plus nécessaires et doivent être désactivées.

photo de la clé 802.11n
Photo RTL8188ETV
photo de la clé wifin.
Photo MT7601U

A noter que la RTL8188ETV manque un peu de sensibilité, elle fonctionne bien à 6 m + 1 mur, mais très mal à 10 m + un plancher béton, ce qui n'est pas le cas pour l'autre.

Boot de la machine Banana Pi

On met la carte SD dans son emplacement, on démarre gtkterm et on branche le cordon secteur. Le listing suivant est la capture par gtkterm des messages émis sur l'UART0. On constate un prompt de login au bout de 5 s après le démarrage du noyau. Le réseau est prêt au bout de 10 s

U-Boot SPL 2016.03 (Mar 30 2016 - 18:11:30)
DRAM: 1024 MiB
CPU: 912000000Hz, AXI/AHB/APB: 3/2/2
Trying to boot from MMC


U-Boot 2016.03 (Mar 30 2016 - 18:11:30 +0200) Allwinner Technology

CPU:   Allwinner A20 (SUN7I)
I2C:   ready
DRAM:  1 GiB
MMC:   SUNXI SD/MMC: 0
*** Warning - bad CRC, using default environment

Setting up a 720x576i composite-pal console (overscan 32x20)
In:    serial
Out:   vga
Err:   vga
SCSI:  SUNXI SCSI INIT
SATA link 0 timeout.
AHCI 0001.0100 32 slots 1 ports 3 Gbps 0x1 impl SATA mode
flags: ncq stag pm led clo only pmp pio slum part ccc apst 
Net:   eth0: ethernet@01c50000
starting USB...
USB0:   USB EHCI 1.00
USB1:   USB OHCI 1.0
USB2:   USB EHCI 0.00
USB3:   USB OHCI 0.0
scanning bus 0 for devices... 1 USB Device(s) found
scanning bus 2 for devices... 1 USB Device(s) found
Hit any key to stop autoboot:  0 
switch to partitions #0, OK
mmc0 is current device
Scanning mmc 0:1...
Found U-Boot script /boot/boot.scr
288 bytes read in 166 ms (1000 Bytes/s)
## Executing script at 43100000
3164008 bytes read in 346 ms (8.7 MiB/s)
30295 bytes read in 173 ms (170.9 KiB/s)
Kernel image @ 0x46000000 [ 0x000000 - 0x304768 ]
## Flattened Device Tree blob at 49000000
   Booting using the fdt blob at 0x49000000
EHCI failed to shut down host controller.
   Loading Device Tree to 49ff5000, end 49fff656 ... OK

Starting kernel ...

[    0.000000] Booting Linux on physical CPU 0x0
[    0.000000] Linux version 4.8.13 (hq@olix) (gcc version 5.3.0 (crosstool-NG crosstool-ng-1.22.0-134-ge1d494a) ) #5 SMP Wed Apr 6 18:28:44 CEST 2016
[    0.000000] CPU: ARMv7 Processor [410fc074] revision 4 (ARMv7), cr=10c5387d
[    0.000000] CPU: div instructions available: patching division code
[    0.000000] CPU: PIPT / VIPT nonaliasing data cache, VIPT aliasing instruction cache
[    0.000000] Machine model: LeMaker Banana Pi
[    0.000000] Memory policy: Data cache writealloc
[    0.000000] psci: probing for conduit method from DT.
[    0.000000] psci: Using PSCI v0.1 Function IDs from DT
[    0.000000] PERCPU: Embedded 12 pages/cpu @ef7c6000 s17484 r8192 d23476 u49152
[    0.000000] Built 1 zonelists in Zone order, mobility grouping on.  Total pages: 260202
[    0.000000] Kernel command line: console=ttyS0,115200 root=/dev/mmcblk0p1 ro rootwait panic=10
[    0.000000] PID hash table entries: 4096 (order: 2, 16384 bytes)
[    0.000000] Dentry cache hash table entries: 131072 (order: 7, 524288 bytes)
[    0.000000] Inode-cache hash table entries: 65536 (order: 6, 262144 bytes)
[    0.000000] Memory: 1031212K/1046952K available (4418K kernel code, 203K rwdata, 1304K rodata, 284K init, 261K bss, 15740K reserved, 0K cma-reserved, 260520K highmem)
[    0.000000] Virtual kernel memory layout:
[    0.000000]     vector  : 0xffff0000 - 0xffff1000   (   4 kB)
[    0.000000]     fixmap  : 0xffc00000 - 0xfff00000   (3072 kB)
[    0.000000]     vmalloc : 0xf0800000 - 0xff800000   ( 240 MB)
[    0.000000]     lowmem  : 0xc0000000 - 0xf0000000   ( 768 MB)
[    0.000000]     pkmap   : 0xbfe00000 - 0xc0000000   (   2 MB)
[    0.000000]     modules : 0xbf000000 - 0xbfe00000   (  14 MB)
[    0.000000]       .text : 0xc0008000 - 0xc059eb48   (5723 kB)
[    0.000000]       .init : 0xc059f000 - 0xc05e6000   ( 284 kB)
[    0.000000]       .data : 0xc05e6000 - 0xc0618f40   ( 204 kB)
[    0.000000]        .bss : 0xc061b000 - 0xc065c484   ( 262 kB)
[    0.000000] SLUB: HWalign=64, Order=0-3, MinObjects=0, CPUs=2, Nodes=1
[    0.000000] Hierarchical RCU implementation.
[    0.000000] 	Build-time adjustment of leaf fanout to 32.
[    0.000000] 	RCU restricting CPUs from NR_CPUS=8 to nr_cpu_ids=2.
[    0.000000] RCU: Adjusting geometry for rcu_fanout_leaf=32, nr_cpu_ids=2
[    0.000000] NR_IRQS:16 nr_irqs:16 16
[    0.000000] Architected cp15 timer(s) running at 24.00MHz (phys).
[    0.000000] clocksource: arch_sys_counter: mask: 0xffffffffffffff max_cycles: 0x588fe9dc0, max_idle_ns: 440795202592 ns
[    0.000007] sched_clock: 56 bits at 24MHz, resolution 41ns, wraps every 4398046511097ns
[    0.000019] Switching to timer-based delay loop, resolution 41ns
[    0.000414] clocksource: timer: mask: 0xffffffff max_cycles: 0xffffffff, max_idle_ns: 79635851949 ns
[    0.000610] clocksource: hstimer: mask: 0xffffffff max_cycles: 0xffffffff, max_idle_ns: 12741736309 ns
[    0.000795] Console: colour dummy device 80x30
[    0.000826] Calibrating delay loop (skipped), value calculated using timer frequency.. 48.00 BogoMIPS (lpj=240000)
[    0.000841] pid_max: default: 32768 minimum: 301
[    0.000950] Mount-cache hash table entries: 2048 (order: 1, 8192 bytes)
[    0.000962] Mountpoint-cache hash table entries: 2048 (order: 1, 8192 bytes)
[    0.001610] CPU: Testing write buffer coherency: ok
[    0.001941] /cpus/cpu@0 missing clock-frequency property
[    0.001959] /cpus/cpu@1 missing clock-frequency property
[    0.001971] CPU0: thread -1, cpu 0, socket 0, mpidr 80000000
[    0.002037] Setting up static identity map for 0x40008280 - 0x400082d8
[    0.003533] CPU1: thread -1, cpu 1, socket 0, mpidr 80000001
[    0.003619] Brought up 2 CPUs
[    0.003638] SMP: Total of 2 processors activated (96.00 BogoMIPS).
[    0.003644] CPU: All CPU(s) started in HYP mode.
[    0.003649] CPU: Virtualization extensions available.
[    0.004369] devtmpfs: initialized
[    0.012324] VFP support v0.3: implementor 41 architecture 2 part 30 variant 7 rev 4
[    0.012681] clocksource: jiffies: mask: 0xffffffff max_cycles: 0xffffffff, max_idle_ns: 19112604462750000 ns
[    0.012804] pinctrl core: initialized pinctrl subsystem
[    0.013937] NET: Registered protocol family 16
[    0.014264] DMA: preallocated 256 KiB pool for atomic coherent allocations
[    0.021257] hw-breakpoint: found 5 (+1 reserved) breakpoint and 4 watchpoint registers.
[    0.021273] hw-breakpoint: maximum watchpoint size is 8 bytes.
[    0.028334] reg-fixed-voltage usb0-vbus: could not find pctldev for node /soc@01c00000/pinctrl@01c20800/usb0_vbus_pin@0, deferring probe
[    0.028388] reg-fixed-voltage usb1-vbus: could not find pctldev for node /soc@01c00000/pinctrl@01c20800/usb1_vbus_pin@0, deferring probe
[    0.028419] reg-fixed-voltage usb2-vbus: could not find pctldev for node /soc@01c00000/pinctrl@01c20800/usb2_vbus_pin@0, deferring probe
[    0.029152] reg-fixed-voltage gmac-3v3: could not find pctldev for node /soc@01c00000/pinctrl@01c20800/gmac_power_pin@0, deferring probe
[    0.029642] SCSI subsystem initialized
[    0.030287] usbcore: registered new interface driver usbfs
[    0.030353] usbcore: registered new interface driver hub
[    0.030420] usbcore: registered new device driver usb
[    0.030569] pps_core: LinuxPPS API ver. 1 registered
[    0.030577] pps_core: Software ver. 5.3.6 - Copyright 2005-2007 Rodolfo Giometti 
[    0.030606] PTP clock support registered
[    0.031675] clocksource: Switched to clocksource arch_sys_counter
[    0.032674] simple-framebuffer 7fe79000.framebuffer: framebuffer at 0x7fe79000, 0x178e00 bytes, mapped to 0xf0900000
[    0.032692] simple-framebuffer 7fe79000.framebuffer: format=x8r8g8b8, mode=656x536x32, linelength=2880
[    0.039386] Console: switching to colour frame buffer device 82x33
[    0.045495] simple-framebuffer 7fe79000.framebuffer: fb0: simplefb registered!
[    0.055124] NET: Registered protocol family 2
[    0.055698] TCP established hash table entries: 8192 (order: 3, 32768 bytes)
[    0.055788] TCP bind hash table entries: 8192 (order: 4, 65536 bytes)
[    0.055914] TCP: Hash tables configured (established 8192 bind 8192)
[    0.056001] UDP hash table entries: 512 (order: 2, 16384 bytes)
[    0.056061] UDP-Lite hash table entries: 512 (order: 2, 16384 bytes)
[    0.056278] NET: Registered protocol family 1
[    0.056733] RPC: Registered named UNIX socket transport module.
[    0.056747] RPC: Registered udp transport module.
[    0.056754] RPC: Registered tcp transport module.
[    0.056760] RPC: Registered tcp NFSv4.1 backchannel transport module.
[    0.057381] hw perfevents: enabled with armv7_cortex_a7 PMU driver, 5 counters available
[    0.058574] futex hash table entries: 512 (order: 3, 32768 bytes)
[    0.069245] NFS: Registering the id_resolver key type
[    0.069335] Key type id_resolver registered
[    0.069342] Key type id_legacy registered
[    0.070493] bounce: pool size: 64 pages
[    0.070768] Block layer SCSI generic (bsg) driver version 0.4 loaded (major 250)
[    0.070791] io scheduler noop registered
[    0.070807] io scheduler deadline registered
[    0.070839] io scheduler cfq registered (default)
[    0.071258] sun4i-usb-phy 1c13400.phy: could not find pctldev for node /soc@01c00000/pinctrl@01c20800/usb0_id_detect_pin@0, deferring probe
[    0.074072] sun7i-a20-pinctrl 1c20800.pinctrl: initialized sunXi PIO driver
[    0.138617] Serial: 8250/16550 driver, 8 ports, IRQ sharing disabled
[    0.141844] console [ttyS0] disabled
[    0.162047] 1c28000.serial: ttyS0 at MMIO 0x1c28000 (irq = 44, base_baud = 1500000) is a U6_16550A
[    0.835749] console [ttyS0] enabled
[    0.862742] 1c28c00.serial: ttyS1 at MMIO 0x1c28c00 (irq = 45, base_baud = 1500000) is a U6_16550A
[    0.895147] 1c29c00.serial: ttyS2 at MMIO 0x1c29c00 (irq = 46, base_baud = 1500000) is a U6_16550A
[    0.971719] ahci-sunxi 1c18000.sata: controller can't do PMP, turning off CAP_PMP
[    0.979242] ahci-sunxi 1c18000.sata: SSS flag set, parallel bus scan disabled
[    0.986427] ahci-sunxi 1c18000.sata: AHCI 0001.0100 32 slots 1 ports 3 Gbps 0x1 impl platform mode
[    0.995397] ahci-sunxi 1c18000.sata: flags: ncq sntf stag pm led clo only pio slum part ccc 
[    1.004872] scsi host0: ahci-sunxi
[    1.008624] ata1: SATA max UDMA/133 mmio [mem 0x01c18000-0x01c18fff] port 0x100 irq 32
[    1.018149] CAN device driver interface
[    1.023099] ehci_hcd: USB 2.0 'Enhanced' Host Controller (EHCI) Driver
[    1.029631] ehci-platform: EHCI generic platform driver
[    1.035253] ohci_hcd: USB 1.1 'Open' Host Controller (OHCI) Driver
[    1.041453] ohci-platform: OHCI generic platform driver
[    1.048525] sunxi-rtc 1c20d00.rtc: rtc core: registered rtc-sunxi as rtc0
[    1.055378] sunxi-rtc 1c20d00.rtc: RTC enabled
[    1.059946] i2c /dev entries driver
[    1.064599] axp20x 0-0034: AXP20x variant AXP209 found
[    1.083256] input: axp20x-pek as /devices/platform/soc@01c00000/1c2ac00.i2c/i2c-0/0-0034/axp20x-pek/input/input0
[    1.098709] axp20x 0-0034: AXP20X driver loaded
[    1.122482] sunxi-wdt 1c20c90.watchdog: Watchdog enabled (timeout=16 sec, nowayout=0)
[    1.131555] sunxi-mmc 1c0f000.mmc: Got CD GPIO
[    1.171876] sunxi-mmc 1c0f000.mmc: base:0xf08d6000 irq:27
[    1.178133] sun4i-ss 1c15000.crypto-engine: no reset control found
[    1.185910] sun4i-ss 1c15000.crypto-engine: Die ID 0
[    1.192583] usbcore: registered new interface driver usbhid
[    1.198158] usbhid: USB HID core driver
[    1.203565] NET: Registered protocol family 17
[    1.208037] can: controller area network core (rev 20120528 abi 9)
[    1.214319] NET: Registered protocol family 29
[    1.218774] can: raw protocol (rev 20120528)
[    1.223064] can: broadcast manager protocol (rev 20120528 t)
[    1.228730] can: netlink gateway (rev 20130117) max_hops=1
[    1.234586] Key type dns_resolver registered
[    1.249984] Registering SWP/SWPB emulation handler
[    1.288795] mmc0: host does not support reading read-only switch, assuming write-enable
[    1.299304] mmc0: new high speed SDHC card at address 59b4
[    1.305431] mmcblk0: mmc0:59b4       14.9 GiB 
[    1.311166]  mmcblk0: p1 p2
[    1.336089] ata1: SATA link down (SStatus 0 SControl 300)
[    1.361775] sun7i-dwmac 1c50000.ethernet: no reset control found
[    1.367781]  Ring mode enabled
[    1.370833]  No HW DMA feature register supported
[    1.375392]  Normal descriptors
[    1.378713]  TX Checksum insertion supported
[    1.383622] sun7i-dwmac 1c50000.ethernet eth0: No MDIO subnode found
[    1.393605] libphy: stmmac: probed
[    1.397014] eth0: PHY ID 001cc915 at 0 IRQ POLL (stmmac-0:00) active
[    1.403386] eth0: PHY ID 001cc915 at 1 IRQ POLL (stmmac-0:01)
[    1.409568] ehci-platform 1c14000.usb: EHCI Host Controller
[    1.415212] ehci-platform 1c14000.usb: new USB bus registered, assigned bus number 1
[    1.423135] ehci-platform 1c14000.usb: irq 29, io mem 0x01c14000
[    1.441721] ehci-platform 1c14000.usb: USB 2.0 started, EHCI 1.00
[    1.448716] hub 1-0:1.0: USB hub found
[    1.452566] hub 1-0:1.0: 1 port detected
[    1.457207] ehci-platform 1c1c000.usb: EHCI Host Controller
[    1.462862] ehci-platform 1c1c000.usb: new USB bus registered, assigned bus number 2
[    1.470730] ehci-platform 1c1c000.usb: irq 33, io mem 0x01c1c000
[    1.491668] ehci-platform 1c1c000.usb: USB 2.0 started, EHCI 1.00
[    1.498636] hub 2-0:1.0: USB hub found
[    1.502476] hub 2-0:1.0: 1 port detected
[    1.507094] ohci-platform 1c14400.usb: Generic Platform OHCI controller
[    1.513776] ohci-platform 1c14400.usb: new USB bus registered, assigned bus number 3
[    1.521697] ohci-platform 1c14400.usb: irq 30, io mem 0x01c14400
[    1.586526] hub 3-0:1.0: USB hub found
[    1.590333] hub 3-0:1.0: 1 port detected
[    1.595041] ohci-platform 1c1c400.usb: Generic Platform OHCI controller
[    1.601741] ohci-platform 1c1c400.usb: new USB bus registered, assigned bus number 4
[    1.609619] ohci-platform 1c1c400.usb: irq 34, io mem 0x01c1c400
[    1.676537] hub 4-0:1.0: USB hub found
[    1.680331] hub 4-0:1.0: 1 port detected
[    1.684774] sunxi-rtc 1c20d00.rtc: setting system clock to 1970-01-01 00:00:10 UTC (10)
[    1.697901] vcc3v0: disabling
[    1.700896] vcc5v0: disabling
[    1.704410] usb0-vbus: disabling
[    1.709451] EXT4-fs (mmcblk0p1): couldn't mount as ext3 due to feature incompatibilities
[    1.718308] EXT4-fs (mmcblk0p1): couldn't mount as ext2 due to feature incompatibilities
[    1.737369] EXT4-fs (mmcblk0p1): mounted filesystem with ordered data mode. Opts: (null)
[    1.745589] VFS: Mounted root (ext4 filesystem) readonly on device 179:1.
[    1.755366] devtmpfs: mounted
[    1.758661] Freeing unused kernel memory: 284K (c059f000 - c05e6000)
- runit: $Id: 25da3b86f7bed4038b8a039d2f8e8c9bbcf0822b $: booting.
- runit: enter stage: /etc/runit/1
=> Welcome to Void!
=> Mounting pseudo-filesystems...
=> Setting up keymap to 'fr'...
=> Setting up RTC to 'UTC'...
=> Starting udev and waiting for devices to settle...
[    2.206854] udevd[88]: starting version 3.1.5
[    2.242545] random: udevd urandom read with 11 bits of entropy available
[    2.610610] sun4i-codec 1c22c00.codec: Codec <-> 1c22c00.codec mapping ok
=> Remounting rootfs read-only...
[    3.061476] EXT4-fs (mmcblk0p1): re-mounted. Opts: (null)
=> Activating btrfs devices...
Scanning for Btrfs filesystems
=> Activating encrypted devices...
=> Checking filesystems:
VOID_ARM: clean, 25553/262144 files, 239993/1048576 blocks
VOID_HOME: clean, 7539/715264 files, 374661/2860544 blocks
[    3.407141] random: nonblocking pool is initialized
=> Mounting rootfs read-write...
[    3.495844] EXT4-fs (mmcblk0p1): re-mounted. Opts: (null)
=> Mounting all non-network filesystems...
[    3.551575] EXT4-fs (mmcblk0p2): mounted filesystem with ordered data mode. Opts: (null)
=> Initializing swap...
=> Initializing random seed...
=> Setting up loopback interface...
=> Setting up hostname to 'lemaker'...
=> Setting up timezone to 'Europe/Paris'...
=> Loading kernel modules...

=> Loading sysctl(8) settings...
* Applying /usr/lib/sysctl.d/void.conf ...
kernel.core_uses_pid = 1
fs.protected_hardlinks = 1
fs.protected_symlinks = 1
* Applying /etc/sysctl.conf ...
=> Initialization complete, running stage 2...
- runit: leave stage: /etc/runit/1
- runit: enter stage: /etc/runit/2
runsvchdir: default: current.
[    4.052390]  RX IPC Checksum Offload disabled
[    4.056762]  No MAC Management Counters available
[    5.007203] udevd[188]: starting version 3.1.5

Void 4.8.13 (lemaker) (console)

lemaker login: [    8.282578]  RX IPC Checksum Offload disabled
[    8.286950]  No MAC Management Counters available
[   10.272359] sun7i-dwmac 1c50000.ethernet eth0: Link is Up - 100Mbps/Full - flow control rx/tx

Installation de la distribution

Les fichiers du root fs ne sont q'un minimum. Void Linux ne se distingue pas des autres distributions et a son installateur de paquets xbps-install et xbps-query pour la recherche. La première chose a faire c'est mettre à jour la distribution. Ensuite chacun installera ses paquets en fonction de son besoin.

xbps-install -Su

Comme nous n'avons pas utilisé l'installatateur officiel, il est nécessaire de finir manuellement.

Installation Mass storage et USB gadget

Pour pouvoir monter les volumes d'une clé USB ou monter un volume de la carte sur la machine host par usb, ou avoir une connexion ethernet par USB, il faut compléter la configuration du noyau soit en créant des modules soit en incluant les fonctionnalités dans le noyau.

Device Drivers
  USB support
    Support for Host-side USB
      Enable USB persist by default
      OTG support
      USB Mass Storage support
      Inventra Highspeed Dual Role Controller (TI, ADI, AW, ...)
        Allwinner (sunxi) 
        Disable DMA (always use PIO) 
      USB Physical Layer drivers 
        NOP USB Transceiver Driver
      USB Gadget Support
        Ethernet Gadget (with CDC Ethernet support)
        Gadget Filesystem
        Function Filesystem
        Mass Storage Gadget
        CDC Composite Device (Ethernet and ACM)
        CDC Composite Device (ACM and mass storage)  
        Multifunction Composite Gadget
        HID Gadget
Exemple 1: Monter une clé USB sur une prise USB host du BPI

La commande lsblk montre les partitions sda* disponibles sur le Banana Pi, à la suite de l'insertion d'une clé USB sur une prise USB host de la carte. mmcblk0 correspond à la carte SD.

[root@lemaker ~]# lsblk
NAME        MAJ:MIN RM  SIZE RO TYPE MOUNTPOINT
sda           8:0    1 14.6G  0 disk 
  sda1        8:1    1    1G  0 part 
  sda2        8:2    1    8G  0 part 
  sda3        8:3    1  5.6G  0 part 
mmcblk0     179:0    0 14.9G  0 disk 
  mmcblk0p1 179:1    0    4G  0 part /
  mmcblk0p2 179:2    0 10.9G  0 part /home
Exemple 2: Monter la partition /home du BPI sur ma machine

La prise OTG du Banana Pi est connectée par un cable micro usb sur une prise USB de mon PC. Si c'est juste pour une démo, on peut faire la commande:

modprobe sunxi
modprobe g_mass_storage file=/dev/mmcblk0p2

Une fenêtre s'ouvre sur mon desktop avec comme titre VOID_HOME, qui est le label donné à la partition mmcblk0p2. La commande lsblk me montre un disque sdb monté sur /run/media/hq/VOID_HOME. La commande lsusb fait appaitre la ligne suivante.

Bus 002 Device 003: ID 0525:a4a5 Netchip Technology, Inc. Pocketbook Pro 903

Pour monter la partition à chaque démarrage, on crée un fichier de configuration /etc/modprobe.d/masssto.conf contenant:

softdep g_mass_storage pre: sunxi
options g_mass_storage file=/dev/mmcblk0p2
install g_mass_storage /sbin/modprobe --ignore-install g_mass_storage

Et on ajoute un fichier /etc/modules-load.d/masssto.conf contenant le nom du module g_mass_storage.

Vous n'avez pas de cable micro usb, vous pouvez avoir à peu près la même fonctionnalité avec sshfs ou avec nfs.

Exemple 3: Se connecter à internet par le cable USB

La prise OTG du Banana Pi est connectée par un cable micro usb sur une prise USB de mon PC. Pour voir quelque chose se passer, il faut charger les modules suivants sur le BPI:

modprobe sunxi
modprobe g_ether

Sur le BPI, un device usb0 apparait:

root@lemaker ~]# ls /sys/class/net
eth0  lo  usb0
[root@lemaker ~]# ip link
3: usb0:  mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
    link/ether da:a1:94:c7:ea:59 brd ff:ff:ff:ff:ff:ff

Sur le Host, un device enp0s29f7u5, ainsi qu'un périphérique USB apparaissent:

[hq@olix temp]$ ls /sys/class/net
enp0s29f7u5  enp4s0  lo
[hq@olix temp]$ ip link
3: enp0s29f7u5:  mtu 1500 qdisc pfifo_fast state DOWN mode DEFAULT group default qlen 1000
    link/ether 6a:74:0c:0a:9f:b6 brd ff:ff:ff:ff:ff:ff
[hq@olix temp]$ lsusb
Bus 002 Device 002: ID 0525:a4a2 Netchip Technology, Inc. Linux-USB Ethernet/RNDIS Gadget

Il faut maintenant configurer les interfaces de chaque coté. d'abord du coté BPI:

ip link set dev usb0 up
ip addr add 192.168.7.2/24 dev usb0
ip route add default via 192.168.7.1

Puis du coté host:

ip link set dev enp0s29f7u5 up
ip addr add 192.168.7.1/24 dev enp0s29f7u5
ip route add 192.168.7.0/24 dev enp0s29f7u5
iptables -A POSTROUTING -t nat -j MASQUERADE -s 192.168.7.0/24
sysctl -w net.ipv4.ip_forward=1

Les 2 dernières commandes permettent de pinger le routeur à partir du BPI. On peut à ce niveau, se connecter par ssh d'une machine vers l'autre et inversement. Il ne reste plus qu'à lancer dnsmasq comme relai dns

Pour atteindre le Banana Pi d'une autre machine du réseau, il est nécessaire, sur cette machine, de rajouter une route, lui disant quelle machine sert de passerelle.

ip route add 192.168.7.0/24 via 192.168.1.11

Installation détecteur infra rouge

La carte Banana Pi possede un récepteur infrarouge, connecté directement au processeur et controllé par le module sunxi-cir du noyau. Avant de le rendre opérationnel, une configuration du noyau est nécessaire.

Device Drivers
  Input device support 
     Generic input layer
  Multimedia support
    Remote Controller support
    compile Remote Controller keymap modules
    Remote Controller devices
     SUNXI IR remote control

Après compilation et installation, on peut charger le module:

modprobe sunxi-cir

Si tout se passe bien, on peut vérifier que sunxi-ir apparait dans le fichier /proc/bus/input/devices et qu'un répertoire /sys/class/rc/rc0 est créé. Le fichier /sys/class/rc/rc0/protocols donne la liste des protocoles compris par le driver. Il faut choisir celui qui correspond à notre télécommande et l'écrire dans ce même fichier

cat /sys/class/rc/rc0/protocols
other [unknown] rc-5 nec rc-6 jvc sony rc-5-sz sanyo sharp mce_kbd xmp
echo -n  rc-5 > /sys/class/rc/rc0/protocols

Le driver est accessible dans /dev/input/event1. Un fichier /etc/udev/rules.d/10-cir.rules permet de nommer définitivement le point d'accès en /dev/input/cir et éventuellement donner des droits.

SUBSYSTEM=="input", ACTION=="add", KERNEL=="event*", ATTRS{name}=="sunxi-ir", SYMLINK+="input/cir"

Lancer evtest, qui est un outil approprié pour tester et appuyer sur les touches de la télécommande:

[root@lemaker ~]# evtest /dev/input/cir
Input driver version is 1.0.1
Input device ID: bus 0x19 vendor 0x1 product 0x1 version 0x100
Input device name: "sunxi-ir"
Supported events:
  Event type 0 (EV_SYN)
  Event type 1 (EV_KEY)
    Event code 152 (KEY_SCREENLOCK)
  Event type 4 (EV_MSC)
    Event code 4 (MSC_SCAN)
Key repeat handling:
  Repeat type 20 (EV_REP)
    Repeat code 0 (REP_DELAY)
      Value    500
    Repeat code 1 (REP_PERIOD)
      Value    125
Properties:
Testing ... (interrupt to exit)
Event: time 9437.411710, type 4 (EV_MSC), code 4 (MSC_SCAN), value 1e01
Event: time 9437.411710, -------------- SYN_REPORT ------------
Event: time 9437.525324, type 4 (EV_MSC), code 4 (MSC_SCAN), value 1e01
Event: time 9437.525324, -------------- SYN_REPORT ------------
Event: time 9442.491425, type 4 (EV_MSC), code 4 (MSC_SCAN), value 1e02
Event: time 9442.491425, -------------- SYN_REPORT ------------
Event: time 9442.605047, type 4 (EV_MSC), code 4 (MSC_SCAN), value 1e02
Event: time 9442.605047, -------------- SYN_REPORT ------------
Event: time 9446.978642, type 4 (EV_MSC), code 4 (MSC_SCAN), value 1e03
Event: time 9446.978642, -------------- SYN_REPORT ------------
Event: time 9447.092258, type 4 (EV_MSC), code 4 (MSC_SCAN), value 1e03
Event: time 9447.092258, -------------- SYN_REPORT ------------

Installation du son

Le processeur de la carte Banana Pi embarque des codecs audio équivalent à une carte son de PC. la carte contient un microphone, une sortie audio sur un connecteur jack 3.5, une entrée stéréo sur le connecteur 1 pas facilement accessible et des soties par hdmi. La configuration du son dans sunxi_defconfig n'est pas faite par défaut, il faut donc la faire:

Device Drivers
  Sound card support 
    Advanced Linux Sound Architecture 
      Generic sound devices (NEW)
      ALSA for SoC audio support
        Allwinner SoC Audio support
          Allwinner A10 Codec Support 

Après compilation et installation, les modules sont chargés automatiquement:

[root@lemaker ~]# lsmod
Module                  Size  Used by
sun4i_codec            10367  3
snd_soc_core          105278  1 sun4i_codec
snd_pcm_dmaengine       3007  1 snd_soc_core
snd_pcm                69800  2 snd_soc_core,snd_pcm_dmaengine
snd_timer              18088  1 snd_pcm
snd                    38886  3 snd_soc_core,snd_timer,snd_pcm
soundcore                858  1 snd

Pour utiliser les commandes aplay, arecord du packet alsa-utils, un fichier de configuration /etc/asound.conf est bien utile. Si card = 0, les sorties analogiques sont utilisées. Pour utiliser hdmi, changer la valeur de card à 1.

pcm.!default {
  type hw
  card 0
  device 0
}
ctl.!default {
  type hw
  card 0
}

Les leds de la carte Banana Pi

La carte Banana P posède 3 leds + 2 sur le connecteur rj45

La led verte D8, pilotée par le GPIO PH24, est à la disposition de l'utilisateur et est accessible par le sysfs. La commande suivante produit une liste de fonctions disponible pour cette led.

cat /sys/class/leds/bananapi:green:usr/trigger
[none] kbd-scrollock kbd-numlock kbd-capslock kbd-kanalock kbd-shiftlock kbd-altgrlock kbd-ctrllock kbd-altlock kbd-shiftllock kbd-shiftrlock kbd-ctrlllock kbd-ctrlrlock axp20x-usb-online mmc0 heartbeat default-on 

Pour changer la fonction il faut écrire le nom de cette fonction dans le fichier trigger. Par exemple:

echo -n heartbeat > /sys/class/leds/bananapi:green:usr/trigger

La led rouge D7 est connectée au circuit d'alimentation 3.3V et ne peut être éteinte qu'en coupant l'alimentation.

La led bleue D6 est connectée à la sortie DVDD33 du circuit RTL8211 d'interface ethernet. Il en est de même des 2 leds du connecteur rj45, la jaune sur la pin LED0-AD0 et la verte sur LED1-AD1. Un programme pour les piloter différemment est disponible ici.

Accès aux gpios

Les gpios sont accessibles par l'interface sysfs /sys. Il faut commencer par exporter le gpio par la commande suivante:

echo -n  > /sys/class/gpio/export

Le problème qui se pose alors est de trouver le numéro du gpio qui atterris sur le connecteur 3 pin 7 par exemple. Le schéma de la carte indique que cette pin à un nom PWM1. Si on cherche ce nom sur le schéma on s'apercçoit qu'il est connecté au pad B19 du microcontrolleur qui, par multiplexage, peut avoir comme fonctionnalités PWM1/TWI4_SDA/PI3. Sur le processeur Allwinner A20 (voir la datasheet) les ports sont nommés PXn avec X allant de A à I et n étant le numéro de bit (bitnum) dans le port pouvant aller de 0 à 31, mais pouvant être différent pour chaque port. Attention, tous les bits ne sont pas utilisés et ne correspondent pas forcément à un port!. Pour calculer le numéro, le port A-I est converti à portnum 0-8 puis multiplié par 32 et additionné du numéro de bit. Ce qui pour notre exemple donne 259.

numéro = portnum * 32 + bitnum
259 = 9 * 32 + 3

La commande d'export de port devient alors:

echo -n 259 > /sys/class/gpio/export

Ceci fait apparaitre un répertoire /sys/class/gpio/gpio259 contenant les fichiers suivants:

ls gpio259
active_low  device  direction  power  subsystem  uevent  value

Le fichier direction permet de modifier ou lire la direction du port (in/out) et le fichier value l'état logique du port visible à l'extérieur par son état électrique (0 / 3.3V).

cat gpio259/direction
out
cat gpio259/value
0
echo -n 1 > gpio259/value
cat gpio259/value
1
echo -n in > gpio259/direction
cat gpio259/direction
in
cat gpio259/value
0

Pour libérer les ressources:

echo -n 259 > /sys/class/gpio/unexport

Pour en savoir plus voir Documentation/gpio/sysfs.txt.

La méthode de calcul du numéro n'est valable que pour le processeur A20. Pour un autre processeur, il faudra redéfinir la formule en s'inspirant des fichiers de la hiérarchie Linux linux-4.8.13/drivers/pinctrl/* correspondant à ce processeur.

Le bus i2c

Le processeur A20 possède 5 TWI controleurs.

La fonctionnalité i2c est intégrée au noyau par défaut et l'interface /sys/class/i2c-dev laisse apparaitre i2c-0 i2c-1. i2c-0 pilote le controleur d'alimentation et i2c-1 les fils TWI2-SDA (pin 3) TWI2-SCK (pin 5) sur le connecteur CON3. La tension est 3.3 V !. Pour les commandes i2cdetect,... le numéro est 1, en effet le bus i2c1 n'est pas déclaré dans le device tree.

Pour tester l'i2c, j'ai voulu utliser un afficheur lcd 2x16 piloté par un processeur at89c2051 réalisant une interface i2c esclave ou interface série, le tout fonctionnant en 5 V. Il faut, pour commencer, réaliser une adaptation de niveau logique 3.3 / 5 V dont voici le schéma :

La fréquence du bus i2c est par défaut 100 kHz, c'est un peu trop rapide pour ma carte dont l'horloge effective est à 7.3728 / 12 Mhz et dont l'interface est faite en logiciel. Une fréquence de 5 ou 10 kHz sera plus approprié. Pour la modifier, il y a 2 moyens, soit modifier le device tree, soit accéder au registre de controle par l'interface /dev/mem. On va donc commencer par modifier le fichier arch/arm/boot/dts/sun7i-a20-bananapi.dts dans les sources Linux et y rajouter la ligne clock-frequency, puis compiler le dts et enfin copier le dtb sur la carte.

...
&i2c2 {
	pinctrl-names = "default";
	pinctrl-0 = <&i2c2_pins_a>;
        clock-frequency = <10000>;
	status = "okay";
};
...

Pour éviter de perdre du temps... Ne pas confondre l'adresse effective i2c et l'octet d'adresse transmis en ligne.

<Adresse i2c> = <octect d'adresse> >> 1.

On peut maintenamt lancer i2cdetect sur le bus 1. L'afficheur est détecté:

hq@lemaker ~ $ sudo i2cdetect -y 1
     0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f
00:          -- -- -- -- -- -- -- -- -- -- -- -- -- 
10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
20: -- -- 22 -- -- -- -- -- -- -- -- -- -- -- -- -- 
30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
70: -- -- -- -- -- -- -- --                         

Un programme minimal permet d'envoyer des messages vers l'afficheur sans empiler des librairies inutiles.

/*
 * i2ctst.c - HQ i2ctst program. It sends a message to a 2x16 lcd display.
 * gcc -Wall -g i2ctst.c -o i2ctst
 */
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

/*
 * message format: 
 *    msg | msg 0A msg | msg 0A msg 0A ... msg
 * first byte is a command byte
 *       0x41 left justified line1
 *       0x61 left justified line2
 *       0x42 right justified line1
 *       0x62 right justified line2
 *       0x43 center justified line1
 *       0x63 center justified line2
 *       0x44 set cursor line1
 *       0x64 set cursor line2
 *       0x45 write one char at cursor line1
 *       0x65 write one char at cursor line2
 *       0x46 blink char at cursor line1
 *       0x66 blink char at cursor line2
 *       0x47 lcd clear
 *       0x48  No blink char at cursor
 *       0x49  Write cmd
 */

int i2c_init(char *dev, int addr)
{
   int fd;

   if ((fd = open(dev, O_RDWR)) < 0) {
      fprintf(stderr, "Failed to open the bus. %s - %s\n",
                        dev, strerror(errno) );
      return fd;
   }

   if (ioctl(fd, I2C_SLAVE, addr) < 0){
      fprintf(stderr, "Failed to set slave addr 0x%x. - %s\n",
                        addr, strerror(errno) );
      return -1;
   }
   return fd;
}

/*
 *  Write a n bytes message 
 */ 
int i2c_write( int fd, char *msg )
{
   int n;
   int nw;

   n = strlen(msg) ;
   nw = write(fd, msg, n);
   if ( nw != n) {
      fprintf(stderr, "Wrote %d - Error writing %d bytes - %s\n",
              nw, n, strerror(errno) );
   }
   return nw;
}

int main(int argc, char **argv)
{
   int fd = i2c_init("/dev/i2c-1", 0x22 ); /* device, slave i2c addr */

   int ret = i2c_write( fd, argv[1] );

   close(fd);

   return ret;
}

Et voici un exemple. Noter que le premier caractère est une commande de format:

sudo ./i2ctst "ABonjour lcd"
sudo ./i2ctst "ble 18 dec"

Controleur PWM

Le processeur A20 fournit un controleur PWM avec 2 canaux. Le controleur est piloté par une fréquence de 24 MHz. Chaque canal divise la fréquence 24 MHz dans un prescaler. Le diviseur est réglage à 120, 180, 240, 360, 480, 12000, 24000, 36000, 48000, 72000 et fournit la fréquence PWM_CLK dont la période sert de reférence dans le signal de sortie. Une période du signal de sortie est définie par n période d' horloges pour le temps actif et m périodes pour le temps total. Ces valeurs m et n sont à écrire dans le registre channel.

modification du device tree arch/arm/boot/dts/sun7i-a20-bananapi.dts

...
&pwm {
        pinctrl-names = "default";
        pinctrl-0 = <&pwm0_pins_a>, <&pwm1_pins_a>;
        status = "okay";
};
...

Le controleur d'alimentation AXP209

Test comparatif de la carte Banana Pi avec UnixBench

Unixbench est un jeu de tests, qui exécuté sur une machine, fournit un nombre pouvant caractériser les capacités de cette machine.

Pour effectuer un test il faut télécharger les sources, compiler ces sources sur la machine que l'on va tester (si possible) et exécuter le test qui dure environ 30 minutes et plus si la machine possède plusieurs processeurs. Vous aurez besoin de gcc, make, perl, libc-devel. Les résultats se trouvent dans le répertoire results.

Cliquer Download Zip sur https://github.com/kdlucas/byte-unixbench
unzip byte-unixbench-master.zip

cd UnixBench
make clean
make
./Run
Carte Banana Pi M1
Operating System result 1 cpu Result n cpus Delta
Arch linux 147.5 na 0
Void Linux musl 232.6 400.1 +57.7 %
Void Linux glibc 180.6 308.0 +22.4 %
Bananian Linux 183.8 na +24.6 %
Armbian Ubuntu 171.4 307.0 +16.2 %
Gentoo arm 141.5 na -4.2 %

Le delta est le rapport entre le résultat de la distribution et celui de Arch Linux, pour un processeur.

Il semblerait que les kernel 3.* n'exploiterait pas les 2 CPUs !. Pour information, voici les résultats pour un Raspberri Pi B:

Carte Raspberri Pi model B
Operating System Result Result n cpus Delta
Arch linux 75.4 0

Il faut éviter de tirer des conclusions trop hatives. En effet si toutes vos applications fonctionnent avec libc musl, c'est le chiffre indiqué, mais si seulement une ne fonctionne pas, vous êtes dans l'obligation de la rejeter pour une autre. Aujourd'hui par exemple, Asterisk ne fonctionne pas avec musl.

Références