Arduino and avr4studio

I have been working with AVR4Studio for my projects and my software performs really well. For display I use a 7 segment LED display. This requires a lot of pins and has a limited number of characters I can use.

The Avago 2904 DIP displays are serial and have 4 digits on a 5x7 dot matrix, I want to use that in combination with a Baby-O. The only example I could find is on Arduino, pin mapping is available in the pololu resources. The example is: http://www.arduino.cc/playground/Main/LedDisplay

I need to send a name or a number to the display, is there a smart way to migrate this to AVR4Studio as I do not want to rewrite my software in Arduino.

Hello.

Unfortunately, I don’t have any good solution for porting the code. I think you would likely need to go through line by line and replace the Arduino library function calls with equivalents that make use of the Pololu AVR library. If you want to try this, I can give you some help if you get stuck.

- Ben

I just replaced my laptop (Vista to W7) and re installed the AVR4Studio by installing the bundle you prepared, I only had to re-install the driver for my AVRISP mkii programmer and all is ok now. That saved me a lot of time.

Then I installed Arduino and found out that I could not reproduce your example because my pololu programmer was outdated. A new one together with an extra Baby-O is on its way so this should be solved when that arrives. I will start with reproducing your demo blink LED.

Next step is to install the Avago matrix display demo on Arduino to see if I can make that work.

From this point on I will start working on migrating the software, the project I am working at allows you to store a value in the eeprom memory by using an acceleration sensor. Pushing a button brings you into the setup menu, the parameter is shown one second, then the value, tilting to the left reduces the numer, to the right increases the number. Keeping the sensor level for 3 seconds writes it to eeprom memory and then it resets the AVR. The program starts when the button is pushed briefly and counts the number set in the memory. This functionality allows me to set parameters in the software without bringing my laptop. I’ll update this post with my progress.

That sounds interesting. I’m interested to hear how it goes, and I’d love to see the code if you do get the Arduino library for the matrix display ported.

- Ben

I am waiting to receive the pololu programmer so I can duplicate the example on your website to see the Baby-O being programmed with Arduino blink LED.

For connecting the Avago 2904 display I will first install the example from the arduino post on Arduino and will use the following pin definitions: Baby-O, Arduino
Data in, DDD1, pin 1
RS, DDD2, pin 2
CLK, DDD4, pin 4
EN, DDD0, pin 0
Reset, DDB0, pin 8

As my boards are powered from an RC ESC at 5V I can use M1A and M1B to power the display, all display connections can then be found on one side of the Baby-O.

Here is the datasheet, that will keep you busy intil the mail arrives.

Question: In de Arduino example a function Serial.begin(9600); is called. Do you know whether this can be messed up by the Baby-O which is working on 20 Mhz and most of the Arduino stuff is at 16 Mhz?
datasheet HCMS29xx.pdf (197 KB)

It seems I amnot the only one trying to do these kind of things.

I found some more information at www.smileymicros.com blog in the article Moving Beyond Arduino, scroll down to Converting the Arduino Blink Example to AVRStudio and then you find a cookbook. This may be a starting point.

I received the controller yesterday, today I finished Arduino blink led with the programmer successfully.

The Arduino example LedDisplay print works fine too, I proved my wiring is correct and the programmer works.

Now turn to AVR4Studio, I will not include the Arduino files into my project as I expect that this will bring too much overhead and conflicts with the rest of my program.

Next on my list is to learn how to configure and initialise an SPI interface. Feel free to come up with some bright ideas

The Pololu AVR library has functions for doing SPI. You might want to start by looking at those. Note, however, that the AVR uses its SPI lines for programming, and having your matrix display connected to these lines could interfere with programming or cause problems with the display. Instead, you might consider using the ATmega328’s USART in synchronous mode. The ATmega328 datasheet has information about how to do this, but please feel free to ask if you find the datasheet confusing.

By the way, I apologize for not responding to your previous post. The baud rate calculations of the Arduino’s Serial.begin() function could use the F_CPU parameter, which would let it correctly account for the different clock speed on the Baby Orangutan. I don’t know for sure if this is the case, though.

- Ben

Yes the data sheet is confusing, every time I open that document it confuses me more and after a little while it starts making sense. Hopefully it will work that way this time.

I want to connect the display to the B and D side of the Baby-O If we can use the PB2 in stead of the PB3 that would make the connections a lot easier.

PortB 0,2,4,5 and PortD 0,1,2,4 are available. PB1 is needed for pwm out and PD7 is used for a button.

After a very cursory glance at the ATmega328 datasheet (see section 20: USART in SPI Mode), it seems like you can use USART0 in SPI master mode, with PD0/RX as master/Baby Orangutan input (MISO), PD1/TX as master/Baby Orangutan output (MOSI), and PD4/XCK as the clock (SCK). I think you should try using the USART rather than the hardware SPI lines.

I agree that the AVR datasheets are not well written, but you eventually learn to read them if you look at them enough. As I said, if you need some help understanding what the datasheet is saying, don’t hesitate to ask. I am also happy to look over reasonably short code snippets, such as those that set up the USART registers. If you have an oscilloscope handy, that could prove very helpful in making sure your SPI code is doing what you think it is (fortunately, you have your Arduino program to use as a known-good comparison point for your signals).

- Ben

Section 18.7 AVR USART MSPIM vs. AVR SPI

What do we do with the RS pin?
Reset of the display can be omitted I think as we can print(" ")

Data in to PD1/TX as master/Baby Orangutan output (MOSI)
RS, PD2 ?
CLK to PD4/XCK as the clock (SCK) to CLK
EN to PD0/RX as master/Baby Orangutan input (MISO)
Reset, PB0

You can connect the RS and CE pins to digital I/O lines of your choosing (however, you would not connect CE to the USART’s RX/MISO pin). You will have to toggle these at the appropriate times in software as the hardware UART won’t do this for you.\

Looking over your display’s datasheet a bit more carefully, it seems like the easiest solution might be to just do all of the control signals in software rather than trying to use a hardware SPI module. The control signals seem quite simple, especially since you don’t have to worry about reading any inputs from the display. If I were in your position, I would write a basic library for the display that just uses digital I/O functions from the Pololu AVR library. You could even make the pin assignments parameters so the library would support arbitrary connections.

- Ben

ok, we will settle for the following wiring.

PB0 to Reset
PB5 to EN
PD0/RX not connected
PD1/TX as master/Baby Orangutan output (MOSI) to Data IN
PD2 to RS
PD4/XCK as the clock (SCK) to CLK

I wrote a test program writing controlword 0 and 1 to the display and then 80 times 2 bits to the display. So I can play now with the even dots on and oneven dots off or any other combination. This works so I understand the sequence to load the register of the display.

Next step is the software serial, I’ll do some reading and get back to you

Great, I’m glad to hear you’re making progress.

Software serial is quite trivial if you’re just sending data as it just involves toggling I/O lines and fixed delays. In C-like pseudo-code it would be something like:

void sendByte(uint8 byte)
{
  for (uint8 i = 0; i < 8; i++)
  {
    clockPinLow();
    delay();
    if (byte & 1)
      dataPinHigh();
    else
      dataPinLow();
    byte <<= 1;
    clockPinHigh();
    delay();
  }
}

You’d need to make sure you get the delays right based on the timing requirements in the display’s datasheet, and you’d need to make sure that you get the clock polarity right (my example above sets the data up to be clocked in by the rising edge of the clock signal). You’ll also need to do the appropriate things with the CE and RS pins (as specified by the datasheet; once again, see the general timing diagram).

- Ben

I did expect delays to be necessary but without them it works. In my application I show every value for at east 1 second so I don’t think there is an issue. I literally followed the text in the display datasheet. Here is how I did it.

[code]RS_HIGH; // First RS is brought to logic high
CE_LOW; // and then CE is brought to logic low

// ******************************* Load control word0 01001111

CLK_LOW; // Low again
DATA_LOW; // 0 Controlword 0, next each successive rising CLK edge will shift the data at the DIN pin
CLK_HIGH; // Next rising CLK edge

CLK_LOW; // Low again
DATA_HIGH; // 1 normal operation, next each successive rising CLK edge will shift the data at the DIN pin
CLK_HIGH; // Next rising CLK edge

CLK_LOW; // Low again
DATA_LOW; // 0 brightness, next each successive rising CLK edge will shift the data at the DIN pin
CLK_HIGH; // Next rising CLK edge

CLK_LOW; // Low again
DATA_LOW; // 0 brightness, next each successive rising CLK edge will shift the data at the DIN pin
CLK_HIGH; // Next rising CLK edge

CLK_LOW; // Low again
DATA_HIGH; // 1 pwm, next each successive rising CLK edge will shift the data at the DIN pin
CLK_HIGH; // Next rising CLK edge

CLK_LOW; // Low again
DATA_HIGH; // 1 pwm, next each successive rising CLK edge will shift the data at the DIN pin
CLK_HIGH; // Next rising CLK edge

CLK_LOW; // Low again
DATA_HIGH; // 1 pwm, next each successive rising CLK edge will shift the data at the DIN pin
CLK_HIGH; // Next rising CLK edge

CLK_LOW; // Low again
DATA_HIGH; // 1 pwm, next each successive rising CLK edge will shift the data at the DIN pin
CLK_HIGH; // Next rising CLK edge

CE_HIGH; // when 8 bits have been loaded the CE line is brought to high
CLK_LOW; // when CLK goes to logic low, new dat is copied
[/code]

I just reviewed the datasheet more carefully and noticed that all of the timing characteristics are less than 100 ns, so you shouldn’t have to worry about adding delays when using a 20 MHz AVR (each instruction will take at least 50 ns).

I’m glad to hear you got it working, and thank you for sharing a portion of your code. If you end up writing a more complete library for this display, I’d love to see it.

- Ben

Last year I mad an echo code for the ATmega168 to work together with the Pololu serial transmitter. This worked great, we do not need the 9600 baudrate for the display but I assume it does no harm.
I defined the uart as follows:

#define BaudRate 9600UL 
UCSR0B = (1<<RXEN0)|(1<<TXEN0); 
UCSR0C = (1<<UCSZ01)|(1<<UCSZ00);
uint16_t ubrr = (uint16_t) ((uint32_t)F_CPU/(16*BaudRate)-1); 
UBRR0H = (uint8_t)(ubrr >> 8); 
UBRR0L = (uint8_t)(ubrr); 

With this code I echo the value transmitted to the ATmega168

while ( !(UCSR0A & (1<<RXC0)) ); //Receive
buffer = UDR0; 
while ( !( UCSR0A & (1<<UDRE0)) ); //Send
UDR0 = buffer; 

0 build errors in the above programm
With the above I assumed all that I needed to add was to enable the SCK with:

XCKn_DDR |= (1<<XCKn); // found in the ATmega168 datasheet

Then I get …error: ‘XCKn_DDR’ undeclared (first use in this function) I don’t undertand why

I am working with the ATmega168 now untill it works, I need the 328 in another project now.

The terminology used in the datasheet is generic and doesn’t necessarily have WinAVR defines. One easy solution is to use the datasheet to determine which ATmega168 pin is XCK and specifically configure that pin as an output. You could also see if:

XCK0_DDR |= 1 << XCK0;

Note that I expect you to have to make several changes to the USART registers in order to get the XCK pin to do what I think you want it to do. (I expect getting the USART to work in sychronous mode will require more than just making the clock pin an output.)

- Ben

I carefully read the datasheet and came up with the following solution, it follows the same steps as my step by step approach. No build errors anymore althoug I still don’t get it why it does not work.

#define F_CPU 20000000UL	// Baby Orangutan frequency (20MHz)
#include <avr/io.h>

#define CE_LOW	PORTB &= ~( 1 << PB5 )	// Define display port status
#define CE_HIGH	PORTB |=  ( 1 << PB5 )  
#define RS_LOW	PORTD &= ~( 1 << PD2 )
#define RS_HIGH	PORTD |=  ( 1 << PD2 )

int main (void)
{
	DDRB |= 1 << PB0; PORTB |=  ( 1 << PB0 );	// Reset stays high and is not used
	DDRB |= 1 << PB5;
	DDRD |= 1 << PD1;				// Set PD1, SPI as output
	DDRD |= 1 << PD2;
	DDRD |= 1 << PD4; 				// Set PD4, SCK as output

	SPCR = (1<<SPE)|(1<<MSTR)|(1<<SPR0)|(1<<CPHA);
		// Enable SPI, Master, set clock rate fck/16, rising edge mode 1
	SPSR = (1<<SPIF);	// Set interrupt flag

	RS_LOW;				// Start value
	CE_HIGH;				// Start value

	RS_HIGH;				// First RS is brought to logic high
	CE_LOW;				// and then CE is brought to logic low

	SPDR = 0x4F; 				// 0x4F = 01001111 control word 0
	while(!(SPSR & (1<<SPIF)));	           // Wait for transmission complete

	CE_HIGH;		// when 8 bits have been loaded the CE line is brought to high

	RS_HIGH;		// First RS is brought to logic high
	CE_LOW;		// and then CE is brought to logic low

	SPDR = 0x81; 		            // 0x81 =  10000001 control word 1
	while(!(SPSR & (1<<SPIF)));	// Wait for transmission complete

	CE_HIGH;		// when 8 bits have been loaded the CE line is brought to high

	RS_LOW;		// First RS is brought low
	CE_LOW;		// then CE is brought low

	unsigned int i;
  	for (i=1;i<=20;i++)	// data entry, for test write 20 times 8 total bits 160
	{
	SPDR = 0x55; 		// try different patterns
	while(!(SPSR & (1<<SPIF)));	// Wait for transmission complete

				// 0x00 00000000
				// 0x55 01010101
				// 0xaa 10101010
				// 0xff 11111111
	}
	CE_HIGH;	// When all 160 bits have been loaded CE is brought to logic high
	return 0;
}

Can you compare your working version to this version using an oscilloscope to see what is different?

- Ben