Setting up atttiny4313 USART as MSPIM (SPI)

Go To Last Post
27 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Apologies, very new to the AVR and C programming world. I have searched the forum and the web and found similar problems but not resolutions that seem to apply to this newbie mind. My best guess is that there is an include file I'm missing (can't figure out which one), the register names are incorrect in the  datasheet or the sample code is incorrect in the datasheet.

 

A search of the WinAvr directories yields a number USARTx.h files (USART_302, USART_319 etc) but can't figure out which one I might need.

 

Of course, the most likely problem is that I don't know what the heck I'm doing :).

 

This seems like it should be relatively straightforward. Using Winavr for compiling etc.

 

Relevant parts of code, copied pretty much verbatim from the datasheet. Register names do seem to match what's in the register descriptions.

 

#include <avr/io.h>
#include <util/delay.h>



void USART_Init( unsigned int baud )
{
UBRR = 0;
/* Setting the XCK port pin as output, enables master mode. */
XCK_DDR |= (1<<XCK);
/* Set MSPI mode of operation and SPI data mode 0. MSB order */
UCSRC = (1<<UMSEL1)|(1<<UMSEL0)|(0<<UCPHA)|(0<<UCPOL)|(0<<UDORD);
/* Enable receiver and transmitter. */
UCSRB = (1<<RXEN)|(1<<TXEN);
/* Set baud rate. */
/* IMPORTANT: The Baud Rate must be set after the transmitter is enabled
*/
UBRR = baud;
}

Getting the dreaded 

error: 'UBRR' undeclared (first use in this function)
error: 'XCK' undeclared (first use in this function)
error: 'UMSEL1' undeclared (first use in this function)
error: 'UMSEL0' undeclared (first use in this function)
error: 'UCPHA' undeclared (first use in this function)

error: 'UDORD' undeclared (first use in this function)

 

Any help would be appreciated.

 

Thanks

Marc

This topic has a solution.
Last Edited: Tue. Jul 9, 2019 - 11:14 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I strongly advise that you use AS7.0 (or MPLABX when it has improved)

 

Using an up to date IDE will ensure that Compiler tools and header files are up to date.

 

Clicking on iotn4313.h shows relevant spelling:

UBRRH, UBRRL

XCK_BIT

UMSEL0, UMSEL1

UCPHA

UDORD

 

We have no idea which WinAVR version you are using.   But my WinAVR-201000110 iotn4313.h has many errors.

 

David.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thanks David,

Plan is to start using AVR studio. Just trying to limit the number of new things I'm learning all at once. 

 

Do I have to add a separate "include" statement for iot4313.h ? Or does that get brought in when io.h evaluates (?) which chip I'm using ?

 

Regardless I was able to get a clean (ish) compile by adding the following define statements and setting the baud rate using UBBRH and UBBRL instead of UBBR

 

#define XCK PD2
#define XCK_DDR DDRD
#define UMSEL1 7
#define UMSEL0 6
#define UDORD 2
#define UCPHA 1
#define UCPOL 0

I also had to change the init code as it looked like the demo code was trying to set a bit to 0 using an OR stmt.

 

Program doesn't work but a least I got it to compile and now can work on the logic ! 

 

Using the most current version on WinAvr

 

Marc

Last Edited: Tue. Jul 9, 2019 - 10:30 PM
This reply has been marked as the solution. 
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

WinAVR worked pretty well.   But current tools work better.

 

If you have a Windows PC I strongly suggest that you use AS7.0

 

No,  you never include iotn4313.h

You include <avr/io.h> and this performs the necessary include.

 

From memory the Tiny4313 appeared at about the birth of WinAVR-20101101

It looks as if they simply kludged the old iotn2313.h

 

As it happened,  Tiny2313A and Tiny4313 introduced new registers and features not present in the old Tiny2313

Another reason for keeping tools "up to date"

 

David.

Last Edited: Tue. Jul 9, 2019 - 10:45 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thanks. I see what you mean. Off to find a good AS7 tutorial.

 

Marc

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

 

 

Amazing how typing up a question can reveal a bunch of answers :). Keep getting closer. I think I'm stuck for good now.

 

One last shot before I give up and go back to bit banging this. SPI has no real advantage for what i'm trying to do (drive some max7219)'s but figure it's a good thing to try to learn new stuff.  I tried running the bit bang code, substituting in the calls to the USART routine, no dice.

 

In order to keep it dead simple I've just connected a 595 shift register with LED's on the outputs to try to see what is being passed on the TX line.  (TX-->SER, XCK-->SRCLK, PB1-->RCLK)

Outputs don't seem to make sense. I've run 2 different bytes

 

Mode is MSB first so for  0b00000111 I would expect 0b11100000 at the output and for 0b11000000 I would expect 0b00000011

 

Results are as follows

Sending 0b00000111 gives  a very brief flash of 0b00000111 and then stays at 0b00001110

Sending 0b11000000 gives  a very brief flash of 0b11000000 and then stays at 0b10000001

 

It's like the MSB is being moved to the LSB instead of being shifted out and then the shifting is off cycle ?

 

Based on David's recommendation I switched to AS7 which made life infinitely better. Confirmed with the debugger that the MSPIM registers are all being set up correctly per the datasheet. Proper data values been sent to UDR. No way I can find that I can track the contents of the UDR in debug mode, hence the shift register. I must be missing something very basic. Relevant code bits below.

#define CS_HIGH()   PORTB |= (1<<PB1)
#define CS_LOW()    PORTB &= ~(1<<PB1)
#define INIT_PORT() DDRB |=  (1<<PB1)
void USART_Init( unsigned int baud )
{

/* Setting the XCK port pin as output, enables master mode. */
XCK_DDR |= (1<<XCK_BIT);
/* Set MSPI mode of operation and SPI data mode 0. MSB order */
UCSRC |= (1<<UMSEL1)|(1<<UMSEL0);
UCSRC &= ~((1<<UCPHA)|(1<<UCPOL)|(1<<UDORD));

/* Enable receiver and transmitter. */
UCSRB |= (1<<TXEN)|(1<<RXEN);
/* Set baud rate. */
/* IMPORTANT: The Baud Rate must be set after the transmitter is enabled
*/

	UBRRH = (unsigned char)(baud>>8);
	UBRRL = (unsigned char) baud;
}
unsigned char USART_Send(uint8_t data)
{
/* Wait for empty transmit buffer */
while ( !( UCSRA & (1<<UDRE)) );
/* Put data into buffer, sends the data */
UDR = data;
}
int main(void)
{
    INIT_PORT();
    USART_Init(1);
	while(1)
	{
		
		CS_LOW();
		USART_Send(0b11000000);
		while ( !( UCSRA & (1<<TXC)) ); //make sure transmission complete
		CS_HIGH(); 
		_delay_ms(1000); 
		
	}
}

 

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Marc_hache wrote:
No way I can find that I can track the contents of the UDR in debug mode,
And you never will. UDR is really two registers at one address. A write only transmit register and a read only receive register. The debugger can never show you what you most recently wrote to it - only what was received.

 

The strongest tool when working with SPI is not actually the debugger for once but a digiscope or logic analyser monitoring the clock and data pins.

Last Edited: Fri. Jul 12, 2019 - 09:32 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Your code "looks" reasonably ok.

I suggest that you use = instead of |= when initialising peripheral registers.

Obviously you use |= for individual Port bits.

 

The other advice is:  BEAUTIFY THE CODE.    Most IDEs let you format with a single keypress.

 

The only gotcha.   You have used TXC incorrectly.   TXC is only cleared by writing 1.    It is easier to use RXC and read UDR.

 

As Cliff said.   A Logic Analyser is the easiest way to view the actual shift data.   And most importantly,   whether CS is released before the data has finished shifting.

 

Yes.   A MAX7219 does all the work.   You do not need speed or efficiency.   So bit-bang is fine.

However an SPI graphics chip might require 460800 SPI bytes just to clear the screen.   USART_MSPI is the best way to handle high traffic.

 

David.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thanks. Just learning C. When I was in school we did our programming on punch cards (I'm not kidding)

 

Above is a combination of cut and paste from the datasheet and my own just to see if i could get it working.

 

So I went back and read the DS on TXC and it's a little confusing:

 

This flag bit is set when the entire frame in the Transmit Shift Register has been shifted out and
there are no new data currently present in the transmit buffer (UDR). The TXC Flag bit is automatically
cleared when a transmit complete interrupt is executed, or it can be cleared by writing

a one to its bit location

So to me when it says "flag bit is set" I assumed that it meant a 1 would be present. This seems to concur with debug mode, after a series of "steps" the TXC bit goes high. However, as you point out, the last  line says it can be cleared by writing a 1 to it's location. Which means I should check for 0?

 

I just tried that and oddly get the exact same results. Weird.

 

Would love to have a logic analyzer but the blinky lights off the shift register will have to do for now :)

 

Marc

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Normally when transmitting you use UDRE not TXC to know when its ready to take another byte. TXC exists almost solely for half-duplex links - where you have to switch direction to be ready to receive - but you cannot do that until you know that the very last bit of the last byte you sent hs gone off down the line. TXC tells you this.

 

Presumably your intention here:

		while ( !( UCSRA & (1<<TXC)) ); //make sure transmission complete
		CS_HIGH(); 

was to do just that? To wait until the byte had finished transfer then change some "CS".  I'm not sure what David meant by:

david.prentice wrote:
You have used TXC incorrectly.   TXC is only cleared by writing 1.
As far as I can see you are only reading it - not trying to clear it?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Yes, transmit only. Sorry, I should have pulled the RXEN enable out of the code, was trying a bunch of stuff to see if anything helped.

 

I am checking to ensure UDRE is empty (while ( !( UCSRA & (1<<UDRE)) );)  before loading another byte. In fact, that was all I was doing at first and the results were even weirder (flipping between two different outputs on each send)  I figured since the processor is running much faster than the serial i/o that maybe the data was getting latched out to the 595 before all the bits were shifted out of the UDR attached shift register, hence checking TXC before setting CS_HIGH().

 

That at least stabilized the output, it's still wrong, but stable.

 

Clearly some sort of timing issue going on, just cannot figure it out. I wonder if the following gives a hint ? You can double buffer so I wondering if somehow the next byte is getting loaded and somehow partially sent in to the UDR shit register ? Can't see how but I'm running out of ideas.

 

A frame starts with the least or most significant data bit. Then the next data bits, up to a total of
eight, are succeeding, ending with the most or least significant bit accordingly. When a complete
frame is transmitted, a new frame can directly follow it, or the communication line can be set to
an idle (high) state.

 

 

Thanks again. I'm just too stubborn to give up.

 

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Marc_hache wrote:
Thanks. Just learning C. When I was in school we did our programming on punch cards (I'm not kidding)

So have many of us freaks!

 

No excuse not to have a logic analyzer any more!

https://www.ebay.com/itm/USB-Log...

 

Well worth having and learning how to use it!

 

Jim

 

Click Link: Get Free Stock: Retire early! PM for strategy

share.robinhood.com/jamesc3274

 

 

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

 

No excuse not to have a logic analyzer any more!

https://www.ebay.com/itm/USB-Log...

 

 

I was wondering if those cheap ones would work. Where's my credit card....

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

The software you want to go with it is "sigrok"

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

You have to study the TXC very carefully.    It is not easy to understand.    Hey-ho.  It is not a "busy" flag.

 

Yes,  a cheap Saleae clone is very useful.   

I use the Saleae software with a clone (or genuine Saleae).    It work very well.

If you feel guilty,   use the Sigrok software.    It does not work quite as well.

 

David.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

david.prentice wrote:
If you feel guilty,
One probably should - the extra you pay for an Saleae presumably isn't about the hardware cost but the amortisation of their software development.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 1

I own a Saleae.    Saleae did not design the hardware.    They simply put the example from the original Cypress evaluation kit into a sexy case.

 

However,   Saleae developed the software that makes it pleasant to use.    And it works with clones as well as the original genuine Saleae.

 

I believe that current Saleae products have hardware designed by Saleae.    And are more sophisticated than the original Logic-8.

All the same.   I am happy to use the original Logic-8.    It is fast enough for AVR work.

 

David.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0
Last Edited: Fri. Jul 12, 2019 - 04:17 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Yes,  that is a regular clone.

the price is about right for a local Canadian shop.   Swift delivery.

obviously a Chinese shop is a lot cheaper but you have to wait for 8-48 days before it arrives.

 

David.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thanks. I guess it's back to bit banging for now. The boys are anxious to have the poker clock ready for our next game. Will revisit once I get the analyzer and figure out how to use it.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Not sure what I'm missing. DS seems pretty clear (other than what they mean by set and not set). Flag is set when the entire frame in the transmit shift register has been shifted out and no new data in UDR. Since I'm not loading any more data in UDR or going CS_HIGH() until TXC is set so there should be no overlap. I don\t suppose there is a way to  see the contents of the shift register in Debug ?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Marc_hache wrote:
I don\t suppose there is a way to  see the contents of the shift register in Debug ?

No, because there are two registers at one address, one is write only for TXBuffer, while the other is read only, for RXBuffer.

 

Jim

 

Click Link: Get Free Stock: Retire early! PM for strategy

share.robinhood.com/jamesc3274

 

 

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Further testing, changed the UBBR to 0 instead of 1....now get an alternating pattern on the LED's. I've seen other code on the net that looks pretty much identical. I feel I must be missing something .....

 

The other nice thing is if I can get this to work is with double buffering I can send the address bit and data bits at the same time to the MAX. Again, not a big deal but kinda elegant.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Marc_hache wrote:
Further testing, changed the UBBR to 0 instead of 1

Have you tried a much slower rate, perhaps your shift register is not keeping up with the data rate....  

I'm assuming your crude logic analyzer is on a bread board. 

 

Jim

 

Click Link: Get Free Stock: Retire early! PM for strategy

share.robinhood.com/jamesc3274

 

 

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hadn't thought of that...tried it at around 2400 bps. No dice.  Although now output is same as byte sent: 0b00000111

 

Argh. Pulling out what little hair I have left.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

In fact, looking at the code for this application note, I can't see any difference (written for a different chip so pins are different but logic sequence is exactly the same as far as I can tell).

 

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

You can generate a vast range of SPI clock speeds with the USART.   e.g. from F_CPU/2 (with UBRR=0) down to a few 100Hz.

 

Most external hardware chips can cope with 8MHz SPI.

If it is an MCU emulating SPI Slave the speed will be much worse.    A 16MHz AVR struggles with servicing SPI interrupts or even continuous clocks.

 

David.