Attiny4313 problem

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

Hello to all! My name is Luca and this is my first post on AVR Freaks!
I have a problem with my attiny4313. My objective is to acquire a signal with a certain frequency and send this value to my pc. For do this, i have programmed the follows periphericals of my attiny:

    External interrupt INT0: I use this to count the pulse signal of the sensor. Timer Counter 0 in CTC mode: I use this to take with certain frequency the count pulse value.
    Usart: To sent the count pulse value to my pc.

This is my code:

#include 
#include 



void initIO(void);
void initUSART(void);
void initExtInterrupt(void);
void initTimerCounter0(void);


int main(void)
{
	initIO();
	initUSART();
	initExtInterrupt();
	initTimerCounter0();
	
	sei();
	
    while(1){
		// turning the thumbs.. 
	}
}

void initIO(void){
	DDRD &= ~(1<<2); // pin D.2 (INT0) it's input
	PORTD |=(1<<2);  // pull-up on D.2 
	
	DDRB |=(1<<0) |(1<<1);
	
}

void initExtInterrupt(void){
	GIMSK |= (1<<INT0);// enable INT0
	MCUCR |= (1<<ISC01) | (1<<ISC00) ; // interrupt on rising edge of input signals
}

void initTimerCounter0(void){
	TIMSK |= (1<<OCIE0A);// enable timer-counter0 interrupt                           
	TCNT0 = 0;
	OCR0A = 194;// 20.03 Hz @ 8/1024 MHz
	TCCR0A |= (1<<WGM01);// timer-counter0 in CTC mode
	TCCR0B |= (1<<CS02) | (1<<CS00);// start timer-counter0 @ FCPU/1024
}

void initUSART(void){
	UCSRB |= (1<<RXCIE) | (1<<UDRIE) | (1<<RXEN) | (1<<TXEN); //enable tx, rx and their interrupts
	UCSRC |= (1<<UCSZ1) | (1<<UCSZ0);// USART setting
	UBRRL = 51;//baud rate @ 9.6K ^ @8Mhz                                          
}


ISR(INT0_vect){// update impulse counter
	PORTB ^= (1<<0);
}

ISR(TIMER0_COMPA_vect){// take the value
	PORTB ^= (1<<1);
}

ISR(USART_UDRE_vect){// Tx a byte
...
}

ISR(USART_RX_vect){// Rx a byte
...
}

This code doesn't work. I used the leds of the my stk500 to verify the program. In this case the led of the impulse counter routine (led 0) blinks, while the led of the timer counter doesn't blinks.
Instead, if I comment the line of code where I go to initialize the device USART:

	initIO();
	//initUSART();
	initExtInterrupt();
	initTimerCounter0();

then both leds blink.
I tested separately each part of the code, and they alone working. but when put together the various pieces of code, they do not work.

There are some problem of compatibility with these device? How i can resolve this problem?

Thank to all.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0
ISR(USART_UDRE_vect){// Tx a byte
...
}

ISR(USART_RX_vect){// Rx a byte
...
} 

Are you sure that these vector names are correct? The datasheet refers to USART0, not USART.

Regards,
Steve A.

The Board helps those that help themselves.

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

Hello Koshchi! Thank so much for the reply!
You're right, but my compiler I have never reported this error

indeed, in my avr studio, the program paints me the key words "USART0_UDRE_vect" and "USART0_RX_vect" but compiles the same, while if I use the keywords "USART_UDRE_vect" and "USART_RX_vect" the program color this word of Magenda and the compiler gives me no errors.
I have read that the original file "iotn4313" has errors, so I upgraded it. Now my avr studio color these keywords and I have no errors by the the compiler.

In any case, I not solve my problem. It 'possible that the attiny4313, has some compatibility problem when using at the same time the time-counter0 and the device USART? I hope it is so, but it is the only thing that comes to mind. I tested separately, each part of the code and each part is working properly. I have problems only when I use in the same program both the timer-counter0 and the USART.

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

Read the Compiler output. If you have a spelling mistake for the ISR vector names it should tell you.

I suggest that you get the program working with polled UART first.

Then attempt the interrupt-driven UART comms. If you still have a problem, post your ISR() code.

Your posted code looks fine to me. The UART and Timers will work fine with correct ISR()s.

David.

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

Hello David,
I'm sorry for the delay of the answer, i'm a bit busy in this period.
However i understand what is the problem. Is the mode of work of the transmitter. If there aren't data in the UDR register, the ISR of transmitter interrupt 'block' others ISR routine so, they don't work until the ISR routine of transmitter sent the data.
This was my error, i get a data every DT, but the USART TX transmist continuosly.
Now i have adopted a solution that consist of enable the USART TX interrupt only when the data are disponible. If the data are disponible, i put the data in a buffer and
i enable the USART TX interrupt. In the relative ISR routine, first i transfer the data from the buffer to the UDR register, and then i disable the USART TX interrupt.
In this way, the code work properly and i can analyse the data using the matlab program.

In yours opinion, are this a good solution to solve this kind of problem?

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

No, it is not a good idea to use interrupts for the USART TX. Polling is simpler.

Once you have polling working, you can try interrupts.

TX is somewhat more complex than RX for interrupts. And since you always know when you want to TX, there is little point in using interrupts. RX is always unexpected - hence interrupts are worthwhile.

When you do use TX interrupt, there are several ways of doing it. e.g. UDRE and TXC. UDRE needs to be turned off and on as required. TXC is simpler. You either have something waiting in your buffer or you don't.

Just study the working TX examples from Atmel, Stang, CodeVision, ...

David.

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

david.prentice wrote:

And since you always know when you want to TX, there is little point in using interrupts. RX is always unexpected - hence interrupts are worthwhile.

You're right! In this case the interrupt has not much sense.
Using the polling i must check continuosly if the USART TX accept a new data. In the positive case, i put the data on the UDR register and i return to check if the peripherical accept a new data.
Using the UDRE interrupt, is the peripherical that notifies when is disponible to accept a new data.
I do the same thing or i'm wrong?
Obviously using the UDRE interrupt routine, i must enable the TX interrupt when the data are disponible, and disable it when all the data are transmit.

I have read a examples code for USART TX from Atmel, i had also studied this from my book.
Following the example and the book, i opted a interrupt solution...

At the first view, using the interrupt the my code work fine, the only problem that i have, is that if i use a buffer of only one element, i read ever the 255 value on my pc. If I use a buffer with more elements, this problem vanish and i read the correct values.
This is the only my doubt on my code.
I'm not a expert for the programming of the microcontrollers, this is my first experience on the programming this devices, and i need to learn a lot of thing about this argument!

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

In practice, you TX multiple bytes at a time. e.g. "Hello, my name is David"

If you poll, you are waiting for say 26ms while the USART sends at 9600 baud.
With interrupts and a sensibly sized buffer, you do not wait at all. You simply write to the buffer. It will still take 26ms to TX the message.

With a trivial buffer, you will still wait because the buffer will not have enough space.

In practice, a 16-byte TX buffer works very well. It depends on your typical traffic.

David.

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

This discussion is very useful for me! :mrgreen:

I haven't taken into account the time needed for transmit at 9600baud. I can generate a data every 50ms about. So i have the time to sent the data over USART because for this i need only 26ms @9600baud, right?

I put my data in a char buffer of 10 elements managed with a circular logic. This work fine because i obtain the result that i expect from this experiment.

For clarity, this is a part of my code:

ISR(TIMER0_COMPA_vect){
	buffer[ind_buffer] = n;// memorizzo la velocità rilevata dal sensore nel buffer 
	n = 0;// azzero il contatore di impulsi
	ind_buffer += 1;
	if (ind_buffer >= BUFFER_SIZE){enableTx(); ind_buffer = 0;} // gestione buffer circolare
}

In this routine i put the number of the pulse count in the buffer. This is activated each 50ms about.

ISR(USART0_UDRE_vect){// funzione per la trasmissione di un byte
	UDR = buffer[ind_tx_buffer]; //trasferisco un byte dal buffer al registro UDR
	ind_tx_buffer += 1;
	if (ind_tx_buffer >= BUFFER_SIZE){disableTx(); ind_tx_buffer = 0;}//gestione buffer circolare
	
}

And in this routine i transmit the element of the buffer over the USART.

PS:
I must do a optical tachometer to measure the velocity of my brushless motor. The output of the optical tachometer is about a pulse signal. Using the external interrupt, i can count this pulses every 50ms about. So, i can send this value over the USART, and using the matlab program, i can generate a graph of measured velocity. This is my objective.

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

I repeat. Use polled TX first.
Get it working.

Then study how to do TX interrupts.

What happens if you send "David"?
Or send "1234567890" ?

It does not matter what PC, MCU, USART ... the textbook is written for. The principle is the same:

Application wants to TX several bytes:
wait until there is room in buffer.
add the new byte to buffer tail.

TXC Interrupt:
if there is data in buffer, remove one byte from buffer head. write it to UDR.

David.

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

Quote:

Application wants to TX several bytes:
wait until there is room in buffer.
add the new byte to buffer tail.

TXC Interrupt:
if there is data in buffer, remove one byte from buffer head. write it to UDR.


Plus the somewhat sublime case of kick-starting it if the buffer was empty just before you inserted a character into it. (Also: Do THAT wrong and you have atomicity problems.)

As of January 15, 2018, Site fix-up work has begun! Now do your part and report any bugs or deficiencies here

No guarantees, but if we don't report problems they won't get much of  a chance to be fixed! Details/discussions at link given just above.

 

"Some questions have no answers."[C Baird] "There comes a point where the spoon-feeding has to stop and the independent thinking has to start." [C Lawson] "There are always ways to disagree, without being disagreeable."[E Weddington] "Words represent concepts. Use the wrong words, communicate the wrong concept." [J Morin] "Persistence only goes so far if you set yourself up for failure." [Kartman]

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

I'm sorry for both, but i'm a bit confused and i not understand you! Please, can you explain me where i'm wrong? I have some idea about that your tell me, but i'm sorry, now i'm confusing and i'm not able to focus them!

Quote:

Application wants to TX several bytes:
wait until there is room in buffer.
add the new byte to buffer tail.

TXC Interrupt:
if there is data in buffer, remove one byte from buffer head. write it to UDR.

I wait until there are a data disponible.
When there are a data, i put them in the buffer.
If the buffer is full, i enable the TX interrupt.

In the ISR routine i sending one byte at time from the buffer to the UDR register, until the buffer is empty. If the buffer is empty, i disable the TX interrupt.

I think that i do the same thing that you tell me, but using the interrupt, or this is that i have in my mind!:? If not, please, can you help me to understand where i'm wrong?

Quote:

Plus the somewhat sublime case of kick-starting it if the buffer was empty just before you inserted a character into it. (Also: Do THAT wrong and you have atomicity problems.)

I'm sorry, but i'm not understand that you tell me!
In the startup phase, the buffer is empty just before that i put the first data in the buffer, but the TX is off, so i can't read anything from the buffer. This is that the code do in my mind!! :?
Where are the atomicity problem that you tell me? Please can you explain me?

Thank! :)

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

Read ANY textbook on interrupt-driven USART.

Or even read the AVR data sheet.

You will understand it better from a textbook written in your own language. Or you could even experiment with a pack of playing cards.

If you start with and empty UART and an empty buffer, the first byte can go straight to the UART.
The 2nd byte can go in the UART's buffer.
The 3rd byte must go into your ring buffer.
...
The 12th byte has filled up your ring buffer.
You must wait until there is room for the 13th byte.

As each byte finishes from the UART, an interrupt occurs. The ISR() takes a byte from your ring buffer. This means you can put the 13th byte in the ring buffer.

It is far easier to do this exercise with balls and a drainpipe. You see how the balls slowly fall out of the bottom. Allowing new balls to go in the top of the pipe.

You want to wait until the pipe is full before you let any balls out of the bottom. Johan and I are saying that you start immediately. You may have to wait occasionally when you fill the top of the pipe faster than the balls fall from the bottom.

Most of the time, you never wait. The 'buffer capacity' (length of pipe) is big enough to hold your typical "message".

David.

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

The tricky thing about using an interrupt on uart transmit is: You don't get an interrupt till after you've transmitted the first character.

So you need your code to do something like:

If the UART isn't sending anything
{
   Send one character.
}

Then you'll start getting your interrupts, and can send the rest of the message, one character at a time on each interrupt.

The largest known prime number: 282589933-1

It's easy to stop breaking the 10th commandment! Break the 8th instead. 

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

Hello to all!

david.prentice wrote:

You want to wait until the pipe is full before you let any balls out of the bottom. Johan and I are saying that you start immediately. You may have to wait occasionally when you fill the top of the pipe faster than the balls fall from the bottom.

Maybe i understand! :twisted:
The problem is that i abuse of the interrupts. In my code i use the TX interrupt in cyclic mode (I wait for the buffer to fill up and then I send it), this is, philosophically, a incorrect use of interrupts, right?

I took your advice, and I found this post:
[url]
https://www.avrfreaks.net/index.p...
[/url]

basing on that code, i modified my. Now I enable the device TX once, and every time I get a data I put it in the buffer and point out the presence of data to TX.

There are the code of the timer0 ISR routine

ISR(TIMER0_COMPA_vect){
	buffer[ind_buffer] = n;// put the new data in the buffer
	n = 0;                 // reset the counter
	ind_buffer += 1;       // increment the buffer index
	tx_counter += 1;       // increment the data available index
        if (ind_buffer >= BUFFER_SIZE){ind_buffer = 0;} // manage ring buffer
	if (tx_counter >= BUFFER_SIZE){tx_counter = 0;} //manage data available
}

and this is the TX ISR routine

ISR(USART0_UDRE_vect){
    if (tx_counter){   // if there are data to transmit
	UDR = buffer[ind_tx_buffer]; //transmit a byte
	ind_tx_buffer += 1;          //increment tx_buffer index
	tx_counter -= 1;             //decrement data available index
	if (ind_tx_buffer >= BUFFER_SIZE){ind_tx_buffer = 0;} //manage ring buffer tx index
    } 
    else{ // if there aren't data to transmit
	UCSRA |= (1<<UDRE); //set UDRE flag to indicate that the TX is ready
    }
}

This solution have sense in the interrupt philosophy? Is correct to think in this way?

Last Edited: Sat. Oct 19, 2013 - 09:00 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:
You don't get an interrupt till after you've transmitted the first character.

I wish I said that. Oh, wait...
Quote:
the somewhat sublime case of kick-starting it if the buffer was empty just before you inserted a character into it.

:wink:

As of January 15, 2018, Site fix-up work has begun! Now do your part and report any bugs or deficiencies here

No guarantees, but if we don't report problems they won't get much of  a chance to be fixed! Details/discussions at link given just above.

 

"Some questions have no answers."[C Baird] "There comes a point where the spoon-feeding has to stop and the independent thinking has to start." [C Lawson] "There are always ways to disagree, without being disagreeable."[E Weddington] "Words represent concepts. Use the wrong words, communicate the wrong concept." [J Morin] "Persistence only goes so far if you set yourself up for failure." [Kartman]

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

Yes, you can use the TX interrupt code from that link.

Observe how the putchar() function 'fills' the buffer.
And the ISR(USART_TXC) 'empties' the buffer.

Note that the putchar() will block when the buffer is full. As the ISR() removes bytes from the buffer, it allows a new byte to go into the buffer.

Since there is the possibility of blocking, you should never call it from an ISR().

In practice, a 5ms Timer interrupt can safely 'add' to putchar()'s buffer if you are transmitting at 9600 baud (1.04ms per byte).

A 1ms Timer interrupt would eventually fill up a buffer that only empties at 1.04ms

In fact, you would never need to worry about UART interrupts if you know that you only putchar() slower than the baud rate. e.g. a 5ms Timer can simply say UDR=c

I repeat. There will be Textbooks and Tutorials that are written in your language. Please use 'respected' tutorials. Many UART topics for AVR are absolute pants.

David.

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

david.prentice wrote:

Observe how the putchar() function 'fills' the buffer.
And the ISR(USART_TXC) 'empties' the buffer.

Note that the putchar() will block when the buffer is full. As the ISR() removes bytes from the buffer, it allows a new byte to go into the buffer.

Since there is the possibility of blocking, you should never call it from an ISR().

I saw this routine. I prefer not follow this routine because in my case, i have a 'big' time for fill the buffer. Also i know the problem about the block call routine in the ISR code.

Quote:

I repeat. There will be Textbooks and Tutorials that are written in your language. Please use 'respected' tutorials. Many UART topics for AVR are absolute pants.

There poor literature about this specific argument in italian. I study a lot on the book, datasheet and tutorials in english. Isn't a problem, also if i haven't a good skill in english... :oops:

I think that in this case the problem is my poor "forma mentis" for this argument. This is my first experience on the microcontroller programming.

I must starting to think plus freaks!! :P

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

I am sure that there are excellent Italian textbooks.
Perhaps Mr Samperi (js) can help.

The general algorithm for a putchar() fill and an ISR() empty has been the same for all time.

It applies to many things in life. e.g. your mains water pressure and water tower. or the water in your house if you have a 'header tank' in the roofspace.

Study the CodeWizard code. It is a standard solution.
Note that there are alternative codes that do the same thing.

Of course, you can write one byte in a Timer ISR() if you know that the UDR is going to be empty.

Most people want to send strings e.g. "David Prentice is a jolly nice chap".
Clearly no UART can copy with 25 bytes at once. Even a 16-byte buffer will be too small. You will block when you get to the 18th byte. (16 bytes in buffer + 1 byte in UDR + 1 byte shifting out of TXD pin)

Don't be proud. Read and copy proven solutions. Then study why and how they work. You may even be able to improve them!

Einstein did not start from scratch. He learned from his schoolteachers and prior knowledge. THen added more to humanity.

David.

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

I have this textbook:
[url]
http://www.amazon.com/AVR-Microc...
[/url]

I didn't found this kind of book in italian in my university library. However isn't a problem! I learn the english!! :)

Quote:

The general algorithm for a putchar() fill and an ISR() empty has been the same for all time.

Quote:

Study the CodeWizard code. It is a standard solution.
Note that there are alternative codes that do the same thing.

I think that this is a producer-consumer problem in software engineering. I have studied this problem, but i have used Java. Using the microcontrollers this is a "bit" different!
I'm working to adapt my knowledge from high level language to low level language. Isn't simple!

Quote:

Don't be proud. Read and copy proven solutions. Then study why and how they work. You may even be able to improve them!

I have follow your advice, and i did some experiment, but now i have some question about. I'm explain:
I did write a simple test code using the usart. I have programmed an external interrupt that generate some numbers, i would put this numbers in a buffer and send them to my pc using the usart.
This is the code:

#include 
#include 


#define BUFFER_SIZE 23
#define UBRR_VALUE 51// @8MHz baud rate is 9600

volatile char buffer[BUFFER_SIZE] = {0};
volatile char ind_buffer = 0;
volatile char ind_tx_buffer = 0;
volatile char tx_counter = 0;

volatile char cmd = 0;
volatile char inp = 0;

char i = 0;


void initUSART(void);
void initExtInterrupt(void);
void initIO(void);

void put_char(char c);

void initExtInterrupt(void);
void initIO(void);

int main(void)
{
	
	initIO();
	initUSART();
	initExtInterrupt();
	
	sei();
	
		
    while(1){
		
		switch(cmd){
			case 1:
				put_char(10);
				cmd = 0;
				break;
			
			default:
			  break;	
		}
    }
}

void initIO(void){
	
	DDRD &= ~(1<<2); //pin D.2 is input (INT0)
	PORTD |=(1<<2);  //pull-up on D.2
	
	DDRB |= (1<<0);  //pin b0 is output  
}

void initUSART(void){
	UCSRB |= (1<<RXCIE) | (1<<RXEN);// enable rx and rx interrupt
	UCSRB |= (1<<UDRIE)| (1<<TXEN);// enable tx and tx interrupt
	UCSRC |= (1<<UCSZ1) | (1<<UCSZ0);//8bit
	UBRRL = UBRR_VALUE;//baud rate @ 9.6K ^ @8Mhz
	
}

void initExtInterrupt(void){
	GIMSK |= (1<<INT0);//enable external interrupt INT0
}

void put_char(char c){ // 
	buffer[ind_buffer] = c;          // store byte
	ind_buffer += 1;
	tx_counter += 1;
	if (ind_buffer >= BUFFER_SIZE){ind_buffer = 0;}
        if (tx_counter >= BUFFER_SIZE){tx_counter = 0;}
}

ISR(USART0_UDRE_vect){// tx routine
    if (tx_counter){
	UDR = buffer[ind_tx_buffer]; //put the byte into the UDR
	ind_tx_buffer += 1;
	tx_counter -= 1;
	if (ind_tx_buffer >= BUFFER_SIZE){ind_tx_buffer = 0;}//manage ring buffer
     } 
     else{
	UCSRA |= (1<<UDRE); //the TX is ready 
     }
}

ISR(USART0_RX_vect){// rx routine
	inp = UDR;      // get a byte from UDR
	switch(inp){
		case 'm':   
			cmd = 1; // start the routine 'm'
			break;
	}
}

ISR(INT0_vect){
	PORTB ^= (1<<0); // test led
	char j = 0;
	for (j=0;j<=20;j++){
		put_char(j);
	}
	
	//while (j<=20){
		//put_char(j);
		//j += 1;
	//}
}

The problem is that i lose few numbers. I create a sequence of 21 numbers (from 0 to 20) in the INT0 interrupt routine, but in the pc side i read only the last numbers (from 12 to 20 for example) and this range varies, repeating the experiments.
I also try to use different buffer size, but substantially i obtain the same result.
What happening? And how i resolve this problem?

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

Like I said earlier. Study the CodeWizard code.

Then trace what happens in your code.
No, I have not tested your code in real life. I am just guessing that the main() will crawl along slower than a snail !

I am sure that there will be excellent Italian textbooks. Note that AVR is irrelevant. An ancient textbook written for a Z80, 8080, 6800 or 6502 would show the principles.

David.

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

Hi David!

The CodeWizard code doesn't work in my case, i don't know why!
However i found an application note (AVR306). The code in this paper, look like the my first solution (enable and disable USART TX interrupt at every data transmission), so i have adapted this code at my problem.
I appreciate your advices, so i will thank you for your help.

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

P. Fleury's uart lib is excellent , you'll have to add the T4313 to the lib.
But that's quite easy

http://homepage.hispeed.ch/peter...

/Bingo