Archive for October, 2007

Embedded x86 Linux

October 11, 2007

Another Update: Check out the new version without squashfs here.
Updated!  I modified the squashfs and init so now the entire init script is executed properly, before it would work, but we were missing a few things in the final init stage.

DebianThis rough draft howto describes my experience, minus most of the goof-ups, of how you can setup a small x86 embedded system. A typical linux box that boots grub does the following:

  • Read the MBR
  • load the kernel pointed to by the bootloader
  • load the initial ram disk
  • execute an init script who’s main purpose is to set the environment up so that the real root file system can be mounted
  • then it mounts the FS and executes the real init script, but only after the preliminary init mounts the real root file system read/write.

Confused yet? It gets worse if you must use a read only file system like an IDE/CF flash disk. The preliminary init (ran from initial ram disk) must mount the real file system (usually squashfs) read only. It also sets up a read/write FS in RAM so that the system may store and use things later like /proc, /dev, and /var. After creating both read only and read/write file systems (FS) it merges them with the unionfs/aufs kernel function in init. Then it switches root and executes the real init. There fortunately are many “LiveCD” scripts that set this up for you automatically. These init scripts (like casper in Debian) are overkill and can break an embedded system whose environment is known ahead of time. Its a bit like using this toilet paper dispenser in a mission critical application, like after eating the Habenero Hotwings and drinking 5 pints of beer from the local pub.

Also I hate all the autodetecting that comes with most live cds, power glitches and other things can trick it and it is slooowwww, Embedded systems must be reliable! Mine are 500MHz dinosaurs with no electro-mechanical parts whatsoever.

I like to boot the target filesystem root on the target hardware as an actual r/w FS first and set everything up the way I want it. This has the side effect of also testing my hardware configuration and allows me to make major changes quickly.

Then I halt and mount the target on another host to freeze the system into my own read-only install. Remember! It must be readonly if we are to run off of flash in the end, b/c of the limited writes.

Here we go………….

First create skeleton debian install:
Usage: debootstrap [OPTION]… <suite> <target> [<mirror> [<script>]]

% debootstrap sid fs-root-debian-sid

Put this file system on a drive and boot your real hardware. Set everything up the best you can (Minor changes can bee made later, don’t worry).

Back at the host:

chroot to new install or boot the real system hardware using a non flash hard drive:

install squashfs-tools, kernel, and same versions of squashfs and unionfs kernel modules
You may have to fix /etc/resolv.conf for this and other apt based installations
# apt-get install kernel-image-xxx unionfs-modules-xxx squashfs-modules-xxx squashfs-tools

unchroot, do:

Create the boot-dir:

# mkdir -p fs-boot/boot/grub

chroot, do:
# apt-get install grub

make sure mkinitramfs and busybox is installed

unchroot, do:

Copy the boot loader

# cp -a fs-root/usr/lib/grub/i386-pc/* fs-boot/boot/grub/

Copy the kernel over:

$ cp -a fs-root/boot/* fs-boot/boot/

Create the squashed FS

% mksquashfs fs-root fs-squashfs.squashfs -all-root # Makes all files owned by root

On the chrooted target, install initramfs-tools
# apt-get install initramfs-tools

Now the tricky part, edit init scripts, then create the initramfs:

chroot to the fs-root and create our squashfs script:
# vim /usr/share/initramfs-tools/scripts/squashfs

modify it to look like the included file “squashfs_script”, some highlights are:

# This is how we mount the rootfs
# substitute /dev/sda1 for what it will be on the target upon boot, I’m using a usb flashdrive
mount -r -t ext2 /dev/sda1 /.tmpfs/.mnt
losetup /dev/loop0 /.tmpfs/.mnt/boot/fs-squashfs.squashfs
mount -r -t squashfs /dev/loop0 /.tmpfs/.sqfs

# Here we create the final rootfs
mount -w -t unionfs -o dirs=/.tmpfs/.overlay=rw:/.tmpfs/.cdrom=ro:/.tmpfs/.sqfs=ro unionfs /.union

# And switch over to the new FS and run the real init, This is done as the last line of the default debian etch init script, not the squashfs script, you should comment out the old last line:

# Chain to real filesystem
maybe_break init
#exec run-init ${rootmnt} ${init} “$@” <${rootmnt}/dev/console >${rootmnt}/dev/console
exec run-init /.union /sbin/init “$@” </.union/dev/console >/.union/dev/console

Now, still crooted as the target, edit /boot/grub/menu.lst to be:

# menu.lst – See: grub(8), info grub, update-grub(8)
default 0
timeout 5

title Debian live
root (hd0,0)
kernel /boot/vmlinuz vga=791 root=/dev/loop0 ramdisk_size=100000 boot=squashfs #username=user hostname=debian persistent
initrd /boot/file1.img
boot
# Note the boot=squashfs tells init to execute scripts/squashfs
# root=/dev/loop0 is our readonly root squashfs mounted in the initscript
# ramdisk_size=100000 gives the kernel (and us) some space (100M) to work with our unionfs

We’re almost done, now make the initramfs, recall we are still chrooted

# mkinitramfs -o file1.img <kernel-version-here>
please put your kenel version int the appropriate spot above (whatever string is appended to /lib/modules on the target)

Exit from chroot and copy the resulting file1.img to your targets’ boot directory /fs-boot/boot/

# cp file1.img /fs-boot/boot/

Now copy fs-root and fs-boot files to your production device, I’m using a usb flash drive (I assume is partitioned this way):

# cp -a fs-boot/* /mnt/sda1/
# cp -a fs-root/fs-squashfs.squashfs /mnt/sda1/

Make sure that the /proc /dev and /sys directories are empty, they will be filled later by the last stages of init on the unionfs

Install grub to the target device so it will boot, I will not cover that here, its covered everywhere else on the net quite well

I usually like to test the setup under vmware or qemu, as it can save time when debugging.

Comments? Mistakes? Help me make this better. I welcome all non-spam feedback.

BRP-PACU Most Major Update Ever, File Release At Last!

October 9, 2007

File Release!!

For those of you new here, BRP-PACU is an open-source program capable of real-time audio analysis of professionally installed loudspeaker systems. The idea is to use a calibrated microphone to measure the response of a room to playing a reference signal which is usually pink-noise but could be Pink Floyd, as long as it has decent spectral characteristics. The measured signal gets fft’d and divided by the reference signal’s fft. This is captured at 3-5 locations. These captures are then averaged and flipped, then used to calibrate the system.

If none of this rings a bell you probably should read some of my other post topics, because this stuff is probably gonna bore you.

It uses GTK+, alsa-lib, gtkdatabox, fftw, and more! Many of the algorithms were first tested and simulated with Gnu-Octave. Sorry windows users, this requires alsa so tough luck, but you could try it under VMWare, VirtualBox, or Qemu, or even an Ubuntu dual boot.

From my Project News page at sourceforge.net:

Posted By: electronjunkie
Date: 2007-10-09 12:30
Summary: Current Project Status I have made significant progress now with this project. While it is still not usable in its current state, it does the following:

  • Displays FFT of Blackman Windowed audio input in real-time.
  • Displays the transfer function, H(f) = Y(f) / X(f), of the measured system (channel one divided by channel two, or output (measured) divided by input (reference)), where X(f), Y(f) is the fourier transform of the output and input respectively.
  • GUI now uses the quick excellently documented gtkdatabox library instead of the scantily documented libgoffice. Great Success!
  • Averaging function for the H(f) frame, so graph doesn’t bounce/jump in time and smoothing of the plot to make the data more readable by humans, ex: H(f) = (H(f-1) + H(f) + H(f+1))/3.
  • Impulse Response now works! h(t) = H-1(F)

*Output is in dB and Octaves like humans hear, as opposed to Voltage and frequency in Hz, with actual frequency in Hz displayed under mouse cursor.

Todo:

  • Add channel 1 & 2 signal indicators
  • Add support for more than the 4 + averaging buffer.
  • Add save as support (so that a session can be saved). This is something even the expensize programs like SMAART do not do. How many times have you sampled a room just to have SMAART or your PC lock up and lose your buffers. It will also allow you to save samples for future reference.

These items are actually trivial to implement. As an engineer all the fft/data related processing is easy to me, the hard part has been the programming read tape (fixing Makefiles to include libraries, using the libraries API’s). But I have learned some excellent concepts along the way.

Currently we are using one thread for the gui/fft app and one thread to obtain the audio. I’ll probably separate the gui from the fft thread, so that I may change the audio thread to a callback instead of polling. Right now I just want to make it work, then I will optimize the coding later.

The code will be released at version 1.0, as it will not be released until I have tested for memory leaks, and actually used it to calibrate a sound system. RT60, and other measurement features will be available in later version releases.