Long-term Memory / A collection of note-to-self's Sun, 14 Apr 2019 13:27:50 +0000 en-US hourly 1 https://wordpress.org/?v=5.1.1 Huawei K4203 on Raspberry Pi 3B+ /2018/12/23/huawei-k4203-on-raspberry-pi-3b /2018/12/23/huawei-k4203-on-raspberry-pi-3b#respond Sun, 23 Dec 2018 20:04:23 +0000 https://blog.dest-unreach.be/?p=3341 I’m making a Raspberry Pi to put at a “remote” location, and I needed network connectivity. I had an old USB 3G dongle lying around. It appears to be a Vodafone-branded Huawei K4302 modem, supporting HSPA+ (no LTE).

Picture of the front of the USB stick.
Picture of the back of the USB stick.

The modem presents itself on the USB bus as follows:

Bus 001 Device 005: ID 12d1:1f1c Huawei Technologies Co., Ltd.
Device Descriptor:
  bLength                18
  bDescriptorType         1
  bcdUSB               2.00
  bDeviceClass            0 (Defined at Interface level)
  bDeviceSubClass         0
  bDeviceProtocol       255
  bMaxPacketSize0        64
  idVendor           0x12d1 Huawei Technologies Co., Ltd.
  idProduct          0x1f1c
  bcdDevice            1.02
  iManufacturer           1 Vodafone(Huawei)
  iProduct                2 HUAWEI Mobile
  iSerial                 3 FFFFFFFFFFFFFFFF
  bNumConfigurations      2
  Configuration Descriptor:
    bLength                 9
    bDescriptorType         2
    wTotalLength           32
    bNumInterfaces          1
    bConfigurationValue     1
    iConfiguration          0
    bmAttributes         0xa0
      (Bus Powered)
      Remote Wakeup
    MaxPower              500mA
    Interface Descriptor:
      bLength                 9
      bDescriptorType         4
      bInterfaceNumber        0
      bAlternateSetting       0
      bNumEndpoints           2
      bInterfaceClass         8 Mass Storage
      bInterfaceSubClass      6 SCSI
      bInterfaceProtocol     80 Bulk-Only
      iInterface              4 Mass Storage
      Endpoint Descriptor:
        bLength                 7
        bDescriptorType         5
        bEndpointAddress     0x81  EP 1 IN
        bmAttributes            2
          Transfer Type            Bulk
          Synch Type               None
          Usage Type               Data
        wMaxPacketSize     0x0200  1x 512 bytes
        bInterval               0
      Endpoint Descriptor:
        bLength                 7
        bDescriptorType         5
        bEndpointAddress     0x01  EP 1 OUT
        bmAttributes            2
          Transfer Type            Bulk
          Synch Type               None
          Usage Type               Data
        wMaxPacketSize     0x0200  1x 512 bytes
        bInterval               1
  Configuration Descriptor:
    bLength                 9
    bDescriptorType         2
    wTotalLength           87
    bNumInterfaces          2
    bConfigurationValue     2
    iConfiguration          0
    bmAttributes         0xa0
      (Bus Powered)
      Remote Wakeup
    MaxPower              500mA
    Interface Association:
      bLength                 8
      bDescriptorType        11
      bFirstInterface         0
      bInterfaceCount         2
      bFunctionClass          2 Communications
      bFunctionSubClass      14
      bFunctionProtocol       0
      iFunction               8 K4203
    Interface Descriptor:
      bLength                 9
      bDescriptorType         4
      bInterfaceNumber        0
      bAlternateSetting       0
      bNumEndpoints           1
      bInterfaceClass         2 Communications
      bInterfaceSubClass     14
      bInterfaceProtocol      0
      iInterface              5 CDC Network Control Model (NCM)
      CDC Header:
        bcdCDC               1.10
      CDC MBIM:
        bcdMBIMVersion       1.00
        wMaxControlMessage   1024
        bNumberFilters       16
        bMaxFilterSize       20
        wMaxSegmentSize      1500
        bmNetworkCapabilities 0x20
          8-byte ntb input size
      CDC Union:
        bMasterInterface        0
        bSlaveInterface         1
      Endpoint Descriptor:
        bLength                 7
        bDescriptorType         5
        bEndpointAddress     0x82  EP 2 IN
        bmAttributes            3
          Transfer Type            Interrupt
          Synch Type               None
          Usage Type               Data
        wMaxPacketSize     0x0010  1x 16 bytes
        bInterval               9
    Interface Descriptor:
      bLength                 9
      bDescriptorType         4
      bInterfaceNumber        1
      bAlternateSetting       0
      bNumEndpoints           0
      bInterfaceClass        10 CDC Data
      bInterfaceSubClass      0 Unused
      bInterfaceProtocol      2
      iInterface              6 CDC Network Data
    Interface Descriptor:
      bLength                 9
      bDescriptorType         4
      bInterfaceNumber        1
      bAlternateSetting       1
      bNumEndpoints           2
      bInterfaceClass        10 CDC Data
      bInterfaceSubClass      0 Unused
      bInterfaceProtocol      2
      iInterface              6 CDC Network Data
      Endpoint Descriptor:
        bLength                 7
        bDescriptorType         5
        bEndpointAddress     0x81  EP 1 IN
        bmAttributes            2
          Transfer Type            Bulk
          Synch Type               None
          Usage Type               Data
        wMaxPacketSize     0x0200  1x 512 bytes
        bInterval               0
      Endpoint Descriptor:
        bLength                 7
        bDescriptorType         5
        bEndpointAddress     0x01  EP 1 OUT
        bmAttributes            2
          Transfer Type            Bulk
          Synch Type               None
          Usage Type               Data
        wMaxPacketSize     0x0200  1x 512 bytes
        bInterval               0
Device Qualifier (for other device speed):
  bLength                10
  bDescriptorType         6
  bcdUSB               2.00
  bDeviceClass            0 (Defined at Interface level)
  bDeviceSubClass         0
  bDeviceProtocol       255
  bMaxPacketSize0        64
  bNumConfigurations      2
Device Status:     0x0001
  Self Powered

Its a fairly typical “flip-flop” device that starts out by pretending to be a storage device (CD-ROM is this case), but can be switched to the actual modem. Under linux, this switching is done by usb_modeswitch

USB reset

Normally, this all goes automatically. But it didn’t.

Every time usb_modeswitch tried to switch the dongle, I got:

usb usb1-port3: disabled by hub (EMI?), re-enabling...

Followed by a complete reset of everything attached to the USB-bus (including wired ethernet). The message (and the search results about the message) seem to be unrelated to mode switching. I don’t think it’s a power issue. The Raspberry Pi is capable to provide 1.2A of power to its USB ports. Since the 3G modem is the only thing plugged in, and a single USB port should not require more than 500mA, I should have 700mA headroom.

The stick is plugged directly into the port, without any extension cord that could pick up EMI, but I tried adding a cord anyway, but got the same behaviour.

But I found it peculiar that the bus reset happens right at the time of the mode-switch, so I looked into that.

Alternative switching method

I found a page describing another switching method, that I automated by adding the following line in /etc/udev/rules.d/99-huawei-modem.rules:

ACTION=="add", ATTR{idVendor}=="12d1", ATTR{idProduct}=="1f1c", RUN+="usb_modeswitch -v 12d1 -p 1f1c -W -I -M 55534243123456780000000000000011062000000101000100000000000000"

This worked every time without resetting the USB bus…

However, while trying to reproduce these issues while writing this post, it just worked every time, even with the normal switching logic…:


USB_ModeSwitch log from Sun Dec 23 09:01:16 GMT 2018

Use global config file: /etc/usb_modeswitch.conf
Adjust delay for USB storage devices ...
 Delay set to 4 seconds

Raw parameters: {--switch-mode} {1-1.1.3:1.0}
Use top device dir /sys/bus/usb/devices/1-1.1.3
Check class of first interface ...
 Interface 0 class is 08.

----------------
USB values from sysfs:
  manufacturer	Vodafone(Huawei)
  product	HUAWEI Mobile
  serial	FFFFFFFFFFFFFFFF
----------------
Found packed config collection /usr/share/usb_modeswitch/configPack.tar.gz
ConfigList: pack/12d1:1f1c pack/12d1:#linux
SCSI attributes not needed, move on
Check config: pack/12d1:1f1c
! matched. Read config data
Extract config 12d1:1f1c from collection /usr/share/usb_modeswitch/configPack.tar.gz
Command line:
usb_modeswitch -W -D  -b 1 -g 5 -v 12d1 -p 1f1c -f $flags(config)

Verbose debug output of usb_modeswitch and libusb follows
(Note that some USB errors are to be expected in the process)
--------------------------------

Read long config from command line

 * usb_modeswitch: handle USB devices with multiple modes
 * Version 2.5.0 (C) Josua Dietze 2017
 * Based on libusb1/libusbx

 ! PLEASE REPORT NEW CONFIGURATIONS !

DefaultVendor=  0x12d1
DefaultProduct= 0x1f1c
TargetVendor=   0x12d1
TargetProductList="157a,1590"
HuaweiNewMode=1
System integration mode enabled

Use given bus/device number: 001/005 ...
Look for default devices ...
 bus/device number matched
  found USB ID 12d1:1f1c
   vendor ID matched
   product ID matched
 Found devices in default mode (1)
Get the current device configuration ...
Current configuration number is 1
Use interface number 0
 with class 8
Use endpoints 0x01 (out) and 0x81 (in)

USB description data (for identification)
-------------------------
Manufacturer: Vodafone(Huawei)
     Product: HUAWEI Mobile
  Serial No.: FFFFFFFFFFFFFFFF
-------------------------
Using standard Huawei switching message
Looking for active driver ...
 OK, driver detached
Set up interface 0
Use endpoint 0x01 for message sending ...
Trying to send message 1 to endpoint 0x01 ...
 OK, message successfully sent
Read the response to message 1 (CSW) ...
 Response successfully read (13 bytes), status 0
Reset response endpoint 0x81
Reset message endpoint 0x01
ok:busdev
--------------------------------
(end of usb_modeswitch output)

Check success of mode switch for max. 20 seconds ...
 Wait for device file system (1 sec.) ...
 Read attributes ...
 All attributes matched
Mode switching was successful, found 12d1:1590 (Vodafone(Huawei): HUAWEI Mobile)
Logger is /usr/bin/logger
Check for AVOID_RESET_QUIRK kernel attribute
 AVOID_RESET_QUIRK activated

All done, exit

Dialing out

Once switched, the modem presents itself as a network interface using the cdc_ether driver, including a DHCP-server. So this usually yields a fully functional network connection, fully automatically.

My SIM-card was PIN-locked. In that case, the modem redirects all HTTP-requests to its web-based interface, and asks for the PIN.

I wanted to automate this step. Which seems to be a bit more complicated than expected. I sniffed a promising call to /api/pin/operate with an XML-body:

<request><OperateType>0</OperateType><CurrentPin>1234</CurrentPin><NewPin></NewPin><PukCode></PukCode><token>302258</token></request>

But I couldn’t reproduces this using Curl. Apparently, the token attribute is not constant. So where does that come from? Luckily, the JavaScript used in the web-interface is not obscured, so it’s fairly easy to find out that it’s a variable set in /html/js/vendor.js, and is different each time. These steps seem to work:

PIN="1234"

TOKEN="$( curl --silent --connect-timeout 5 http://192.168.9.1/html/js/vendor.js | grep 'var STR_AJAX_VALUE' | sed 's/.*"\([0-9]*\)".*/\1/' )"

curl -v http://192.168.9.1/api/pin/operate -d "<request><OperateType>0</OperateType><CurrentPin>${PIN}</CurrentPin><NewPin></NewPin><PukCode></PukCode><token>${TOKEN}</token></request>"

]]>
/2018/12/23/huawei-k4203-on-raspberry-pi-3b/feed 0
BeagleBone Black – the device tree (overlay) /2017/07/16/beaglebone-black-the-device-tree-overlay /2017/07/16/beaglebone-black-the-device-tree-overlay#respond Sun, 16 Jul 2017 13:17:12 +0000 https://blog.dest-unreach.be/?p=3203 The linux kernel is responsible for managing all the hardware. Which brings us to the question: how does it know what hardware there is to manage? On traditional PC platforms, the kernel can read out a lot of information from the BIOS. But on embedded devices such as the BeagleBone (Black), there is no BIOS to read from.

The answer is that you simply tell the kernel what hardware is present. The way you do that, is by providing a device tree during boot. This tree lists all the hardware that is present on the system, along with the needed parameters.

For example:

memory {
  device_type = "memory";
  reg = <0x80000000 0x10000000>;
};

This tells the kernel that it has 256MB (0x10000000 bytes) of memory, mapped from 0x80000000 onwards. The device tree has such an entry for every hardware part. These nodes are organised in a tree, so that the mailbox for PRU0 is located under the mailboxes node, so it can reuse lots of parameters. Update: I’ve found a really good explanation of the device tree for the Raspberry Pi [local copy]. The device tree is exactly the same, but the way to load overlays is different.

The kernel needs a flattened version of this device tree to boot, aptly called the flattened device tree (fdt). The boot-loader should provide this when booting a kernel (much like the initramdisk). The device tree compiler can be used to compile device trees in to flattened device trees (and the other way around, but you lose some symbolic references in that direction).

Overlays

The device tree is only read at boot, which means it’s not possible to dynamically add/change hardware after boot. To solve this problem, BeagleBone has developed the device tree overlay, a changeset that can be applied (and un-applied!) to the device tree. BeagleBone needed this to support their Capes, hence the name cape manager.

The device tree also checks for exclusive usage of hardware resources. It makes sure that you can’t allocate a single PIN to 2 different functions at once.

This device tree fragment will enable Pin 8-11 as a Dallas 1-wire master:

/dts-v1/;
/plugin/;

/ {
  compatible = "ti,beaglebone", "ti,beaglebone-black";

  part-number = "DS18B20-IO";

  exclusive-use =
    "P8.11", "gpio1_13";

  fragment@0 {
    target = <&am33xx_pinmux>;
    __overlay__ {
      ds18b20_pinmux: pinmux_ds18b20 {
        pinctrl-single,pins = < 0x034 0x37 // P8_11 (GPIO1_13): mode 7 (gpio), pull up, Rx enabled >;
      };
    };
  };

  fragment@1 {
    target = <&ocp>;
    __overlay__ {
      onwire@0 {
        compatible = "w1-gpio";
        pinctrl-names = "default";
        pinctrl-0 = <&ds18b20_pinmux>;
        status = "okay";

        gpios = <&gpio1 13 0>
      };
    };
  };
};

PRU

In order to use GPIO pins from the PRU, you need to load a device tree fragment, at least to let the kernel know that you intend to use hardware components. And while you’re at it, you can ask the kernel to configure them for you as well. I needed 4 GPIO pins for my PRU logic. They were located on GPIO2, which is otherwise unused. Without the device tree, the whole GPIO-hardware was put in shutdown by the kernel, which took me a while to figure out. The following device tree overlay enables these parts.

/dts-v1/;
/plugin/;

/ {
  compatible = "ti,beaglebone", "ti,beaglebone-black";

  part-number = "DHT22-PRU-IO";  // Arbitrary name used for reference

  exclusive-use =
    "P8.7", "gpio2_2",
    "P8.8", "gpio2_3",
    "P8.9", "gpio2_5",
    "P8.10", "gpio2_4";

  fragment@0 {
    target = <&am33xx_pinmux>;
    __overlay__ {
      dht22_pru_pinmux: pinmux_dht22_pru {
        pinctrl-single,pins = <
          0x090 0x37 // P8_07 (TIMER4): mode 7 (gpio), pull up, Rx enabled
          0x094 0x37 // P8_08 (TIMER7): mode 7 (gpio), pull up, Rx enabled
          0x09c 0x37 // P8_09 (TIMER5): mode 7 (gpio), pull up, Rx enabled
          0x098 0x37 // P8_10 (TIMER6): mode 7 (gpio), pull up, Rx enabled
        >;
      };
    };
  };

  fragment@1 {
    target = <&ocp>;
    __overlay__ {
      dht22_pru_helper {
        compatible = "gpio-of-helper";
        pinctrl-names = "default";
        pinctrl-0 = <&dht22_pru_pinmux>;
        status = "okay";

        P8_07 {
          gpio-name = "P8_07";
          gpio = <&gpio2 2 0>;
          input;
          dir-changeable;
        };
        P8_08 {
          gpio-name = "P8_08";
          gpio = <&gpio2 3 0>;
          input;
          dir-changeable;
        };
        P8_09 {
          gpio-name = "P8_09";
          gpio = <&gpio2 5 0>;
          input;
          dir-changeable;
        };
        P8_10 {
          gpio-name = "P8_10";
          gpio = <&gpio2 4 0>;
          input;
          dir-changeable;
        };
      };
    };
  };
};

Next step is to compile this overlay, and apply it to the device tree:

dtc -O dtb -o DHT22-PRU-IO-00A0.dtbo -b 0 -@ overlay.dts
cp DHT22-PRU-IO-00A0.dtbo /lib/firmware/.
echo "DHT22-PRU-IO" > /sys/devices/platform/bone_capemgr/slots
cat /sys/devices/platform/bone_capemgr/slots

You can unload the overlay by echo’ing -$slotnumber to the slots file.

]]>
/2017/07/16/beaglebone-black-the-device-tree-overlay/feed 0
BeagleBone Black – PRU programming /2017/07/16/beaglebone-black-pru-programming /2017/07/16/beaglebone-black-pru-programming#respond Sun, 16 Jul 2017 12:42:17 +0000 https://blog.dest-unreach.be/?p=3205 I chose the BeagleBone Black (amongst other things) for the embedded microcontrollers (PRUs): Besides your usual ARM Cortex processor, you can put two “Programmable Real-time Units” to work. These are 2 RISC-cores clocked at 200MHz, optimised for real-time processing:

  • Most instructions take 1 cycle (external memory access takes longer)
  • No async interrupt handling, but provisions to efficiently check for pending interrupts
  • Enhanced GPIO mode, that allows some pins to be directly controlled by the PRU, bypassing the normal GPIO-logic. This boosts performance down to 5ns latencies.

Enabling the PRU

There are two methods for accessing the PRUs from the Linux kernel. The “old” method, “pruss” or “uio”, exposes the entire PRU memory region to userspace. This allows for maximal flexibility, but you need to do everything yourself, such as communications.

The “new” method, “rproc”, works differently: The kernel assumes responsibility for the remote processor, and protects it from userspace. Additional drivers are needed to allow userspace to communicate with the PRU, and these drivers define what is and is not allowed.

I chose to use the rproc-method, but most of what is written below applies to both methods. Newer kernels (4.9.36 at least) don’t start the PRU’s automatically on boot. You need to start the manually by echo start > /sys/class/remoteproc/remoteproc1/state. Stopping the PRU is left as an exercise for the reader 😉 Note that on my setup, PRU0 was assigned remoteproc1 (the M3 power management processor is assigned remoteproc0).

Writing code for the PRU

TI provides an assembler, and even a full IDE suite, but I wanted to stay with my known tools. There is a GCC-variant that compiles to PRU-opcodes. It’s even available as a pre-compiled Debian package called “gcc-pru” from Robert Nelson’s repo. Unfortunately, Robert only has a Jessie-build available, but it seems to work fine on Stretch as well.

As with most embedded projects, the first thing to get working is the blinking LED. I learned a lot from the blinking LED “functionality” I found on GitHub, especially about the rproc-part. It took me countless hours to figure everything out, but in the end it worked.

Getting a blinking LED

GPO 21 of GPIO bank 1 is wired to the blue USR0 LED, normally showing the heartbeat. You can use this output to test the PRU without adding any additional hardware. Start by disabling the heartbeat, so it doesn’t interfere: echo "none" >/sys/class/leds/beaglebone:green:usr0/trigger.

The PRU code is super basic. main.S:

#define CONST_PRUCFG 4
#define GPIO1 0x4804c000
#define GPIO_CLEARDATAOUT 0x190
#define GPIO_SETDATAOUT 0x194

    .text
    .section .init0, "x"
    .global __start
__start:
    // Enable OCP master port to access external memory
    // otherwise the PRU will stall when trying
    LBCO      r0, CONST_PRUCFG, 4, 4    // Load SYSCFG in to r0
    CLR       r0, r0, 4         // Clear SYSCFG[STANDBY_INIT] to enable OCP master port
    SBCO      r0, CONST_PRUCFG, 4, 4    // Write r0 to SYSCFG

main:
    LDI32 r2, 1<<21
    LDI32 r3, GPIO1 | GPIO_SETDATAOUT
    SBBO r2, r3, 0, 4    // write 1<<21 in to GPIO1 SETDATAOUT

    // Delay loop, count down r0 to zero
    LDI32 r0, 0x08000000
DEL1:
    SUB r0, r0, 1
    QBNE DEL1, r0, 0

    LDI32 r2, 1<<21
    LDI32 r3, GPIO1 | GPIO_CLEARDATAOUT
    SBBO r2, r3, 0, 4    // write 1<<21 in to GPIO1 CLEARDATAOUT
 
    // Delay loop, count down r0 to zero
    LDI32 r0, 0x08000000
DEL2:
    SUB r0, r0, 1
    QBNE DEL2, r0, 0

    // repeat
    JMP main

    // unreachable
    LDI r31.b0, 35 // interrupt to host
    HALT

    /* Dummy data, required by remoteproc loader */
    .data
    .section .resource_table,"aw",@progbits
my_resource_table:
    .word 1, 0, 0, 0 /* struct resource_table base */
    .word 0 /* uint32_t offset[1] */

You can compile this by using:

pru-gcc -g -Os -Wall -Wextra -minrt -mmcu=am335x.pru0 -nostdlib -nodefaultlibs -nostartfiles main.S -o am335x-pru0-fw

The pru_rproc kernel driver loads two firmware files: /lib/firmware/am335x-pru0-fw and am335x-pru1-fw in the same directory, one for each PRU. Copy the generated ELF-binary there, and start the PRU by:

echo start > /sys/class/remoteproc/remoteproc1/state

The firmware files contain, besides the actual code to run, a resource table. This table is used to ask the kernel to set up some things before starting the PRU, such as interrupt mappings, communication channels, …

]]>
/2017/07/16/beaglebone-black-pru-programming/feed 0
BeagleboneBlack – install from scratch /2017/07/15/beagleboneblack-install-from-scratch /2017/07/15/beagleboneblack-install-from-scratch#respond Sat, 15 Jul 2017 13:17:57 +0000 https://blog.dest-unreach.be/?p=3251 While having pre-configured devices is super-fun for getting started quickly, I usually want to know exactly what is installed on them. So I spent some time installing my BeagleBone from scratch.

U-Boot – the bootloader

First step is the boot-loader. The ROM bootloader loads the 2nd stage bootloader in to on-chip RAM and executes it. On-chip RAM is limited to just over 100kB, not enough for a full fledged bootloader. So U-boot is itself split in 2 stages, typically called MLO and u-boot.img.

To build these, I downloaded the git repository of U-Boot, applied Robert Nelson’s patches (you’ll recognise that name if you did some BeagleBone Googling before) and did:

patch -p1 < 0001-am335x_evm-uEnv.txt-bootz-n-fixes.patch
make distclean
make am335x_boneblack_config
make

I have no idea what these patches do, but everyone seems to apply them…

You can probably cross-compile these on your x86-based workstation, but I just run the compile on the BeagleBone itself. I copied the resulting files to the SD-card: MLO and u-boot.img. Booting with S2 pressed greeted me with:

U-Boot SPL 2017Trying to boot from MMC1
reading u-boot.img
reading u-boot.img


U-Boot 2017.07-00043-g8822c8f (Jul 11 2017 - 19:34:01 +0000)

CPU  : AM335X-GP rev 2.1
I2C:   ready
DRAM:  512 MiB
No match for driver 'omap_hsmmc'
No match for driver 'omap_hsmmc'
Some drivers were not found
Reset Source: Power-on reset has occurred.
MMC:   OMAP SD/MMC: 0, OMAP SD/MMC: 1
Using default environment

Board: BeagleBone Black
 not set. Validating first E-fuse MAC
Net:   eth0: MII MODE
cpsw
Press SPACE to abort autoboot in 2 seconds

A minimal Debian image

I used debootstrap to generate a minimal Debian environment:

debootstrap --verbose --variant=minbase stretch /mnt http://deb.debian.org/debian/

I bootstrapped in to a loop-mounted file, but you can do that straight to an SD-card if you’re brave.

I had trouble getting this to work from the shipped Wheezy. debootstrap stopped with:

I: Extracting liblzma5...
I: Extracting zlib1g...
E: no . cannot create devices

The problem seems to be that Wheezy doesn’t use devfs. I tar’ed up /dev and export DEVICES_TARGZ=/mnt/dev.targz to get through this point, then removed the extracted files from the target.

Since minbase is really minimal, I added the following:

  • apt-get install --no-install-recommends openssh-server
  • apt-get install vim iproute2 iputils-ping kmod less ifupdown init udev
  • echo "deb http://repos.rcn-ee.com/debian/ stretch main" >> /mnt/etc/apt/sources.list; apt-get update
  • apt-get install linux-image-4.9.36-ti-r45
  • echo "/dev/mmcblk0p2 / ext4 defaults 0 1" > /mnt/etc/fstab
  • cp /etc/hosts /mnt/etc/hosts
  • configure /etc/network/interfaces or /etc/network/interfaces.d/

OK, well, to be honest, the above list was compiled from several trail-and-error attempts to get the image to boot… Who could have guessed you need a kernel to actually boot 😉 If you’re lazy, you can just extract my tarball, and try to log in on 192.168.7.2 via USB with SSH as root (password admin).

Now you can either manually boot the kernel in U-Boot:

load mmc 0:2 ${loadaddr} /boot/vmlinuz-4.9.36-ti-r45
load mmc 0:2 ${fdtaddr} /boot/dtbs/4.9.36-ti-r45/am335x-boneblack.dtb
set bootargs console=tty0 console=ttyS0,115200n8 root=/dev/mmcblk0p2 ro rootfstype=ext4 rootwait fixrtc init=/lib/systemd/systemd
bootz ${loadaddr} - ${fdtaddr}

Or put the equivalent commands in uEnv.txt on the FAT partition: (I copied the kernel & Flattened Device Tree file to the FAT partition (mmc 0:1) for easier debugging).

bootargs=console=tty0 console=ttyS0,115200n8 root=/dev/mmcblk0p2 ro rootfstype=ext4 rootwait fixrtc init=/lib/systemd/systemd
uenvcmd=load mmc 0:1 ${loadaddr} kernel.img; load mmc 0:1 ${fdtaddr} fdt; bootz ${loadaddr} - ${fdtaddr}

Some notes:

  • The boot takes ~3 minutes longer than it should, because systemd waits for eth0 to come up (which it won’t because it’s not connected), only giving up after a few minutes.
  • If you have trouble getting the serial console to work because systemd can’t find dev-ttyS0.device, make sure you installed udev

 

]]>
/2017/07/15/beagleboneblack-install-from-scratch/feed 0
BeagleBone Black – boot process /2017/07/15/beaglebone-black-boot-process /2017/07/15/beaglebone-black-boot-process#respond Sat, 15 Jul 2017 13:16:35 +0000 https://blog.dest-unreach.be/?p=3211 Booting up a modern microprocessor is more like a journey than a recipe. The Texas Instruments Sitara AM3358 processor, powering the BeagloBone Black is no different.

The journey starts when the Power Management IC brings up the different voltage lines of the CPU in the correct order. The CPU initialises itself and starts executing its ROM bootloader code.

The ROM bootloader reads in the status of the 16 SYSBOOT pins. According to the BeagleBone Black’s System Reference Manual (section 6.7.1, local copy), the board has these pins wired to 0b01 00 00 0 0 00 1 11100, but pin SYSBOOT[2] can be pulled down by pushing S2. The Technical Reference Manual (section 26.1.5.2.1, local copy) will tell you the important difference between these 2 options is mainly the boot sequence:

  • Normal mode: MMC1, MMC0, UART0, USB0
  • With S2 pushed: SPI0, MMC0, USB0, UART0

Since the BeagleBone’s eMMC is connected to MMC1 (cfr BBB SRM section 6.4.2), and the micro SD card slot to MMC0, S2 effectively allows you to skip the eMMC when booting, and boot straight from SD.

The bootloader will (cfr section 26.1.7.5 of the TRM) read 4 sectors (sector nr 0, 256, 512 and 768) and look for a TOC structure. If found, it will load the next bootloader from there. If this fails, the bootloader looks for an active primary FAT12/16 or FAT32 partition in the MBR partition table, and tries to load a file named MLO (which seems to stand for Mmc LOader) from the root directory. This next bootloader, usually U-Boot’s Second Program Loader, then takes over. The ROM bootloader provides some information about the boot (e.g. which device is currently booted from), but it’s up to this new bootloader to use this info.

What actually happens

You can see what actually happens by connecting to the BBB with a TTL-level (3.3V) RS232 adapter. The J1 connector (6 pins, above the P9 header) is connected to UART0 as follows:

  • pin 1 (marked with a dot): GND
  • pin 4: Rx (i.e. to BBB)
  • pin 5: Tx (i.e. from BBB)

The (default) parameters are 115200 baud, 8 databits, no parity, 1 stopbit. I use kermit to provide a terminal emulator on a second device (but other options are possible).

The boot-up of the build-in eMMC starts off like this:

U-Boot SPL 2014reading args
spl_load_image_fat_os: error reading image args, err - -1
reading u-boot.img
reading u-boot.img

This looks like the SPL loading the 3rd stage bootloader (located in u-boot.img). The 2nd stage bootloader (the MLO file) needs to fit in on-chip RAM (slightly over 100kB usable), which is not enough for a full fledged boot-loader, hence this split in 2 (additional) stages. The boot goes on:

U-Boot 2014.04-00014-g47880f5 (Apr 22 2014 - 13:23:54)

I2C: ready
DRAM: 512 MiB
NAND: 0 MiB
MMC: OMAP SD/MMC: 0, OMAP SD/MMC: 1
*** Warning - readenv() failed, using default environment

Net: <ethaddr> not set. Validating first E-fuse MAC
cpsw, usb_ether
Hit any key to stop autoboot: 0
gpio: pin 53 (gpio 53) value is 1
Card did not respond to voltage select!
mmc0(part 0) is current device
Card did not respond to voltage select!
gpio: pin 56 (gpio 56) value is 0
gpio: pin 55 (gpio 55) value is 0
gpio: pin 54 (gpio 54) value is 0
mmc1(part 0) is current device
gpio: pin 54 (gpio 54) value is 1
SD/MMC found on device 1
reading uEnv.txt
1709 bytes read in 7 ms (238.3 KiB/s)

This looks like U-Boot tries to boot of MMC0 (the SD-card slot) first, even though the ROM-bootloader choose MMC1 first. Since there is no SD-card inserted, this fails, and U-Boot continues on to MMC1 (the on-board eMMC), where it reads the uEnv.txt file.

Note that in this setup, U-Boot runs its compiled-in boot script. So overriding the bootcmd variable in uEnv.txt is useless, since it’s loaded too late. The default boot script loads this uEnv.txt file, and executes the uenvcmd variable, if defined. So you can use that variable to customise your boot.

]]>
/2017/07/15/beaglebone-black-boot-process/feed 0
BeagleBone Black – Operating System /2016/10/29/beaglebone-black-operating-system /2016/10/29/beaglebone-black-operating-system#respond Sat, 29 Oct 2016 18:27:54 +0000 https://blog.dest-unreach.be/?p=3176 My BeagleBone Black came pre-installed with a 2-year-old Debian Wheezy on it’s eMMC chip (image, hashes). The out-of-the-box experience is actually quite impressive: the BeagleBone presents itself over the USB bus as a mass storage device with the needed drivers and some documentation. Once you install the driver (only the RNDIS is needed, the Black does not have a serial-over-USB anymore), you can just surf to the BeagleBone and control USER-LEDs from your web browser. Impressive!

But I don’t want nor need these fancy features eating up CPU, disk space and RAM, so I went looking for a minimal Debian image to use. Besides the bare minimum, I wanted the Ethernet-over-USB to work, and SSH.

  1. Get a copy of the BeagleBoard image builder
  2. Build a rootfs tarball for the desired config. I used bb.org-debian-jessie-console-v4.4, which matched my requirements quite nicely. You can see the (additional) packages that will be installed listed in the corresponding config file.
    ./RootStock-NG.sh -c bb.org-debian-jessie-console-v4.4
  3. From the generated directory inside deploy, run
    ./setup_sdcard.sh --img-1gb ~/disk-image.img --dtb beaglebone

    I wanted to keep the FAT boot partition, which is no longer needed, so I reverted that part of the commit before running the above command.

  4. dd the generated image (hash) onto an SD card.

To boot from the SD card, press the boot button (S2) at power-on and release when the 4 User-LEDs are on. Be patient: it took my board ~90 seconds to get SSHd up and running.

Note: sometimes, udhcpd would refuse to start. Rebooting (i.e. press the power button (S3) briefly, wait for the LEDs to go off, press-and-hold S2, press S3, release S2 when 4 LEDs are on) helped. I’m guessing it’s a race condition on bootup that sometimes prevent udhcpd from starting. Manually assigning your side 192.168.7.1/24 also works.

You can use the /opt/scripts/tools/grow_partition.sh script to grow the root partition to the actual size of the SD card instead of the 1GB it originally has.

]]>
/2016/10/29/beaglebone-black-operating-system/feed 0
OS X Image Capture hanging at “Waiting for scanner…” /2016/03/13/os-x-image-capture-hanging-at-waiting-for-scanner /2016/03/13/os-x-image-capture-hanging-at-waiting-for-scanner#comments Sun, 13 Mar 2016 09:00:38 +0000 https://blog.dest-unreach.be/?p=3149 I have an Epson WiFi multifuncional, and was very happy to see that I needed no additional software at all to make it work. OS X had everything built in. For scanning, I use Image Capture. It’s fairly basic, but it does the job of scanning a batch of duplex pages in to a single PDF.

Sometimes, however, Image Capture hangs on “Waiting for scanner…”. Restarting Image Capture doesn’t help; restarting the multifunctional neither, nor did turning the Mac’s WiFi off and on again. Restarting OS X entirely did solve the issue, but I don’t call that a solution.

Today, I came across a post of Packetrider on an HP forum. He figured out that killing the Image Capture Extension process solves the problem as well:

killall "Image Capture Extension"
]]>
/2016/03/13/os-x-image-capture-hanging-at-waiting-for-scanner/feed 1
TP-Link Archer C7 power consumption /2016/01/18/tp-link-archer-c7-power-consumption /2016/01/18/tp-link-archer-c7-power-consumption#respond Mon, 18 Jan 2016 19:24:53 +0000 http://blog.dest-unreach.be/?p=3109 When I buy electronic devices, I always keep an eye on their power consumption. Especially the power drain that you’ll get 24/7. For most devices, this is their “standby” power consumption, but some devices are left on all day long. My broadband router, a TP-Link Archer C7 running OpenWRT 15.05 Chaos Calmer, is in this last category.


So I measured the power consumption of the Archer C7 starting up. Below is the result. I’ve stopped measuring once the device was fully operational.

archerC7

Note that the steady state power consumption is 3.5W, which costs around €6.1/year at current prices.

]]>
/2016/01/18/tp-link-archer-c7-power-consumption/feed 0
B-box 3 power consumption /2016/01/18/b-box-3-power-consumption /2016/01/18/b-box-3-power-consumption#comments Mon, 18 Jan 2016 19:20:29 +0000 http://blog.dest-unreach.be/?p=3105 When I buy electronic devices, I always keep an eye on their power consumption. Especially the power drain that you’ll get 24/7. For most devices, this is their “standby” power consumption, but some devices are left on all day long. The b-box 3 of Proximus is in this last category.


So I measured the power consumption of a b-box 3 starting up. Below is the result. I’ve stopped measuring once the device was fully operational.
bbox3 power consumption
Note that the steady state power consumption is 8.5W, which costs around €15/year at current prices.

]]>
/2016/01/18/b-box-3-power-consumption/feed 5
Comment spam /2015/11/12/comment-spam /2015/11/12/comment-spam#respond Thu, 12 Nov 2015 14:27:13 +0000 http://blog.dest-unreach.be/?p=2959 Akismet recently decided to revoke my API key, so I got overwhelmed with spam comments again. So I’m trying something new: a quiz before you can comment. Let’s see how this works out.

]]>
/2015/11/12/comment-spam/feed 0