First Steps with OlinuXino A20 Micro

An SD-Card with Debian image sold by Olimex is used as a system base.

A Debian image for the A20 may be found here, writing the image to an SD-card is described here.

Recipes

top

Using Package Manager on Debian

Cited from The Debian GNU/Linux FAQ: The Debian package management tools :
"aptitude is the preferred program for daily package management from console"

Bring everything up to date

aptitude update
aptitude safe-upgrade

Install package

aptitude install <package>
top

Network Setup

Links

Network Configuration via ifup/ifdown

An entry in /etc/network/interfaces like the following, brings up the ethernet interface automatically on boot (or on plugging in) and configures it via DHCP.

auto eth0
allow-hotplug eth0
iface eth0 inet dhcp

An entry to /etc/network/interfaces like the following sets up a static configuration:

iface eth0 inet static
 address 131.152.125.102
 netmask 255.255.255.0
 gateway 131.152.125.254
 dns-domain zoo.unibas.ch
 dns-nameservers 131.152.1.1 131.152.1.5

Using guessnet

guessnet is a script which may be used together with the ifup/ifdown network setup system, to configure network interfaces dependent on the network environment. It is possible to configure different IP addresses for every subnet an interface is used with.

Links
Example configuration with guessnet

The following /etc/network/interfaces entries using package guessnet try to set up ethernet interface eth0 with a static configuration (vesal), if it detects participation in the subnet where a certain host may be reached.

If the static configuration fails, DHCP is tried.

WLAN is configured as an access point in any case.

auto lo eth0
iface lo inet loopback

mapping eth0
  script /usr/sbin/guessnet-ifupdown
  # List of stanzas guessnet should scan for:
  #   use all but exclude wlan7
  map !wlan7
  # Profile to select when all tests fail
  map default: dhcp

# guessnet interface to detect the absence of cable
iface interface inet manual
  test missing-cable
  pre-up echo No link present.
  pre-up false

iface vesal inet static
  address 131.152.125.102
  netmask 255.255.255.0
  gateway 131.152.125.254
  dns-domain zoo.unibas.ch
  dns-nameservers 131.152.1.1 131.152.1.5
  # Check for one of these hosts:
  test peer address 131.152.125.254 mac 00:00:0c:07:aC:7d source 131.152.125.102

# possible guessnet default
iface dhcp inet dhcp

# get wlan up as an access point
#auto wlan7
allow-hotplug wlan7
iface wlan7 inet static
address 10.10.0.1
netmask 255.255.255.0
gateway 192.168.1.1
dns-domain erl.obsvermes.org
dns-nameservers 192.168.1.1
top

Starting services on boot time

Links

Using SysV init

The debian image used with OLinuXino A20 uses SysV-Init for starting and stopping services.

Start a service

service <init script> start
Stop a service

service <init script> stop
Enable a service

insserv <init script>
Disable a service

insserv -r <init script>
Writing my own service

The following init script /etc/init.d/sunxikbd_shutdown is working so far but can still afford improvement.

It is meant to start the program I wrote to react on a press of one of the "Android" buttons, the OLinuXino-A20-Micro has. The program will be described below under the paragraph Shutdown on GPIO Event.

Use update-rc.d to manage the runlevel symlinks in /etc/rcX.d. Carefully read it's man page as it is not obvious, how update-rc.d works.

Init script sunxikbd_shutdown
#! /bin/sh

### BEGIN INIT INFO
# Provides:   sunxikbd_shutdown
# Required-Start: $local_fs $remote_fs $syslog $keyboard-setup
# Required-Stop: $local_fs $remote_fs $syslog $keyboard-setup
# Should-Start:
# Should-Stop:
# Default-Start:  2 3 4 5
# Default-Stop:   0 1 6
# Short-Description: Shutdown on key event 
# Description: Shutdown on key event on "Android" sunxi keyboard key press.
#     
### END INIT INFO

PATH=/sbin:/bin:/usr/sbin:/usr/bin
DESC="Shutdown on android key event"
NAME=sunxikbd_shutdown
DAEMON_NAME=sxkbdact
DAEMON=/root/cvs/arm_boards/A20/sxkbdact
DAEMON_OPTS=
DAEMON_ARGS=
CMD="shutdown -h now"
DEVICE="/dev/input/event2"
KEY="KEY_ESC"
PIDFILE=/var/run/$NAME.pid
SCRIPTNAME=/etc/init.d/$NAME


test -f $DAEMON || exit 0

# Read configuration variable file if it is present
[ -r /etc/default/$NAME ] && . /etc/default/$NAME

# Load the VERBOSE setting and other rcS variables
. /lib/init/vars.sh

. /lib/lsb/init-functions

#
# Function that starts the daemon/service
#
do_start()
{
  # Return
  #   0 if daemon has been started
  #   1 if daemon was already running
  #   2 if daemon could not be started
  start-stop-daemon --start --quiet --pidfile $PIDFILE --exec $DAEMON --test > /dev/null \
    || return 1
  start-stop-daemon --start --quiet --pidfile $PIDFILE --exec $DAEMON -- \
    -D "$DEVICE" -x "$CMD" -c "$KEY" -f \
    || return 2
  # Add code here, if necessary, that waits for the process to be ready
  # to handle requests from services started subsequently which depend
  # on this one.  As a last resort, sleep for some time.
}

#
# Function that stops the daemon/service
#
do_stop()
{
  # Return
  #   0 if daemon has been stopped
  #   1 if daemon was already stopped
  #   2 if daemon could not be stopped
  #   other if a failure occurred
  start-stop-daemon --stop --quiet --retry=TERM/30/KILL/5 --pidfile $PIDFILE --name $DAEMON_NAME
  RETVAL="$?"
  [ "$RETVAL" = 2 ] && return 2
  # Wait for children to finish too if this is a daemon that forks
  # and if the daemon is only ever run from this initscript.
  # If the above conditions are not satisfied then add some other code
  # that waits for the process to drop all resources that could be
  # needed by services started subsequently.  A last resort is to
  # sleep for some time.
  start-stop-daemon --stop --quiet --oknodo --retry=0/30/KILL/5 --exec $DAEMON
  [ "$?" = 2 ] && return 2
  # Many daemons don't delete their pidfiles when they exit.
  rm -f $PIDFILE
  return "$RETVAL"
}


case "$1" in
  start)
    [ "$VERBOSE" != no ] && log_daemon_msg "Starting $DESC" "$NAME"
    do_start
    case "$?" in
      0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;;
      2) [ "$VERBOSE" != no ] && log_end_msg 1 ;;
    esac
    ;;

  stop)
    [ "$VERBOSE" != no ] && log_daemon_msg "Stopping $DESC" "$NAME"
    do_stop
    case "$?" in
      0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;;
      2) [ "$VERBOSE" != no ] && log_end_msg 1 ;;
    esac
    ;;

  status)
    status_of_proc "$DAEMON" "$DAEMON_NAME" && exit 0 || exit $?
    log_end_msg $?
    ;;

  *)
    #
    echo "Usage: $SCRIPTNAME {start|stop|status}" >&2
    exit 3
    ;;

esac

exit 0
top

WLAN Access Point

Some articles on the topic

Checking the type of the WLAN adapter

root@A20:~# lsusb
Bus 004 Device 006: ID 148f:5370 Ralink Technology, Corp. RT5370 Wireless Adapter

I have here a Ralink RT5370 USB Wireless Adapter, so the firmware-ralink package is needed.

Install packages

Make sure that all needed packages are installed:

aptitude install firmware-ralink hostapd iw wireless-tools

for dhcp (see isc-dhcpd setup below):
aptitude install isc-dhcp-server
alternativly:
aptitude install dnsmasq

dnsmasq additionally allows for DNS forwarding. See: Debian Wiki article.

Determine WLAN device name

Check which device name is assigned to the WLAN adapter:

root@A20:~# ip link list
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 16436 qdisc noqueue state UNKNOWN mode DEFAULT 
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UNKNOWN mode DEFAULT qlen 1000
    link/ether 02:85:05:02:05:6e brd ff:ff:ff:ff:ff:ff
3: tunl0: <NOARP> mtu 1480 qdisc noop state DOWN mode DEFAULT 
    link/ipip 0.0.0.0 brd 0.0.0.0
6: wlan7: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN mode DEFAULT qlen 1000
    link/ether 00:87:34:64:88:ef brd ff:ff:ff:ff:ff:ff

Set up WLAN network interfave

  root@A20:~# ifconfig wlan7 10.10.0.1/24 up

An entry in /etc/network/interfaces like the following, brings up the WLAN interface automatically on plugging in the USB WLAN adapter.

allow-hotplug wlan7
iface wlan7 inet static
address 10.10.0.1
netmask 255.255.255.0
gateway 192.168.1.1
dns-domain erl.obsvermes.org
dns-nameservers 192.168.1.1

Set up dhcpd

Setup a configuration for dhcpd in /etc/dhcp/dhcpd.conf

ddns-update-style none;
ignore client-updates;
authoritative;
option local-wpad code 252 = text;

# option definitions common to all supported networks...
option domain-name "erl.obsvermes.org";
option domain-name-servers 192.168.1.1;

default-lease-time 600;
max-lease-time 7200;

subnet 10.10.0.0 netmask 255.255.255.0 {
  range 10.10.0.16 10.10.0.31;
  option routers 10.10.0.1;
  option subnet-mask 255.255.255.0;
  option broadcast-address 10.10.0.255;
  option domain-name-servers 10.10.0.1;
  option time-offset 0;
  default-lease-time 1209600;
  max-lease-time 1814400;
}

Run dhcpd:

  root@A20:~# dhcpd -4 -cf /etc/dhcp/dhcpd.conf wlan7

Or, using the init script:

root@A20:~# /etc/init.d/isc-dhcp-server start

Using dnsmasq for DHCP and DNS

A better solution for DHCP than using dhcpd probably is dnsmasq as it also offers DNS forwarding.

The contents of /etc/dnsmasq.conf for my needs looks as follows:

interface=wlan7
# dhcp-range=[tag:<tag>[,tag:<tag>],][set:<tag>,]<start-addr>[,<end-addr>][,<mode>][,<netmask>[,<broadcast>]][,<lease time>]
dhcp-range=wlan7,10.10.0.16,10.10.0.31,12h
# dhcp-host=[<hwaddr>][,id:<client_id>|*][,set:<tag>][,<ipaddr>][,<hostname>][,<lease_time>][,ignore]
dhcp-host=48:02:2a:c5:ca:b4,d40a,10.10.0.2,cam2,infinite
dhcp-host=48:02:2a:c5:cc:7b,d40a,10.10.0.3,cam3,infinite

See dnsmasq (8)

Set up hostapd

Setup a configuration for hostapd in /etc/hostapd/hostapd.conf

interface=wlan7
driver=nl80211
country_code=CH
hw_mode=g
channel=11
ssid=dslrsrv
#bridge=br0
logger_syslog=-1
logger_syslog_level=0
logger_stdout=-1
logger_stdout_level=2
dump_file=/tmp/hostapd.dump
ctrl_interface=/var/run/hostapd
ctrl_interface_group=0
beacon_int=100
dtim_period=2
wpa=2
wpa_passphrase=secret pass phrase

Run hostapd:

root@A20:~# hostapd -dd /etc/hostapd/hostapd.conf

Or, using the init script:

In /etc/default/hostapd set

DAEMON_CONF="/etc/hostapd/hostapd.conf"
root@A20:~# /etc/init.d/hostapd start

Masquerading

To eanble access through the WLAN AP using NAT (masquerading) to the internet on the wired ethernet adapter, set in in /etc/sysctl.conf:

net.ipv4.ip_forward = 1

Additionally an iptables rule to route the packets from WLAN to the external ethernet is needed.
Most easily this is probaly done with one of the firewalling packages like arno-iptables-firewall.

aptitude install arno-iptables-firewall

arno-iptables-firewall is configured with the file /etc/arno-iptables-firewall/firewall.conf, which at least needs the following entries:

EXT_IF="eth0"
INT_IF="wlan7"
INTERNAL_NET="10.10.0.0/24"
NAT=1
OPEN_TCP="ssh http"
DENY_UDP_NOLOG="67 68 137 138 631 8612 17500 22936 57621"
Links

Making everything started on boot time

top

Spindown Idling Harddisk

Links

Manually set harddisk spindown_time

Set the harddrive spindown timeout:

hdparm -S 12 /dev/sda

A value of zero means "timeouts are disabled": the device will not automatically enter standby mode.
Values from 1 to 240 specify multiples of 5 seconds, yielding timeouts from 5 seconds to 20 minutes.
Values from 241 to 251 specify from 1 to 11 units of 30 minutes, yielding timeouts from 30 minutes to 5.5 hours.
A value of 252 signifies a timeout of 21 minutes.
A value of 253 sets a vendor-defined timeout period between 8 and 12 hours,
and the value 254 is reserved.
(see man 8 hdparm)

Checking drive state:

hdparm -C /dev/sda

/etc/hdparm.conf

A block like the following in /etc/hdparm.conf should setup the advanced power management for /dev/sda to a mode with spindown and a spindown timeout of 1 minute.

/dev/sda {
  apm = 127
  spindown_time = 12 # 12*5s: 1 min
}
Issues

My drive (a Western Digital 320 GB WD3200BJKT-00F4T0) spins down after a timeout of around 15 minutes, no matter which spindown_time is set.

When using apm 127 it spins down within a few seconds.

The reason for these issues is not yet clear, maybe another power management utility is interacting (pm-utils?).

Tools

The following is a tiny bash script which prints the time when the harddisk spins down.

echo -n "/dev/sda touch  : "; date; touch /hd/touch &>/dev/null; sync; \
while [ 1 ]; do re=`hdparm -C /dev/sda`; pat=' standby'; \
  if [[ $re =~ $pat ]]; then echo -n "/dev/sda standby: "; date; break; fi; sleep 5; \
done
top

SATA Cable Set

SATA Cable Set from Olimex

To connect and power a SATA disk, Olimex sells a cable set. It consists of a short SATA cable and a SATA power cable with a JST connector fitting the socket intended for supplying 5V to a disk.

Watch out: The power cable from Olimex connects the red wire at the JST to the inner black wire on the SATA side, and the black wire at the JST to the red wire on the SATA side.

If you want to modify the SATA power cable or want to make your own check polarity and don't rely on the usual wire color coding for this.

top

Shutdown on GPIO Event

Links

Using "Android"-Buttons

Make shure the module /lib/modules/3.4.xx+/kernel/drivers/input/keyboard/sun4i-keyboard.ko is loaded:

modprobe sun4i-keyboard

Use evtest (debian package) tool to print input events.
evtest source

Make sun4i-keyboard load on boot

Add it to /etc/modules:

i2c-sunxi
lcd
sunxi-codec
#sun4i-ts
sun4i-keyboard
hdmi

Programming a Daemon to do a Shutdown on Input Event

Links
Shutdown Daemon Implementation

I wrote a little program which may react on events of the linux input system and may execute an arbitrary program on a detected event. Source may be downloaded here.

An init script starts the daemon on boot.

top

GPIO Interrupts

Links

top

Resizing root Partition on SD Card

Links

Growing root fs Using cfdisk and resize2fs

As the original Debian image from Olimex has a size of 4GB but I am using a 16GB SD card, I want to grow the root partition to make the SD card space fully usable.

It is possible to do this even with the partition mounted as root file system, but the start of the new root partition needs to be aligned with the old root partition!

Use cfdisk to list current partition data of the SD card:

root@A20:~# cfdisk -Ps /dev/mmcblk0
Partition Table for /dev/mmcblk0

               First       Last
 # Type       Sector      Sector   Offset    Length   Filesystem Type (ID) Flag
-- ------- ----------- ----------- ------ ----------- -------------------- ----
   Pri/Log           0        2047      0#       2048 Free Space           None
 1 Primary        2048       34815      0       32768 Linux (83)           None
 2 Primary       34816     7774207      0     7739392 Linux (83)           None
   Pri/Log     7774208    30881791      0    23107584 Free Space           None

After writing the 4GB image to the 16GB SD card, use cfdisk to delete the partition with the root file system and all partitions listed after the one with the root fs, if there are some.

Still in cfdisk, create a new partition using all available space (or less, if you would like to create other partitions, e.g. swap).

reboot, and run

resize2fs /dev/mmcblk0p2

Shrink down an Image

Shrinking an image produced by dd command involves:

Example:

losetup -P /dev/loop0 bootable_card.img   # attach image file to /dev/loop0
e2fsck -f /dev/loop0p1                         # check/repair file system for clean state
resize2fs -M /dev/loop0p1                      # resize (shrink) file system as much as possible
gparted /dev/loop0                             # use GUI partitioner to shrink partition

Using the GUI gparted, shrink the partition as much as possible.

sfdisk -d bootable_card.img

sfdisk reports the sizes of the partition contained in the image file:

# partition table of bootable_card.img
unit: sectors

bootable_card.img1 : start=     2048, size= 15196160, Id=83
bootable_card.img2 : start=        0, size=        0, Id= 0
bootable_card.img3 : start=        0, size=        0, Id= 0
bootable_card.img4 : start=        0, size=        0, Id= 0

Truncate the image file to the size needed to contain the complete partitions, i.e. 15196160 plus one sectors, sector size is 512 bytes.

truncate --size=$(( (15196160+1)*512)) bootable_card.img
losetup -d losetup -d /dev/loop0               # detach image file from /dev/loop0

see http://softwarebakery.com/shrinking-images-on-linux

Unlike growing, shrinking of filesystem is not possible online. So the filesystem needs to be unmounted to be shrinken.

top

GPS Module on UEXT1

Introdution

A20-OLinuXino-Micro with GPS Module An Adafruit Ultimate GPS Breakout may be directly wired to the UEXT1 (or 2) connector of the A20-OLinuXino-Micro. The UART6, which is wired to the UEXT1 connector seems to correspond to the /dev/ttyS1 device and UART7 is wired to the UEXT2 connector corresponding to /dev/ttyS2 device in the debian linux.

Packages to install

aptitude install gpsd gpsd-clients ckermit

The terminal program ckermit is used to test the serial output of the GPS module on /dev/ttyS1 for UEXT1.

Wiring of GPS to UEXT1

GPS Module UEXT1 Pin# UEXT1 Pin Function UEXT2 Pin# UEXT2 Pin Function
VIN 1 3.3V 1 3.3V
GND 2 GND 2 GND
RX 3 UART6-TX 3 UART7-TX
TX 4 UART6-RX 4 UART7-RX
UEXT Connector Pin out

Running Tests

When powered, the GPS module's LED should blink in a one second interval as long as it has no fix yet and blinks once every 15 seconds, when a fix is found.

Running

kermit -Y -l /dev/ttyS1 -b 9600 -p n -c

does not work, as kermit needs to be told to ignore the Carrier Detect signal by a command SET CARRIER-WATCH OFF and I didn't find out, how to do this on the command line (-C "set carrier-watch off" does not work).

Instead create a ~/.kermrc file with the following contents:

set line /dev/ttyS1
set speed 9600
set carrier-watch off
set parity none
set stop-bits 1
set modem none
set prompt ttyS1>

And run

kermit -c

As a result, you should see the GPS module spitting out NMEA data packets as below:

$GPRMC,053006.799,V,,,,,0.00,0.00,060180,,,N*45
$GPVTG,0.00,T,,M,0.00,N,0.00,K,N*32
$GPGGA,053007.799,,,,,0,0,,,M,,M,,*4E
$GPGSA,A,1,,,,,,,,,,,,,,,*1E

Running gpsd and connect to it

Run the the gpsd (-N = do not daemonize)

gpsd -N /dev/ttyS1

Run a client to gpsd, like:

cgps -s -u m

producing an output like the following:

┌───────────────────────────────────────────┐┌─────────────────────────────────┐
│    Time:       2014-05-27T20:00:32.000Z   ││PRN:   Elev:  Azim:  SNR:  Used: │
│    Latitude:    47.568911 N               ││  16    71    238    30      Y   │
│    Longitude:    7.603869 E               ││  27    56    298    18      Y   │
│    Altitude:   328.8 m                    ││  21    50    061    21      Y   │
│    Speed:      0.8 kph                    ││  18    47    105    44      Y   │
│    Heading:    294.4 deg (true)           ││  22    35    157    48      Y   │
│    Climb:      6.0 m/min                  ││   3    35    294    17      Y   │
│    Status:     3D FIX (24 secs)           ││  33    30    210    32      N   │
│    Longitude Err:   +/- 3 m               ││  19    24    286    22      N   │
│    Latitude Err:    +/- 4 m               ││   7    12    323    24      N   │
│    Altitude Err:    +/- 18 m              ││  15    05    062    14      N   │
│    Course Err:      n/a                   ││  29    03    100    17      N   │
│    Speed Err:       +/- 32 kph            ││   8    02    344    24      N   │
│    Time offset:     0.532                 ││  26    02    030    00      N   │
│    Grid Square:     JN37tn                ││                                 │
└───────────────────────────────────────────┘└─────────────────────────────────┘
top

Links

top
line
This site maintained by:
lukas.zimmermann@unibas.ch
My public PGP key
last updated: 2014-12-02 Valid CSS! Valid XHTML 1.0 Strict