Sunday, 30 July 2017

HI3518 Camera Module - Part 1 - Replacing Pre-Installed Image

Introduction

I recently purchased a cheap camera module off Aliexpress based on the HI3518 and the AR0130 image sensor. I plan for this post to be the first of a series covering this module. This post will cover how to build a basic Linux image and boot it. This will serve as the starting point for further exploring what the module has to offer and the quality of the images it produces. The aim is to build an image that can be booted without having to overwrite the existing OS (stored in flash), making the changes non-permanent and allowing you to boot back into the original OS at any point.




Getting Started

There are a number of blogs on the internet covering how to get started with these HI3518 modules so I don't plan on going into too much detail and instead will provide a brief overview of what you need to do.

Some useful resources you might like to look at include:

Before we dive into compiling a new image for the module you will first need to get access to the debug console. This is accessed through the serial port.

Serial Output

The HI3518 module has an unpopulated 3-pin connector for a serial connection, which exposes GND, TX and RX. Typing "hi3518 pinout" into a search engine will get you a description of the pins.

I soldered on a JST 1.25mm connector so I could easily hook up a USB-to-serial adaptor.

U-Boot

You will then be able to interact with the module using the serial console, e.g. using screen:

screen /dev/ttyUSB0 115200

Note: you will need to make sure you have permission to access the device otherwise you will just see the message "[screen is terminating]" when attempting to run the above command.

The module uses U-Boot as its bootloader.
The U-Boot install on the module is configured to auto boot into the Linux OS unless it receives CTRL+C within a particular delay, in this case 1 second.

If you type CTRL+C to stop the boot process you will drop to a U-Boot prompt.

The Original Image

If you let the module auto-boot it will boot into the original image.

Telnet

On the module I have, the original image did not provide a console once it booted the Linux OS. Instead it was necessary to telnet onto the device. Unfortunately this was not entirely straight forward for this module since it did not appear to have telnet running. 

In the end, to be able to telnet into the original Linux OS I needed to first back up the romfs.cramfs image, from U-Boot, and modify it before flashing it back onto the device.

The changes needed to be made to the file /etc/init.d/rcS

rcS is the startup script for the system and it contained a section that starts some services that looked like this:

netinit
cp /bin/upgraded /utils/ -f
/utils/upgraded &
ifconfig eth2 down
macGuarder &
sysinit &
searchIp &
#wlandaemon &
#route_switch &

I modified it to look like this:

netinit
# cp /bin/upgraded /utils/ -f
# /utils/upgraded &
# ifconfig eth2 down
# macGuarder &
telnetd &
sysinit &
searchIp &
#wlandaemon &
#route_switch &

Basically, I added a line to start telnetd and found that I also needed to comment out the macGuarder line.

Building New Image

The original image is not very interesting so I wont go into detail about it. Instead I'll go straight on to building a new image.

There is an SDK floating round the internet that could be used, but the much easier option is to use a version of Buildroot up on Github that has been patched to target the HI3518.

The aim is to build an image that can be booted without having to first write it to the flash. This can be achieved by building an initramfs image. An initramfs image combines the root filesystem (rootfs) and the Linux kernel into a single image. It should be noted that due to the way U-Boot works there is a limit on the uncompressed size of the resulting image (16MB). This means that we will need to make sure we do not include too many packages in the image otherwise we will have problems when trying to boot it.

So lets start.

Buildroot

First you will need to clone the Github repository.

I've made a fork of the Github repository and added a branch with the default configuration updated to match that used in this post. You may wish to checkout that branch, otherwise you can start from the original repository.

To checkout the original repository you can run the command:

git clone --depth=1 https://github.com/hi35xx/hi35xx-buildroot.git

Alternatively, to checkout the branch I made for this blog post use the command:

git clone -b mark4h-blog-post-1 --depth=1 https://github.com/mark4h/hi35xx-buildroot.git

You will then need to change directory into the repository.

cd ./hi35xx-buildroot

Configuring

Loading Default Configuration

Once you have checked out the code, you can then load the default configuration for this board, which is based on the HI3518 v100, by running the command:

make hi3518v100_defconfig

Once the default configuration has been loaded you then have the option to customise the image that will be built. There are three menus through which to configure the build:
  • Buildroot
  • Linux Kernel
  • Busybox

Configuring Buildroot

The buildroot specific options can be configured by running the command:

make menuconfig

This is an overview of the changes I made. In particular, to save space and reduce compile time I removed all unwanted packages.

Set:
  • Build options -> Enable compiler cache
  • System configuration -> Locales to keep -> en_GB

Leave:
  • Hardware handling -> himpp -> himpp for chip -> hi3518/hi3516 v100)

Disable:
  • Target packages -> Audio and video applications -> live-streamer
  • Target packages -> Fonts, cursors, icons, sounds and themes -> Bitstream Vera
  • Target packages -> Graphic libraries and applications (graphic/text) -> SDL
  • Target packages -> Hardware handling -> dbus
  • Target packages -> Hardware handling -> himpp -> Sensor driver libraries -> [all except Aptina AR0130]
  • Target packages -> Interpreter languages and scripting -> luajit
  • Target packages -> Libraries -> Graphics -> fontconfig
  • Target packages -> Libraries -> Graphics -> freetype
  • Target packages -> Libraries -> JSON/XML -> expat
  • Target packages -> Libraries -> Multimedia -> live555
  • Target packages -> Libraries -> Other -> libev
Set:
  • Filesystem images -> cpio the root filesystem (for use as an initial RAM filesystem)
  • Compression method (xz)
  • Filesystem images -> initial RAM filesystem linked into linux kernel
Disable:
  • Filesystem images -> squashfs root filesystem
  • Filesystem images -> tar the root filesystem
Disable:
  • Bootloaders -> U-Boot
Exit and save the configuration

Configuring Linux

To configure the Linux Kernel you can run the command:

make linux-menuconfig

The default Linux Kernel configuration already has all the important options required for this build set up as needed, including the ability to boot an initramfs.

So, the only change I made was to disable the watchdog timer under:

Device Drivers -> Watchdog Timer Support

Configuring Busybox

To configure Busybox you can run the command:

make busybox-menuconfig

However, I did not make any changes to the default Busybox configuration so this is not necessary.

Build

Once you have finished configuring the build process it is just a case of building the image.
This can be done by running the command:

make

Once compilation has finished you should find the image, named uImage, in the output/images directory.

Booting Image

The steps for booting the resulting image are:
  • Connect the module to the development computer and configure the network
  • Power on the module and drop into the U-Boot console
  • Load the image into the RAM over TFTP
  • Set the U-Boot bootargs environment variable
  • Boot the image
This means you will first need to set up a TFTP server.

TFTP Server

There are many options for setting up a TFTP server.
On Ubuntu I installed atftpd:

sudo apt-get install atftpd

I also updated the firewall:

sudo ufw allow from 192.168.2.2 to any port tftp

You can then copy the image into the tftp directory, e.g.

mkdir /srv/tftp/blog-1
cp output/images/* /srv/tftp/blog-1/

Configuring Network

You will need to connect the camera module to the same network as the computer running the TFTP server. In this post I had the camera module connected directly to the development computer and had created a separate subnet where the development computer had the IP address 192.168.2.1 and the camera module could use the IP address 192.168.2.2.

U-Boot settings

Once you have configured the ethernet and added the image to the TFTP directory you are ready to boot the image. You will need to power up the module and press CTRL+C to drop into the U-Boot console. You can then run the following commands, editing them where necessary to match the network configuration you have used and the location you put the image in the TFTP directory.

These commands download the image from the TFTP server to the RAM of the camera module at the address 0x82000000 and then boot the image.

setenv ipaddr 192.168.2.2
setenv gatewayip 192.168.2.1
setenv serverip 192.168.2.1 
tftp 0x82000000 blog-1/uImage
setenv bootargs mem=36M console=ttyAMA0,115200


bootm 0x82000000

Finally

If the image boots successfully you should be able to log in using the root user.

One of the functions I tested in the newly build image was the Ethernet connection.
First I had to edit network configuration:

vi /etc/network/interfaces

And then restart networking:

/etc/init.d/S40network restart

However, pinging the development computer did not work, suggesting there was something wrong with the Ethernet configuration.

# ping 192.168.2.1
PING 192.168.2.1 (192.168.2.1): 56 data bytes
^C
--- 192.168.2.1 ping statistics ---
172 packets transmitted, 0 packets received, 100% packet loss

I tried a few things but have not been able to get the Ethernet to work, so this will have to form the topic of the next blog post.

Comments

This has been a relatively brief overview of how to build an image for a HI3518 based camera module and has not gone into exhaustive detail about each step. If you experience any problems feel free to leave a comment.

6 comments:

  1. set ethernet to mii from rmi with pinmux_hi3518e.sh

    ReplyDelete
  2. Hi Douglas,

    Thanks for the suggestion.
    Switching to mii from rmii in pinmux_hi3518e.sh didn't work for me.
    Take a look at part 2 to see what I had to do to get it working.

    mark4h

    ReplyDelete
  3. This comment has been removed by the author.

    ReplyDelete
  4. Hi,
    Does this mean I can re-program this module?

    ReplyDelete
  5. thanks mark4H for this blog - it is nice alternative to the hard-to-follow SDK doc from the manufacturer! it worked on my module, which is hi3518e+ov9712 w/ 32M RAM.

    ReplyDelete
  6. I've wrote something about the Hikam S6 (based on HI3518E):

    https://gist.github.com/JanLoebel/b5dafcda555323785d32ccb7d643dbcd

    ReplyDelete