Current Updates

This blog is an informal, and sometimes intermittent, record of my MEng project.

Friday, 3 February 2012

Getting Things Right

Yesterday I had some issues making the AVR work properly.  I couldn't get any output to appear on the LEDs I'd connected - I'd already found that the Data Direction Register (DDR) wasn't set correctly, and modified the code, but there was still some problem.

Checking the voltage at the PORTB pins showed that they were floating, i.e. set up as inputs.  The voltage at the !RESET pin was high, so no problems there.

It occurred to me that perhaps the fuse bits were set incorrectly, though I assumed, for instance, that a lack of clock would have made the device unprogrammable.

I checked the fuse bits using AVRdude, and verified they were as per the datasheet's specified defaults.  The next tools to be examined were the compiler, linker and IDE.  It's quite simple to set up an AVR project in Code::Blocks, but somehow I'd not done it correctly.  Perhaps I'd done it to try it out before I'd selected the particular microcontroller I was going to use.  In any case, I had the toolchain set up to build for an ATmega128, which is not an ATmega1284P.  I changed the setup to use the correct unit, and rebuilt the project.

After programming the device, the output was still not correct, though the LEDs were doing something.  After modifying the loop delay in the LED flasher, the system worked alright.  I eventually discovered the _delay_ms function, and used it instead of a nop loop (with F_CPU set to 1000000 to match the operating frequency).


After examining the listings produced by the toolchain, I found that the release version strips out a lot of unused code, and inlines some functions.  This is very useful indeed, and the listings seem to be quite helpful.  The debug version is easy to navigate, and is interspersed with lines of the source.  The release version is harder to navigate, but the debug version provides a useful reference to match up with.

I had a poke around in some of the files for avr-gcc, and found floating point math, and setjmp, amongst others.  I wondered if the latter could be useful in performing some form of multitasking, though later found out that many implementations assume that the saved environment remains on the stack, i.e. longjmp allows 'multiple returns', but won't restore a complete environment like a proper volatile environment handler.


I migrated the port test function into a separate module, and changed the code to allow testing on all ports.  To make testing easier, I built a small LED indicator module which plugs into breadboard, with a flying ground lead.
Everyone should have one of these!

I checked all of the AVR ports using this module, and found all of them to be working, apart from the middle 4 pins on PORTC - I checked the datasheet and found that these are used for the JTAG interface, which is enabled by default.

Having tested the ports, I wrote code to operate the PWM unit on Timer/Counter 2 (which is an 8-bit unit - plenty for controlling motors).  This unit is on PORTD, which is also used for the UART, and keeps other ports free for the moment.

I coded up a test sequence, to drive both motors forwards, backwards, and then apply a brake.  Each command is accompanied by a rising then falling ramp, in phase-correct PWM mode.  This mode was chosen as the datasheet advises that it is more suited to motor control, and provides a high enough operating frequency.  I understand the difference in the waveforms, but I don't as yet know why one is better for motor control.

Initially, the PWM test didn't work, because I hadn't set the DDR latch in my code - this was a simple fix and now I know that any output from a pin typically needs the DDR bit to be set.

I tested the program using the LED board, then wired up the motor controller and verified its operation properly.

No comments:

Post a Comment

Comments are moderated. Sometimes it might take me a long time to get round to it, so please be patient.