Category Archives: c

Linkit Smart 7688 OpenWRT 18.06 and I2C

The I2C bus is a bus is used to interface with small sensor devices in a system. Recently I needed to collect data from an MCP3424 ADC using the Linkit Smart 7688. The Linkit ships with the OpenWRT CC 15.05 firmware which now is 3+ years old, so I wanted to use a more updated system. Lucky for me, OpenWRT just released 18.06 this month, the first release where OpenWRT and LEDE re-aligned. I installed the 18.06 firmware on the Linkit, however the default build doesn’t have the I2C drivers. Here are the steps to get the I2C bus working on OpenWRT 18.06 on the Linkit Smart 7688.

opkg update
opkg install kmod-i2c-code kmod-i2c-mt7628
lsmod (Ensure the new modules are is loaded)
ls /dev/ (List the devices in /dev)

After running the ‘ls /dev/’ command you should see the i2c-0 device listed. This device file controls the hardware connected to the SCL and SDA pins. Use the fopen, ioctl commands in C to control the port. WARNING: The Linkit I2C driver appears to always respond with a valid return integer. This is different than other drivers, which will respond with success for an ACK message and failure integers for a NACK message. Take a look at the elinux info on I2C here:

LinkIt Smart 7688 Toolchain with OpenWRT

My last post was about how to get the LinkIt Smart 7688 embedded Linux module running and updating the firmware. This post in the series is going to explain the next step in the embedded development sequence, getting a cross compiler GCC toolchain working for the target to start developing software in C and C++.

A cross compiling toolchain is a crucial piece in any embedded development effort. While the LinkIt has programming languages built in such as python, lua, and node, many times system programmers need a native C/C++ toolchain to program low level fast systems. Many embedded platforms, such as the RaspberryPi, come with a toolchain already built and running on the system. This is handy for quick development but you are limited to compiling on the target processor, in this case 580MHz which can be a slow and painful process. A cross compiler is a compiler that runs on a PC and generates binary programs that run on a different machine. The LinkIt is a MIPS processor, so we need a compiler that runs on a typical PC (Most likely x86_64) and generates programs that run on MIPS.

The OpenWRT SDK Toolchain

OpenWRT’s build system is based on Buildroot, a set of tools for generating embedded Linux systems. The Buildroot system downloads all the packages needed for a system, compiles them for the target and builds an image. To compile the packages Buildroot downloads and makes a cross compiler toolchain which we can use for our system! OpenWRT does a great job of putting all the toolchain pieces together in an SDK when the image is built. Because the LinkIt is based on the ramips target of the 15.01 Chaos Calmer, the SDK is available on the build root servers. You can find the packages here: . On a 64bit Linux system, simply download the OpenWrt-SDK-15.05.1-ramips-mt7688_gcc-4.8-linaro_uClibc- file and decompress it. Windows cross compilers do exist or can be built but are outside of the scope of this post.

The OpenWRT SDK contains the GCC compiler, plus all the other tools needed to link and package binary files. The SDK also contains all the libraries required to link a Linux application such as the C library (LibC), pthreads, librt, etc. You will find the tools in the following locations in the bz2 package:

  • GCC Compiler: staging_dir/toolchain-mipsel_24kec+dsp_gcc-4.8-linaro_uClibc-
  • GCC libraries (RFS): staging_dir/target-mipsel_24kec+dsp_uClibc-

Using the Toolchain

Lets make a ‘hello world’ application for the LinkIt with the OpenWRT SDK toolchain. Create a test file:

int main(int argc, char ** argv)
printf(“Hello world\n”);
return 0;

Now compile the test program with the toolchain from the SDK:

<PATHTOBIN>/mipsel-openwrt-linux-gcc -c test.c -o test.bin

There should be no errors or warnings when you do the compile, and the output will be test.bin, an application that will only run on the LinkIt. The compiler also wanted the STAGING_DIR environment variable set with ‘export STAGING_DIR=<PATHTOSTAGINGDIR>’. You can confirm that the binary is for MIPS with the ‘file’ command:

file test.bin

Simply copy the binary file to the Linkit /root/ directory and run with ./test.bin. If your Linkit is connected to the network you can copy using scp.

scp test.bin root@<IP_ADDRESS>:/root/

Running the binary with ./test.bin from the /root/ directory and you should see the “Hello world” output.

Working with the LinkIt Smart 7688

As an embedded systems engineer I am always interested in new systems. I’ve worked with the NixCore X1 boards and got pretty deep in to the OpenWRT/LEDE environment. For those that don’t know, OpenWRT is a Linux system designed for deeply embedded systems with pretty limited resources. It was designed to be run on routers like the Linksys WRT54G series but it is much more than that. I’ve been keeping my eye on dev boards and SOMs that support OpenWRT and I came across the LinkIt series of boards from Seeed Studios and Mediatek, specifically the LinkIt Smart 7688. These are fully supported by OpenWRT, are FCC certified and available for only $15 each! I purchased one of the LinkIt Smart 7688 boards a while back and haven’t really messed with it too much. Since Protologcal was due for a new post I thought I would share my experience working with the LinkIt, booting it up for the first time, poking around the insides, and then upgrading the firmware.


  • MT7688AN Mediatek SOC
  • 580MHz
  • 128MB RAM
  • 22 GPIO
  • 3x UART
  • SPI
  • I2C
  • USB Host
  • Ethernet connections (100 base)
  • 802.11bg/g/n 2.4GHz

First boot:

With OpenWRT embedded systems like the LinkIt, there is almost always a serial port console allowing access to the bootloader and the root system. This allows developers to upgrade the firmware from a physical connection with the least amount of software. This is the starting point for all of my embedded system hacking, get the console and see what the system does.

I added the LinkIt to a breadboard, found the pinout diagram, connected up my FTDI232R-3v3 cable to UART2 as per this info, 57600 baud 8-N-1. Powering up the board through the micro-USB and you get the very familiar Ralink uBoot menu (Ralink is the original SOC+WiFi manufacturer purchased by Mediatek). uBoot is a bare-metal bootloader application that allows you to update the firmware on the device before the ‘true’ system boots. We will dive more in to that later. By default uBoot times out after a few seconds and hands control off to the Linux system partition which boots the kernel and enables the system. After a ton of messages we can hit enter and are dropped in to the standard OpenWRT console.

I was really impressed to see the standard OpenWRT 15.01 Chaos Calmer banner on the console, this to me means that Seeed or Mediatek didn’t do a lot of messing around with the stock system. For those who have worked with OpenWRT the system was pretty vanilla, the WiFi config uses the standard /etc/config/wireless, the init system appears to be unmodified, opkg reported all the packages (stock package list here), dropbear ssh server, etc. This is really really good to see, nothing crazy was running and taking up 100% CPU, so we have a pretty darn open development platform right out of the box, nicely done Mediatek!

Firmware upgrades:

I like to roll my own OpenWRT firmware, that way I have full control and I know what is installed in the system (no NSA or botnet backdoors!). Before getting in to building a custom OpenWRT image I like know that I can go back to the stock image if I really mess something up. Mediatek has a lot of information on how to upgrade the firmware on their Mediatek Labs website, so after some reading here is how you can flash a new image:

  • From stock firmware there is a web based flashing utility that uploads an image file and uses OpenWRT’s sysupgrade utility
  • You can also copy the firmware image to a USB drive and use uBoot to flash the image
  • uBoot has menu options for downloading via Serial and TFTP

The web upgrade UI is from the device, so you need to connect a computer to the open WiFi access point “Linkit_XXXXX” and go to from a browser. Using the web based upgrade path I was able to upgrade my LinkIt to the latest 0.9.4 firmware just as a test. This upgrade took a few minutes and there was no real indication on what was going on, other than the blinking orange LED. The serial console didn’t show anything during the sysupgrade, so you just have to upload and hope for the best.

The uBoot USB based upgrade path is a little better. First you copy your image file to a FAT formatted USB drive and name it lks7688.img. Then you plug the drive in to an USB OTG cable connected to the USB data port. Hold the wifi button on the LinkIt and reset the device with the reset button. With the serial console connected you can see that uBoot detects the wifi button held down, and after 5 seconds it starts searching for a USB drive. What is interesting is that the console outputs:

“5: System Load Linux then write to Flash via USB Storage.”

If you look at the boot menu there is no option for 5, it jumps from 4 to 7. Rebooting without the wifi button pressed, and entering 5 into the uboot menu and the system drops in to the same USB update routine, so there are a few ways to start this upgrade.

When uBoot finds the drive it will automatically burn the lks7688.img system image file to the correct location in the SPI flash. The system reboots and you have a new firmware image. The USB update still takes about 2 minutes, but that’s better than the 3+ minutes for the web update method. I did not try the serial or TFTP upgrade methods, that is going to take some digging in to the SPI flash partitioning done by Mediatek, but I’m sure it is possible. Again, I was really happy to see there is a commonly accepted bootloader method to upgrade firmware, not some janky software solution!

Overall, I am quite impressed with the LinkIt Smart 7688, it is powerful, open, well documented, and cheap embedded system. The next steps are to create a footprint in Eagle PCB, make a few adapter boards for some hardware I have here, and then build a custom OpenWRT image. In a later post I will go over how to build and download OpenWRT, with support for the WiFi hardware on the LinkIt, to make a truly custom embedded Linux platform!

NixCore X1 with RGB LED Strip

My friends here in Colorado started a new company called NixCore, a Linux enabled processor board that takes 1 Watt of power. They asked me to take their new NixCore X1 product for a spin and see what I could make with it. I looked around the lab/office and came upon my RGB LED strip from China. Since this RGB strip uses a variant of SPI I thought it would be a good test for the little NixCore X1 board.

The NixCore X1 is an Ralink RT5350 SoC (System on Chip) processor running at 360MHz, with 8MB of flash, and 32MB of RAM. The board takes only 1 watt of power (less than 200mA at 5V) and has all the outputs you would expect from a microcontroller, I2C, GPIO, PWM. It also has software based SPI (Since the SPI port is used by the flash) which is still pretty fast. I’ve worked with embedded Linux systems and know how much of a pain it is to get a driver running, so having a Linux install with an SPI driver exposed to userspace was a godsent. With some commands, a simple C file, and a Buildroot compiler I was able to port my Mbed code to the NixCore X1 pretty easily. All I had to do is make a new SPI device on some GPIO pins, open the “/dev/spidev1.0” device and start writing data to it, the driver takes care of all the hard stuff. Using C you can fopen(“/dev/spidev1.0″,”w”) and then write as any other file. Here are the steps:

Build the compiler:
NixCore helped me out with that, but just select mips32r2, Little Endian and uClib on Buildroot and you should be good.

Compile the code:
Given the code, you can control the strip via the command line
(Make sure you add -I and -L entries to the buildroot install)

Install the spi-gpio-custom-driver on the running X1:
insmod spi-gpio-custom bus0=1,22,23,24,0,50000

Run the code:

This driver is software based and (from my tests) runs up to 400KHz. It uses GPIOs 22 as CLK,23 as MOSI and 24 MOSI (Even though there is no input data) on the NixCore X1. This translates to pins 27,30 and 22 on the header. I hooked up the RGB strip directly to the 3.3V CLK and MOSI and wrote a simple C file based on my Mbed code.

Honestly, to my surprise I was able to control a single pixel of the strip right off the bat, I expected the driver functioned but I was still a little skeptical. It didn’t take long to address the entire strip. At a comm rate of 50KHz this updates the strip at about 40ms or 25 HZ. As I mentioned the rate could be updated to about 400KHz which would be about 200Hz for a 5M strip, more than enough to beat the human eye.

After I made the C application to set the color I took it a step further and added a web page and CGI script to change the color of the strip based on a web page.

Here are some videos of the strip in action:

And, of course, the code and webpage for the processing: Code1, Code2, Makefile, Webpage files.
Goto http://[IP_ADDRESS]/color.html

Overall I really like the NixCore X1 (I am biased since they are my buddies) but you might want to check them out at

LED light strip LPD6803 code

Wow, it’s been a crazy few months. I am taking some courses for my masters, started a few contracting gigs and went to China with DangerousPrototypes Hacker Camp. There is so much to write about and I’ve been dropping the ball on Protological. Time to change that. Time for some cool LED stuff!

While in China I picked up a 5 meter “5050” 12V LED strip with 30 LEDs per meter for 90RMB which is $14.50 USD. I didn’t buy the controller because I wanted to control it with a microcontroller of course! The controller chip is a knockoff LPD6803 LED driver chip that listens for clocked data. The only datasheet I could find was from Adafruit here and the english is really, really bad. I didn’t know ‘grey’ == ‘color’?! After some playing around I figured out the protocol for how the data is sent. The commands are 16-bit and shifted out MSB first, the clock is idle low and the data is latched in on the high transition of the clock. The MSB is always 1 to indicate that the value is data and the 3 colors are 5 bits each; allowing for 31 steps in brightness.

1000 0000 0000 0000

One would think that the colors are Red, Green and Blue, however some testing showed they are Green, Red and Blue.

1000 0000 0000 0000
D|Grn ||Red ||Blue|

So if you want to turn on an LED with 1 step of RGB the byte value is 1 00001 00001 00001 = 1000 0100 0010 0001 = 0x8421;

These strips can be chained together, so to ‘reset’ the strip pixel ID and have it listen for a new set of colors you send 32 0’s which is 8 bytes of 0x00. Once I got the protocol figured out it was really easy to hook up a micro and control the strip.

I used an LPC1768 Mbed microcontroller (because it’s super easy) and made a demo program with some simple animations. The strip is 30 LEDs per meter, 5 meters long. Each LED ‘pixel’ is a group of 3 RGB LEDs and they all show the same color. So there are 50 groups of 3 in my 5 meter strip. The way I drive the LEDs is I make a uint16_t array in RAM for the 50 pixels, then create a timer to run through the array and send it out to the strip using the SPI hardware. With 8 bytes of reset, 100 bytes of data, at 500KHz I was able to address the whole strip in about 4ms. I set my timer to update the strip at 10ms, giving me a 100Hz refresh rate.

The rest of the application just writes the data array in memory and lets the timer clock it out to the strip. I included the code here with 4 demos. This will build in the Mbed compiler and uses the P5 & P6 SPI pins on the LPC1768 for data and clock. It should be pretty straight forward to port to an Arduino or other microcontroller, just setup a timer and update the SPI config and write functions.

Here is a video of the demos in action:

And the source file: ledstrip_mbed_demo.cpp

Enjoy, Drew