tag:blogger.com,1999:blog-80308815735513761922024-03-13T18:37:22.031-07:00Eclectic ShortcutOh, that's how I should have done it...Wileurhttp://www.blogger.com/profile/00334738425060233729noreply@blogger.comBlogger2125tag:blogger.com,1999:blog-8030881573551376192.post-43244510617604327412013-02-26T12:47:00.000-08:002013-02-26T12:47:29.407-08:00Gray scale LCD data transferThe other day <a href="http://hackaday.com/2013/02/25/using-a-flashing-lcd-monitor-to-transfer-data/">hackaday.com</a> posted about Connor Taylor and others that uses a computer screen to transfer data to their micro controllers. I immediately thought, wow that is just so cool, no more cables for firmware updates. Just add a photo transistor to each project and you're done!<br />
But the projects mentioned all suffer from the same problem: 60Hz refresh rate only gives you a few bits of data per second. Uploading just a few kb of data would take hours.<br />
So after pondering this I thought why not use gray scale? The following is my proof of concept in the hope that someone will take it further and make it truly useful.<br />
<br />
<a name='more'></a><br />
<br />
My goal would be to make a firmware update tool that can be used by any user on any computer. Ambitious, but either it works everywhere or another solution is needed.<br />
<br />
To test my idea i grabbed an old photo transistor from the parts bin and hooked it up to my multimeter that is set to read resistance. A quick Google search for gray scale turned up this image.<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://th04.deviantart.net/fs22/PRE/f/2007/360/6/d/Gray_Scale_by_pcpa1.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="119" src="http://th04.deviantart.net/fs22/PRE/f/2007/360/6/d/Gray_Scale_by_pcpa1.jpg" width="320" /></a></div>
<br />
By holding the photo transistor to the screen I was able to get different readings for all the 19 fields on top. The darkest measured 533k, the second darkest 518k, somewhere in the middle 407k and the whitest one 57k. The transistor could be used in a voltage divider and then connected to an ADC.<br />
Depending on the light sensor used some kind of logarithmic
conversion might be necessary, preferably in hardware to maximize the
usable range of the ADC. <br />
<div class="separator" style="clear: left; text-align: center;">
<a href="http://4.bp.blogspot.com/-H40xH3zyHoQ/US0aENdORDI/AAAAAAAAADM/JJDqk_uo9gU/s1600/DSC01007.JPG" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" height="150" src="http://4.bp.blogspot.com/-H40xH3zyHoQ/US0aENdORDI/AAAAAAAAADM/JJDqk_uo9gU/s200/DSC01007.JPG" width="200" /></a>
<a href="http://3.bp.blogspot.com/--LcZfMRW2AQ/US0aED0QNEI/AAAAAAAAADU/1fyFm_cnSlQ/s1600/DSC01008.JPG" imageanchor="1" style="float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" height="150" src="http://3.bp.blogspot.com/--LcZfMRW2AQ/US0aED0QNEI/AAAAAAAAADU/1fyFm_cnSlQ/s200/DSC01008.JPG" width="200" /></a>
<a href="http://3.bp.blogspot.com/-Zmu1xoC3h1I/US0aELmTEpI/AAAAAAAAADQ/UOBCdwcaKmk/s1600/DSC01009.JPG" imageanchor="1" style="float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" height="150" src="http://3.bp.blogspot.com/-Zmu1xoC3h1I/US0aELmTEpI/AAAAAAAAADQ/UOBCdwcaKmk/s200/DSC01009.JPG" width="200" /></a></div>
<a href="http://2.bp.blogspot.com/-G5G1QIUr0zo/US0aE3RCDYI/AAAAAAAAADk/DLF1KswJsCg/s1600/DSC01010.JPG" imageanchor="1" style="float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" height="150" src="http://2.bp.blogspot.com/-G5G1QIUr0zo/US0aE3RCDYI/AAAAAAAAADk/DLF1KswJsCg/s200/DSC01010.JPG" width="200" /></a>
<br />
<div class="separator" style="clear: left; text-align: center;">
</div>
Now this worked on my screen, but what about people with different brightness settings or white balance? It wouldn't be that hard to flash the whitest white and the blackest black for a few seconds before the data stream starts. Then the receiver can either set limits in software(cheap) or adjust some external offset/amplifier circuitry(more advanced) to get the most dynamic range.<br />
<br />
To achieve data synchronization some kind of predefined flash pattern could be used to calibrate a timer on the receiver. The timer could then be continuously adjusted as data comes in. There should be enough variation to detect individual frames.<br />
<br />
4bit nibbles shouldn't be any problem to transfer. Depending on the external circuitry 5 and 6 bits could also work. 8 would be ideal but might be hard to get to work accurately without to much external circuitry.<br />
<br />
Someone mentioned using the back light for flashing data. Though harder to control and with fewer steps the possibly higher data rate might be more than worth it.<br />
<br />
Google "gray scale 256 steps" for the real challenge.<br />
<br />
Please take this and improve it, I would love to be able to drop the USB dongle on my next project!Wileurhttp://www.blogger.com/profile/00334738425060233729noreply@blogger.com0tag:blogger.com,1999:blog-8030881573551376192.post-78609301699226182932011-04-30T08:22:00.000-07:002013-02-27T00:03:10.714-08:00uClinux on the LPC-E2468<style type="text/css">
p { margin-bottom: 0.08in; }a:link { }
</style><b>The story...</b><br />
Some time ago I was given an Olimex LPC-E2468 development board. My company bought it for a project but ended up not using it. A couple of weeks ago I finally got around to hooking it up and very soon understood why they didn't. The manual from Olimex basically says to run 'make config' and 'make', and you will have a kernel image to load onto the board. Sounds too easy to be true? You're right!<br />
<br />
In this article I will try boil down more than a week of compiling, googling, recompiling, scrapping it all, compiling again, giving up, starting over... I will try explain the steps necessary to compile a working kernel and create a romfs image.<br />
<br />
<a name='more'></a><br /><br />
<b>Disclaimer and tips</b><br />
Before we start, I take no responsibility for any consequences of doing anything mentioned on this page. It worked for me. It might crash your system, even though it should work fine.<b> </b><b></b><br />
I assume you are a fairly advanced Linux user, who know how to compile software from source. I use Ubuntu and the packages are for this ditribution, but the methods are generic. I also assume that the normal GCC toolchain is installed. On Ubuntu this can be done with 'sudo aptitude install build-essentials'.<br />
I posted the paths I used but unless your username is andreas, make sure what you copy and paste match your reality. Also, depending on linux version and the date you try this, you might get a differently named binutils archive, so check the paths. <br />
You will not modify your main /usr, /lib, /etc tree, but you will use sudo to install packages so take care.<br />
I have not figured out an easy way to include code in the blog that preserves linebreaks in the blog so check your commands before running them. Especially the long one for configuring elf2flt.<br />
Last, but not least, do NOT run 'make clean' or 'make mrproper' in your uClinux tree. You will loose all configuration files and have to setup a complete kernel from scratch... <br />
All that said, let's get started.<br />
<br />
<b>Get it going</b><br />
The first major step is to install the arm-linux-gcc toolchain. This proved to be quite a a challenge since one part depends on another and you only have the latest error message to work with. The following is what I came up with.<br />
<ol>
<li><b>Install necessary packages.</b> These were needed on my system. If your's complain about anything else do a search in your repository for the developer version that contains the header files with descriptions.<br />
You'll need compressor for elf2flt later on. Choose, lzma-dev was available on Ubuntu 8.04 and xz-utils in 9.10. Both seem to work. <br />
Genromfs is used to create the romfs image with your filesystem.<br />
Binutils wants texinfo to build the manual that we won't use...<br />
Tftpd is for loading the images on to the board in the end.<br />
<span style="font-family: "Courier New",Courier,monospace;">sudo aptitude install ncurses-dev genromfs texinfo tftpd xz-utils</span> <br />
<br />
</li>
<li><b>Create a build directory.</b> This is wher we will put everything else. Open a terminal and create a new directory called arm:<br />
<span style="font-family: "Courier New",Courier,monospace;">mkdir arm</span><br style="font-family: "Courier New",Courier,monospace;" /><span style="font-family: "Courier New",Courier,monospace;">cd arm</span><br />
<br />
</li>
<li><b>Copy files from the CD to your build directory.</b><br />
This is easiest done with a graphical tool like Nautilus. Copy uClinux-dist-lpc_e2468.tgz from the uClinux-dist directory and arm-linux-gcc-4.1.1-920t.tar.bz2 from Utils.<br />
<br />
</li>
<li><b>Unpack the arm-linux-gcc.</b> This is the compiler and linker for the ARM architecture.<br />
<span style="font-family: "Courier New",Courier,monospace;">tar jxf arm-linux-gcc-4.1.1-920t.tar.bz2</span><br />
Rename it to make it easier to work with<br />
<span style="font-family: "Courier New",Courier,monospace;">mv 4.1.1-920t uclibc</span><br />
<br />
</li>
<li><b>Set paths to the new directories.</b> <br />
<span style="font-family: "Courier New",Courier,monospace;"> PATH=$PATH:~/arm/uclibc:~/arm/uclibc/bin:~/arm/uclibc/arm-linux/bin</span><br />
You can also add this to your .bashrc file so that every new shell will have the paths.<br />
<br />
</li>
<li><b>Build binutils binaries.</b> We don't actually need the executables, just some object files to link in when building elf2flt later on.<br />
<span style="font-family: "Courier New",Courier,monospace;">sudo aptitude download binutils-source</span><br />
Extract it with:<br />
<span style="font-family: "Courier New",Courier,monospace;">mkdir binutils-source</span><br style="font-family: "Courier New",Courier,monospace;" /><span style="font-family: "Courier New",Courier,monospace;">dpkg -x binutils*.deb binutils-source</span><br />
The Ubuntu package had another compressed image inside, which we will move to our root and uncompress:<br />
<span style="font-family: "Courier New",Courier,monospace;">cd binutils-source/usr/src/binutils</span><br style="font-family: "Courier New",Courier,monospace;" /><span style="font-family: "Courier New",Courier,monospace;">mv binutils-2.18.0.tar.bz2 ~/arm/</span><br style="font-family: "Courier New",Courier,monospace;" /><span style="font-family: "Courier New",Courier,monospace;"> cd ~/arm</span><br style="font-family: "Courier New",Courier,monospace;" /><span style="font-family: "Courier New",Courier,monospace;"> tar jxf binutils-2.18.0.tar.bz2</span><br />
Configure and build:<br />
<span style="font-family: "Courier New",Courier,monospace;">cd binutils-2.18.0* </span><br style="font-family: "Courier New",Courier,monospace;" /><span style="font-family: "Courier New",Courier,monospace;">./configure --target=arm-linux</span><span style="font-family: "Courier New",Courier,monospace;"> --prefix=/home/andreas/arm</span><br style="font-family: "Courier New",Courier,monospace;" /><span style="font-family: "Courier New",Courier,monospace;">make</span><br />
Don't make install, we only need the object files for the next step<br />
<br />
</li>
<li><b>Build elf to flat utility.</b> This convert ELF headers to a flat format. I've not dug deep into how this works, but it is tool we need. It will replace the original linker with a script that adds this functionality and then calls the linker. Thus you need to configure it with the path to your build root.<br />
Download elf2flt from git, <a href="https://docs.blackfin.uclinux.org/doku.php?id=toolchain:elf2flt">https://docs.blackfin.uclinux.org/doku.php?id=toolchain:elf2flt</a><br />
Unpack the archive:<br />
<span style="font-family: "Courier New",Courier,monospace;">tar jxf elf2flt*.tar.bz2</span><br />
Configure and build: (replace the paths to match your name and version)<br />
<span style="font-family: "Courier New",Courier,monospace;">./configure --target=arm-linux --prefix=/home/andreas/arm/ --with-bfd-include-dir=/home/andreas/arm/binutils-2.18.1~cvs20080103/bfd --with-libbfd=/home/andreas/arm/binutils-2.18.1~cvs20080103/bfd/libbfd.a --with-libiberty=/home/andreas/arm/binutils-2.18.1~cvs20080103/libiberty/libiberty.a </span><span style="font-family: "Courier New",Courier,monospace;">--with-binutils-include-dir=</span><span style="font-family: "Courier New",Courier,monospace;">/home/andreas/arm/binutils-2.18.1~cvs20080103/include</span><br />
Edit ld-elf2flt.c and comment out #include <filenames.h>. Don't know what it does except give errors... Works fine without, though.<br />
<span style="font-family: "Courier New",Courier,monospace;"> nano ld-el2flt.c</span><br style="font-family: "Courier New",Courier,monospace;" /><span style="font-family: "Courier New",Courier,monospace;"> make</span><br style="font-family: "Courier New",Courier,monospace;" /><span style="font-family: "Courier New",Courier,monospace;"> make install</span><br />
<br style="font-family: "Courier New",Courier,monospace;" /> </li>
<li> <b>The next big step</b> is to prepare the uClinux tree so that it compiles It turned out that some crucial things were left out when shipped. Well, we'll correct them below. Don't run any make commands before this is done. Unpack the uClinux-dist. This is the kernel tree, filesystem image and user space programs. You will probably spend most of your time configuring the files in here. If you somehow mess up the configuration or get lost you can always remove this directory and unpack it again.<br />
<span style="font-family: "Courier New",Courier,monospace;">tar zxf uClinux-dist-lpc_e2468.tgz</span><br />
<br />
</li>
<li><b>Fix the directory structure.</b> It turned out that some crucial things were misnamed or missing, so here we add some symlinks and rename the kernel directory. <br />
The first thing the make script will complain about after running 'make menuconfig' is that it can't find the kernel directory 'linux-2.6.21.4.lpc2468.patched.x'. If you look closely you'll see it's named almost the same as the one in your directory, so we'll rename it.<br />
<span style="font-family: "Courier New",Courier,monospace;">cd uClinux-dist-lpc_e2468</span><br />
Change name of linux dir <br />
<span style="font-family: "Courier New",Courier,monospace;"> mv linux-2.6.24.2-lpc2468-patched/ linux-2.6.24.2.lpc2468.patched.x </span><br />
Add armnommu symlink in arch <br />
<span style="font-family: "Courier New",Courier,monospace;"> cd linux-2.6.24.2.lpc2468.patched.x/arch </span><br style="font-family: "Courier New",Courier,monospace;" /><span style="font-family: "Courier New",Courier,monospace;"> ln -s arm armnommu </span><br />
Add asm-armnommu symlink in include <br />
<span style="font-family: "Courier New",Courier,monospace;">cd ../include </span><br style="font-family: "Courier New",Courier,monospace;" /><span style="font-family: "Courier New",Courier,monospace;"> rm asm ;# remove the old one, it's wrong</span><br style="font-family: "Courier New",Courier,monospace;" /><span style="font-family: "Courier New",Courier,monospace;"> ln -s asm-arm asm-armnommu </span><br style="font-family: "Courier New",Courier,monospace;" /><span style="font-family: "Courier New",Courier,monospace;"> ln -s asm-armnommu asm </span><br style="font-family: "Courier New",Courier,monospace;" /><span style="font-family: "Courier New",Courier,monospace;"> cd .. </span><br style="font-family: "Courier New",Courier,monospace;" /><span style="font-family: "Courier New",Courier,monospace;"> cd .. </span><br />
Add symlink to default config <br />
<span style="font-family: "Courier New",Courier,monospace;">cd vendors/NXP/LPC2468 </span><br style="font-family: "Courier New",Courier,monospace;" /><span style="font-family: "Courier New",Courier,monospace;"> ln -s config.linux-2.6.x config.linux-2.6.24.2.lpc2468.patched.x </span><br style="font-family: "Courier New",Courier,monospace;" /><span style="font-family: "Courier New",Courier,monospace;"> cd .. </span><br style="font-family: "Courier New",Courier,monospace;" /><span style="font-family: "Courier New",Courier,monospace;"> cd .. </span><br style="font-family: "Courier New",Courier,monospace;" /><span style="font-family: "Courier New",Courier,monospace;"> cd ..</span><br />
<br />
</li>
<li><b>Configure the kernel</b>. Now that the enviroment is all set up we can start configuring the kernel for the first compilation.<br />
<span style="font-family: "Courier New",Courier,monospace;"> make menuconfig</span><br />
Verify that the Vendor/Product Selection is correct<br />
In Kernel/.../Settings choose Customize Kernel Settings and Customize Vendor/User Settings.<br />
Press Exit, Exit and save changes<br />
<br />
</li>
<li><b>Kernel configuration. </b>In the Kernel configuration go to Boot Options->Default Command Line. By default it tries to load the initial ram disk from the wrong address(well it could probably work, but the one below seems to be more standard) and more inportantly it uses the wrong console. The latter means that your kernel might be working fine, you would just not see any output (or maybe garbage) unless you change your terminal speed, which is inconvenient in the middle of a session. This took me a while to figure out. Paste this line in to the text field.<br />
<span style="font-family: "Courier New",Courier,monospace;"> root=/dev/ram initrd=0xA0800000,4096K console=ttyS0,115200N8</span><br />
<br />
</li>
<li><b>More kernel. </b>System Type. We have 16Mb of RAM, which is 0x1000000 bytes.<br />
Set correct SDRAM size to <span style="font-family: "Courier New",Courier,monospace;">0x01000000</span><br />
Set board type to <span style="font-family: "Courier New",Courier,monospace;">Olimex LPC-E2468</span><br />
<br />
</li>
<li><b>Exit all the way </b>and Save changes. The Vendor/User config will popup. Just Exit and save changes. While this seems unnecessary it sets default values for a lot of options that you would otherwise have to set one by one on the command line. Now you are ready to compile.<br />
<br />
</li>
<li><b>Build the kernel and rom filesystem.</b> Because I'm curious about how long time it takes I usually run it with time and print the date/time when it finishes.<br />
<span style="font-family: "Courier New",Courier,monospace;"> time make;date</span><br />
<br />
</li>
<li><b>Find your files.</b> If everything goes well the kernel image will be located at <span style="font-family: "Courier New",Courier,monospace;">linux-2.6.24.2.lpc2468.patched.x/arch/arm/boot/Image</span><br />
and the romfs image will be<br />
<span style="font-family: "Courier New",Courier,monospace;">images/romfs.img</span><br />
While the second one seem obvious, the kernel location is not. There is actually an <span style="font-family: "Courier New",Courier,monospace;">image.bin </span>file in images but it's too big and doesn't work. I found the correct one by trial and error, and by looking for one that was roughly the size of the precompiled one.<br />
</li>
<li><b>Setup tftpd and assign a static IP address. </b>There are many ways to do it but this works for me. I have a crossed Ethernet cable between my board and laptop, but you can just as well use a switch and straight cables, which also has the benefit of not losing the connection every time you unplug the board. Some computers can use a straight cable direct to another device.<br />
If you are using a GUI Linux you can set a static IP there, I happen to use <span style="font-family: "Courier New",Courier,monospace;">192.168.0.202</span>. On the command line it is<br />
<span style="font-family: "Courier New",Courier,monospace;">sudo ifconfig eth0 192.168.0.202</span><br />
tftpd uses <span style="font-family: "Courier New",Courier,monospace;">/srv/tftp</span> as root directory on Ubuntu so you can either copy your files there or, more convieniently, make symlinks to your image and boot directory.<br />
<span style="font-family: "Courier New",Courier,monospace;">ln -s /home/andreas/arm/uClinux-dist-lpc_e2468/images /srv/tftp/images</span><br style="font-family: "Courier New",Courier,monospace;" /><span style="font-family: "Courier New",Courier,monospace;">ln -s /home/andreas/arm/uClinux-dist-lpc_e2468/linux-2.6.24.2.lpc2468.patched.x/arch/arm/boot/ /srv/tftp/boot</span><br style="font-family: "Courier New",Courier,monospace;" /><span style="font-family: "Courier New",Courier,monospace;">ln -s /srv/tftp/boot/Image linux.bin</span><br style="font-family: "Courier New",Courier,monospace;" /><span style="font-family: "Courier New",Courier,monospace;">ln -s /srv/tftp/images/romfs.img romfs.bin</span><br />
The last two are not necessary but are the names used in the default uBoot tftp_boot script, and that speeds up testing, since you can type 'run tftp_boot' in u-boot to load everything in one step.<br />
<br />
</li>
<li><b>Set up the board.</b> Plug in the board via USB and start a terminal. Assuming your board is the only USB-serial adapter it would be:<br />
<span style="font-family: "Courier New",Courier,monospace;"> screen /dev/ttyUSB0 115200</span><br />
Press reset on the board and you should see uBoot starting up. Press any key to interrupt the loading process to get a command prompt.<br />
Check the environment variables for network settings:<br />
<span style="font-family: "Courier New",Courier,monospace;">printenv</span><br />
You should see something like this:<br />
<span style="font-family: "Courier New",Courier,monospace;">ipaddr=192.168.0.157</span><br style="font-family: "Courier New",Courier,monospace;" /><span style="font-family: "Courier New",Courier,monospace;">netmask=255.255.255.0</span><br style="font-family: "Courier New",Courier,monospace;" /><span style="font-family: "Courier New",Courier,monospace;">ethaddr=00:de:ad:b0:05:02</span><br style="font-family: "Courier New",Courier,monospace;" /><span style="font-family: "Courier New",Courier,monospace;">serverip=192.168.0.100</span><br />
Change serverip to match your computer's IP and save to flash:<br />
<span style="font-family: "Courier New",Courier,monospace;">setenv serverip 192.168.0.202</span><br />
<span style="font-family: "Courier New",Courier,monospace;">saveenv<br />
</span></li>
<li><b>Download the firmware. </b>First load the kernel to RAM:<br />
<span style="font-family: "Courier New",Courier,monospace;">tftpboot 0xa0008000 /boot/Image</span><br />
Then load the ROM file system:<br />
<span style="font-family: "Courier New",Courier,monospace;">tftpboot 0xa0800000 images/romfs.img</span><br />
Finally start the kernel:<br />
<span style="font-family: "Courier New",Courier,monospace;">go 0xa0008000</span><br />
</li>
<li><span style="font-family: "Courier New",Courier,monospace;"><span style="font-family: Georgia,"Times New Roman",serif; font-size: small;"><b>Voila! </b>The kernel should be loading and in few seconds you get a command prompt. <br />
You have aquite limited system at this stage, but you can always run 'make menuconfig' to change kernel features and user packages.</span></span></li>
</ol>
<br />
<br />
<br />
<br />
<br />
<div style="margin-bottom: 0in;">
<br /></div>
Wileurhttp://www.blogger.com/profile/00334738425060233729noreply@blogger.com2