Firmware

At a Glance

Using ohloh's command line utility 'ohcount', I have the following information about the code that forms the firmware of Pedro.

Language Files Code Comment Comment % Blank Total
C 9 609 54 8.1% 250 913
make 1 30 3 9.1% 15 48
Total 10 639 57 8.6% 265 961

The source can be viewed and downloaded from my github.

The Journey

Learning how to program micro controllers took a while, first I had to get my head around bit manipulation and bitwise operators, but that didn't take long and I was soon making LEDs blink. Every now and then I would set myself a challenge, at first these were fairly simple but they became more advanced. Also, they always had something to do with the final product. So hopefully when it came to putting everything together, I could just collect the various pieces and just glue them. Examples of the kind of work I was doing can be seen in the AVR Code section.

The internet helped me greatly to learn, especially seeing other's examples. The excellent AVR Freaks forum helped with a lot of problems and also included really informative tutorials, such as this one.

By mid April I had the firmware to receive instructions via serial and to move the motors. At this point, I was drawing squares. The holy grail for the plotter was a perfect circle, and this just wasn't happening. Either the plotter would start and just stop randomly, or it would try and draw a line forever, or something else unexpected and random. And it is like this that it stayed for quite some time. I did several rewrites with no success. Still unexpected behaviour was happening.

On the Royal Wedding weekend, my uncle, Gavin, and his family came to stay with my mother and I. I had told him about this project a while ago. So, when he came I showed him what I had done, and what was going on. So, his first response was: "Well, show us your code then", so being a little intimidated, I showed him what I had done. Gavin game me a few pointers as to how I should do things so I made some major changes at this point. I changed the structure of the data within the micro controller (very nice structs & unions) and also made a unified way sending the data, with start and end bytes and command identifiers. I also implemented a circular buffer to hold the data, which worked quite nicely. Though this made everything look nice it did not fix my problem of the lost circle.

The problem was getting the data from one end to the other. It was possible that while the motors were turning some sort of interference was causing the serial data to be corrupted, there were many other possibilities. Gavin's idea was to send a chunk of data off, to complete all of it, then to stop and receive the next load. This however, did not work.

After a few days of feeling like giving up, I had an idea. I made a small change in the code which resulted in a large change in output, the idea was to go into an infinite loop until you receive a valid instruction. Before, it would receive a load of instructions and go through them. When it finished that instruction it would send a byte back requesting the next one. So, in this method bytes are being sent and received all the time. And while they are doing this, the motors are stopped. But at a fast baud rate this is unnoticeable.

So, the main loop is very simple:


for(;;) {
//wait here until a valid command is found...
	while (!decodeNext()) {}
				
	if (executeCommands()) { 
		//got next command to process
		
		switch (currentCommand.commandCode) {
			case COMMAND_CODE_PEN_UP:
				movePenUp();
				break;
			case COMMAND_CODE_PEN_DOWN:
				movePenDown();
				break;
			case COMMAND_CODE_MOVE_REL:
				moveRel(currentCommand.command.moveRel.x, currentCommand.command.moveRel.y);
				break;
			case COMMAND_CODE_MOVE_ABS:
				moveAbs(currentCommand.command.moveAbs.x, currentCommand.command.moveAbs.y);
				break;
			case COMMAND_CODE_CHANGE_STEP_DELAY:
				changeStepDelay(currentCommand.command.changeDelay.time);
				break;
				
				
			default:
				break;
		}
		
		housekeep();
			
	}
}

This solved almost all the problems. Sometimes, the plotter would just stop drawing. So it was time to get out my debugging technique: send numbers back over serial. An example of output to debug looks a little like this:

sent start
readBytes = 99 7 41 99 7 42 99 7 43 
readBytes = 99 7 44 99 7 45 99 7 46 99 7 47 99 7 48 99 7 49 99 7 50 99 7 51 99 7 52 99 7 
readBytes = 53 99 7 54 99 7 55 99 7 56 99 7 57 57 99 7 58 99 7 59 99 7 60 6 32 32 
readBytes = 32 
readBytes = 32 32 32 32 32 
readBytes = 32 
readBytes = 32 
readBytes = 32 
readBytes = 32 
readBytes = 32 
readBytes = 32 
readBytes = 32 213 

Not the easiest to figure out what's going.

It turned out that the solution to 99% of the problem was to check if the sent command was valid, this is done by just checking the start and stop bytes as well as checking the command length. If the command is not valid, then send a special character which upon being read decrements the counter on the Sybil side which then repeat the last command. This seemed to solve it.