Forum Menu




 


Log in Problems?
New User? Sign Up!
AVR Freaks Forum Index

Post new topic   Reply to topic
View previous topic Printable version Log in to check your private messages View next topic
Author Message
societyofrobots
PostPosted: Aug 02, 2008 - 10:43 PM
Hangaround


Joined: Nov 29, 2007
Posts: 134


I want to set up my AVR to run a program, but if something is ever detected on the UART, it would stop running the program and instead receive data from the UART.

How do I set up this interrupt? Is it possible?

_________________
How do YOU make a robot?
http://www.societyofrobots.com
 
 View user's profile Send private message Visit poster's website 
Reply with quote Back to top
eskoilola
PostPosted: Aug 03, 2008 - 01:12 AM
Hangaround


Joined: May 06, 2008
Posts: 461
Location: Finland

Well. All I can tell You is to read:

1. The MCU data sheet
2. The compiler manual
3. Some examples after doing that homework

_________________

Yet another home page
 
 View user's profile Send private message Visit poster's website 
Reply with quote Back to top
JohanEkdahl
PostPosted: Aug 03, 2008 - 01:27 AM
10k+ Postman


Joined: Mar 27, 2002
Posts: 21355
Location: Lund, Sweden

Quote:

Is it possible?

Yes.
Quote:

How do I set up this interrupt?

Depends on what compiler or assembler you use, and on the AVR model you use.

Pseudocode (sketchy):
Code:

int UARTflag 0;

InterruptServiceRoutine()
{
   UARTflag = 1;

   // Also handle the incoming character (eg. store it in a variable
   // so that the code in main can get it and process it further
}

int main(void)
{
   // Set up your UART parameters here

   while (1) {
      if (UARTflag == 0) {
         // Run your initial program here
      }
      else {
         // Run your UART-receiving code here
      }
   }
   return 0;
}
 
 View user's profile Send private message Visit poster's website 
Reply with quote Back to top
societyofrobots
PostPosted: Aug 03, 2008 - 01:41 AM
Hangaround


Joined: Nov 29, 2007
Posts: 134


I'm a weak programmer, so I'll need more hints than 'read the datasheet' Shocked

Quote:
Some examples after doing that homework

Know of any? No luck on my not-so-educated search . . . I basically need someone to give me some good hints and links to places to read up on it.

Quote:
Depends on what compiler or assembler you use, and on the AVR model you use.

AVR Studio with gcc, ATmega640. The ATmega640/2560/etc microcontroller seems to be a serious weakness here at avrfreaks.net, because 90% of my questions on it go unanswered . . . AVRlib doesn't even support it, so I've had to rewrite a lot of code . . .


edit: Oh and that pseudocode won't work, as it requires and if statement to check a flag. I however need to jump out of code *immediately* and not wait for a while loop to cycle.

_________________
How do YOU make a robot?
http://www.societyofrobots.com
 
 View user's profile Send private message Visit poster's website 
Reply with quote Back to top
JohanEkdahl
PostPosted: Aug 03, 2008 - 01:58 AM
10k+ Postman


Joined: Mar 27, 2002
Posts: 21355
Location: Lund, Sweden

Quote:

I'm a weak programmer

Then you need to take small steps: Learn one little simple thing. Then the next. Taking many small steps you will stand a much better chance to get to your goal than trying to take one giant leap.

One, not so small, step would be to get the reception of data on the USART working. So you will need to read the USART ection of the data sheet. You might not understand all of it, but you need to read it so that you have a feeling for when the answer to a question might be in there and it is time for you to return to the data sheet.

You will also need to understand interrupt mechanisms in general, and how they are implemented with avr-gcc.

One obvious complication is that when implementing reception of USART data, how do you know if it is functioning? One way would be to just transmit the received character on the USART again. If you attach your AVR to a serial port on a PC and run a terminal program there you will then be able to type characters that will be echoed back by the AVR ans shown in the terminal program.

Another way would be to display any received character on eight LEDs and still use a PC terminal program to send characters to the AVR.

IIRC there is a USART tutorial in the Tutorial forum. Seek it out!

Might we be enlightened by some more details of the application? This would give us a better chance to give good help. (Or have you come up with the business idea of the century...? Wink )
 
 View user's profile Send private message Visit poster's website 
Reply with quote Back to top
societyofrobots
PostPosted: Aug 03, 2008 - 02:16 AM
Hangaround


Joined: Nov 29, 2007
Posts: 134


You misunderstand what I asked . . .

I have the UART working already. I can read data, arrays, streams, whatever and process it fine. I can easily have my program wait for data in a while loop, too.

The question is, how do I trigger an interrupt to jump my avr out of its currently running program to go into another program. Its not as simple as a timer interrupt or digital pin interrupt.

As you can see in the below pseudocode, the avr is busy calculating and can't just sit in a wait_for_uart_data() loop forever:

Code:
while(1)
{
int i;
i++;//avr busy calculating important stuff
}
uart_interrupt(void)
{
receive_uart_data_stream();
}

_________________
How do YOU make a robot?
http://www.societyofrobots.com
 
 View user's profile Send private message Visit poster's website 
Reply with quote Back to top
JohanEkdahl
PostPosted: Aug 03, 2008 - 02:36 AM
10k+ Postman


Joined: Mar 27, 2002
Posts: 21355
Location: Lund, Sweden

OK, so look in my pseudo-code above. You don't want to have a heavy ISR. Although exceptions can be discussed, generally you want an ISR to do the absolute necessary, in your case get the received character and store it in some intermediary place, and then bail out. Your main program runs in an endless loop, switching between the two tasks (calculating important stuff and dealing with received USART data depending on some variable(s) shared between the ISR and the main program.

It might well be that UART data comes in such a high speed that you will need a buffered solution. The IR stuffs data into a buffer. The main program picks data out of that buffer until it's empty. This way, although the main program might be in the middle of dealing with a character that originated from the USART new incoming data can readily be accepted as it will not overrun elder data. The size and structure of this buffer depends on the incoming data rate, and how heavy processing of that data is.

Search this site, Google etc for "ring buffer".

And again: There is a tutorial in the Tutorial forum on using interrupt driven serial communications. Search it out.

Quote:

Oh and that pseudocode won't work, as it requires and if statement to check a flag. I however need to jump out of code *immediately* and not wait for a while loop to cycle.

That pseudocode is as close as I can get without knowing more about the specific application. The only one knowing more is you, claiming that you need to jump out immediately. This demands a re-write of the "important calculations" part so that it is possible to get out of it immediately, and as you said nothing more than "calculating important stuff" the only thing that can be said is that that code needs to check if it should stop doing what it's doing often enough for it to be able to stop immediately. Whatever that means. In one CPU clock cycle? Before the next character arrives in the USART? Before the moon falls down?

More details on what you are actually trying to do will yield better answers.
 
 View user's profile Send private message Visit poster's website 
Reply with quote Back to top
societyofrobots
PostPosted: Aug 03, 2008 - 03:08 AM
Hangaround


Joined: Nov 29, 2007
Posts: 134


Ok I'll better explain what the code is doing.

The code will always be 'calculating important stuff' forever. Non-stop. Until the moon falls down. The time changing results end up as changes on various output pins, but thats not important.

Now the UART data can come at any time (from some other microcontroller or PC). Every 10ms, or even every 10 years - 100% unpredictable. If the avr is in the middle of calculating something important, I don't care, I want it to exit *immediately* and start accepting UART data.

To have it 'calculate something' for 1ms, then check the uart in a while loop, repeat, will not work. It could entirely miss uart data in that 1ms delay.

Quote:

There is a tutorial in the Tutorial forum on using interrupt driven serial communications. Search it out.

I'm looking at it now, and on quick glance it appears to have code in it that I want. I'll report back if I get stuck.
http://www.avrfreaks.net/index.php?name ... riven+uart

_________________
How do YOU make a robot?
http://www.societyofrobots.com
 
 View user's profile Send private message Visit poster's website 
Reply with quote Back to top
stevech
PostPosted: Aug 03, 2008 - 10:48 AM
Raving lunatic


Joined: Dec 18, 2001
Posts: 5214


If you aren't experienced with interrupts and that rot, then have your main program be in a loop that checks the UART status bits to see if a byte has come in. If so, input that byte and either act upon what that byte tells you, or buffer it for later use when the rest of the expected bytes come in.

Of course, you'll need this loop to check at a rate higher than the bytes per second that can arrive, based on your chosen baud rate and other things.
 
 View user's profile Send private message  
Reply with quote Back to top
clawson
PostPosted: Aug 03, 2008 - 12:59 PM
10k+ Postman


Joined: Jul 18, 2005
Posts: 69326
Location: (using avr-gcc in) Finchingfield, Essex, England

Well I'm puzzled. I read this entire thread and I still don't see how the psuedo-code that Johan posted at the start isn't the answer to the "problem"? What I'd probably do is actually disable the RX interrupt as soon as the fist char s received - pass it across to main (in fact it might even be the "flag" itself?) and then continue with polling there once you've switched to "UART mode"

_________________
 
 View user's profile Send private message  
Reply with quote Back to top
JohanEkdahl
PostPosted: Aug 03, 2008 - 01:34 PM
10k+ Postman


Joined: Mar 27, 2002
Posts: 21355
Location: Lund, Sweden

So the reason to stop immediately is that you don't want to loose data, and nothing else. This is no new problem. You're dealing with a classic.

IMO the way to deal with it is to do jut what I said above: Let the ISR buffer incoming data. It does so *immediately* (as it is an ISR...). The rest of the treatment of incoming data happens in main, where you can allow yourself not to react lightning fast as the data has now been buffered.
 
 View user's profile Send private message Visit poster's website 
Reply with quote Back to top
societyofrobots
PostPosted: Aug 03, 2008 - 06:24 PM
Hangaround


Joined: Nov 29, 2007
Posts: 134


There are reasons interrupts exist, just trust me that this is one of them. =P

(its not worth explaining my algorithm)

Quote:
What I'd probably do is actually disable the RX interrupt as soon as the fist char s received - pass it across to main (in fact it might even be the "flag" itself?) and then continue with polling there once you've switched to "UART mode"

Thanks, in addition to that ISR code which I think will work (I haven't tested my code yet), this additional tip helps too =)

_________________
How do YOU make a robot?
http://www.societyofrobots.com
 
 View user's profile Send private message Visit poster's website 
Reply with quote Back to top
societyofrobots
PostPosted: Aug 04, 2008 - 04:59 AM
Hangaround


Joined: Nov 29, 2007
Posts: 134


Just a check to see if I am doing this right . . .

so data is recieved by uart1
the ISR is called
within the ISR, interrupts are turned off
a function that collects the data stream is called
after all data is received, interrupts turned back on

Code:
ISR(USART_RXC1_vect) //trigger interrupt when uart1 receives data
   {
   cli();//turn off interrupts
   get_data();//exit interrupt and get data
   }

void get_data(void)
   {
   receive_all_data();//recieve full data stream
   uartFlushReceiveBuffer(1);//flush out receive buffer
   sei();//turn on interrupts
   }

void main(void)
   {
   do_important_stuff();
   }

Looks good?

edit: My compiler doesnt like 'USART_RXC1_vect' . . . if my AVR has multiple UARTs, how do I specify which in the ISR? Does it matter? This is the error:

warning: 'USART_RXC1_vect' appears to be a misspelled signal handler

I get the same error for USART_RXC_vect . . .

_________________
How do YOU make a robot?
http://www.societyofrobots.com
 
 View user's profile Send private message Visit poster's website 
Reply with quote Back to top
Xendris
PostPosted: Aug 04, 2008 - 06:12 AM
Rookie


Joined: Apr 08, 2008
Posts: 22
Location: Portland, OR

I'm going to jump in here. It sounds to me like what the OP needs is a pre-emptive OS. His requirements are:

1) Run a background task continually.
2) On USART Rx, trigger a higher-priority task that handles the input.
3) (Assumption) After the input is handled or a timeout reached, return control to #1.

The most efficient way to do this would be to grab a copy of FreeRTOS or AvrX, compile an example, then modify it to suit the needs of this project. Tradeoff: more complexity in having to learn the RTOS for less complexity in having to implement a custom task-switcher.
 
 View user's profile Send private message  
Reply with quote Back to top
buffi
PostPosted: Aug 04, 2008 - 07:55 AM
Resident


Joined: Aug 24, 2001
Posts: 513
Location: Hamburg, Germany

For your interrupt signal name: See (google -> avr-libc) -> avr-libc home page -> online docs -> reference -> avr/interrupt.h for all currently supported interrupt handlers. All the UART interrupt names are very similar in gcc, but some have one more 0 or 1 here and there.

In your ISR, you should only store the byte you just received. Store it in a buffer, and increment some counting variable. You can decide if enough data has been received in your main loop or in your ISR, and process it.

Also look for circular buffer code or FIFO code something like that.

_________________
I tend to post off-topic replies when I've noticed some interesting detail.
Feel free to stop me.
 
 View user's profile Send private message Visit poster's website 
Reply with quote Back to top
curtvm
PostPosted: Aug 04, 2008 - 08:59 AM
Raving lunatic


Joined: Sep 21, 2005
Posts: 2318


Quote:
My compiler doesnt like 'USART_RXC1_vect'
In avr studio you are 2 clicks away from the correct name (ok, its 3 if a double-click counts as 2), look in iomxx0_1.h (its USART1_RX_vect). No matter what the datasheet or anyone else says, the header file will have the final say.

You don't need to disable irq's in an irq, and you don't need to enable them at the end of the irq function. Its all taken care of.
 
 View user's profile Send private message  
Reply with quote Back to top
clawson
PostPosted: Aug 04, 2008 - 01:17 PM
10k+ Postman


Joined: Jul 18, 2005
Posts: 69326
Location: (using avr-gcc in) Finchingfield, Essex, England

Quote:
It sounds to me like what the OP needs is a pre-emptive OS

You need to introduce the complexity of an RTOS as soon as one interrupting source is identified in a project?!? I don't think so. (IMHO)

_________________
 
 View user's profile Send private message  
Reply with quote Back to top
stevech
PostPosted: Aug 04, 2008 - 09:47 PM
Raving lunatic


Joined: Dec 18, 2001
Posts: 5214


clawson wrote:
Quote:
It sounds to me like what the OP needs is a pre-emptive OS

You need to introduce the complexity of an RTOS as soon as one interrupting source is identified in a project?!? I don't think so. (IMHO)


I don't think the OP even needs interrupts! As in my earlier post.
 
 View user's profile Send private message  
Reply with quote Back to top
bobgardner
PostPosted: Aug 04, 2008 - 10:10 PM
10k+ Postman


Joined: Sep 04, 2002
Posts: 23460
Location: Orlando Florida

Show him the numbers. The interrupt, save a couple of regs, grab the char from the uart, put it in the receive buffer/array, increment buffer pointer, pop back a few regs, reti... all those instructions might fit in 2 or 3 usecs or less. A char arrives every 83usec at 115200 bps, so the act of grabbing chars takes 2 usec every 80 usec, 1/40th of the cpu, 2.5%. You have 97% cpu time left for computation. Good exposition if I say so myself.

_________________
Imagecraft compiler user
 
 View user's profile Send private message Send e-mail Visit poster's website 
Reply with quote Back to top
Display posts from previous:     
Jump to:  
All times are GMT + 1 Hour
Post new topic   Reply to topic
View previous topic Printable version Log in to check your private messages View next topic
Powered by PNphpBB2 © 2003-2006 The PNphpBB Group
Credits