Showing posts with label linux. Show all posts
Showing posts with label linux. Show all posts

2011-01-15

SolarLight (8) - Plastic Fixing Rig et altri.

In the new year I decided to further develop my SolarLight, I had to build a rigid rig to hold the light over my peppers vase. After some thought I decided to use plastic (polystyrol) to keep it lightweight. I used standard PVC glue (used for water/sewage pipes or spudguns) and Polystyrene.
To cut the boards I used standard hand tools (hand saw, metal file and sandpaper), thinking back I would be better off if I had used a table saw... With a good saw and speed setting I think I could do it all in one. I don't have a table saw, nor the space for it, maybe I'll use the Dremel mini-saw adaptor (Dremel 670) or one of the Proxxon mini/micro table saws.
The glueing of the parts was fast and clean, if you do something like this remember to do it out in the open or in a well ventilated place, toxic fumes come out while the parts are being chemically soldered. I found most of the plastic sheets and profiles here.


I started out by trying one of the few available 2D-CAD packages for linux, I used QCAD community edition that had a pre-compiled for my OpenSuse11.3 in the contrib repository. Learning a new tool has always it's steep learning curves, but I got what I wanted. I will try to use it for my future mechanical drawings of cases and front panels.



After the assembly I noticed that I forgot some openings for the LED connector and fixing, so it is just hanging for now. I also changed the battery pack I had for a 3x AA NiMH 2300mAh batteries. This was a mistake, the solar cell was selected based on a battery capacity of around 700mAh (an old NiCd pack I had laying around) and size of the board. Although with the batteries charged I got a good hour and a half of light, the next recharge period was a full week... from this page I would need 40 hours of sunlight to fully charge the battery as the solar panel output current is below the C/40 ratio... Taking into account that the average daily sunlight time of about 8h,(and in my south facing flat it's reduced to 4-5), that in Holland the sky is mostly cloudy for days in a row, that the solar cell outputs roughly 15mA with direct sunlight, I could expect to have a fully charged battery (with the NiMH pack) every two weeks.. With the NiCd I could expect once two sunny days (more or less what I was looking for). So I have to go back to smaller batteries, probably another junk 3x AAA NiCd pack I have around.
I also roughly measured the efficiency of power supply and made some tests. The maximum output current I managed was 700mA, more than that and the battery voltage would hit the under voltage protection I had built in, this is about 50% of the LEDs Power. I also had to add a heatsink to the LED as its temperature was rapidly increasing beyond the "can you touch it" capability (a rule of thumb I learned...). So I used a stable DC power supply and varied the input voltage, input current, output voltage and output current at about 25% LED power level (3.2V@300mA). The results are a bit disappointing, the efficiency is about 50% from the calculated 70%. I don't think the losses are semiconductor related but mostly the passive components (inductor resistance and capacitor inductance and resistance). The good point is that output voltage is mostly independent of input voltage...
I also did some improvements on the code and ordered some new SMD components, I'm planing on building a SMD version and extend the project to a bike light (with the electronics inside the lamp's casing), we'll see how that goes, later I'll publish the updated software.
I included a graceful degradation system to reduce the output power as the battery depletes its charge, the processor now sleeps between ADC conversions both to save power and reduce noise (I cannot disable the Timer as the PWM must run), I changed the charging process but not counting the hours of charge but only by checking the battery voltage as this allows an external charger (not sun) and finally I converted the code to be compile in linux (avr-gcc/gas).
It's a long post and I have some more post hanging in for further editing.. I'll try to keep up with one a week and I'm already falling behind.

2010-12-30

gdb-stub for m68k quirks and tricks

After some investigation I finally realized how most of the gdb-stub works and how you can make it work, I also found out what doesn't work and that there are some things I still don't fully understand.
After having a stub that I could download to the target's ROM (in this case an EPROM Emulator) and would properly communicate to the gdb running on the host, I built a C runtime assembly file (crt0.s) and linker command to place the program in the available RAM. Since I had done a similar work for the stub running in ROM, it was only a question of changing some parameters and some basic code at the start up routine.
The test program was very simple, I didn't want to test any advance feature just a simple program flow with loops.

When I added a coded breakpoint in the code, all would work consistently, I could continue without a worry, control flow would be transferred back to the stub when the breakpoint was hit.
But as soon as I added a gdb break point what I expected to happen was, gdb(host) would read the contents of the instruction at the breakpoint and substitute it by a breakpoint opcode (TRAP). From reading the gdb-stub code and most internet references, a breakpoint should be a TRAP #1 instruction, I had setup the gdb-stub to intercept TRAP #1 instructions and report them as breakpoint to gdb(host), but every time I place a breakpoint I would get a privilege violation at the address following the one of the breakpoint.
The problem was that gdb(host) instead of adding a TRAP #1 (0x4e41) would add a TRAP #F (0x4e4f) (!!!), see it in the below:
I set a break point at line 20 of the code, gdb(host) tries a Z0 command but the stub doesn't implement it, gdb(host) acknowledges it, then it reads the code at the breakpoint position (m4074,2 with reply 2039), then writes a trap instruction at this address (M4074,2:4e4f).

You'll need to click on it to see it ok, sorry couldn't solve this one in the old fashion way..
When after several tries I decided to check "everything" that came in and out of the stub, I check that the instruction is in fact a TRAP #F and not a TRAP #1 as I was made to think, naturally I had not set the gdb-stub to catch these exceptions, then the stub would return to the address following the trap which is not an instruction, hence the privilege violation.
This problem above is probably solve in some gdb configuration line, but I didn't found it yet.. If I do I'll post it back here.
The second problem is only detected when you get these breakpoints to work. After the breakpoint the PC is pointing to breakpoint+2, before you continue you need to roll the PC back by two. This can be done either by the stub or gdb itself. I chose to do it at the stub, but it is possible to do it at the gdb(host) (also some configuration option must be there...). The only problem with any of these is that once a breakpoint is hit, it must be disabled before execution continues.
Gdb(host) just before you continue changes the instruction at the breakpoint address to a trap, then execution continues, when the breakpoint is hit control is given back to the stub and the instruction at the breakpoint is replaced by the previous. If the PC is rolled back by two, at the next continue, the same breakpoint will be hit without further processing... so we are blocked... An option would be to control everything from gdb(host), before continue, single step one instruction (the breakpoint instruction), change the breakpoint by a trap and then continue... I will have to investigate a bit further to see if this is already implemented in gdb but it seems (as Mythbusters would say Plausible).
If you are also curious about why the coded breakpoint (TRAP #0) above is different than the gdb-inserted breakpoint (TRAP #1 or #F) it is because gdb-inserted breakpoints must roll back the PC, coded ones do not.

2010-02-10

Next Project Minimal CP/M 68k

The Solarlight project has been taking more than normal, but the truth is I haven't had much time lately...so I decided to announce my next project, revive a minimal CP/M-68k system and document the process. The main components are a MC68008 CPU, a MC68901 MPU, 512K of SRAM, 32k EPROM, and a IDE/ATA connector. The MPU (multi-peripheral unit) will serve as UART and probably as basic memory manager, the IDE interface will probably be based in GIDE or something similar. While I'm still working on the schematics, I've already built the base circuit from my hand written schematics... here's a picture.

The sources and documentation of the code are available in Gaby's site. This site used the sources to build a VAX version, so the sources appear not to have suffered from too much of "bit rot".
For cross compiling and debugging I'll try to use binutils/gcc/gdb in remote mode. I'll try to build the cross tools (elf format, coff has been since long time killed) and a remote gdb-stub to download and debug some initial code... we'll see how it goes..
Here I've already built the cross-compiler toolchain for m68k-elf (binutils-2.20, gcc-core-3.4.6, gdb-6.8 and newlib 1.18.0), I didn't use a more recent one because from searching gcc-3.x.x is easier to cross compile with the newlib, and I wanted to use a smaller libraries than libc.
Download the sources from the gnu ftp site (except for newlib that is here), I followed this guide because not only it appeared simpler (no "bootstrap compiler" step) but also it is dedicated to embedded systems. Don't forget to move newlib and libgloss inside the gcc directory and after the binutils compile put them in the path. I also used gnu gdb instead of insight but no other than that.
Finally set the path in your .profile for your convenience, see here for details on OpenSuse.
My first objective after building the system on a breadboard is to download a small m68k assembly program to the EPROM EMULATOR and see it run, then a small C program and finally a gdb-stub. Then I'll have to repeat the process since from that point on there must be a change in the linker file as programs stop being linked to ROM but linked to RAM.
I've successfully assembled a "loop:nop,nop,bra.s loop" but a few problems or "unknowns" remain...
I've created my simple assembly file called test.S

/*
* test.S -- test file for assembler output
*/

#include "asm.h"
.title "test.S - test file for assembler output m68k-elf-as"
#define STACKSIZE 0x4000

.data

.text

.extern __stack

.global SYM (_start)
SYM (_start):
nop
nop
bra.s _start

I assemble it with "m68k-elf-gcc -c test.S -o test.o" then link it still with gcc "m68k-elf-gcc test.o -o test.x -nostartfiles -nostdlib -v -fpic -WL,Ttest.ld"
I had to include the -nostartfiles and -nostdlib to remove the standard crt0 and the global constructors for C++.
My current linker file is very simple and probably some things are missing for a full C program compilation but for now things appear to be ok.

/* ld file for rom programs */
/* for 8 cycles rom is at 0x00000 (fetch SP and PC), from then on 0x80000
/* STARTUP(crt0.o) - no startup file*/
OUTPUT_ARCH(m68k)
OUTPUT_FORMAT(srec)
SEARCH_DIR(.)
/*
*Setup the memory map of mini68k, stack grows down from high memory.
*/
MEMORY {
ram (rwx) : ORIGIN = 0x01000, LENGTH = 0x80000-0x01000
rom : ORIGIN = 0x80000, LENGTH = 64K }
/*
* allocate the stack to be at the top of memory, since the stack
* grows down, also PUSH => -(SP) = xx, i.e. predecrement therefore
* first stack address never gets written
*/

PROVIDE (__stack = 0x80000);

SECTIONS
{
.text :
{
_stext = .;
*(.text .text.*)
. = ALIGN(0x4);
_etext = .;
} > rom

.data :
{
*(.data .data.*)
_edata = .;
} > ram

.bss :
{
. = ALIGN(0x4);
__bss_start = . ;
*(.bss .bss.*)
_end = ALIGN (0x8);
__end = _end;
} > ram
} /* missing in the initial file - causes an error ld does not complain! - beware */

Then I can also successfully convert the object file test.x to a SRECORD file with the command "m68k-elf-objcopy -O srec test.x test.S19" and then revert the intermediate object file test.x to assembler with "m68k-lef-objdump -d -X test.x > test.dis"
After successfully removing all the initialization code gcc attaches to your code (with -nostartfiles -nostdlib(p.s. you only need the first one since you don't add any library function)) I was left with one question, why is my code placed at absolute address 0x80000054?? when I told in the linker file to put it at 0x80000 (less a few zeros in the middle) Here is the disassembly:

test.x: file format elf32-m68k

Disassembly of section .text:

80000054 <_start>:
80000054: 4e71 nop
80000056: 4e71 nop
80000058: 60fa bras 80000054 <_start>

Ok, this was a bug. I forgot a } in the memory definitions of the linker file *.ld... After adding it the code was located at the correct place 0x80000.
Well there are still some hurdles to overcome, namely:
- placing the start SP and start address in vectors 0 and 1;
- place the other vector in ram
- place the code in proper ROM addresses (and the initial SP,PC)
- download the code and see it run...
... the path through cross-gcc appears to be hard ...

2009-09-15

Building GCC toolchain for AVR

Recently, along with my Arduino-ethernet-shield I bought a Arduino-Diecimilia fitted with a ATMega328, only to find out that my compiler set-up wouldn't work. A quick investigation (here and here) showed me that my current gcc toolchain (4.2.2) didn't support the '328.
OpenSuse repositories provide an avr-gcc toolchain that can be used with the Arduino IDE for Arduinos fitted with the ATMega8 (very old) to the ATMega168 (old), for the ATMega328 you must build the toolchain yourself (at least for now).
I tried to follow general cross gcc building instructions (more on this on another day), but it didn't work. Using gcc bleeding edge of technology sometimes has its problems. Also there are some patches that must be applied to the source.
So I decided to follow the build script provided by the AVR-Freaks forum. You must become a member in order to download the script. It is still not the latest version of GCC 4.4.1, but it is recent enough (4.3.3) for ATMega328.
The pre-requisites are quite important, you can install binutils-devel (BFD support) from the Opensuse repositories and download the mpfr from here. Compile and install mpfr.

$./configure
$make
$su
#make install
#exit
$

Then run the scripts in order:

$ ./getfiles.sh
$ ./get-patches.sh
$ su
# ./buildavr-no-insight.sh
# ./buildinsight.sh
# exit
$

The build scripts ask you a couple of questions and in the end suggest some clean-up, once it starts you have time for few coffees...
Finally test your configuration:

$ avr-ld -v
GNU ld (GNU Binutils) 2.19.1 + coff-avr-patch (20050630)
$ avr-gcc -v
Using built-in specs.
Target: avr
Configured with: ../../source/gcc-4.3.3/configure -v --target=avr --disable-nls --prefix=/usr/local/avr --with-gnu-ld --with-gnu-as --enable-languages=c,c++ --disable-libssp --with-dwarf2
Thread model: single
gcc version 4.3.3 (GCC)

And you're good to go...

UPDATE: 2011.03.13
I recently installed OpenSUSE 11.3 and redid the installation. It works very well but you still need to do the following (these changes are, or may not be OpenSUSE specific):
- as su create and edit a /etc/bash.bashrc.local, add the following lines:

# User specific environment and startup programs
PREFIX=/usr/local/avr
export PREFIX

PATH=$PATH:$HOME/bin:$PREFIX/bin
export PATH

This will enable all users to access the build tools.
Then you need to do the following:

# chmod 777 /var/lock
# chmod 777 /dev/ttyUSB0
# chmod 777 /dev/ttyS0
# chmod 777 /dev/ttyS1

these last two are for my serialports.. I need to remind myself of doing it for minicom.
and finally create a udev rule for avrisp mk ii.
created a file 89-usbprog.rules in the rules.d directory (as su) and add the lines:

# udev rules file for some usb connected mcu programmers

# Atmel devices
#
ATTR{idVendor}=="03eb", ATTR{idProduct}=="2104", MODE="0666", GROUP="users", SYMLINK+="avrispmkII"
ATTR{idVendor}=="03eb", ATTR{idProduct}=="2103", MODE="0666", GROUP="users", SYMLINK+="avrunknown-%n"
ATTR{idVendor}=="03eb", ATTR{idProduct}=="2107", MODE="0666", GROUP="users", SYMLINK+="avrdragon-%n"

# Microchip devices
#
ATTR{idVendor}=="04d8", ATTR{idProduct}=="0033", MODE="0666", GROUP="users", SYMLINK+="pickit2"

as seen here with minor adaptations and your done...
test it with the arduino-IDE, compile and download the blink example.
test avrisp with a simple command:
avrdude -p t15 -c avrisp2 -P usb

PS. this solution also works

2009-05-05

Munny Software

Finally I had the time and the patience to write a "clean version" of the Munny code.
I wanted to use avr-as instead of AVR-Studio, it was much more difficult than what I expected. Information about using avr-as is scarce and I was unable to find an example of an assembler only project for avr-as. The main problem was that when you use preprocessor commands you must use preprocessor comments!
So remember the following:

#define ADC_SETTLE -32 /* arround 20ms */ GOOD
#define ADC_SETTLE -32 ;arround 20ms WRONG

I'm not a web-wizard but I wanted to post the code "online", I tried using google code. Probably I'm not using correctly and I don't think it was designed for such small projects but here is the link to the download.
Because the project might interest to more than one community I also tried to posted the project at the AVRFreaks site, usually the place to search for information when dealing with avr-gcc toolchain but unfortunately I cannot add a file to the project...
Programming the flash is straight forward with avrdude, but programming the oscillator calibration value and the fuses needs some more work. I used the interactive mode of avrdude ( -t) :
read calibration
write flash 0x3ff calibration_value
read flash 0x3ff 0x10
Here is a picture of the PCB during testing:

The software is a bit difficult to understand, the micro is put to sleep most of the time except once once every 32 times of watchdog resets.

Then a temperature measure is made, a port pin is used to power the temperature sensor and the micro is put to sleep for some 20ms, then a analog to digital conversion is started and the micro put to sleep again until the conversion is finished. Then the value is stored and the sensor is powered down (to save maximum power).

The following step is calculating the colors function of the temperature, according to the temperature one of Red, Green or Blue or a mix of two is calculated. Each color has a value of [0..255].

Finally blinking the LED, a software 3 channel pwm controller is created, a counter is incremented every Timer1 output compare and the calculated color values are compared with this running counter. When the counter value is higher than the set value the corresponding LED color is turn off, otherwise turned on. Timer 1 is set to auto reload every 1/25.6 ms this gives a 256 bit resolution every 10ms, this make the colour mixing invisible to the eye. After 100 repeated counter runs the micro goes to sleep until next Watch dog reset.

2009-03-17

Arduino Suse 10.3 installation

I had to reinstall SUSE Linux 10.3 in my Laptop and after installing the Operating System the first thing to install was the Arduino development IDE and the AVR cross toolchain.
If you have added Packman repositories just install the following packages, although most are in the Main OSS repositorie:
cross-avr-gcc
cross-avr-binutils
avr-libc
avrdude

The latter is a command line application that programs AVRs (and other micros), it is also useful if you program AVRs outside the Arduino environment.
The really important steps follow, as superuser do:
#chmod 777 /var/lock
#chmod 777 /dev/ttyUSB0

These are also useful when using minicom (/var/lock) and USB serial port to comunicate with RS232 computers (/dev/ttyUSB0).
These instructions were adapted from here, some of the steps are not necessary, others really important.


To use my AVRISP mk II in SUSE 10.3 I needed to change a udev rules to add the device as accessible to every use, I added the following line at the end of /etc/udev/rules.d/50-udev-default.rules :
# AVRISP mk II
SUBSYSTEM=="usb",SYSFS{idVendor}=="03eb",SYSFS{idProduct}=="2104",MODE="0666"
It turns out that it still doesn't work... when trying to use avrdude with the -P usb option it complaints that it was not compiled with USB support...
Uninstall avrdude (keep uisp, avrlibc needs one of them otherwise yast complains), download the sources then configure and install to /opt/cross..

# gunzip -c avrdude-5.8.tar.gz | tar xf -
# cd avrdude-5.8
# ./configure --prefix=/opt/cross
# make
# su
# make install

Test it connecting the AVRISP mk II to an Arduino with the command:
#avrdude -c avrispmkII -p m168 -P usb

2009-03-16

Time Lapse Agriculture

I always thought the one of the great pleasures of being a farmer was to "see plants grow". Maybe I'm too impatient, but after looking at them for 15 minutes and see nothing I decided to try and do a time lapse video.
Ana tried her film first, she used a regular camera and took pictures every 15 minutes for two days (most of it). Later I ordered the pictures, reduced the size and composed the video. In order to keep the same illumination during the day, she used an halogen lamp over the plants. Naturally it is quite clear that this fakes the results and her plants grow super fast...
I decided to use a computer and a webcam to do the job for me. First I tried a logitech quickcam messenger but the resolution was very coarse, it needs special drivers in linux and it does not auto adjust for the brightness.
Next, Tiago borrowed me a Philips Webcam PCVC830K, it worked out of the box in Suse 10.3, resolution is 640x480 and adjusts for the brightness.
I created two scripts, one to take the pictures every 6 minutes and another to compose the video.
Here is the snapshot script:
#!/bin/bash
## adapted from http://mydebian.blogdns.org/?p=261#more-261
## Takes a picture every (wait) seconds and renames it ${now}

# how long to wait between each download
wait=360

## main endless loop ##
while true
do
now=$(/bin/date '+%Y%m%d%H%M%S')

## fetch new webcam shot ##

ffmpeg -s vga -r 1 -t 1 -f video4linux -i /dev/video0 -y plant.jpg
mv plant.jpg "${now}.jpg"
## echo "${now:8:2}" just the hour
echo "${now}"
/bin/sleep $wait

done
Here is the script to compose the video:

#!/bin/bash
mencoder -ovc copy -mf w=640:h=480:fps=15:type=jpg 'mf://*.jpg' -o time.avi
During the shoot I hit the box with the vacuum cleaner, so there's a small shift... be warned. The shoot takes place from Friday night to Monday morning. The plant box is facing south and is close to the TV, so during the night there's a first level of darkness, then when we turn off the TV the only light is the webcam red led. The red led allows us to see some, although little movement.
Here is the video...

2009-01-26

Linux on Compact Flash

Recently I bought an used odd Thinkpad X40 in Ebay, it has a French keyboard (ugh!) and a DIY touchscreen, Bluetooth but no WLAN. Since its hard disk was starting to fail I decided to try out and insert a Compact Flash as hard disk. I ordered a 8GB super fast x133 online, but this weekend I could not wait and since 4GB SanDisk's Ultra II were at 24€, I decided to try it now!
I already had a 1.8 inch IDE to compact flash adapter (bought earlier here), in hardware terms it is really plug and play! The BIOS and the computer think that they have a normal (although not hitachi) 4GB hard drive.


I managed to install Suse 10.3 and perform all the updates, it had to be a small install to fit in 4GB but enough to run the familiar KDE and OpenOffice. The installation goes slower than with the normal hard drive, but once you get to the Network update speed is about the same.
Then I edited the file /etc/fstab as according to this page.
Here's what I did:

su
vi /etc/fstab

Then edited the line with the line

xxxdisk-idxxxxx / ext3 relatime,errors=remount-ro 0 1

adding the noatime option. Normally every time you read a file, the time is written back to the drive. The noatime option disables this.

xxxdisk-idxxxxx / ext3 relatime,errors=remount-ro 0 1

Then added the following lines. They move most temporary files to a ram disk.

tmpfs /tmp tmpfs defaults,noatime 0 0
tmpfs /var/run tmpfs defaults,noatime 0 0
tmpfs /var/log tmpfs defaults,noatime 0 0
tmpfs /var/lock tmpfs defaults,noatime 0 0
tmpfs /var/tmp tmpfs defaults,noatime 0 0
tmpfs /var/lib/dhcp3 tmpfs defaults,noatime 0 0


I did not write the line for Mozilla Firefox because I am not sure if Novell/Suse whatever have changed the temporary directory. Another site that looks like having good information is this one.
After the installation and configuration I tested the hard drives for read speed, and the Compact Flash does not come very far behind! But the big test is endurance rather than speed. Here are the screenshots, the top one reports on the current X40 (with magnetic hard drive), the bottom one the test on the compact flash and the listing of the /etc/fstab.

As SU you must run the command:
# hdparm -t /dev/sda1

/dev/sda1:
Timing buffered disk reads: 56 MB in 3.08 seconds = 18.21 MB/sec
The CF disk reported 14 MB/s, which is 22% less... I still think it is not a big gap as with a bigger investment €€€ one could get better transfer rates (there are 8GB cards on the market advertising 30MB/s and more).

I think a good idea would be to have a mixed system on the same card, a compact flash on one side and a 1Gb dram on the other (for temp files, var, log, etc). One of the adapters that I found has a second connector on the back of the card, maybe it could be used with a small microcontroller, FPGA or CPLD to connect to a cheap SDRAM and provide a second volatile disk for all the changing data.