Kernel compile
Home Page Up ACARS decoder ADS-B dump1090 AIS receiver Cross-compiling Kernel compile Monitoring NTP RTC Wall Clock Updating GPSD

 

Recompiling the Raspberry Pi kernel
to add PPS support

Obsolete information - no longer required for NTP!

Based on notes kindly provided by Rob Windgassen.  The steps below are from me following the notes as a proof-reading exercise - checking they work.  Note that an 8 GB SD card or greater is required to recompile the kernel, but not to run the recompiled kernel.  If you are looking to cross-compile on a Linux PC see here.

The first try I had was from a Zip file which appeared to be corrupt.  When expanding the Zip archive I got an error message about a symlink being too long.  Instead, I used a .tar.gz file which appeared to be OK.

Please note that, thankfully, recompiling the kernel is no longer required to add PPS support.

Getting and compiling the kernel

Starting from the home directory after logging in:

  • $ mkdir kern
  • $ cd kern
  • $ wget https://github.com/raspberrypi/linux/archive/rpi-3.6.y.tar.gz
    • about 100 MB for 3.6
    • about 118 MB for 3.12
  • $ tar xvfz rpi-3.6.y.tar.gz  (takes several minutes)
  • $ mv linux-rpi-3.6.y rpi-3.6.y  (just to keep in step with Rob's document)
  • $ wget https://raw.github.com/lampeh/rpi-misc/master/linux-pps/linux-rpi-pps-gpio-bcm2708.diff
  • $ HERE=$(pwd)
  • $ cd rpi-3.6.y/arch/arm/mach-bcm2708/
  • $ patch --backup bcm2708.c < $HERE/linux-rpi-pps-gpio-bcm2708.diff
  • got Hunk #3 succeeded at 756 (offset 39 lines)
  • $ cd $HERE
  • $ cd rpi-3.6.y
  • If cross-compiling:
    • Set an environment variable KERNEL_SRC to point to the location of the source, e.g. 
      $ export KERNEL_SRC=/home/david/kern/rpi-3.6.y/
    • Set an environment variable CCPREFIX to point to the location of tools e.g.
      $ export CCPREFIX=/home/david/kern/rpi-3.6.y/tools/arm-bcm2708/arm-bcm2708-linux-gnueabi/bin/arm-bcm2708-linux-gnueabi-
  • $ make mrproper (takes about a minute)
  • $ zcat /proc/config.gz > .config
    • In April 2017 Jason Taylor reported a "permission denied" problem getting past this step, even when running with "sudo".  Ideas, anyone?
  • Alternative if cross-compiling:
    • $ cp arch/arm/configs/bcmrpi_defconfig .config  but this then takes ages at the following step.  Decided to take one from raspi-5 instead!
  • $ make oldconfig
  • $ make menuconfig  (got an error that ncurses was not installed, so the next step...)
  • $ sudo apt-get install ncurses-dev  (and now retry the menuconfig)
  • $ make menuconfig
  • The prompts below are slightly different to those in Rob's guide
  • Now first make sure "tickless system" is off. Navigate through the menu like
  • General setup --->
        Timers subsystem ---> [ ]
            Tickless System (Dynamic Ticks)
  • Next turn on PPS support
  • Device Drivers --->
        PPS support --->
            <M>  PPS support
            [ ] PPS debugging messages (NEW)
            <*> PPS kernel consumer support
                *** PPS clients support ***
            < > Kernel timer client (Testing client, use for debug)
            < > PPS line discipline
            <M> PPS client using GPIO
  • The following added after the first attempt failed with error "failed to request GPIO 18"
  • Device Drivers --->
        -*- GPIO Support --->
            --- GPIO Support
            [ ] Debug GPIO calls
            [*] /sys/class/gpio/... (sysfs interface)
            *** Memory mapped GPIO drivers: ***
            <*> Generic memory-mapped GPIO controller support (MMIO platform)
    (no other options set here)
  • Now we build a new kernel
  • make  (took nine and a quarter hours)
  • 2nd attempt: start at 07:00, Nov 11.  Will it be any faster as most of the stuff is already compiled?  Yes!  Just 8 minutes.
  • make modules  (five minutes on 2nd attempt)
  • The next steps put the binaries of loadable modules and the kernel at their target position and this must be performed with root privilege. To be sure the old kernel is left as is the new kernel is named kernel_new.img.
  • $ sudo -i
  • # cd /home/pi/kern/rpi-3.6.y/
  • # make modules_install  (takes about a minute)
  • cp ./arch/arm/boot/zImage /boot/kernel_new.img

At this point, I decided to make an image of the 8 GB SD card, just in case!  Take a note of the OS name when you next log in.  Mine was:

Linux raspberrypi 3.6.11+ #538 PREEMPT Fri Aug 30 20:42:08 BST 2013 armv6l

  • $ sudo nano /boot/config.txt
  • Change/add the text that it looks like (the kernel= line may be missing, by default it uses kernel.img)
  • kernel=kernel_new.img
    # kernel=kernel.img
  • $ sudo reboot

First attempt

After logging in the next time, the OS version was:

Linux raspberrypi 3.6.11 #1 PREEMPT Sun Nov 10 18:50:53 UTC BST 2013 armv6l

  • $ sudo modprobe pps-gpio
  • $ dmesg | tail

At this point, I got the following error messages:

[ 297.355427] pps_core: LinuxPPS API ver. 1 registered
[ 297.355457] pps_core: Software ver. 5.3.6 - Copyright 2005-2007 Rodolfo Giometti <giometti@linux.it>
[ 297.358603] pps-gpio: failed to request GPIO 18
[ 297.358644] pps-gpio: probe of pps-gpio failed with error -22

However, I did still have the rpi_gpio_ntp program running, which may have taken hold of pin GPIO18.  Even after killing this program I still could not get the test to work.  Rob mentioned that he needed the extra kernel configuration step mentioned above, but this did not seem to make a difference for me, but I am not saying that the step is unnecessary.

Second attempt

OS version: Linux raspberrypi 3.6.11 #2 PREEMPT Mon Nov 11 07:04:42 UTC 2013 armv6l

Tried the commands as before:

  • $ sudo modprobe pps-gpio
  • $ dmesg | tail

and got similar error messages, but the rpi_gpio_ntp program was still running.  After some experimentation, I found that in this case it was better to load the pps-gpio module at boot time, thus preventing the rpi_gpio_ntp program from accessing pin GPIO18.  Taking up Rob's instructions:

  • $ sudo nano /etc/modules - and add the following lines
  • # kernel mode PPS (for ntp)
    pps-gpio

After a reboot to load the pps-gpio module, use the dmesg command to look for PPS messages in the message file:

  • $ dmesg | grep pps

[ 9.785006] pps_core: LinuxPPS API ver. 1 registered
[ 9.786398] pps_core: Software ver. 5.3.6 - Copyright 2005-2007 Rodolfo Giometti <giometti@linux.it>
[ 9.797366] pps pps0: new PPS source pps-gpio.-1
[ 9.798916] pps pps0: Registered IRQ 188 as PPS source

You can then install the pps-tools to see the transitions on pin GPIO18 from your PPS source.

  • $ sudo apt-get install pps-tools
  • $ sudo ppstest /dev/pps0

trying PPS source "/dev/pps0"
found PPS source "/dev/pps0"
ok, found 1 source(s), now start fetching data...
source 0 - assert 1384157027.999982273, sequence: 99 - clear 0.000000000, sequence: 0
source 0 - assert 1384157028.999981147, sequence: 100 - clear 0.000000000, sequence: 0
source 0 - assert 1384157029.999981015, sequence: 101 - clear 0.000000000, sequence: 0
source 0 - assert 1384157030.999981881, sequence: 102 - clear 0.000000000, sequence: 0
source 0 - assert 1384157031.999981745, sequence: 103 - clear 0.000000000, sequence: 0
source 0 - assert 1384157032.999981605, sequence: 104 - clear 0.000000000, sequence: 0

I had the RPi synced to a local stratum-1 source when I ran that test.  Finally, you will need to (re-)configure NTP to use kernel-mode PPS rather than your existing source.  I find the type 22 ATOM driver quite convenient for this.
 

Note from Pete Stephenson

Pete Stephenson writes: Between your page and http://ntpi.openchaos.org/pps_pi/ and a little bit of experience I was able to get things working fine, but there were a few caveats: the package "bc" is a build-time dependency for kernels >3.9.x (such as the one in Raspbian).  Evidently bc is commonly installed with a variety of packages and so many people wouldn't notice, but when I tried the build on a fresh-from-the-download-site Raspbian install it failed about an hour into the compile.

The Device Tree

Recent versions of Raspbian use the Device Tree as a means of managing device drivers.  Matthew George kindly supplied this note concerning the extra steps required.
 

Re-using your work on another PC

Saving your compiled kernel and modules

You may to copy that work onto another Raspberry Pi, without all the time taken to recompile the kernel once again.  You can do that just copying the kernel and the module tree.  Log back into your home directory, and enter the following Zip commands.  I found that I didn't have zip on raspi-5, so I first had to collect it:

  • $ sudo apt-get install zip

Then I ran these commands to create two separate Zip files, one with the kernel itself, and the second with the modules which the kernel may load:

  • zip kernel.3.6.11-pps-gpio18.zip /boot/kernel_new.img
  • zip -r modules.3.6.11-pps-gpio18.zip /lib/modules/3.6.11/kernel
  • zip -g modules.3.6.11-pps-gpio18.zip /lib/modules/3.6.11/*

I then copied the .zip files to an FTP server which multiple Raspberry Pi cards could see.  Remember to use binary (image) mode when saving the files to the FTP server.  You could use a memory stick or other transfer means if you prefer.
 

Restoring your compiled kernel and modules to a new RPi

This follows the work I have mentioned before, but this time with my own zip archives.  Please note that the files above will only work with the 3.6.11 kernel (or 3.6.11+).  No, I don't know what would happen if you used the wrong version of the files.  

First, create a backup of the SD card you intend to upgrade!

First create a new directory such as "pps" under your home directory, and use FTP to restore the zip files you created.  Remember to use binary (image) mode when restoring the files.  You could also use the copies I have on my Web server:

  • mkdir pps
  • cd pps
  • wget http://www.satsignal.eu/raspberry-pi/kernel.3.6.11-pps-gpio18.zip
  • wget http://www.satsignal.eu/raspberry-pi/modules.3.6.11-pps-gpio18.zip

Now you can unzip the files ("$ sudo apt-get install zip unzip" if you get command not found below).  We are working in the pps directory, just created.

  • $ unzip kernel.3.6.11-pps-gpio18.zip
  • $ unzip modules.3.6.11-pps-gpio18.zip

You should now have two new directories, boot and lib, corresponding to directories on the SD card.  Copy the new kernel image to the boot directory:

  • $ cd boot
  • $ sudo cp kernel_new.img /boot/

Now we need to move the modules tree from the location expanded to by the zip command to the equivalent location in the /lib/modules tree for the new kernel (3.6.11).  By inspection, on my recompiled card, the new modules are located at:

/lib/modules/3.6.11

whereas the as-installed OS had modules at:

/lib/modules/3.6.11+

so we need a command to relocate the 3.6.11 module tree from the zip expansion, into the /lib/modules/ tree.  I used these command, to make things as least likely to go wrong as possible (famous last words!).  Move the 3.6.11 tree into the /lib/modules/ tree:

  • $ cd ~/pps/lib/modules/
  • $ sudo mv 3.6.11 /lib/modules/3.6.11

Next, we need to edit the /boot/config.txt, and the /etc/modules files as described above.

  • Change/add the text that it looks like (the kernel= line may be missing, by default it uses kernel.img)
  • $ sudo nano /boot/config.txt
  • kernel=kernel_new.img
    # kernel=kernel.img
  • $ sudo nano /etc/modules - and add the following lines
  • # kernel mode PPS (for ntp)
    pps-gpio

And finally, boot up the new configuration:

  • $ sudo reboot

Note that you may need to set the modules so that the PPS starts automatically as described above.

 

Acknowledgements

My thanks to Rob Windgassen for making this information available, and for his work on the Raspberry Pi kernel configuration, and to ???? for the patches from linux-rpi-pps-gpio-bcm2708.diff.

 
Copyright © David Taylor, Edinburgh   Last modified: 2021 Jan 31 at 10:00