Arduino and avr4studio

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

I do not have a scope, this is the working example

#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 DATA_LOW	PORTD &= ~( 1 << PD1 )
#define DATA_HIGH	PORTD |=  ( 1 << PD1 ) 
#define RS_LOW	PORTD &= ~( 1 << PD2 )
#define RS_HIGH	PORTD |=  ( 1 << PD2 ) 
#define CLK_LOW	PORTD &= ~( 1 << PD4 )
#define CLK_HIGH	PORTD |=  ( 1 << PD4 ) 

int main (void)
{
	DDRB |= 1 << PB0; PORTB |=  ( 1 << PB0 );
	DDRB |= 1 << PB5;
	DDRD |= 1 << PD1;
	DDRD |= 1 << PD2;
	DDRD |= 1 << PD4;

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

	//*** setup display

	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

	// Load control word 1 10000001

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

	CLK_LOW;		// Low again
	DATA_HIGH;		// 1 Controlword 1, 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, 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, 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, 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, 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, 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, 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 Serial, 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

	//*** end setup displsy

	//*** begin zebra
	RS_LOW;		// First RS is brought low
	CE_LOW;		// then CE is brought low

	unsigned int i;
  	for (i=1;i<=80;i++)	// data entry, for test write 80 times 00, 01, 10 or 11 total bits 160
	{
		CLK_LOW;	// Low again
		DATA_LOW;	// Next each successive rising CLK edge will shift the data at the DIN pin
		CLK_HIGH;	// Next rising CLK edge

		CLK_LOW;	// Low ready to rise
		DATA_HIGH;	// Next each successive rising CLK edge will shift the data at the DIN pin
		CLK_HIGH;	// Next CLK rising edge

	}

	CE_HIGH;	// When all 160 bits have been loaded CE is brought to logic high

	CLK_LOW; 	// When CLK is next brought low, new data is latched into the dot drivers   

	//*** end zebra, all uneven dots should be off
	return 0;
}

One of your problems is that you are using the Baby Orangutan’s SPI module, but you are not using the pins that correspond with that module. The SPI module uses pins PB3 (MOSI), PB4 (MISO), and PB5 (SCK). I think you are still using the pins that would correspond to USART SPI pins.

- Ben

That is probably true, according the Atmega168 datasheet I need to set the UMSEL for Synchronous USART so SCK will move to PD4, I assume TXEN takes care of PD1, when I try this it won’t build.

UCSR0B = (1<<RXEN0)|(1<<TXEN0); 		// Enable receiver and transmitter.
UCSR0C = (1<<UMSEL0); 			// Synchronous USART
SPCR = (1<<SPE)|(1<<MSTR)|(1<<SPR0)|(1<<CPHA)|(0<<CPOL);
// Enable SPI, Master, set clock rate fck/16, rising edge

error: ‘UMSEL0’ undeclared (first use in this function)

I think you’re still not understanding that the AVR’s hardware SPI module is not the same as the hardware USART. Using the USART for SPI does not involve using the SPI registers, such as SPCR. If you read through section 20 of the datasheet, you’ll see that it makes no reference to the SPI registers. Have you looked at the sample C code in section 20 for initializing the USART and sending data?

As far as your compilation issues go, just because a term is in the datasheet does not mean it is defined by WinAVR. If you find that a definition is missing, you can look through the appropriate included WinAVR header files to see if it is defined under a slightly different name, or you can replace it with the actual value. In your case, the problem is that there are two UMSEL bits:

Bit 7:6 – UMSELn1:0: USART Mode Select

The “n” here is the USART number, which is 0, so I expect there to be two defines you can use: UMSEL01 and UMSEL00. If these don’t work, you can see from the register description that these are bits 7 and 6 of the register, so you can just directly set those bits:

UCSR0C = (1<<6);

However, this brings up another problem. We’re talking here about using the USART in Master SPI mode, which requires both UMSEL bits to be set. You seem to be trying to use the USART in synchronous serial mode, which is different. In synchronous serial mode, you will not get the same behavior as described in section 20 of the datasheet.

By the way, I still think your best bet is to just bitbang the protocol like you already have (though I would generalize it so that you can just call functions to send an arbitrary eight bits).

- Ben

I started this thread with the following question:
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.

The answer is that there are no shortcuts. Writing a smart solution from scratch requires a higher level of background knowledge than I can deliver.

So your advice to focus on 160BlinkLeds is probably the best way to operate. As I am running out of time I will stick to the 7 segment solution I am using at the moment.

This thread ends here.

An amazing 20000 readers visited this post, one of them must have been from Atmel, with Atmel Studio 7 you can import any Arduino sketch and continue to program in Atmel Studio.

I’ve only tried for a few minutes, but my experience is ‘import Arduino’ gets lost for anything more complicated than blink. This is a problem of using things like Arduino (ruins your ability to use professional approaches later). Arduino was made for artist, by artist, it should stay in that field.