Notes on fixing a broken Gentoo grub install…

Last night I switched HDs on my Gentoo laptop. In the process of doing this, I reset the bios… this was a bad idea, as I had used efibootmgr to setup my UEFI firmware to boot Linux.

Now, at this point the reasonable thing to do is boot from a usb stick, chroot into the Gentoo install and either re-run efibootmgr or install grub… I didn’t have a usb stick/other installation media handy… I did however have a SSD with Debian installed. My laptop only has 1 SATA bay however (both the Gentoo install and the Debian install are on SATA drives). These notes document what I did, in case I need to do this again in the future…

So… I decided to boot into Debian. Create a ramdisk with a working Debian install, chroot to this. Then swap in the Gentoo SSD, chroot to the Gentoo install and install grub. This post documents my notes on this process.

First boot into Debian, then as root create a ramdisk.

swapoff
mount -t tmpfs -o size=2048m none /mnt/ramdisk

I probably could have used debbootstrap or something else… but I decided to copy everything I needed across manually. First I setup the dev,sys and proc directories:

cd /mnt/ramdisk
mkdir dev
mkdir sys
mkdir proc
mount --rbind /dev ./dev
mount --rbind /sys ./sys
mount --rbind /proc ./proc

Now copy across files needed for a more or less working system:

cp -r /etc .
cp -r /bin .
cp -r /sbin .
mkdir usr
cp -r /usr/bin ./usr
cp -r /usr/sbin ./usr
cp -r /lib64 .
cp -r /lib .

In order to setup grub, I also needed the vfat module and 437 codepage modules. It’s easier to load them now…

modprobe vfat
modprobe nls_cp437

Next we pivot_root to use our new ramdisk… I guess chrooting will work too…

mkdir /tmp/ramdisk/old_root
pivot_root /tmp/ramdisk /tmp/ramdisk/old_root

You can also chroot into the ramdisk… but if you exit and re-login you should be in the new root (you might need to restart login…).

I now pulled out the Debian SATA drive (there’s probably a way to umount it cleanly… I didn’t… this is bad don’t do it). And inserted the Gentoo drive.

Mount the gentoo drive somewhere and chroot into it:

mkdir gentoo;mount /dev/sdb5 ./gentoo
cd gentoo
mount --rbind /dev ./dev
mount --rbind /sys ./sys
mount --rbind /proc ./proc
chroot gentoo

Within the gentoo install you should be able to install grub, or do whatever else you want to do. For me the grub install commands are:

mount /boot
grub-install /dev/sda --target=x86_64-efi --efi-directory=/boot --removable
grub-mkconfig -o /boot/grub/grub.cfg

My laptop (Lenovo x230) doesn’t boot unless I used –removable.

ILX511 Interface PCB for ICE40HX8K

Based on my previous experiments with the ICE40HX8K/AD9552/ILX511 Linearpcb, I’ve put together the above PCB. It’s not perfect, but it should aid further experimentation… Kicad files and gerbers below:

Kicad files

Gerbers

ILX511 Update

A quick update on my previous blog post on using the ILX511 with an ICE40 fpga. I setup the CCD in the configuration shown above. The ND filter is an ND1000 (ND 3.0). The only change to the code in the previous post is to use a 4Mbps in the UART:

uart = UART(divisor=6)

The serial output looks much cleaner now (minicom, use Ctrl-A u to add linefeeds, set speed to 4mbps). In the capture below I’m scanning the laser across the CCD:

Notes on using a ILX511 Linear CCD, AD9225 ADC, ICE40HX8K and Nmigen

The messy pile of hacks above is my first attempt at getting an ILX511 Linear CCD working. I’m using a ICE40HX8K FPGA (Lattice evaluation board). An AD9225 ADC is used to acquire data. An AD823 is used to amplify the signal from the CCD. 2N7002s are used to convert the 3.3v signals to 5v for the CCD. I needed to use 1K pullups to get the required 100ns rise time required…

The horribly filmed scope trace below shows the ROG signal (resets to start of frame) and amplified Vout.

The setup is quite sensitive. I had to use a ND1000 (ND 3.0) in front of the filter. In the video above I’m running a laser pointer back an forth across the CCD, and you can see the peak move relative to the ROG impulse.

The code below is used to drive the CCD. Both the code below and the board are horrible messes. There seem to be a few issues with the code and the output is not as clear as shown in the scope trace. Part of the issue is likely that I’m trying to write data out to the UART as I’m acquiring it. I need to buffer one line (or pixels) and then dump it out to the UART…

But everything more or less works, and it’s probably time to design a PCB if I want to move forward. I’ll then have something stable to work with when rewriting the code. A tarball of the code is here. A listing is also below, it uses the pll code from kbob (modified for the HX8K on the evaluation board) and uart.py from the nmigen repository.

#!/usr/bin/python3

from nmigen import *
from uart import *
from nmigen_boards.ice40_hx8k_b_evn import *
from nmigen.build import *

from pll import PLL


class Top(Elaboratable):

    def elaborate(self, platform):
        # B1 is clock
        adcclk = [ Resource("ad9225clk", 0, Pins("B1", dir="o"), Attrs(IO_STANDARD="SB_LVCMOS")) ]

        adc = [ Resource("ad9225", 0, Pins("B2 C1 C2 D1 D2 E2 F1 F2 G2 H1 H2 J2", dir="i"),  Attrs(IO_STAN
DARD="SB_LVCMOS")) ]

        # pins 3 4 11
        ilx511shsw = [ Resource("ilx511shsw", 0, Pins("N3", dir="o"), Attrs(IO_STANDARD="SB_LVCMOS")) ]
        ilx511clk  = [ Resource("ilx511clk" , 0, Pins("N2", dir="o"), Attrs(IO_STANDARD="SB_LVCMOS")) ]
        ilx511rog  = [ Resource("ilx511rog" , 0, Pins("M2", dir="o"), Attrs(IO_STANDARD="SB_LVCMOS")) ]

        platform.add_resources(adc)
        platform.add_resources(adcclk)
        platform.add_resources(ilx511shsw)
        platform.add_resources(ilx511clk)
        platform.add_resources(ilx511rog)


        # PLL Stuff

        # If you don't specify dir='-', you will experience a world
        # of debugging pain.
        clk_pin = platform.request(platform.default_clk, dir='-')

        m = Module()
        pll = PLL(freq_in_mhz=12, freq_out_mhz=24)

        m.domains += pll.domain     # override the default 'sync' domain

        timer = Signal(28)
        timerRog = Signal(28)

        #Connect TX to B12
        led0     = platform.request('led', 0)
        muart    = platform.request('uart')
        data     = platform.request('ad9225',0)
        dataclk  = platform.request('ad9225clk',0)
        ccd_shsw = platform.request('ilx511shsw',0)
        ccd_clk  = platform.request('ilx511clk',0)
        ccd_rog  = platform.request('ilx511rog',0)
        dataA = Signal(8)
        rdy   = Signal(1)

        with m.If(timer[8]): #9
            m.d.sync += [
              rdy.eq(1),
              timer.eq(0)
            ]
        with m.Else():
            m.d.sync += [
                timer.eq(timer + 1)
            ]


        timerD = Signal(4)
        m.d.sync += [
            timerD.eq(timerD+1)
        ]
        with m.If(rdy == 1):
            m.d.sync += [
                rdy.eq(0)
            ]

        with m.If(timerRog[15]): #16
            m.d.sync += [
              ccd_rog.eq(1),
              timerRog.eq(0),
              timerD.eq(0),
              timer.eq(0),
              dataA.eq(0x0A),
              rdy.eq(1)
            ]
        with m.Else():
            m.d.sync += [
                timerRog.eq(timerRog + 1),
                dataA.eq(data.i[8:11] + 0x2E),
            ]

        with m.If(timerRog[11]):
            m.d.sync += [
                ccd_rog.eq(0),
            ]


        with m.If(ccd_rog == 0):
            m.d.sync += [
                ccd_clk.eq(timerD[-1])
            ]
        with m.Else():
            m.d.sync += [
                ccd_clk.eq(0)
            ]

        m.d.comb += [
            pll.clk_pin.eq(clk_pin),
            dataclk.eq(timer[5])
        ]

        m.d.comb += [
            ccd_shsw.eq(1) # use Sample and Hold.
        ]

        # UART

        uart = UART(divisor=208)
        uart.tx_o = muart.tx


        m.d.comb += [
            uart.tx_data.eq(dataA),
            uart.tx_rdy.eq(rdy)
        ]

        m.submodules += [pll, uart]

        return m


if __name__ == '__main__':
    platform = ICE40HX8KBEVNPlatform()

    platform.build(Top(), do_program=True)