2010-02-27

Das Blinklicht with gcc-elf-m68k

The first program you write when you learn a language is the "hello world" classic, in a embedded system where you don't have a serial port (or you don't know if it is working) you have to use "das blinklicht" example. Er... it's just a blinking LED.
After setting up the cross compiler tool chain you'll need to set up the linker script and the crt0.s files.
The linker script defines where (in physical addresses) is the RAM and ROM of your system, which sections of code go into where and in my case the reset vector and initial stack pointer. There are still some things missing (namely libraries, floating point and multiplication/aritmetic), but I'm a step closer. I must admit that I found these (crt0.s and ldscript) on the net but I don't remember where or who did them. I've just change them a little.
Although the ROM is mapped on reset during the first 8 clocks at 0x00000, after the 8th clock ROM gets mapped at 0x80000. When you are programming a real eprom (or using my "linux-updated" rom emulator) you must move the code to the bottom of the ROM. This is accomplished with the command "AT".

GCC creates a section of code for "initialized data" called .data, this section is put into ROM and at the start it is copied into RAM (at CRT0.S), with the blinklicht program I don't use any .data or .bss or even stack, so for now I will not test if this works.

Without using optimizations -O2 your software loops will not be cleared by the optimizer, and it is pretty easy calculate the time taken for the software loops.

I had calculated an access to the MFP m68901 every 15us with a 4MHz clock and what I had was 30us.. I found the "problem" the next day, the instruction timing sheets are for the m68000 with its 16bit data bus, a 68008 takes two memory cycles for each of m68000, therefore twice as long.
The simple makefile is here

SolarLight (7) - Software, AVR assembly


Ok, finally google docs supports any type of file so I can post all the project files in one place: code, gerbers, gEDA design files and spreadsheet with the calculations, requirements. It is all here.
I decided to try out pastebin, so I'm updating this post with the code for everyone to take a peek... In this version I'm still working on the "when to turn on" routine, I think it still doesn't work as I initially intended... pastbin doesn't look so good to paste long assembly lines, but here it goes anyway..

The software as it is now is working, it has some problems and "room for improvement" but it is working! You know the motto: Make it work, make it better!, make it faster!

One of the improvements would be to limit the time the light is ON to about 30min-45minutes, this would allow the battery charge to progressively increase during the good sunlight days and progressively decrease on a sequence of bad sunlight days (as in this year for example).
Other improvement could be a full darkness detection and adjust a 12h no light clock from there. It has happened that during the day when a big cloud (and/or heavy rain/heavy snow) the measured light level goes down to the "night" level, then if there's enough battery the light turns on... it shouldn't and I'm sure this winter is exceptional, but the only way to prevent this is to detect the lowest darkness point and count 12 hours from there, and only from then on the light would turn on when it is dark.

In the code I added a debug routine that is included when the two variables are uncommented (DEBUG and DB_CNT), when I wanted to output a value I load it in the DEBUG variable and call dbug. The byte is output in the status LED serially MSB first, there is a long (2 cycles) high pulse followed by clock and MSB data, clock and bit 6 data... clock and LSB data.

Finally my biggest problem was the branch instructions, the AVR has the following:
BRLO - Branch if Lower (UNSIGNED)
BRLT - Branch if Less than (SIGNED)
BRGE - Branch if Greater or Equal (SIGNED)
BRSH - Branch if Same or Higher (UNSIGNED)
I was not used to have these complex branch instructions, I'm used to Zero Flag set, Zero Flag Clear, Carry set, Carry clear... I'm specially not used to having a different branch for signed or unsigned... So I chose wrong.. result the jumps were not taken when they should. The ADC values are unsigned when read (0..255) but if you start calculating with them you can get signed (negative) values and then you have to use signed instructions.
AVR assembly programmer beware!

A final word about the Code, it was assembled with Atmel AVR Studio Assembler (Win), it doesn't output the number of cycles per instruction... a bit of a let down... :-)
And with this post I finish this project.... Woo Hoo!! Project is dead, long live the new Project...

SolarLight (6) - PCB Fabrication and Assembly

Using gEDA for producing gerbers turned out to be easier than I thought.
Recently the gEDA project has been under fire in slashdot due to its "complicated", "non intuitive interface" and lack of documentation. I really don't think that the documentation is that bad, it is scattered but it is not bad, just look here. I haven't meet an Open Source project that didn't suffer from the same problem, even (and particularly) the GNU tools. As soon as you get out of the mainstream gcc/gas/ld/gdb you're almost on your own, searching bits and pieces in the internet. Some of the best GNU project documents have been written by a commercial enterprise (either redhat, cygnus or other).
I call it Anarchic-Knowledge (or Anarco-Conhecimento in Portuguese), everyone omits to write what he finds trivial, forgetting that what is trivial to him, might not be for the community that will use the product. Then a plurality of tutorials, blog posts and guides show up, each one showing how they did it "their way". A new user has to pick all these pieces, try more than one and finally write a "I did it my way" post... And we all learn from this experience.It is not the lack of documentation, it is just the way that Open Source grows.
Back to the how I did it... :-)
I followed this tutorial, I had a single page schematic so it was easy to generate the netlist. I created a single project file with the schematic libraries, I used my own symbols since not only I wanted to learn how to do them but also I had a MOSFET with two Drain Pins that I could use each in an independent circuit. I used shell scripts to get the job done, I tried once a Makefile but I realized that I would have to change the Makefile for every project (even smaller ones), a shell script can do that at invocation time.
I also created some Footprints for my project (also for educational purposes), I had them in a library directory and used jcl's gnetlist invocation but with my directory instead. PCB must also be configured to have a pointer to your library in the "File-Preferences-Library".
First follow what gschem2pcb tells you to do, open the file, import the parts, spread them and execute the command, then I put in most of the mechanical details, using the outline layer in a place where no components were place, size of the board, cuts, groves and fixing holes. Also check now for the DRC tolerances in the File-Preferences Menu.
Then the fun begins, it is a very iterative process: place, route, looks good? can I do it better? with less vias? other mechanical problems? heat sinks/problems? repeat until satisfied with the design.
Then I place some more information on the silkscreen, plus signs on the connectors, output indication, board reference, moved the references so that all are visible when the components are soldered and facing the same side (so that you don't need to rotate the board to read the references). I also place on the top and bottom layer a square with the layer number inside, so that you can identify the layers on the gerbers and on the boards.
I was going to use Olimex pcb prototype services for my first gEDA boards so I needed to limit the number of drill sizes, they have some drill sizes that are considered standard and any other is considered extra (and you pay more), luckily someone from the gEDA-user group already made a drill mapping file for Olimex after executing the script run DRC again! Here's my final PCB result.

You can also export to png the two sides of the board in a "photo-like" picture, some people claim it gives better reading and it is easier to spot errors.

If you have no errors in the last DRC you're ready to produce your gerbers, and this part is as easy as pressing the correct button in export. Then with gerbv, check if the gerbers look nice and the drill sizes are correct.
Recently a good question came up in the geda-user mailing list, it sums it up nicely but the first reply reminded me of something I didn't do and should have done...
Print out your surface copper layers and put the parts on the printout to make sure they match.

yup, I designed my resistors with a 1/8W in mind and then I couldn't find any I had to use 1/4W.. so the resistors didn't fit in place. My DIP 4 for the MOSFET also didn't had big enough holes, apparently International Rectifier didn't stick to the normal DIP drill sizes, probably due to current capability or thermal conductivity. In that point, with some hindsight, I would increase the copper area connected to the drain, that could be a good heat sink for the MOSFET. I also should have thought a bit more on how to fix the board to the pole, with the new batteries the SolarLight is much heavier, I should have devised other way to fix it. Here's the board in place, note the resistors in two layers.
UPDATE: The resistor that is hanging and has two sockets is the gate resistor of the MOSFET, if you check the spreadsheet with the calculations you can see that the gate current has great influence in the MOSFET power (losses), so I made it low enough to still allow programming easily (now at 100R). When programming the micro the light turns on, but without any damaging effect as long as the frequency (of programming is high enough 250k) and the pattern is sufficiently random (see here for a bigger problem with ISP port sharing).


One last remark, if you buy microcontrollers in ebay and they say "New, Old Stock" it doesn't mean that they are not programmed, they can be factory programmed and that doesn't mean that they are not new! In case of the ATTiny15L, the low voltage programming mode can be disabled by this factory programming, if you solder it to the board you'll not be able to reprogram it. You need to remove it from the board and use a HVProgrammer like AVRDragon for example. Learned the hard way...

2010-02-19

CPLD SMD Soldering

Having received my boards and with my Weller working it was time to solder. I started with the CPLD adaptor, an adaptor I've build for my stack of old MACH211SP... I could also test my SMD soldering skills.
Here is the first step where two opposite pins of the PLCC are soldered into place. Next I'll have to "restart" my DesignDirect program in Windows XP. On a side note here's the schematic of the board.

Weller WTCP-S Repair

This week as I was about to start soldering my boards my old trusted Weller WTCP-S started to fail, first ocasionally it wouldn't heat up until shaken, lattely not at all.
Wanting to fix it (if possible) I opened it to check the famous "Magnastat", these Soldering Irons operate on the principle of the Curie Temperature, where a magnet loses its magnetic properties at a certain temperature point.
Inside the casing there's a ferromagnetic piston and the tip is also magnet with a predetermined Curie point (the number on the bottom of the tip), when the temperature is reached the magnet losses its properties, the piston is no longer pulled and the contact at the bottom opens, opening the heating circuit.

I had to open the contact casing and clean the contacts, put it back together and test....

While cleaning the contacts the wiring came loose, so now I was facing a chicken'n'egg problem, how to solder a soldering iron?, the local hackerspace was the answer, I meet some really nice people in really nice location and they had a spare soldering iron I could use in their "electronics shack".
Anyway got home, tested it and it works for now... but I expect it to fail again soon... I'm ordering a replacement today...

2010-02-17

SolarLight (5) - PCBs!!!

I finally had the time to pick my PCBs at the mail. I was thrilled to see who it went... My first linux made PCBs!
Everything went ok, except for a few minor point where I'm the only one to blame...
Here are the pics to the solarlight board and the others, the last one is the RFadaptor that didn't go as well as I expected, but I'm the only one to blame....
Here is the one where the wholes are just the size of the pins (just not enough for them to get through)...

I'll post how to get from PCB design to send them to Olimex (for example) for production. It's not that difficult but you need to follow some steps.

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 ...

Reverse Engineering a EPROM emulator

While I'm waiting for the SolarLight PCBs to arrive I went on think about other projects...
I had an old EPROM emulator that I bought a long time ago in ePay. It is quite small and it doesn't consume much power but it worked from the parallel port and the old DOS software was reluctant to work even under WinXP.
I had to redone the parallel port interface board, as a soldered IC (74125) blew up when I powered the PC after the target board (note to self: power first PC then target). It was quite simple to draw up the schematic and redo the circuit on a perfboard. When I tried the DOS software with my new board all worked OK, I was sure that the schematic and hardware were correctly reverse engineered.
Of the 5 signals coming out of the parallel port, Reset and Output Enable were easy to spot, the others I suspected downloaded the data serially.


Reverse engineering software, on the other hand is far from trivial. I first tried my two channel xscope, but since there are actually three important variables it was difficult to really discover what was the sequence of events. Furthermore there was a start sequence where transitions where at the millisecond range and a program sequence where things happened at the microsecond range.
Then I remembered I had a PICKIT 2, a tool I bought and used about two years ago to do a short Microchip PIC development (and re-learning since when I first learned about PICs the 16C84 was the craze, obsolete today). PICKit 2 was not only relatively cheap, programmed most of the devices, it also included a logic analyzer and a UART for remote debugging, all connected to a USB port. I must give a note of remark to Microchip that this was a stroke of genius, a scope is a an expensive tool, but by adding this functionality to a device-programmer is a well needed help in many non-working projects.
I created a fixed intel hex file with 3 bytes 0x22,0xAA,0x44 than ran the program in a dosbox in windows (and using a parallel port access - Windows bypass - tool) waited for the signals to come out on the other side. Sometimes it worked, others it didn't but I registered the ones that did.

This in the above waveform the real data download is pictured, in this particular case I shifted the data to position 0x0001. From here it was easier to identify the signals, first is the clock, second data and third advance to next memory address.
Then to capture the initial reset sequence I downloaded bigger programs, just to measure the timings of the sequence.

As you can see the waveforms are very detailed and although one cannot read signals above 500Khz chances are 99% of hobby projects will never need more than that.
The code will be published or given as soon as I finish the other source file interpreters (S-Record, Binary and hex) for now only intel-hex works, I will also try to clean up the code and have it hosted in google code or similar as soon as I understand properly how to use it. I'll try to host all the software produced under a single project otherwise it is a waste of google's space.
So that people that still have a similar eprom emulator, the name of the package was "MicroRom Eprom Emulator" and produced or sold by "Squarewave Electronics". Here is a picture of my test bench, the Eprom emulator is the big fat thing on the left, the top LEDs are the data out, the lower green leds the four LSBits, the selector on the top right corner is a BCD selector and finally the yellow led on its right is the reset signal.