Sep 242011
 
I2C fun

I realized quickly that the MultiAVR library is only the core Arduino library. What is missing are the non-core ones, like the I²C library (AKA TWI or “Wire”). Expecting a serious re-write, I was pleasantly surprised to see that I had to make exactly one change:

*** /usr/share/arduino/libraries/Wire/utility/twi.c     2011-01-10 14:28:07.000000000 +0900
--- /home/harald/workspace/BlinkSanguino/utility/twi.c  2011-09-24 22:38:53.283676108 +0900
***************
*** 69,74 ****
--- 69,77 ----
      // as per note from atmega8 manual pg167
      sbi(PORTC, 4);
      sbi(PORTC, 5);
+   #elif defined(__AVR_ATmega644P__) || defined(__AVR_ATmega1284P__)
+     sbi(PORTC, 0);
+     sbi(PORTC, 1);
    #else
      // activate internal pull-ups for twi
      // as per note from atmega128 manual pg204

and that was it.

In one day I was able to talk to:

  1. the LCD (16×2 characters)
  2. an PCF8574A (8 bit I/O)
  3. an PCF8583 (RTC)
  4. an MCP23017 (16 bit I/O)
The last one has a strange behaviour: Port A and B seem to be swapped.

 

Sep 232011
 
Upgraded Arduino

Sanguino is a project which needed a slightly more powerful CPU, so they made Arduino libraries work on the ATmegaxx4 series work. It’s popular as it has slightly more of everything: FLASH, RAM, EEPROM, I/O pins and UARTs. Unfortunately that was when Arduino was at release 18. Current is 22. I could not make this even compile release 18 under Eclipse/avr-gcc 4.3.5.

Luckily someone was not too happy about Arduino only supporting their CPUs (ATmega8/168/328 and ATmega1280 and 2560) either. AVR has very similar CPUs with slightly different I/O configuration, but they are all pretty compatible. So they adopted the Arduino core libraries to run on pretty much any AVR CPU which looks sensible, including the ATmegaxx4 series.

Those libraries did not compile out-of-the box either, but minor modifications concerning the definition of port_to_mode_PGM and related fixed this:

-const uint16_t PROGMEM port_to_mode_PGM[] =
+volatile uint8_t * PROGMEM port_to_mode_PGM[] =
-const uint16_t PROGMEM port_to_output_PGM[] =
+volatile uint8_t * PROGMEM port_to_output_PGM[] =
-const uint16_t PROGMEM port_to_input_PGM[] =
+volatile uint8_t * PROGMEM port_to_input_PGM[] =
and in pins_arduino.h:
-extern const uint16_t PROGMEM port_to_mode_PGM[];
-extern const uint16_t PROGMEM port_to_input_PGM[];
-extern const uint16_t PROGMEM port_to_output_PGM[];
+extern volatile uint8_t * PROGMEM port_to_mode_PGM[];
+extern volatile uint8_t * PROGMEM port_to_input_PGM[];
+extern volatile uint8_t * PROGMEM port_to_output_PGM[];

Compiling the traditional blink program worked as expected.

For reference and for all those who want to use Eclipse, Arduino libraries and a ATmega644P resp. ATmega1284P, here the archives of the Eclipse projects: MultiAVR20.zip and BlinkSanguino.zip.



 

Sep 192011
 
Programming AVRs

Programming an AVR microcontroller can be done by many ways. If you have an Arduino bootloader like this, it can be done via serial interface. If you use the one and only serial interface though, that’s not the best option.

One method is to use an existing Arduino, which is neat if you have one or want to use one dedicated as programmer.  Or you could get a dedicated programmer or something more generic. Or an FT245R. Which I happen to have flying around.

The instructions are simple to follow and worked out-of-the-box as long as the tested version of AVRDUDE and libftdi is used.

I installed this special version into /usr/local. Here some example invocations:

  • Setting fuses (default frequency of an 644P is 1MHz, so you must use -B 1 to slow the programming down):
    sudo avrdude-ftdi -v -p m644p -c ft245r -P ft0 -B 1 -U lfuse:w:0xE2:m -U hfuse:w:0x99:m -U efuse:w:0xFD:m
  • Reading all 64KB FLASH from the 644P (takes 13s):
    sudo avrdude-ftdi -v -p m644p -c ft245r -P ft0 -U flash:r:/tmp/644flash.hex:i

Small update: /etc/avrdude.conf must contain this:

programmer
  id    = "ftdi";
  desc  = "SparkFun FTDI Basic Breakout";
  type  = ft245r;
  miso  = 1;  # CB0
  sck   = 0;  # CB1
  mosi  = 2;  # CB2
  reset = 4;  # CB4
;