Building and setup Ångström distribution from scratch

Host platform: Desktop 10.10 Target platform: Olimex CS-E9302 Development board

1. Overview Ångström was started by a small group of people who worked on the OpenEmbedded, OpenZaurus and OpenSimpad projects to unify their effort to make a stable and userfriendly distribution for embedded devices like handhelds, set top boxes and network-attached storage devices and more. All Ångström binaries are built using OpenEmbedded. OpenEmbedded offers a best-in-class cross-compile environment. It allows developers to create a complete Distribution for embedded systems. Some of the OpenEmbedded advantages include: . support for many hardware architectures . multiple releases for those architectures . tools for speeding up the process of recreating the base after changes have been made . easy to customize . runs on any . cross-compiles 1000's of packages including GTK+, , the X Windows system, Mono, Java, and about anything else you might ever need Bitbake handles the parsing and execution of the data files. The data itself is of various types; recipes which give details about particular pieces of , class data which is an abstraction of common build information (e.g. how to build a ) and configuration data for machines, policy decisions, etc., which acts as a glue and binds everything together. Bitbake knows how to combine multiple data sources together, each data source being referred to as a layer. Bitbake is responsible for parsing the metadata, generating a list of tasks from it and then executing them. The most common usage is packagename where packagename is the name of the package you wish to build (from now on called the target). This often equates to the first part of a .bb filename, so to run the simple- package_1.2.3.bb file, you might type bitbake simple-package. Several different versions of simple-package might exist and bitbake will choose the one selected by the distribution configuration. Bitbake will also try to execute any dependent tasks first so before building simple-package it would build a and glibc if not already built.

The Metadata (recipes) are .bb files that are usually referred to as 'recipes'. In general, a recipe contains information about a single piece of software such as where to download the source, any patches that are needed, any special configuration options, how to compile the source files and how to package the compiled output. Class (.bbclass) files contain information which is useful to share between metadata files. An example is the autotools class which contains the common settings that any application using autotools would use. The configuration (.conf) files define various configuration variables which govern what Poky does. These are split into several areas, such as machine configuration options, distribution configuration options, compiler tuning options, general common configuration and user configuration (local.conf).

2. Setup OpenEmbedded toolchain

First of all you may want to install some useful packages(if you haven’t installed them already). Next commands have to be executed as root user.

apt-get install nano mc openssh-server lrzsz htop

Now you can work on SSH terminal. Required software for OpenEmbedded can be found at OE host distributions wiki.

Check that /bin/sh (ls -l /bin/sh) is not symbolically linked to dash. "dash" is a POSIX compliant shell that is much smaller than "bash" -- however some broken shell scripts still make use of bash extensions while calling into /bin/sh. To work around this issue call

dpkg-reconfigure dash and select No when it asks you to install dash as /bin/sh.

If you don’t want to use packages from repository, you can build them manually from source. For this purpose check all OpenEmbedded Required Software or use special script for Ubuntu distribution I prefer to use packages from Ubuntu universe repository. So let’s start with installing of necessary packages:

apt-get install sed wget cvs subversion -core coreutils unzip texi2html texinfo docbook-utils gawk python-pysqlite2 diffstat help2man make gcc build-essential g++ desktop-file-utils chrpath

Then we have to install some supplementary packages:

apt-get install libxml2-utils xmlto python-psyco

OPTIONAL: following packages and their dependencies need to be installed in order to build the bitbake documentation (warning: over 160MB of installed packages).

apt-get install docbook

Building and setup Ångström distribution from scratch page 2 of 54

This package is necessary to build some packages (in particular the esound documentation needs it).

NOTE: If you are building in container (LXC/OpenVZ) check presence of loadkeys tool (/bin/loadkeys). If there is no loadkeys, install console- tools package.

apt-get install console-tools

Finally we have to install automake and autoconf packages

apt-get install automake autoconf autoconf2.13 autoconf-archive gnu-standards autoconf-doc libtool gettext

Now we have all needed packages for using OpenEmbedded toolchain.

3. Setup Ångström environment

First we have to create directory where to setup an environment. My choise is /angstrom in root directory, but you are free to use whatever you want

mkdir /angstrom

We have to change owner of directory – all other commands have to be executed as non root user. In this case I’ll use user named user

chown user.user /angstrom

Now login as non root user:

su – user

Building Ångström includes a setup script - go to the the setup-scripts repository and clone it, the URLS are on top of that page. You should end up doing something like: git clone git://git.angstrom-distribution.org/setup-scripts /angstrom

Next step is to define our target machine and start updating process

MACHINE=cs-e9302 ./oebb.sh update

After executing of script – OpenEmbedded and BitBake will be obtained. Also script creates a environment file with all needed path variables. This file is stored in user home directory. It’s recommended to execute this in user profile. Edit file ~/.bashrc.

nano ~/.bashrc and add following line in the end of file:

. ~/.oe/environment-2008

Restart your terminal. Check if everything is fine by typing:

bitbake --version

Building and setup Ångström distribution from scratch page 3 of 54

You should see something like

BitBake Build Tool Core version 1.12.0, bitbake version 1.12.0

To complete process we have to run first building of package(image) using the Angstrom script. I choose to build nano package

MACHINE=cs-e9302 ./oebb.sh bitbake nano

After a wait we already have the basic structure. It should looks like picture below:

4. Custom bbfile repository

In next steps we will make custom bbfile repository in order to make modifications in distributions and recipes without any change in OpenEmbedded repository. OpenEmbedded, Bitbake and packages sources are stored in /angstrom/sources directory. Let's create our custom repository

mkdir /angstrom/sources/local bbfile collections exist to allow the user to have multiple repositories of bbfiles that contain the same exact package. Edit the configuration file

nano /angstrom/build/conf/local.conf and add the following in the end of file

BBFILES =+ "/angstrom/sources/local/recipes/*/*.bb" BBFILE_COLLECTIONS = "local oe" BBFILE_PATTERN_local = "/angstrom/sources/local" BBFILE_PRIORITY_local = "5" BBFILE_PATTERN_oe = "/angstrom/sources/" BBFILE_PRIORITY_oe = "0" BBPATH =. "${BBFILE_PATTERN_local}:"

I suggest to comment out the following line

INHERIT += "rm_work"

This option will keep all temporary files in process of recipes building.

Another option for custom bbfile repositories is bitbake layers. bitbake has a powerful mechanism called layers which provides a way to handle this

Building and setup Ångström distribution from scratch page 4 of 54 extension in a fully supported and non-invasive fashion. It is easy to add the layers path to the BBLAYERS variable in your bblayers.conf.

# LAYER_CONF_VERSION is increased each time build/conf/bblayers.conf # changes incompatibly LCONF_VERSION = "1"

BBFILES ?= ""

# Add your overlay location to BBLAYERS # Make sure to have a conf/layers.conf in there BBLAYERS = " \ /angstrom/sources/local \ /angstrom/sources/openembedded \ "

Bitbake parses the conf/layer.conf of each of the layers in BBLAYERS to add the layers packages, classes and configuration. To create your own layer, independent of the main OpenEmbedded repository, you need only create a directory with a conf/layer.conf file and add the directory to your bblayers.conf.

BBFILES =+ "${LAYERDIR}/recipes/*/*.bb" BBPATH =. "${LAYERDIR}:" BBFILE_COLLECTIONS =+ "local" BBFILE_PRIORITY_local = "10" BBFILE_PATTERN_local = "^${LAYERDIR}/"

5. Building linux kernel

We are going to build the latest version of linux kernel (2.6.37) for cs- e9302 target platform. However our machine configuration couldn't be found at OpenEmbedded linux recipes for latest kernel version

Building and setup Ångström distribution from scratch page 5 of 54

Next few steps demonstrate process of configuring and building latest linux kernel in Angstrom distribution. First build the kernel normally with bitbake by running this command:

bitbake virtual/kernel

This will create a source directory in /angstrom/build/tmp- angstrom_2008_1/work/cs-e9302-angstrom-linux-gnueabi/. In this case it will be /angstrom/build/tmp-angstrom_2008_1/work/cs-e9302-angstrom-linux- gnueabi/linux-2.6.24-r46/

Add the following file in your build configuration directory

nano /angstrom/build/conf/site.conf and add preferred version of linux kernel

PREFERRED_VERSION_linux ?= "2.6.37"

Next we will add some patches to the kernel. We want ADC and LED driver support which can't be found in main stream of linux kernel. All patches will be added in the following directory

/angstrom/sources/local/recipes/linux/linux-2.6.37

Bitbake must know for our patches, so we have to edit file

/angstrom/sources/local/recipes/linux/linux_2.6.37.bb and add the following lines

SRC_URI_append_cs-e9302 = " \ file://ep93xx_adc_driver. \ file://ep93xx_adc_driver_my.patch \ file://ep93xx_leds.patch \ " ep93xx_adc_driver.patch could be downloaded from here. However there is some bugs and incompatibility with our linux kernel version. Next ep93xx_adc_driver_my.patch fixes these problems

diff -uNr linux-2.6.37.org/arch/arm/mach-ep93xx/adc.c linux-2.6.37/arch/arm/mach-ep93xx/adc.c --- linux-2.6.37.org/arch/arm/mach-ep93xx/adc.c 2011-08-27 09:56:00.000000000 -0400 +++ linux-2.6.37/arch/arm/mach-ep93xx/adc.c 2011-08-27 09:54:57.000000000 -0400 @@ -38,6 +38,8 @@ #include #include

+#include + #include

static inline void ep93xx_adc_set_reg(void __iomem *reg, diff -uNr linux-2.6.37.org/arch/arm/mach-ep93xx/edb93xx.c linux-2.6.37/arch/arm/mach- ep93xx/edb93xx.c --- linux-2.6.37.org/arch/arm/mach-ep93xx/edb93xx.c 2011-08-27 09:56:00.000000000 -0400 +++ linux-2.6.37/arch/arm/mach-ep93xx/edb93xx.c 2011-08-27 09:50:57.000000000 -0400 @@ -33,9 +33,13 @@

#include

+#include +#include + #include

Building and setup Ångström distribution from scratch page 6 of 54

#include

+static struct ep93xx_hwmon_data ts72xx_hwmon_info;

static void __init edb93xx_register_flash(void) { @@ -45,6 +49,8 @@ } else { ep93xx_register_flash(2, EP93XX_CS6_PHYS_BASE, SZ_16M); } + + ep93xx_hwmon_device.dev.platform_data = &ts72xx_hwmon_info; }

static struct ep93xx_eth_data __initdata edb93xx_eth_data = { @@ -110,6 +116,71 @@ } }

+#define TS72XX_ADC0 (ADC_SW_YM_IN | ADC_SW_APWR_REF) +#define TS72XX_ADC1 (ADC_SW_SXP_IN | ADC_SW_APWR_REF) +#define TS72XX_ADC2 (ADC_SW_SXM_IN | ADC_SW_APWR_REF) +#define TS72XX_ADC3 (ADC_SW_SYP_IN | ADC_SW_APWR_REF) +#define TS72XX_ADC4 (ADC_SW_SYM_IN | ADC_SW_APWR_REF) + +// TODO: board dependant +// TS-7200: ADC0, ADC4 +// TS-7250: ADC0 to ADC4 +// TS-7260: Vin, 5V_104, ADC2, Vcore, ADC4 +// TS-7300: 5V, 1.2V, ADC2, 1.8V, ADC4 + +// 0V gives 0, 3.3V gives c. 50000 +// TODO: self calibrate by using VBAT and Load resistor switches +static struct ep93xx_hwmon_data ts72xx_hwmon_info = { + /* POWER_IN*10K/150K (4.5-20V) */ + .in[0] = &(struct ep93xx_hwmon_chcfg) { + .name = "ts72xx-vin", + .channel = TS72XX_ADC0, + .mult = 33*(15+1), + .div = 500*1, + }, + /* PC104_5V*10K/54.9K (5V) */ + .in[1] = &(struct ep93xx_hwmon_chcfg) { + .name = "ts72xx-v5", + .channel = TS72XX_ADC4, + .mult = 33*(549+100), + .div = 500*100, + }, + /* Vcore (1.8V) */ + .in[2] = &(struct ep93xx_hwmon_chcfg) { + .name = "ts72xx-vcore", + .channel = TS72XX_ADC2, + .mult = 33*1, + .div = 500*1, + }, + /* User ADC on DIO2.8 (0-3.3V) */ + .in[3] = &(struct ep93xx_hwmon_chcfg) { + .name = "ts72xx-dio2.8", + .channel = TS72XX_ADC3, + .mult = 33*1, + .div = 500*1, + }, + /* User ADC on DIO2.10 (0-3.3V) */ + .in[4] = &(struct ep93xx_hwmon_chcfg) { + .name = "ts72xx-dio2.10", + .channel = TS72XX_ADC1, + .mult = 33*1, + .div = 500*1, + }, + /* EP93XX.VBAT (1.8V) */ + .in[5] = &(struct ep93xx_hwmon_chcfg) { + .name = "ep93xx-vbat", + .channel = ADC_SW_VBAT_IN|ADC_SW_APWR_REF, + .mult = 33*1, + .div = 500*1, + }, + /* EP93XX.DAC (?) */ + .in[6] = &(struct ep93xx_hwmon_chcfg) { + .name = "ep93xx-vdac", Building and setup Ångström distribution from scratch page 7 of 54

+ .channel = ADC_SW_DAC_IN|ADC_SW_APWR_REF, + .mult = 33*1, + .div = 500*1, + }, +};

static void __init edb93xx_init_machine(void) { @@ -118,6 +189,8 @@ ep93xx_register_eth(&edb93xx_eth_data, 1); edb93xx_register_i2c(); edb93xx_register_pwm(); + platform_device_register(&ep93xx_analog_device); + platform_device_register(&ep93xx_hwmon_device); }

diff -uNr linux-2.6.37.org/arch/arm/mach-ep93xx/Kconfig linux-2.6.37/arch/arm/mach- ep93xx/Kconfig --- linux-2.6.37.org/arch/arm/mach-ep93xx/Kconfig 2011-08-27 09:56:00.000000000 -0400 +++ linux-2.6.37/arch/arm/mach-ep93xx/Kconfig 2011-08-27 09:53:14.000000000 -0400 @@ -45,6 +45,11 @@

endchoice

+config EP93XX_ADC + bool "Support ADC" + help + Say 'Y' here if you want your kernel to support the ADC. + config MACH_ADSSPHERE bool "Support ADS Sphere" depends on EP93XX_SDCE3_SYNC_PHYS_OFFSET diff -uNr linux-2.6.37.org/drivers/hwmon/ep93xx-hwmon.c linux-2.6.37/drivers/hwmon/ep93xx- hwmon.c --- linux-2.6.37.org/drivers/hwmon/ep93xx-hwmon.c 2011-08-27 09:56:23.000000000 -0400 +++ linux-2.6.37/drivers/hwmon/ep93xx-hwmon.c 2011-08-27 09:57:30.000000000 -0400 @@ -30,6 +30,8 @@ #include #include

+#include + #include #include

@@ -246,7 +248,7 @@ attr->index = channel; attr->dev_attr.attr.name = attrs->in_name; attr->dev_attr.attr.mode = S_IRUGO; - attr->dev_attr.attr.owner = THIS_MODULE; + //attr->dev_attr.attr.owner = THIS_MODULE; attr->dev_attr.show = ep93xx_hwmon_ch_show;

ret = device_create_file(dev, &attr->dev_attr); @@ -264,7 +266,7 @@ attr->index = channel; attr->dev_attr.attr.name = attrs->label_name; attr->dev_attr.attr.mode = S_IRUGO; - attr->dev_attr.attr.owner = THIS_MODULE; + //attr->dev_attr.attr.owner = THIS_MODULE; attr->dev_attr.show = ep93xx_hwmon_label_show;

ret = device_create_file(dev, &attr->dev_attr); @@ -308,7 +310,7 @@

platform_set_drvdata(dev, hwmon);

- init_MUTEX(&hwmon->lock); + sema_init(&hwmon->lock, 1); //init_MUTEX(&hwmon->lock);

/* Register with the core ADC driver. */

Building and setup Ångström distribution from scratch page 8 of 54

The last patch (ep93xx_leds.patch) adds LED driver support to the kernel. It's based on this patch, but with fixes to the incompatibly of linux kernel version

diff -uNr linux-2.6.37.org/arch/arm/mach-ep93xx/core.c linux-2.6.37/arch/arm/mach- ep93xx/core.c --- linux-2.6.37.org/arch/arm/mach-ep93xx/core.c 2011-08-28 04:05:15.000000000 -0400 +++ linux-2.6.37/arch/arm/mach-ep93xx/core.c 2011-08-28 01:46:27.000000000 -0400 @@ -41,6 +41,7 @@

#include #include +#include

#include

@@ -170,6 +171,109 @@ .offset = ep93xx_gettimeoffset, };

+/************************************************************************* + * GPIO handling for EP93xx + *************************************************************************/ +static unsigned char gpio_int_unmasked[3]; +static unsigned char gpio_int_enabled[3]; +static unsigned char gpio_int_type1[3]; +static unsigned char gpio_int_type2[3]; + +static void update_gpio_int_params(int abf) +{ + if (abf == 0) { + __raw_writeb(0, EP93XX_GPIO_A_INT_ENABLE); + __raw_writeb(gpio_int_type2[0], EP93XX_GPIO_A_INT_TYPE2); + __raw_writeb(gpio_int_type1[0], EP93XX_GPIO_A_INT_TYPE1); + __raw_writeb(gpio_int_unmasked[0] & gpio_int_enabled[0], EP93XX_GPIO_A_INT_ENABLE); + } else if (abf == 1) { + __raw_writeb(0, EP93XX_GPIO_B_INT_ENABLE); + __raw_writeb(gpio_int_type2[1], EP93XX_GPIO_B_INT_TYPE2); + __raw_writeb(gpio_int_type1[1], EP93XX_GPIO_B_INT_TYPE1); + __raw_writeb(gpio_int_unmasked[1] & gpio_int_enabled[1], EP93XX_GPIO_B_INT_ENABLE); + } else if (abf == 2) { + __raw_writeb(0, EP93XX_GPIO_F_INT_ENABLE); + __raw_writeb(gpio_int_type2[2], EP93XX_GPIO_F_INT_TYPE2); + __raw_writeb(gpio_int_type1[2], EP93XX_GPIO_F_INT_TYPE1); + __raw_writeb(gpio_int_unmasked[2] & gpio_int_enabled[2], EP93XX_GPIO_F_INT_ENABLE); + } else { + BUG(); + } +} + + +static unsigned char data_register_offset[8] = { + 0x00, 0x04, 0x08, 0x0c, 0x20, 0x30, 0x38, 0x40, +}; + +static unsigned char data_direction_register_offset[8] = { + 0x10, 0x14, 0x18, 0x1c, 0x24, 0x34, 0x3c, 0x44, +}; + +void gpio_line_config(int line, int direction) +{ + unsigned int data_direction_register; + unsigned long flags; + unsigned char v; + + data_direction_register = + EP93XX_GPIO_REG(data_direction_register_offset[line >> 3]); + + local_irq_save(flags); + if (direction == GPIO_OUT) { + if (line >= 0 && line < 16) { + /* Port A/B. */ + gpio_int_unmasked[line >> 3] &= ~(1 << (line & 7)); + update_gpio_int_params(line >> 3); + } else if (line >= 40 && line < 48) {

Building and setup Ångström distribution from scratch page 9 of 54

+ /* Port F. */ + gpio_int_unmasked[2] &= ~(1 << (line & 7)); + update_gpio_int_params(2); + } + + v = __raw_readb(data_direction_register); + v |= 1 << (line & 7); + __raw_writeb(v, data_direction_register); + } else if (direction == GPIO_IN) { + v = __raw_readb(data_direction_register); + v &= ~(1 << (line & 7)); + __raw_writeb(v, data_direction_register); + } + local_irq_restore(flags); +} +EXPORT_SYMBOL(gpio_line_config); + +int gpio_line_get(int line) +{ + unsigned int data_register; + + data_register = EP93XX_GPIO_REG(data_register_offset[line >> 3]); + + return !!(__raw_readb(data_register) & (1 << (line & 7))); +} +EXPORT_SYMBOL(gpio_line_get); + +void gpio_line_set(int line, int value) +{ + unsigned int data_register; + unsigned long flags; + unsigned char v; + + data_register = EP93XX_GPIO_REG(data_register_offset[line >> 3]); + + local_irq_save(flags); + if (value == EP93XX_GPIO_HIGH) { + v = __raw_readb(data_register); + v |= 1 << (line & 7); + __raw_writeb(v, data_register); + } else if (value == EP93XX_GPIO_LOW) { + v = __raw_readb(data_register); + v &= ~(1 << (line & 7)); + __raw_writeb(v, data_register); + } + local_irq_restore(flags); +} +EXPORT_SYMBOL(gpio_line_set);

/************************************************************************* * EP93xx IRQ handling @@ -897,6 +1001,14 @@ platform_device_register(&ep93xx_pcm_device); }

+/************************************************************************* + * EP93xx leds peripheral handling + *************************************************************************/ +static struct platform_device ep93xx_led_device = { + .name = "ep93xx-led", + .id = -1, +}; + extern void ep93xx_gpio_init(void);

void __init ep93xx_init_devices(void) @@ -913,4 +1025,5 @@ platform_device_register(&ep93xx_rtc_device); platform_device_register(&ep93xx_ohci_device); platform_device_register(&ep93xx_leds); + platform_device_register(&ep93xx_led_device); } diff -uNr linux-2.6.37.org/arch/arm/mach-ep93xx/include/mach/ep93xx-regs.h linux- 2.6.37/arch/arm/mach-ep93xx/include/mach/ep93xx-regs.h --- linux-2.6.37.org/arch/arm/mach-ep93xx/include/mach/ep93xx-regs.h 2011-08-28 04:05:15.000000000 -0400 +++ linux-2.6.37/arch/arm/mach-ep93xx/include/mach/ep93xx-regs.h 2011-08-28 01:50:12.000000000 -0400 @@ -105,6 +105,19 @@ Building and setup Ångström distribution from scratch page 10 of 54

#define EP93XX_GPIO_B_INT_STATUS EP93XX_GPIO_REG(0xbc) #define EP93XX_GPIO_EEDRIVE EP93XX_GPIO_REG(0xc8)

+#define EP93XX_GPIO_F_INT_TYPE1 EP93XX_GPIO_REG(0x4c) +#define EP93XX_GPIO_F_INT_TYPE2 EP93XX_GPIO_REG(0x50) +#define EP93XX_GPIO_F_INT_ACK EP93XX_GPIO_REG(0x54) +#define EP93XX_GPIO_F_INT_ENABLE EP93XX_GPIO_REG(0x58) +#define EP93XX_GPIO_A_INT_TYPE1 EP93XX_GPIO_REG(0x90) +#define EP93XX_GPIO_A_INT_TYPE2 EP93XX_GPIO_REG(0x94) +#define EP93XX_GPIO_A_INT_ACK EP93XX_GPIO_REG(0x98) +#define EP93XX_GPIO_A_INT_ENABLE EP93XX_GPIO_REG(0x9c) +#define EP93XX_GPIO_B_INT_TYPE1 EP93XX_GPIO_REG(0xac) +#define EP93XX_GPIO_B_INT_TYPE2 EP93XX_GPIO_REG(0xb0) +#define EP93XX_GPIO_B_INT_ACK EP93XX_GPIO_REG(0xb4) +#define EP93XX_GPIO_B_INT_ENABLE EP93XX_GPIO_REG(0xb8) + #define EP93XX_AAC_PHYS_BASE EP93XX_APB_PHYS(0x00080000) #define EP93XX_AAC_BASE EP93XX_APB_IOMEM(0x00080000)

diff -uNr linux-2.6.37.org/arch/arm/mach-ep93xx/include/mach/gpio.h linux- 2.6.37/arch/arm/mach-ep93xx/include/mach/gpio.h --- linux-2.6.37.org/arch/arm/mach-ep93xx/include/mach/gpio.h 2011-08-28 04:05:15.000000000 -0400 +++ linux-2.6.37/arch/arm/mach-ep93xx/include/mach/gpio.h 2011-08-27 19:12:03.000000000 - 0400 @@ -5,6 +5,16 @@ #ifndef __ASM_ARCH_GPIO_H #define __ASM_ARCH_GPIO_H

+#define GPIO_IN 0 +#define GPIO_OUT 1 + +#define EP93XX_GPIO_LOW 0 +#define EP93XX_GPIO_HIGH 1 + +extern void gpio_line_config(int line, int direction); +extern int gpio_line_get(int line); +extern void gpio_line_set(int line, int value); + /* GPIO port A. */ #define EP93XX_GPIO_LINE_A(x) ((x) + 0) #define EP93XX_GPIO_LINE_EGPIO0 EP93XX_GPIO_LINE_A(0) diff -uNr linux-2.6.37.org/drivers/leds/Kconfig linux-2.6.37/drivers/leds/Kconfig --- linux-2.6.37.org/drivers/leds/Kconfig 2011-08-28 04:05:52.000000000 -0400 +++ linux-2.6.37/drivers/leds/Kconfig 2011-08-27 04:49:38.000000000 -0400 @@ -369,6 +369,12 @@ and 5Big Network v2 boards. The LEDs are wired to a CPLD and are controlled through a GPIO extension bus.

+config LEDS_EP93XX + tristate "LED Support for Cirrus Logic EP93xx" + depends on LEDS_CLASS && ARCH_EP93XX + help + This option enables support for the Cirrus Logic EP93xx based boards. + config LEDS_TRIGGERS bool "LED Trigger support" depends on LEDS_CLASS diff -uNr linux-2.6.37.org/drivers/leds/leds-ep93xx.c linux-2.6.37/drivers/leds/leds-ep93xx.c --- linux-2.6.37.org/drivers/leds/leds-ep93xx.c 1969-12-31 19:00:00.000000000 -0500 +++ linux-2.6.37/drivers/leds/leds-ep93xx.c 2011-08-28 01:35:20.000000000 -0400 @@ -0,0 +1,119 @@ +/* + * LEDs driver for Cirrus Logic EP93xx + * + * Author: Petr Stetiar + * + * Based on leds-corgi.c by Richard Purdie + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + */ + +#include +#include +#include +#include Building and setup Ångström distribution from scratch page 11 of 54

+#include +#include +#include + +static void ep93xx_green_led_set(struct led_classdev *led_cdev, enum led_brightness value) +{ + if (value) + gpio_line_set(EP93XX_GPIO_LINE_GRLED, EP93XX_GPIO_HIGH); + else + gpio_line_set(EP93XX_GPIO_LINE_GRLED, EP93XX_GPIO_LOW); +} + +static void ep93xx_red_led_set(struct led_classdev *led_cdev, enum led_brightness value) +{ + if (value) + gpio_line_set(EP93XX_GPIO_LINE_RDLED, EP93XX_GPIO_HIGH); + else + gpio_line_set(EP93XX_GPIO_LINE_RDLED, EP93XX_GPIO_LOW); +} + + +static struct led_classdev ep93xx_green_led = { + .name = "ep93xx:green", + .default_trigger = "none", + .brightness_set = ep93xx_green_led_set, +}; + +static struct led_classdev ep93xx_red_led = { + .name = "ep93xx:red", + .default_trigger = "heartbeat", + .brightness_set = ep93xx_red_led_set, +}; + +#ifdef CONFIG_PM +static int ep93xx_led_suspend(struct platform_device *dev, pm_message_t state) +{ + led_classdev_suspend(&ep93xx_green_led); + led_classdev_suspend(&ep93xx_red_led); + return 0; +} + +static int ep93xx_led_resume(struct platform_device *dev) +{ + led_classdev_resume(&ep93xx_red_led); + led_classdev_resume(&ep93xx_green_led); + return 0; +} +#endif + +static int ep93xx_led_probe(struct platform_device *pdev) +{ + int ret; + + gpio_line_config(EP93XX_GPIO_LINE_GRLED, GPIO_OUT); + gpio_line_config(EP93XX_GPIO_LINE_RDLED, GPIO_OUT); + + ret = led_classdev_register(&pdev->dev, &ep93xx_green_led); + if (ret < 0) + return ret; + + ret = led_classdev_register(&pdev->dev, &ep93xx_red_led); + if (ret < 0) + led_classdev_unregister(&ep93xx_green_led); + + return ret; +} + +static int ep93xx_led_remove(struct platform_device *pdev) +{ + led_classdev_unregister(&ep93xx_green_led); + led_classdev_unregister(&ep93xx_red_led); + return 0; +} + +static struct platform_driver ep93xx_led_driver = { + .probe = ep93xx_led_probe, + .remove = ep93xx_led_remove, +#ifdef CONFIG_PM + .suspend = ep93xx_led_suspend, Building and setup Ångström distribution from scratch page 12 of 54

+ .resume = ep93xx_led_resume, +#endif + .driver = { + .name = "ep93xx-led", + }, +}; + +static int __init ep93xx_led_init(void) +{ + return platform_driver_register(&ep93xx_led_driver); +} + +static void __exit ep93xx_led_exit(void) +{ + platform_driver_unregister(&ep93xx_led_driver); +} + +module_init(ep93xx_led_init); +module_exit(ep93xx_led_exit); + +MODULE_AUTHOR("Petr Stetiar "); +MODULE_DESCRIPTION("Cirrus Logic EP93xx LED driver"); +MODULE_LICENSE("GPL"); diff -uNr linux-2.6.37.org/drivers/leds/Makefile linux-2.6.37/drivers/leds/Makefile --- linux-2.6.37.org/drivers/leds/Makefile 2011-08-28 04:05:52.000000000 -0400 +++ linux-2.6.37/drivers/leds/Makefile 2011-08-27 10:17:21.000000000 -0400 @@ -45,6 +45,8 @@ # LED SPI Drivers obj-$(CONFIG_LEDS_DAC124S085) += leds-dac124s085.o

+obj-$(CONFIG_LEDS_EP93XX) += leds-ep93xx.o + # LED Triggers obj-$(CONFIG_LEDS_TRIGGER_TIMER) += ledtrig-timer.o obj-$(CONFIG_LEDS_TRIGGER_IDE_DISK) += ledtrig-ide-disk.o

Now we have to configure linux kernel. Run the following command

bitbake -c configure virtual/kernel

This will create a source directory in /angstrom/build/tmp- angstrom_2008_1/work/cs-e9302-angstrom-linux-gnueabi/. In this case it will be /angstrom/build/tmp-angstrom_2008_1/work/cs-e9302-angstrom-linux- gnueabi/linux-2.6.37-r4/

Next step is to modify the kernel configuration based on the existing configuration. Please ensure you have ncurses development package installed

apt-get install libncurses5-dev

Copy default configuration file from linux kernel sources.

cp /angstrom/build/tmp-angstrom_2008_1/work/cs-e9302-angstrom-linux- gnueabi/linux-2.6.37-r4/linux-2.6.37/arch/arm/configs/ep93xx_defconfig /angstrom/build/tmp-angstrom_2008_1/work/cs-e9302-angstrom-linux- gnueabi/linux-2.6.37-r4/linux-2.6.37/.config

Let’s modify linux kernel configuration. Do this by passing a command argument to bitbake.

bitbake –c menuconfig virtual/kernel

This invokes one of the standard kernel configuration tools menuconfig which provides a minimalist GUI based on the ncurses library.

Building and setup Ångström distribution from scratch page 13 of 54

NOTE: If this command does not launch an ncurses window, you are likely missing some tools on your workstation. For Ubuntu users, I have a check- installed.py script you can use to check your system. You can find it here - oe-build-essentials-project.

We are going to change some options in kernel configuration: - System type: [Enter] Cirrus EP93XX Implementation Options [Enable] Support ADC [Disable] Support ADS Sphere [Disable] Support Cirrus Logic EDB9301 [Disable] Support Cirrus Logic EDB9307 [Disable] Support Cirrus Logic EDB9312 [Disable] Support Cirrus Logic EDB9315 [Disable] Support Glomation GESBC-9312-sx [Disable] Support Contec Micro9-High [Disable] Support Contec Micro9-Lite [Disable] Support Technologic Systems TS-72xx SBC

- Device drivers: [Enter] Memory Technology Device: [Disable] NAND Device Support [Enter] Block Devices: [Module] Loopback device support [Module] Network block device support [Enable] Misc devices [Enter] Misc devices [Enable] EP93XX PWM support [Enter] Network device support: [Disable] Ethernet (1000 Mbit) [Disable] Ethernet (10000 Mbit) [Disable] Wireless LAN [Enter] USB Network Adapters [Module] USB KLSI KL5USB101-based ethernet device support [Module] USB Pegasus/Pegasus-II based ethernet device support [Module] USB RTL8150 based ethernet device support [Module] Multi-purpose USB Networking Framework [Module] Davicom DM9601 based 1.1 10/100 ethernet devices [Module] SMSC LAN75XX based USB 2.0 gigabit ethernet devices [Module] SMSC LAN75XX based USB 2.0 10/100 ethernet devices [Module] GeneSys GL620USB-A based cables [Module] Profilic PL-2301/2302 based cables [Module] MosChip MCS7830 based Ethernet adapters [Module] Host for RNDIS and ActiveSync devices [Disable] eTEK based host-to-host cables (Advance, Belkin, …) [Disable] Embedded Arm Linux links (iPaq, …) [Disable] (stock ROMs) and compatible

[Enter] I2C support: [Disable] I2C Core Debugging Messages [Disable] I2C Algorithm Debugging Messages [Disable] I2C Bus Debugging Messages [Enable] SPI support [Enter] SPI support: [Enable] Cirrus Logic EP93XX SPI controller [Enable] User mode SPI device driver support [Enter] GPIO support: [Enable] /sys/class/gpio…(sysfs interface) [Enter] Hardware monitoring support

Building and setup Ångström distribution from scratch page 14 of 54

[Enable] EP93XX on-chip ADC [Enable] Include raw channel attributes in sysfs [Disable] Multifunction Device Drivers [Enter] USB support: [Enable] USB Modem (CDC ACM) support [Enable] USB Atached SCSI [Enter] USB Serial Converter Support [Enable] USB Generic Serial Driver [Module] USB AIRCable Dongle Driver [Module] USB ARK Micro 3116 USB Serial Driver [Module] USB Belkin and Peracom Single Port Serial Driver [Module] USB Winchiphead CH341 Single Port Serial Driver [Module] USB Digi International AccelePort USB Serial Driver [Module] USB CP210x family of UART Bridge Controllers [Module] USB Cypress M8 USB Serial Driver [Module] USB Empeg empeg-car MARK I/II Driver [Module] USB FTDI Single Port Serial Driver [Module] USB Fundamental Software Dongle Driver [Module] USB Handspring Visor / Palm m50x / Sony Clie Driver [Module] USB IR Dongle Serial Driver [Module] USB Garmin GPS Driver [Module] USB IPWirelless ( UMTS TDD) Driver [Module] USB Infinity USB Unlimited Phoenix Driver [Module] USB Moschip 7720 Serial Driver [Module] USB Moschip 7840/7820 USB Serial Driver [Module] USB Prolific 2303 Single Port Serial Driver [Module] USB Ours Technology Inc. OTi-6858 USB To RS232 Bridge Controller [Module] USB Qualcomm Auxiliary Serial Port Driver [Module] USB Qualcomm Serial Modem [Module] USB SPCP8x5 USB To Serial Driver [Enable] USB Gadget support [Enter] USB Gadget support [Module] Gadget Zero (DEVELOPMENT) [Module] Ethernet Gadget (with CDC Ethernet support) [Module] Mass Storage Gadget [Module] Serial Gadget (with CDC ACM and CDC OBEX support) [Module] CDC Composite Device (Ethernet and ACM) [Module] HID Gadget [Enable] MMC/SD/SDIO card support [Enable] LED Support [Enter] LED Support [Enable] LED Class Support [Enable] LED Support for Cirrus Logic EP93XX [Enable] LED Trigger Support [Enable] LED Timer Trigger [Enter] Real time clock: [Disable] Dallas/Maxim DS1307/37/38/39/40, ST M4T00, EPSON RX- 8025 [Disable] ST M48T86/Dallas DS12887

- File systems [Enter] DOS/FAT/NT Filesystems [Module] MSDOS fs support [Module] VFAT (Windows-95) fs support [Module] NTFS file system support [Enter] Miscellaneous filesystems [Enable] JFFS2 summary support [Enable] Advanced compression options for JFFS2

Building and setup Ångström distribution from scratch page 15 of 54

- Kernel hacking: [Disable] Kernel debugging

When you are done, the new kernel configuration file can be found here /angstrom/build/tmp-angstrom_2008_1/work/cs-e9302-angstrom-linux- gnueabi/linux-2.6.37-r4/linux-2.6.37/.config

We have to add linux recipe in our repository. Create directory

mkdir -p /angstrom/sources/local/recipes/linux

First let's copy the bbfile recipe of linux kernel from OpenEmbedded repository:

cp /angstrom/sources/openembedded/recipes/linux/linux_2.6.37.bb /angstrom/sources/local/recipes/linux/linux_2.6.37.bb Now edit file

nano /angstrom/sources/local/recipes/linux/linux_2.6.37.bb and change line

require linux.inc to

require ${BBFILE_PATTERN_oe}/recipes/linux/linux.inc

Then we have to create linux configuration file directory mkdir -p /angstrom/sources/local/recipes/linux/linux-2.6.37/cs-e9302/

Copy configuration file to local repository

cp /angstrom/build/tmp-angstrom_2008_1/work/cs-e9302-angstrom-linux- gnueabi/linux-2.6.37-r4/linux-2.6.37/.config /angstrom/sources/local/recipes/linux/linux-2.6.37/cs-e9302/defconfig

Finally build the kernel

bitbake virtual/kernel

After building the image file could be found at

/angstrom/build/tmp-angstrom_2008_1/deploy/glibc/images/cs-e9302/

5. Building java VM

JamVM is a new Java Virtual Machine which conforms to the JVM specification version 2 (blue book). In comparison to most other VM's (free and commercial) it is extremely small. Last available JamVM version in OpenEmbedded repository is 1.5.3, but we want to build last available version which is 1.5.4. Jamvm version is obtained at distribution level and it’s impossible to provide it at local configuration level. That’s why we will make our copy of distribution. Next few commands will copy all necessary files

mkdir –p /angstrom/sources/local/conf/distro/include

Building and setup Ångström distribution from scratch page 16 of 54

cp /angstrom/sources/openembedded/conf/distro/angstrom-2008.1.conf /angstrom/sources/local/conf/distro/ cp /angstrom/sources/openembedded/conf/distro/include/angstrom-2008-preferred- versions.inc /angstrom/sources/local/conf/distro/include/ cp /angstrom/sources/openembedded/conf/distro/include/angstrom-codec-engine- latest-preferred-versions.inc /angstrom/sources/local/conf/distro/include/ cp /angstrom/sources/openembedded/conf/distro/include/angstrom-glibc.inc /angstrom/sources/local/conf/distro/include/ cp /angstrom/sources/openembedded/conf/distro/include/angstrom.inc /angstrom/sources/local/conf/distro/include/ cp /angstrom/sources/openembedded/conf/distro/include/angstrom-jalimo.conf /angstrom/sources/local/conf/distro/include/ cp /angstrom/sources/openembedded/conf/distro/include/angstrom-ldflags.inc /angstrom/sources/local/conf/distro/include/ cp /angstrom/sources/openembedded/conf/distro/include/angstrom-package-ipk.inc /angstrom/sources/local/conf/distro/include/ cp /angstrom/sources/openembedded/conf/distro/include/arm-thumb.inc /angstrom/sources/local/conf/distro/include/ cp /angstrom/sources/openembedded/conf/distro/include/glibc-internal.inc /angstrom/sources/local/conf/distro/include/ cp /angstrom/sources/openembedded/conf/distro/include/preferred-opie-versions- 1.2.4.inc /angstrom/sources/local/conf/distro/include/ cp /angstrom/sources/openembedded/conf/distro/include/sane-toolchain-java.inc /angstrom/sources/local/conf/distro/include/ cp /angstrom/sources/openembedded/conf/distro/include/toolchain-internal.inc /angstrom/sources/local/conf/distro/include/

Edit file

nano /angstrom/sources/local/conf/distro/include/angstrom-jalimo.conf and change the content of file with the following

# Put a 'require conf/distro/include/angstrom-jalimo.conf' in your local.conf if you want to build from the jalimo overlay

# initial stuff PREFERRED_VERSION_jamvm-initial = "1.4.5" PREFERRED_VERSION_classpath-initial = "0.93"

# Native VM # Cacao native #PREFERRED_PROVIDER_virtual/java-native ?= "cacao-native" #SRCREV_pn-cacao-native ?= "c7bf150bfa46" #PREFERRED_VERSION_cacao-native = "0.99.3"

# Classpath native PREFERRED_VERSION_classpath-native = "0.98"

Building and setup Ångström distribution from scratch page 17 of 54

# JamVM native PREFERRED_PROVIDER_virtual/java-native ?= "jamvm-native" PREFERRED_VERSION_jamvm-native = "1.5.4"

# Native compiler settings PREFERRED_PROVIDER_virtual/javac-native = "ecj-bootstrap-native" PREFERRED_VERSION_libecj-bootstrap = "3.6"

# Target VM PREFERRED_VERSION_cacao = "0.99.3" PREFERRED_VERSION_cacaoh-native = "0.99.3"

PREFERRED_VERSION_jamvm = "1.5.4" PREFERRED_PROVIDER_swt3.4- = "swt3.4-gtk" PREFERRED_PROVIDER_classpath = "classpath"

PREFERRED_VERSION_openjdk-6-jre = "6b18-1.8.5" PREFERRED_VERSION_icedtea6-native = "1.7.10"

# Stage JAR files not into ARCH related dirs STAGING_DIR_JAVA = "${STAGING_DIR}/java" STAGING_DATADIR_JAVA ?= "${STAGING_DIR_JAVA}"

We are going to copy Jamvm recipe from OpenEmbedded repository

mkdir –p /angstrom/sources/local/recipes/ cp –R /angstrom/sources/openembedded/recipes/jamvm /angstrom/sources/local/recipes

Next we have to create recipe for latest JamVM version by typing

nano /angstrom/sources/local/recipes/jamvm /jamvm_1.5.4.bb and finally add the following in file

require jamvm.inc

SRC_URI += "file://-jni.patch;striplevel=0"

PR = "r3"

do_configure_prepend() { # Replaces the placeholder OE_LIBDIR_JNI with the JNI library directory # configured in OE. sed -i -e "s|OE_LIBDIR_JNI|${libdir_jni}|" src/dll.c

Building and setup Ångström distribution from scratch page 18 of 54

}

SRC_URI[md5sum] = "7654e9657691f5f09c4f481ed4686176" SRC_URI[sha256sum] = "7865693698bc4322cabe1014a4b7ebdec1bc1daf45f1a4457b6e908a4446b124"

If JamVM have to be build without GUI support, edit file nano /angstrom/sources/local/recipes/jamvm /jamvm.inc and change the lines

EXTRA_OECONF = "--with-classpath-install-dir=${prefix} --libdir=${libdir}/jamvm" CFLAGS += "-DDEFAULT_MAX_HEAP=16*MB" with this one

EXTRA_OECONF = "--without-x --without-alsa --disable-gtk-peer --disable-gconf-peer - -disable-examples --with-classpath-install-dir=${prefix} --libdir=${libdir}/jamvm" CFLAGS += "-DDEFAULT_MAX_HEAP=8*MB"

Everything about JamVM is now configured, so you can build it by

bitbake jamvm

6. Building a custom package

To add package you need to write a recipe for it. Writing a recipe means creating a .bb file which sets various variables. Recipes usually use names of the form: packagename_versionnumber.bb. Simple directory structure of package “mladen” could be created as is presented below:

mkdir -p /angstrom/sources/local/recipes/mladen mkdir -p /angstrom/sources/local/recipes/mladen/files

We are going to use as example, mladen_1.0.bb, its code is presented below:

DESCRIPTION = "Mladen Application" PR = "r0"

SRC_URI = "file://mladen.c \ file://README.txt"

S = ${WORKDIR}

do_compile() { ${CC} ${CFLAGS} ${LDFLAGS} ${WORKDIR}/*.c -o mladen }

Building and setup Ångström distribution from scratch page 19 of 54

do_install() { install -m 0755 -d ${D}${bindir} ${D}${docdir}/mladen install -m 0755 ${S}/mladen ${D}${bindir} install -m 0644 ${WORKDIR}/README.txt ${D}${docdir}/mladen }

To understand what is described above, use the following table that summaries the main variables often used in the recipes: Variable Description

The package name. Determined from the recipe filename - everything up until the PN first underscore is considered to be the package name. For the sample- recipe_1.0.0.bb recipe the PN variable would be set to "sample-recipe".

The package version. Determined from the recipe filename - everything between PV the first underscore and the final .bb is considered to be the package version. For the sample-recipe_1.0.0.bb recipe the PV variable would be set to "1.0.0".

The package name and versions separated by a hyphen. For the sample- P recipe_1.0.0.bb recipe the P variable would be set to "sample-recipe-1.0.0".

The package release. This should be explicitly set in the recipe, if not set it defaults PR to "r0".

The working directory is where the source code is extracted, where files (other than patches) are copied, and where the logs and installation files are created. WORKDIR WORKDIR is initialized to PN-PV-PR, so for example recipe sample- recipe_1.0.0.bb, the value of WORKDIR would be set to "sample-recipe_1.0.0-r0" (assuming that the recipe set PR to "r0")

This is the unpacked source directory.

Bitbake expects to find the extracted source for a package in a directory called packagename-version in the WORKDIR directory. This is the directory which it will change to before patching, compiling and installing the package.

S For example, let's assume we have a package recipe called sample-recipe_1.0.0.bb and we are extracting the source from the sample-1.0.0.tar.gz file. Bitbake expects the source to end up in a directory called sample-1.0.0 within the WORKDIR.

If the source does not end up in this directory, then bitbake needs to be told this by explicitly setting S.

This is the destination directory. It specifies where your package should be installed. The packaging system takes the contents of this directory and packages it for installation on the target.

D The directory structure beneath D should reflect where the package files are to end up in the target system. For example, if a package file is intended to end up in /usr/bin on the target system, the recipe should install the files into ${D}/usr/bin.

It is considered poor practice to directly specify /usr/bin. The build system

Building and setup Ångström distribution from scratch page 20 of 54

provides a set of variables that you should use instead (see table in Appendix). So for the example above, the proper installation directory specification would be ${D}${bindir}

Specifies the text that will be displayed by the package management system to DESCRIPTION describe what the package is.

MANTAINER The name of the mantainer and usually an e-mail address

LICENSE The package license name

If there were dependencies on any other packages to build or run, we would list DEPENDS them here.

SRC_URI Tell the build system where to find source code for the package

FILES_${PN} Describes the list of files to be installed

RDEPENDS A list of recommended packages to be installed

The example recipe code above specified the name of the source files „mladen.c“ and „README.txt“ with a file:// prefix, this is the way you must do it, if the source code is located in the local file system.

„mladen.c“ is simple C program presented below

#include

int main(int argc, char** argv) { int i; for (i=0;i<10;i++) { printf("Hello world!\nFrom the new Mladen application\n\n"); } return 0; } and README.txt contains simple package documentation

This is just a doc file in the Mladen application.

To build a “mladen” package, simply type the following at a console prompt. You don't need to cd into the package directory to do this. BitBake knows where to look for recipes and it will automatically find and build the “mladen” package.

bitbake mladen

7. Building a custom image

Building and setup Ångström distribution from scratch page 21 of 54

Ångström images can be customized to satisfy particular requirements. Building a custom image is simple like building of custom recipe. We are going to use minimal-image as template, but in addition to add some extra packages

mkdir -p /angstrom/sources/local/recipes/images

Add new file for custom image

nano /angstrom/sources/local/recipes/images/minimal-osgi.bb with the following content

require ${BBFILE_PATTERN_oe}/recipes/images/minimal-image.bb

IMAGE_INSTALL += "\ jamvm \ nano \ librxtx-jni \ mladen \ "

export IMAGE_BASENAME = "minimal-osgi"

By creating a custom image, a developer has total control over the contents of the image. It is important use the correct names of packages in the “IMAGE_INSTALL” variable. The names must be in the OpenEmbedded notation instead of Debian notation, for example "glibc-dev" instead of "libc6-dev" etc. Run building of image:

bitbake minimal-osgi

After building image file could be found here: /angstrom/build/tmp- angstrom_2008_1/deploy/glibc/images/cs-e9302/Angstrom-minimal-osgi-glibc- ipk-2011.03-cs-e9302.rootfs.tar.bz2

8. Deployment

First let’s install necessary packages: apt-get install tftpd-hpa nfs-kernel-server apache2

Let’s make public directory for root file system and kernel. Execute as root user:

mkdir -p /var/www/pub/9302 cd /var/www/pub/9302

Extract root file system

tar -jxvf /angstrom/build/tmp-angstrom_2008_1/deploy/glibc/images/cs- e9302/Angstrom-minimal-osgi-glibc-ipk-2011.03-cs-e9302.rootfs.tar.bz2

Building and setup Ångström distribution from scratch page 22 of 54

We are going to create virtual host for accessing local binary repository from target platform. So edit file

nano /etc/apache2/sites-available/default and add the following in the of file

ServerAdmin webmaster@localhost

DocumentRoot /angstrom/build/tmp-angstrom_2008_1/ Options FollowSymLinks AllowOverride None Options Indexes FollowSymLinks MultiViews AllowOverride None Order allow,deny allow from all

ScriptAlias /cgi-bin/ /usr/lib/cgi-bin/ AllowOverride None Options +ExecCGI -MultiViews +SymLinksIfOwnerMatch Order allow,deny Allow from all

ErrorLog ${APACHE_LOG_DIR}/error.log

# Possible values include: debug, info, notice, warn, error, crit, # alert, emerg. LogLevel warn

CustomLog ${APACHE_LOG_DIR}/access.log combined

Alias /doc/ "/usr/share/doc/" Options Indexes MultiViews FollowSymLinks AllowOverride None Order deny,allow Deny from all

Building and setup Ångström distribution from scratch page 23 of 54

Allow from 127.0.0.0/255.0.0.0 ::1/128

Now restart apache

/etc/init.d/apache2 restart

Next edit file

nano /var/www/pub/9302/etc/network/interfaces and make eth0 with static configuration

# Wired or wireless interfaces auto eth0 #iface eth0 inet dhcp #iface eth1 inet dhcp iface eth0 inet static address 192.168.1.200 netmask 255.255.255.0 network 192.168.1.0 gateway 192.168.1.1 In this case IP address of target platgorm will be 192.168.1.200

Also edit /var/www/pub/9302/etc/resolv.conf to point to local DNS. Next step is to configure feed links in target platform NOTE:IP address of host platform is 192.168.1.155

Edit file

nano /var/www/pub/9302/etc//base-feed.conf and change feed location from

src/gz base http://feeds.angstrom- distribution.org/feeds/unstable/ipk/glibc/armv4t/base to

src/gz base http://192.168.1.155:8080/deploy/glibc/ipk/armv4t

Edit file

nano /var/www/pub/9302/etc/opkg/cs-e9302-feed.conf and change feed location from

src/gz cs-e9302 http://feeds.angstrom- distribution.org/feeds/unstable/ipk/glibc/armv4t/machine/cs-e9302 to

src/gz cs-e9302 http://192.168.1.155:8080/deploy/glibc/ipk/cs-e9302

Building and setup Ångström distribution from scratch page 24 of 54

Edit file

nano /var/www/pub/9302/etc/opkg/noarch-feed.conf and change feed location from

src/gz no-arch http://feeds.angstrom-distribution.org/feeds/unstable/ipk/glibc/all to

src/gz no-arch http://192.168.1.155:8080/deploy/glibc/ipk/all

For NFS server configuration edit file

nano /etc/exports and the following in the end of file

/var/www/pub 192.168.1.0/24(rw,nohide,no_root_squash,insecure,no_subtree_check,async)

For TFTP server configuration edit file

nano /etc/default/tftpd-hpa and the change the line

TFTP_DIRECTORY="/var/lib/tftpboot" with this one

TFTP_DIRECTORY="/var/www/pub"

Now restart NFS and TFTP servers

/etc/init.d/tftpd-hpa restart /etc/init.d/nfs-kernel-server restart

Final step is to run our target platform. Connect RS232_0 serial port of development board to PC with baud rate of 57600. You can use any software for serial communication like PuTTY or SercureCRT(in Windows). Turn on power supply. Press CTRL + C. Use the following Redboot options:

RedBoot> fconfig -l Run script at boot: true Boot script: .. load -v -r -b 0x80000 -h 192.168.1.155 -m http /pub/9302/boot/zImage .. exec -c "root=/dev/nfs nfsroot=192.168.1.155:/var/www/pub/9302 ip=192.168.1.200:192.168.1.1:255.255.255.0 console=ttyAM0,57600n8"

Boot script timeout (1000ms resolution): 5 Use BOOTP for network configuration: false Gateway IP address: 192.168.1.1 Local IP address: 192.168.1.200 Local IP address mask: 255.255.255.0

Building and setup Ångström distribution from scratch page 25 of 54

Default server IP address: 192.168.1.1 DNS server IP address: 192.168.1.1 Set eth0 network hardware address [MAC]: true eth0 network hardware address [MAC]: 0x00:0x00:0x00:0x00:0x54:0x33 GDB connection port: 9000 Force console for special debug messages: false Network debug at boot time: false RedBoot>

In configuration options above linux kernel is loading from host platform through HTTP. In case of using TFTP you should use

load -v -r -b 0x80000 9302/boot/zImage

Root file system could be loaded from USB flash disk too. Please follow the instructions bellow in order to setup root file system on USB disk.

mkfs -t ext2 -b 1024 -m 0 /dev/sdb

Let’s turn off checks for problems with file system

tune2fs -c 0 -i 0 /dev/sdb

Mount the disk

mount /dev/sdb /mount

Copy file system

cp -R /var/www/pub/9302/* /mount

Unmount the disk

umount /dev/sdb

Redboot option to load root file system from USB flash disk is

exec -c "console=ttyAM0 root=/dev/sda1 rootdelay=6"

Example of successful boot

Using base address 0x00080000 and length 0x001b4c3c Linux version 2.6.37.2 (user@ubuntu) (gcc version 4.3.3 (GCC) ) #1 Tue Aug 16 03:31:39 EDT 2011 CPU: ARM920T [41129200] revision 0 (ARMv4T), cr=c0007177 CPU: VIVT data cache, VIVT instruction cache Machine: Cirrus Logic EDB9302 Evaluation Board Memory policy: ECC disabled, Data cache writeback Built 1 zonelists in Zone order, mobility grouping on. Total pages: 8016 Kernel command line: root=/dev/nfs nfsroot=192.168.1.155:/var/www/pub/9302 ip=192.168.1.200:192.168.1.1:255.255.255.0 console=ttyAM0,57600n8

Building and setup Ångström distribution from scratch page 26 of 54

PID hash table entries: 128 (order: -3, 512 bytes) Dentry cache hash table entries: 4096 (order: 2, 16384 bytes) Inode-cache hash table entries: 2048 (order: 1, 8192 bytes) Memory: 8MB 8MB 8MB 8MB = 32MB total Memory: 28872k/28872k available, 3896k reserved, 0K highmem Virtual kernel memory layout: vector : 0xffff0000 - 0xffff1000 ( 4 kB) fixmap : 0xfff00000 - 0xfffe0000 ( 896 kB) DMA : 0xffc00000 - 0xffe00000 ( 2 MB) vmalloc : 0xc6000000 - 0xfe800000 ( 904 MB) lowmem : 0xc0000000 - 0xc5800000 ( 88 MB) modules : 0xbf000000 - 0xc0000000 ( 16 MB) .init : 0xc0008000 - 0xc0023000 ( 108 kB) .text : 0xc0023000 - 0xc034ee00 (3248 kB) .data : 0xc0350000 - 0xc036a560 ( 106 kB) NR_IRQS:120 VIC @fefb0000: id 0x00041190, vendor 0x41 VIC @fefc0000: id 0x00041190, vendor 0x41 Calibrating delay loop... 99.73 BogoMIPS (lpj=498688) pid_max: default: 32768 minimum: 301 Mount-cache hash table entries: 512 CPU: Testing write buffer coherency: ok NET: Registered protocol family 16 ep93xx clock: PLL1 running at 400 MHz, PLL2 at 192 MHz ep93xx clock: FCLK 200 MHz, HCLK 100 MHz, PCLK 50 MHz ep93xx dma_m2p: M2P DMA subsystem initialized bio: create slab at 0 SCSI subsystem initialized usbcore: registered new interface driver usbfs usbcore: registered new interface driver hub usbcore: registered new device driver usb NET: Registered protocol family 2 IP route cache hash table entries: 1024 (order: 0, 4096 bytes) TCP established hash table entries: 1024 (order: 1, 8192 bytes) TCP bind hash table entries: 1024 (order: 0, 4096 bytes) TCP: Hash tables configured (established 1024 bind 1024) TCP reno registered UDP hash table entries: 256 (order: 0, 4096 bytes) UDP-Lite hash table entries: 256 (order: 0, 4096 bytes) NET: Registered protocol family 1 RPC: Registered udp transport module. RPC: Registered tcp transport module. RPC: Registered tcp NFSv4.1 backchannel transport module. NetWinder Floating Point Emulator V0.97 (extended precision) JFFS2 version 2.2. (NAND) (SUMMARY) © 2001-2006 Red Hat, Inc. msgmni has been set to 56 io scheduler noop registered io scheduler deadline registered (default)

Building and setup Ångström distribution from scratch page 27 of 54

Serial: AMBA driver apb:uart1: ttyAM0 at MMIO 0x808c0000 (irq = 52) is a AMBA console [ttyAM0] enabled apb:uart2: ttyAM1 at MMIO 0x808d0000 (irq = 54) is a AMBA apb:uart3: ttyAM2 at MMIO 0x808e0000 (irq = 55) is a AMBA physmap platform flash device: 01000000 at 60000000 physmap-flash.0: Found 1 x16 devices at 0x0 in 16-bit bank. Manufacturer ID 0x000089 Chip ID 0x000018 /Sharp Extended Query Table at 0x0031 Intel/Sharp Extended Query Table at 0x0031 Using buffer write method cfi_cmdset_0001: Erase suspend on write enabled Searching for RedBoot partition table in physmap-flash.0 at offset 0xfe0000 7 RedBoot partitions found on MTD device physmap-flash.0 Creating 7 MTD partitions on "physmap-flash.0": 0x000000000000-0x000000040000 : "RedBoot" 0x000000040000-0x000000540000 : "netbsd" 0x000000540000-0x000000a40000 : "netbsd_install" 0x000000a40000-0x000000d40000 : "ramdisk.gz" 0x000000d40000-0x000000ee0000 : "dImage" 0x000000fc0000-0x000000fc1000 : "RedBoot config" mtd: partition "RedBoot config" doesn't end on an erase block -- force read-only 0x000000fe0000-0x000001000000 : "FIS directory" ep93xx-eth version 0.1 loading eth0: ep93xx on-chip ethernet, IRQ 39, 00:00:00:00:54:33 ohci_hcd: USB 1.1 'Open' Host Controller (OHCI) Driver ep93xx-ohci ep93xx-ohci: EP93xx OHCI ep93xx-ohci ep93xx-ohci: new USB bus registered, assigned bus number 1 ep93xx-ohci ep93xx-ohci: irq 56, io mem 0x80020000 usb usb1: New USB device found, idVendor=1d6b, idProduct=0001 usb usb1: New USB device strings: Mfr=3, Product=2, SerialNumber=1 usb usb1: Product: EP93xx OHCI usb usb1: Manufacturer: Linux 2.6.37.2 ohci_hcd usb usb1: SerialNumber: ep93xx hub 1-0:1.0: USB hub found hub 1-0:1.0: 3 ports detected usbcore: registered new interface driver cdc_acm cdc_acm: v0.26:USB Abstract Control Model driver for USB modems and ISDN adapters usbcore: registered new interface driver uas Initializing USB Mass Storage driver... usbcore: registered new interface driver usb-storage USB Mass Storage support registered. usbcore: registered new interface driver usbserial USB Serial support registered for generic usbcore: registered new interface driver usbserial_generic usbserial: USB Serial Driver core ep93xx-rtc ep93xx-rtc: rtc core: registered ep93xx-rtc as rtc0 i2c /dev entries driver ep93xx_wdt: EP93XX watchdog, driver version 0.3 (nCS1 disable detected)

Building and setup Ångström distribution from scratch page 28 of 54

TCP cubic registered NET: Registered protocol family 10 NET: Registered protocol family 17 NET: Registered protocol family 15 ep93xx-rtc ep93xx-rtc: setting system clock to 1970-01-01 00:02:00 UTC (120) usb 1-1: new full speed USB device using ep93xx-ohci and address 2 usb 1-1: New USB device found, idVendor=0951, idProduct=1607 usb 1-1: New USB device strings: Mfr=1, Product=2, SerialNumber=3 usb 1-1: Product: DataTraveler 2.0 usb 1-1: Manufacturer: Kingston usb 1-1: SerialNumber: 001372982BA9B9519000006C usb 1-1: selecting invalid altsetting 1 scsi0 : usb-storage 1-1:1.0 scsi 0:0:0:0: Direct-Access Kingston DataTraveler 2.0 PMAP PQ: 0 ANSI: 0 CCS IP-Config: Guessing netmask 255.255.255.0 IP-Config: Gateway not on directly connected network. sd 0:0:0:0: [sda] 7839744 512-byte logical blocks: (4.01 GB/3.73 GiB) sd 0:0:0:0: [sda] Write Protect is off sd 0:0:0:0: [sda] Assuming drive cache: write through sd 0:0:0:0: [sda] Assuming drive cache: write through sda: sda1 sd 0:0:0:0: [sda] Assuming drive cache: write through sd 0:0:0:0: [sda] Attached SCSI removable disk VFS: Mounted root (nfs filesystem) on device 0:12. Freeing init memory: 108K INIT: version 2.86 booting Please wait: booting... Starting udev udevd (257): /proc/257/oom_adj is deprecated, please use /proc/257/oom_score_adj instead. EXT3-fs (sda): error: can't find ext3 filesystem on dev sda. EXT2-fs (sda): error: can't find an ext2 filesystem on dev sda. EXT2-fs (sda1): warning: mounting unchecked fs, running e2fsck is recommended Root filesystem already rw, not remounting Caching udev devnodes Populating dev cache NOT configuring network interfaces: / is an NFS mount Tue Aug 16 03:47:00 UTC 2011 INIT: Entering runlevel: 5 Creating Dropbear SSH server RSA host key. Will output 1024 bit rsa secret key to '/etc/dropbear/dropbear_rsa_host_key' Generating key, this may take a while... Public key portion is: ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAAAgwDdZLxBD/mE091ON8H9+yPw9w67os2sw8YTOO/iNJX4lUzMiikLmKjrypGDdPFd1 sLXuZUU+sl64gaovKDUHhoG70+twylyOaVW8i/FABx7qcD42itl1jIS27AETWGiJNopZ2HQQjshjoRwW/DfiPQsihXoaI xcebDsMbvoANe/4YiT root@cs-e9302 Fingerprint: md5 e9:f5:58:62:9c:33:b4:2e:c6:4a:79:80:ba:9a:ea:3b Starting Dropbear SSH server: dropbear. Starting syslogd/klogd: done

Building and setup Ångström distribution from scratch page 29 of 54

.------. | | .-. | | |-----.-----.-----.| | .----..-----.-----. | | | __ | ---'| '--.| .-'| | | | | | | | |--- || --'| | | ' | | | | '---'---'--'--'--. |-----''----''--' '-----'-'-'-' -' | '---'

The Angstrom Distribution cs-e9302 ttyAM0

Angstrom 2011.03 cs-e9302 ttyAM0

cs-e9302 login:

8. Meteo Recipe

This recipe demonstrates bulding of Java Application with GPIO and ADC support. Accessing of GPIO and ADC is made through dynamic libraries written in C. In Java this interface is available through JNI bindings.

First let’s make base structure of recipe

mkdir –p /angstrom/sources/local/recipes/meteo/files/bin mkdir –p /angstrom/sources/local/recipes/meteo/files/lib mkdir –p /angstrom/sources/local/recipes/meteo/files/meteo/channels mkdir –p /angstrom/sources/local/recipes/meteo/files/meteo_test

Bin – directory for compiled JAVA files Lib – sources of C library Meteo – JAVA API sources Meteo_test – JAVA Test API sources

Let’s add necessary files in lib directory

DigitalChannel.c

First let’s make base structure of recipe

#include "meteo_channels_DigitalChannel.h" #include #include #include #include #include

#define TRUE 0x01 #define FALSE 0x00

int pwm_flag = FALSE;

Building and setup Ångström distribution from scratch page 30 of 54

char *uitos(unsigned int number) { unsigned int n = number; int size = 1; do { size++; n /= 10; } while(n >= 1); char *buffer = (char *) malloc(size); if(buffer == NULL) { printf("Cannot allocate memory.\n"); exit(1); } memset(buffer, 0, size); sprintf(buffer, "%d", number); return buffer; }

void exportGPIO(unsigned int number) { FILE *fp; int size, count; //Using sysfs we need to write "gpioNumber" to /sys/class/gpio/export //This will create the folder /sys/class/gpio/gpio"gpioNumber" if((fp = fopen("/sys/class/gpio/export", "wb")) == NULL) { printf("Cannot open export file.\n"); exit(1); } char *gpioNumber = uitos(number); //Write our value of "gpioNumber" to the file size = strlen(gpioNumber); count = fwrite(gpioNumber, sizeof(char), size, fp); fclose(fp); if(size != count) { printf("Fwrite error.\n"); exit(1); } //printf("...export file accessed, new pin %s now accessible\n", gpioNumber); free(gpioNumber); }

void unexportGPIO(unsigned int number) { FILE *fp; int size, count; //Using sysfs we need to write "gpioNumber" to /sys/class/gpio/export //This will create the folder /sys/class/gpio/gpio"gpioNumber" if((fp = fopen("/sys/class/gpio/unexport", "wb")) == NULL) { printf("Cannot open unexport file.\n"); exit(1);

Building and setup Ångström distribution from scratch page 31 of 54

} char *gpioNumber = uitos(number); //Write our value of "gpioNumber" to the file size = strlen(gpioNumber); count = fwrite(gpioNumber, sizeof(char), size, fp); fclose(fp); if(size != count) { printf("Fwrite error.\n"); exit(1); } //printf("...unexport file accessed, new pin %s now unaccessible\n", gpioNumber); free(gpioNumber); }

void directionGPIO(unsigned int number, const char *gpioDirection) { FILE *fp; int size, count; char *gpioNumber = uitos(number); size = strlen("/sys/class/gpio/gpio") + strlen(gpioNumber) + strlen("/direction"); char *path = (char *) malloc(size); count = sprintf(path, "%s%s%s", "/sys/class/gpio/gpio", gpioNumber, "/direction"); if(count != size) { printf("Sprintf error.\n"); exit(1); } //SET DIRECTION //Open the LED's sysfs file in binary for reading and writing, store file pointer in fp if((fp = fopen(path, "wb")) == NULL) { printf("Cannot open direction file.\n"); exit(1); } //Write our value of "out" or "in" to the file size = strlen(gpioDirection); count = fwrite(gpioDirection, sizeof(char), size, fp); fclose(fp); if(size != count) { printf("Fwrite error.\n"); exit(1); } //printf("...direction of pin %s set to %s\n", gpioNumber, gpioDirection); free(path); free(gpioNumber); }

unsigned int readGPIO(unsigned int number) { FILE *fp; int size, count; unsigned int value;

Building and setup Ångström distribution from scratch page 32 of 54

char *gpioNumber = uitos(number); size = strlen("/sys/class/gpio/gpio") + strlen(gpioNumber) + strlen("/value"); char *path = (char *) malloc(size); count = sprintf(path, "%s%s%s", "/sys/class/gpio/gpio", gpioNumber, "/value"); if(count != size) { printf("Sprintf error.\n"); exit(1); } //GET VALUE //Open the LED's sysfs file in binary for reading, store file pointer in fp if((fp = fopen(path, "rb")) == NULL) { printf("Cannot open value file.\n"); exit(1); } size = sizeof(char); char *gpioValue = (char *) malloc(size); count = fread(gpioValue, sizeof(char), size, fp); fclose(fp); if(size != count) { printf("Fread error.\n"); exit(1); } value = atoi(gpioValue); //printf("...value of pin %s set to %d...\n", gpioNumber, value); free(path); free(gpioNumber); free(gpioValue); return value; }

void writeGPIO(unsigned int number, unsigned int value) { FILE *fp; int size, count; char *gpioNumber = uitos(number); size = strlen("/sys/class/gpio/gpio") + strlen(gpioNumber) + strlen("/value"); char *path = (char *) malloc(size); count = sprintf(path, "%s%s%s", "/sys/class/gpio/gpio", gpioNumber, "/value"); if(count != size) { printf("Sprintf error.\n"); exit(1); } //SET VALUE //Open the LED's sysfs file in binary for writing, store file pointer in fp if((fp = fopen(path, "wb")) == NULL) { printf("Cannot open value file.\n"); exit(1); } char *gpioValue = uitos(value);

Building and setup Ångström distribution from scratch page 33 of 54

size = strlen(gpioValue); //Write our value of "gpioNumber" to the file count = fwrite(gpioValue, sizeof(char), size, fp); fclose(fp); if(size != count) { printf("Fwrite error.\n"); exit(1); } //printf("...value of pin %s set to %s...\n", gpioNumber, gpioValue); free(path); free(gpioNumber); free(gpioValue); }

void nsleep(double seconds) { struct timespec req = {0}, rem = {0}; time_t sec = (int) seconds; unsigned long nsec = seconds * 1000000000L - sec * 1000000000L; req.tv_sec = sec; req.tv_nsec = nsec; nanosleep(&req, &rem); }

JNIEXPORT void JNICALL Java_meteo_channels_DigitalChannel_export(JNIEnv *env, jobject obj, jint number, jstring direction) { /*Extracting information from the parameter */ const char *gpioDirection = (*env)->GetStringUTFChars(env, direction, 0);

exportGPIO(number); directionGPIO(number, gpioDirection);

/*Releasing the Java String once you have got the C string is very important!!!*/ (*env)->ReleaseStringUTFChars(env, direction, gpioDirection); }

JNIEXPORT void JNICALL Java_meteo_channels_DigitalChannel_unexport(JNIEnv *env, jobject obj, jint number) { unexportGPIO(number); }

JNIEXPORT jint JNICALL Java_meteo_channels_DigitalChannel_read(JNIEnv *env, jobject obj, jint number) { return readGPIO(number); }

JNIEXPORT void JNICALL Java_meteo_channels_DigitalChannel_write(JNIEnv *env, jobject obj, jint number, jint value) { writeGPIO(number, value); }

Building and setup Ångström distribution from scratch page 34 of 54

JNIEXPORT void JNICALL Java_meteo_channels_DigitalChannel_stopPWM(JNIEnv *env, jobject obj, jint number) { pwm_flag = TRUE; }

JNIEXPORT void JNICALL Java_meteo_channels_DigitalChannel_pwm(JNIEnv *env, jobject obj, jint number, jdouble f, jdouble k) { //Export GPIO exportGPIO(number); directionGPIO(number, "out");

double t, t1, t2;

t = 1.0 / f; t1 = t * k / 100.0; t2 = t * (100.0 - k) / 100.0;

//Run an infinite loop - will require Ctrl-C to exit this program while(1) { if(pwm_flag == TRUE) { unexportGPIO(number); break; } if(t1 > 0) { writeGPIO(number, 1); //high level nsleep(t1); } if(t2 > 0) { writeGPIO(number, 0); //low level nsleep(t2); } } }

C implementation and JNI exports for export, direction, read and write GPIO channels. In addition there is function for software PWM. It can be used to test the system time quantum.

AnalogChannel.c

/* ADC Operation ======1 To enable clocks for the ADC block, set the TSEN bit in the Syscon section (ADCClkDiv register). 2 Set the DeviceCfg.ADCEN bit. 3 Clear the DeviceCfg.ADCPD bit. 4 Select an input. First unlock the software lock by writing 0xAA to the ADCSWLock register. Then write an appropriate value (selected from Table 20-2on page520) to the

Building and setup Ångström distribution from scratch page 35 of 54

ADCSwitch register. 5 To poll, read the ADCResult register repeatedly. Bit 31 of this register is the SDR, or Synchronous Data Ready, bit. This bit is set when a new valid conversion value appears in this register and is cleared when this register is read. So when two consecutive reads show the bit clear and then set, the second read has the new valid value. 6 Conversion data may also be processed using interrupts from this module. If bit 11 in the ADCIntEn register (the RINTEN bit) is set, an interrupt occurs whenever the SDR bit in the ADCResult register is set. Therefore, an interrupt handler can read the ADCResult register whenever a new valid sample appears in the register, which both returns a new conversion value and clears the interrupt.

Register Memory Map ======Address Name SW locked Type Size Description ------0x8090_0000 Reserved 0x8090_0004 Reserved 0x8090_0008 ADCResult No Read Only 32 bits ADC result register. 0x8090_000C Reserved 0x8090_0010 Reserved 0x8090_0014 Reserved 0x8090_0018 ADCSwitch Write Read/Write 28 bits ADC Switch Matrix control register. 0x8090_001C Reserved 0x8090_0020 ADCSWLock NA Read/Write 1-bit read ADC software lock register. 8-bit write 0x8090_0024 ADCIntEn No Read/Write 9 bits ADC Interrupt Enable Register

0x8093_0090 ADCClkDiv Yes R/W 32 ADC Clock Divider

0x8093_0080 DeviceCfg Yes R/W 32 Device configuration

ADC result register: 0x8090_0008

Bit 31: SDR: Synchronous Data Ready Bit 0-12: AD: Analog-to-digital converter output at 12-bit resolution

ADCSwitch: 0x8090_0018

Input to Measure ADC Switch Value ADC4 0x0000_0610

Building and setup Ångström distribution from scratch page 36 of 54

ADC3 0x0000_0620 ADC2 0x0000_0640 ADC1 0x0000_0680 ADC0 0x0000_0608

ADCSWLock: 0x8090_0020

SWLCK Software lock bits WRITE: The Unlock value for this feature is 0xAA READ: During a read operation SWLCK[0] has the following meaning: 1 = Unlocked for current bus access. 0 = Locked

ADCIntEn: 0x8090_0024

RINTEN: Bit 11: Synchronous Data Ready Interrupt Enable. Setting this bit results in an interrupt whenever the Synchronous Data Ready (SDR) bit in the ADCResult register is set.

ADCClkDiv: 0x8093_0090

ADCEN: Bit 31: ADC clock enable. ADIV: Bit 16: ADC clock divider value. 0 - ADC Clock is divide-by-16 from the external oscillator. 1 - ADC Clock is divide-by-4 from the external oscillator.

DeviceCfg: 0x8093_0080

ADCPD: Bit 2: ADC Power Down. 1 - ADC and clocks are powered down. 0 - ADC and clocks are active. ADCPD must be zero for normal ADC operation. ADCEN: Bit 17: ADC Enable. The ADCEN bit does not affect the ADC power state. ADC power down is directly controlled by the ADCPD bit. 1 = ADC Interface enabled. 0 = ADC Interface disabled. */

#include "meteo_channels_AnalogChannel.h" #include #include #include #include #include

Building and setup Ångström distribution from scratch page 37 of 54

#include #include #include #include

#include "peekpoke.h" #include "ep93xx_adc.h"

/* Prototypes */ int get_channel_value(int channel);

/* globals */ static unsigned long adc_page, syscon_page; static int devmem;

int get_channel_value(int channel) { int cur_ch, avg, i;

switch(channel) { case 0: cur_ch = ADC_CH0; break; case 1: cur_ch = ADC_CH1; break; case 2: cur_ch = ADC_CH2; break; case 3: cur_ch = ADC_CH3; break; case 4: cur_ch = ADC_CH4; break; }

//discard first two samples read_channel(adc_page, cur_ch); read_channel(adc_page, cur_ch);

avg = 0; //read 10 more samples for(i = 0; i < 10; i++) { usleep(10000); avg += read_channel(adc_page, cur_ch);

Building and setup Ångström distribution from scratch page 38 of 54

}

avg /= 10;

if(avg < 0x7000) avg += 0x10000;

avg -= 40905;

return avg; }

JNIEXPORT void JNICALL Java_meteo_channels_AnalogChannel_init(JNIEnv *env, jobject obj) { devmem = open("/dev/mem", O_RDWR|O_SYNC); assert(devmem != -1);

adc_page = (unsigned long) mmap(0, getpagesize(), PROT_READ|PROT_WRITE, MAP_SHARED, devmem, ADC_PAGE); assert(&adc_page != MAP_FAILED);

syscon_page = (unsigned long) mmap(0, getpagesize(), PROT_READ|PROT_WRITE, MAP_SHARED, devmem, SYSCON_PAGE); assert(&syscon_page != MAP_FAILED);

init_ADC(adc_page, syscon_page); }

JNIEXPORT void JNICALL Java_meteo_channels_AnalogChannel_destroy(JNIEnv *env, jobject obj) { assert(munmap(&adc_page, getpagesize()) == -1); assert(munmap(&syscon_page, getpagesize()) == -1); close(devmem); }

JNIEXPORT jint JNICALL Java_meteo_channels_AnalogChannel_read(JNIEnv *env, jobject obj, jint channel) { return get_channel_value(channel); }

JNIEXPORT jdouble JNICALL Java_meteo_channels_AnalogChannel_readAsVoltage(JNIEnv *env, jobject obj, jint channel) { int value = get_channel_value(channel); return ((double)value * 3.3) / 49732; }

C API implementation and JNI exports for accessing and reading ADC channels.

Building and setup Ångström distribution from scratch page 39 of 54 ep93xx_adc.h

#define ADC_PAGE 0x80900000 #define ADCRESULT_OFFSET 0x0008 #define SDR_MASK 0x80000000 #define DATA_OFFSET 0x0008 #define DATA_MASK 0xFFFF #define ADCSWITCH_OFFSET 0x0018 #define ADC_CH0 0x0608 #define ADC_CH1 0x0680 #define ADC_CH2 0x0640 #define ADC_CH3 0x0620 #define ADC_CH4 0x0610 #define ADCSWLOCK_OFFSET 0x0020 #define UNLOCK_VAL 0xAA

#define SYSCON_PAGE 0x80930000 #define ADCCLKDIV_OFFSET 0x0090 #define SYSCON_UNLOCK 0x00C0 #define TSEN_MASK 0x80000000 #define DEVICECFG_OFFSET 0x0080 #define ADCPD_MASK 0x02 #define ADCEN_MASK 0x20000

/* prototypes */ void init_ADC(unsigned long adc_page, unsigned long syscon_page); int read_channel(unsigned long adc_page, unsigned short channel); static char is_ADC_busy(unsigned long adc_page);

void init_ADC(unsigned long adc_page, unsigned long syscon_page) { unsigned long val;

/* set TSEN bit */ val = PEEK32(syscon_page + ADCCLKDIV_OFFSET); //unlock the software lock POKE32(syscon_page + SYSCON_UNLOCK, UNLOCK_VAL); POKE32(syscon_page + ADCCLKDIV_OFFSET, TSEN_MASK | val);

/* set ADCEN bit */ val = PEEK32(syscon_page + DEVICECFG_OFFSET); POKE32(adc_page + SYSCON_UNLOCK, UNLOCK_VAL); //unlock the soft lock POKE32(syscon_page + DEVICECFG_OFFSET, val | ADCEN_MASK);

/* clear ADCPD bit */ val = PEEK32(syscon_page + DEVICECFG_OFFSET);

Building and setup Ångström distribution from scratch page 40 of 54

POKE32(adc_page + SYSCON_UNLOCK, UNLOCK_VAL); //unlock the soft lock POKE32(syscon_page + DEVICECFG_OFFSET, val & ~ADCPD_MASK); }

int read_channel(unsigned long adc_page, unsigned short channel) { unsigned long val;

POKE32(adc_page + ADCSWLOCK_OFFSET, UNLOCK_VAL); //unlock the soft lock

//write ADCSwitch reg to select channel POKE32(adc_page + ADCSWITCH_OFFSET, channel);

while(is_ADC_busy(adc_page)); //poll ADCResult

//read result from data regisyyter val = PEEK32(adc_page + DATA_OFFSET) ;

val = val & DATA_MASK;

return val; }

static char is_ADC_busy(unsigned long adc_page) { unsigned long val;

val = PEEK32(adc_page + ADCRESULT_OFFSET);

if((val & SDR_MASK) == SDR_MASK) return TRUE;

return FALSE; }

Peekpoke.h

// We can't expect that a dereference of an unsigned short * always // produces a ldrh or strh since the compiler may choose to use // a byte write instead. Hence, we emit the peeks and pokes using // inline assembler. --JO static inline unsigned short PEEK16(unsigned long addr) { unsigned short ret;

asm volatile ( "ldrh %0, [ %1 ]\n"

Building and setup Ångström distribution from scratch page 41 of 54

: "=r" (ret) : "r" (addr) : "memory" ); return ret; }

static inline void POKE16(unsigned long addr, unsigned short dat) { asm volatile ( "strh %1, [ %0 ]\n" : : "r" (addr), "r" (dat) : "memory" ); }

static inline unsigned long PEEK32(unsigned long addr) { unsigned long ret;

asm volatile ( "ldr %0, [ %1 ]\n" : "=r" (ret) : "r" (addr) : "memory" ); return ret; } static inline void POKE32(unsigned long addr, unsigned long dat) { asm volatile ( "str %1, [ %0 ]\n" : : "r" (addr), "r" (dat) : "memory" ); } static inline unsigned char PEEK8(unsigned long addr) { unsigned char ret;

asm volatile ( "ldrb %0, [ %1 ]\n" : "=r" (ret) : "r" (addr) : "memory" ); return ret;

Building and setup Ångström distribution from scratch page 42 of 54

} static inline void POKE8(unsigned long addr, unsigned char dat) { asm volatile ( "strb %1, [ %0 ]\n" : : "r" (addr), "r" (dat) : "memory" ); }

#define TRUE 0x01 #define FALSE 0x00

Next we have to add necessary JAVA API files in meteo directory

DigitalChannel.java

package meteo.channels;

public class DigitalChannel { public native void export(int number, String direction); public native void unexport(int number); public native int read(int number); public native void write(int number, int value); public native void pwm(int number, double f, double k); public native void stopPWM(int number); static { System.loadLibrary("DigitalChannel"); } }

AnalogChannel.java

package meteo.channels;

public class AnalogChannel { private native void init(); public native void destroy(); public native int read(int channel); public native double readAsVoltage(int channel); public AnalogChannel() { this.init(); } static { System.loadLibrary("AnalogChannel"); } }

Building and setup Ångström distribution from scratch page 43 of 54

JAVA API has no main class, so it can’t be tested directly after deployment. That’s why there is another class MeteoTest which can be used for basic test of API functionallity. This class is located in meteo_test directory

MeteoTest.java

package meteo_test;

import java.text.DecimalFormat; import meteo.channels.*;

public class MeteoTest { private static AnalogChannel analog; private static DigitalChannel digital;

private static double f = 70.0; //Hz private static double k = 50.0; //% private static int pwmGPIO = 8;

private static class PwmTest extends Thread { public void run() { digital.pwm(pwmGPIO, f, k); System.out.println("PWM Stopped"); } public void stopPWM() { digital.stopPWM(pwmGPIO); } }

public static void main(String[] args) { // Analog Channel Test DecimalFormat dFormat = new DecimalFormat("0.000");

System.out.println("Read all 5 ADC channels:"); analog = new AnalogChannel(); for(int i = 0; i < 5; i++) { System.out.println("Analog channel " + i + " value: " + analog.read(i) + ", as voltage: " + dFormat.format(analog.readAsVoltage(i)) + "V"); } analog.destroy();

// Digital Channel Test //Integer to keep track of whether we want on or off

Building and setup Ångström distribution from scratch page 44 of 54

boolean toggle = false; int value = 0; int gpio = 0;

System.out.println("Digital channel test: export GPIO 6, 8 as output and GPIO 4 as input."); digital = new DigitalChannel(); digital.export(6, "out"); digital.export(8, "out"); digital.export(4, "in"); for(int i = 0; i < 10; i++) { toggle = !toggle; value = digital.read(4); gpio = value == 0 ? 6 : 8; if(toggle) { digital.write(gpio, 1); } else { digital.write(gpio, 0); } try { Thread.sleep(1000); } catch (InterruptedException e) { System.out.println("thread interrupted"); } } digital.unexport(6); digital.unexport(8); digital.unexport(4);

System.out.println("Start PWM Test for 5 seconds."); PwmTest test = new PwmTest(); test.start(); try { Thread.sleep(5000); } catch (InterruptedException e) { System.out.println("thread interrupted"); } test.stopPWM(); } }

Finally we have to add meteo recipe

Building and setup Ångström distribution from scratch page 45 of 54 meteo_1.0.bb

DESCRIPTION = "JAVA Meteo Application" PR = "r0"

DEPENDS = "classpath classpath-tools-native"

inherit autotools java-library

SRC_URI = "file://meteo/* \ file://meteo_test/* \ file://lib/* \ file://bin"

S = ${WORKDIR}

do_compile() { #JAVAH="gjavah -classpath \$(CLASSPATH) -d \$(DEST) -jni" \ JAVAH="gjavah -jni" JAR=gjar \ #JAVAC="javac -classpath \$(CLASSPATH) -d \$(TOP)/ -O -source 1.3 -target 1.3" \ JAVAC="javac" JAVAINCLUDEDIR=${STAGING_INCDIR}/classpath \ GLIBTOOL="${TARGET_SYS}-libtool --tag=CC"

${JAVAC} meteo/channels/AnalogChannel.java ${JAVAC} meteo/channels/DigitalChannel.java ${JAVAH} -classpath ${S} -d lib/ meteo.channels.AnalogChannel ${JAVAH} -classpath ${S} -d lib/ meteo.channels.DigitalChannel ${CC} ${CFLAGS} ${LDFLAGS} -shared -I${JAVAINCLUDEDIR} lib/AnalogChannel.c - o lib/libAnalogChannel.so ${CC} ${CFLAGS} ${LDFLAGS} -shared -I${JAVAINCLUDEDIR} lib/DigitalChannel.c -o lib/libDigitalChannel.so ${JAR} cvf bin/meteo.jar meteo ${JAVAC} -classpath bin/meteo.jar meteo_test/MeteoTest.java ${JAR} cmf meteo_test/headers.txt bin/meteo_test.jar meteo_test/*.class }

do_install() { install -d ${D}/${libdir_jni} install -d ${D}/${datadir_java}

METEO_PATH="${D}/${libdir_jni}" \ JHOME="${D}/${datadir_java}" \ GLIBTOOL="${TARGET_SYS}-libtool"

Building and setup Ångström distribution from scratch page 46 of 54

install -m 0755 ${S}/lib/lib*.so ${METEO_PATH} install -m 0755 ${S}/bin/*.jar ${JHOME} }

do_stage() { oe_jarinstall -s bin/meteo.jar oe_jarinstall -s bin/meteo_test.jar }

PACKAGES = "lib${PN}-jni lib${PN}-dev lib${PN}-jni-dbg lib${PN}-test ${JPN}"

FILES_lib${PN}-jni = "${libdir_jni}/lib*.so" FILES_lib${PN}-dev = "${libdir_jni}/lib*.la ${libdir_jni}/lib*.a" FILES_lib${PN}-jni-dbg = "${libdir_jni}/.debug/lib*.so" FILES_lib${PN}-test = "${datadir_java}/*_test.jar"

Build meteo recipe with the following command bitbake meteo && bitbake package-index

After successful build on target platform you can deploy the following packages:

Libmeteo-jni – dynamic libraries. They will be installed as libAnalogChannel.so and libDigitalChannel.so in /usr/lib/jni directory

Libmeteo-java – JAVA API archive. It will be installed as meteo.jar in /usr/share/java directory

Libmeteo-test – JAVA API Test application. It will be installed as meteo_test.jar in /usr/share/java directory.

Let’s deploy our application on target platform. Execute the following command on target platform.

opkg update && opkg install libmeteo-jni && opkg install libmeteo-java && opkg install libmeteo-test

Start test application

cd /usr/share/java java –jar meteo_test.jar

Another important issue is how to use our Java API in OSGi. API jar file is located at

/angstrom/build/tmp-angstrom_2008_1/work/armv4t-angstrom-linux- gnueabi/meteo-1.0-r0/bin/meteo.jar

Building and setup Ångström distribution from scratch page 47 of 54

Open Eclipse. Go to File->New->Plug-in Project. Enter project name like picture bellow:

Click on Next. Choose J2SE-1.3 as Execution Environment.

Building and setup Ångström distribution from scratch page 48 of 54

Click on Finish.

We have to create directory for our external Jar file - Right click on Project folder, click on New -> Folder and enter lib as Folder Name. Copy meteo.jar to lib directory. Right click again on Project folder and click on Properties. Select Java Build Path from left navigation menu and click on Add Jars…

Select meteo.jar from meteo_bundle/lib directory and click OK.

Building and setup Ångström distribution from scratch page 49 of 54

Open Activator.java in meteo_bundle/src/meteo_bundle directory. Paste the following content package meteo_bundle;

import java.text.DecimalFormat;

import org.osgi.framework.BundleActivator; import org.osgi.framework.BundleContext; import meteo.channels.*;

/** * The activator class controls the plug-in life cycle */ public class Activator implements BundleActivator {

// The plug-in ID public static final String PLUGIN_ID = "meteo_station"; //$NON-NLS-1$ // Analog channel private static AnalogChannel analog; // Digital channel private static DigitalChannel digital;

private static double f = 70.0; //Hz private static double k = 50.0; //% private static int g = 8; //PWM out GPIO number private static int l = 5; //Seconds for PWM lifetime

// The shared instance private static Activator plugin;

/** * The constructor */ public Activator() { }

Building and setup Ångström distribution from scratch page 50 of 54

public void start(BundleContext context) { System.out.println("Meteo Bundle started"); DecimalFormat dFormat = new DecimalFormat("0.000");

System.out.println("Read all 5 ADC channels:"); analog = new AnalogChannel(); for(int i = 0; i < 5; i++) { System.out.println("Analog channel " + i + " value: " + analog.read(i) + ", as voltage: " + dFormat.format(analog.readAsVoltage(i)) + "V"); } analog.destroy();

// Digital Channel Test //Integer to keep track of whether we want on or off boolean toggle = false; int value = 0; int gpio = 0;

System.out.println("Digital channel test: export GPIO 6, 8 as output and GPIO 4 as input."); digital = new DigitalChannel(); digital.export(6, "out"); digital.export(8, "out"); digital.export(4, "in"); for(int i = 0; i < 10; i++) { toggle = !toggle; value = digital.read(4); gpio = value == 0 ? 6 : 8; if(toggle) { digital.write(gpio, 1); } else { digital.write(gpio, 0); } try { Thread.sleep(1000); } catch (InterruptedException e) { System.out.println("thread interrupted"); } } digital.unexport(6); digital.unexport(8); digital.unexport(4);

System.out.println("Start PWM Test for " + l + " seconds with frequency " + f + " and duty cycle " + k); Pwm pwm = new Pwm(digital, f, k, g); pwm.start(); try { Thread.sleep(l * 1000); } catch (InterruptedException e) { System.out.println("thread interrupted"); } pwm.stopPWM(); }

public void stop(BundleContext context) { System.out.println("Meteo Bundle stopped"); }

/** * Returns the shared instance * * @return the shared instance */ public static Activator getDefault() { Building and setup Ångström distribution from scratch page 51 of 54

return plugin; }

}

Add new class called Pwm.java

package meteo_bundle;

import meteo.channels.DigitalChannel;

public class Pwm extends Thread { private DigitalChannel digital; private double f; //Hz private double k; //% private int g; //PWM out GPIO number

public Pwm(DigitalChannel digital, double f, double k, int g) { this.digital = digital; this.f = f; this.k = k; this.g = g; } public void run() { this.digital.pwm(this.g, this.f, this.k); System.out.println("PWM Stopped"); } public void stopPWM() { digital.stopPWM(g); } }

We have to add our jar file to Classpath. Double click MANIFEST.MF in meteo_bundle/META-INF directory. Click on Runtime in Plug-in content section. Click on Add buton in Classpath section and select meteo.jar file from lib directory

Building and setup Ångström distribution from scratch page 52 of 54

Click on Dependencies section. Clear all required plugins by clicking on Remove button. Click on Add… and select only org.eclipse.osgi plugin. Press CTRL + S to save configuration.

Next click on Run -> Run Configurations on top menu. Right click on OSGi Framework an select New. Enter configuration name – meteo_bundle for example. Click on Deselect All, select meteo_bundle and click on Add Required Bundles. Click on Apply.

Finally we have to export our application for deployment on target platform. In Eclipse click on File -> Export and select Plug-in Development -> Deployable plug-ins and fragments. Click on Next and select meteo_bundle. Click on Browse button to select output directory – you can create new directory – meteo_bundle for example. Click on Finish. Create new directory named configuration in output directory selected in previous step. Create new file config.ini with the following content

osgi.noShutdown=true osgi.bundles=\ plugins/meteo_bundle@start\

osgi.bundles.defaultStartLevel=4 osgi.configuration.cascaded=true eclipse.ignoreApp=true

Finally we have to download OSGi framework bundle. Go to Equinox download page, select Latest build and download only framework as jar file. Save file in meteo_bundle directory root. In the end we have to deploy and test our bundle. You can create archive of project directory and transfer it to target platform through HTTP. After extracting you can run application with the following command Building and setup Ångström distribution from scratch page 53 of 54

java -jar org.eclipse.osgi_3.7.0.v20110613.jar -Xms1M -Xmx8M -console

You can see output bellow

osgi> Meteo Bundle started Read all 5 ADC channels: Analog channel 0 value: 37931, as voltage: 2.517V Analog channel 1 value: 24855, as voltage: 1.649V Analog channel 2 value: 24855, as voltage: 1.649V Analog channel 3 value: 24855, as voltage: 1.649V Analog channel 4 value: 24857, as voltage: 1.649V Digital channel test: export GPIO 6, 8 as output and GPIO 4 as input. Start PWM Test for 5 seconds with frequency 70.0 and duty cycle 50.0 PWM Stopped ss

Framework is launched.

id State Bundle 0 ACTIVE org.eclipse.osgi_3.7.0.v20110613 1 ACTIVE meteo_bundle_1.0.0.201108131302

osgi> stop 1 Meteo Bundle stopped

osgi>

Building and setup Ångström distribution from scratch page 54 of 54