Author Options:

Calling all AVR wizards! (I need some more help!) Updated! Answered

New stuff's in bold

I'm trying to build a clock-type-thing for my research project this year, and I need some help.

First, I need to know how I can run my ATtiny2313 off of a 12mhz external clock. No, not crystal, external clock. (this holds true)

Second, I need to know how to use interrupts (in general) to program a clock. I really just need some bare code or help, and any help is greatly appreciated.

So, I figured out how to use interrupts, and it's pretty simple, actually - I'm just having one small problem - why can't I write to global variables in an interrupt service routine (ISR)? Any clues on how I can talk back to the main routine from an interrupt?


Picture courtesy of Oskay!



10 years ago

CC-licensed picture!
Hey, that's my photo. I don't mind if you use it (that's what the CC license is for) but you really should give me credit, you know. Even the CC license says so.

Have you got your AVR cooperating fully now?

He talked to me last night, and this seems to sum it up: So, I figured out how to use interrupts, and it's pretty simple, actually - I'm just having one small problem - why can't I write to global variables in an interrupt service routine (ISR)? Any clues on how I can talk back to the main routine from an interrupt? He also mentioned that the interrupts just stopped working about 30 or so, I'm not sure if he got that fixed...

Have you got your global ISR-modified variables declared as "volatile" ? If not, the compiler is likely to optimize away access to the variable in the non-interrupt code. (oh; I see gmoon has Already said this.)

Yep! I did that, and it works flawlessly! My only problems now are... well.... impossible. I'll see if I can type up the scenario.... but my dad's an EE major, and he said it's impossible too. I'll also double check all my connections, and see what the hell is going on with an o-scope. (excuse my language) Thanks for all the help, though. I really needed it!

Okay! Awesome! (well..... kind of......) So I gave up on that other project I was working on (for now), and now I'm working on the clock. I actually finished writing up a clock using the internal clock and ISR's , and now I'm going to try to burn the fuses and code a bit to make it run on the external! Hoorai! I might edit the post later on in the week and let you guys know what happened - but I'm on a huge timed deadline - I have until monday night to make a braille clock that sets itself via the WWVB signal... I still have to work on USART communication between this WWVB module I made and the uC, and that should be it! Sigh, that's still a TON of work, though (for me, at least)... I'm such a noobie! -Josh

Cool project(s)! Yeah, let us know how it shakes out--that's a lot of work to do in a couple days... (and make an 'ible, too.)

The braille clock isn't actually "my" project..... I'm mentoring two juniors in my school's research program (I'm a senior). Unfortunately, I'm not that great of a teacher, and we're on a serious time limit, so I end up doing most of the work.

I'm going to have them write up an 'ible when we're done =)

By the way, after you burn fuses, do you have to re-burn them each time you program the chip? I'm having trouble programming my chip now that I burned the fuses so that it runs on an extermal oscillator (which is still attached)

(quick response, I'm on my way out...) Right--the clock source needs to be attached once you set that w/fuses. RE: ISP at higher speeds: I bricked a atmega8 by programming fuses (w/uisp) once it was running at 8mhz (I've not tried to recover it with HV programming on my STK500, yet.) The moral--your mileage will vary when using home-made DAPA parprot cables (length of the cable, parallel port differences, etc.) ISP programming itself should work at any speed, and is very reliable with the STK500, I'm told (I just haven't gotten around to using mine.) But there is a bitclock option in avrdude--that may allow you to tune it for the 12mHz clock...


Right now I'm working on a WWVB decoder.

I think I've got it down, but I'll post if I need help =)

Sorry - I forgot to include the credit line in my last edit - it's up now!

Ah! my bad!

I kind of just found it on google, but I'll give you some credit now =)

Not quite.... it's actually being quite irrational right now.... and I have no clue wth is going on.

I got the whole main routine - to interrupt thing, but now there's other problems - much bigger ones...

I'll update tomorrow - I'm wiped.

Sorry, just read part two. My mind was demystified concerning timers and interrupts after I read every bit of this tutorial twice... thrice... and then some:
Newbies Guide to AVR Timers

Seriously, go back and forth between the data sheet and that guide and you could BUILD your own chip from scratch (well, not quite).

Thanks so much! This definitely helped a bit! (or byte =P)


10 years ago

Yep--see page 29. Do your homework, though. It's easy to set fuses wrong, so the chip is not programmed for the intended clock source. If that happens, and the expected xtal/ clock source, etc. is missing, the chips won't respond to any commands (AVRs 'bricked' like that can be recovered with high-voltage programming, but you'd need an STK-500 board or equiv.)


I know what the fuses should be set to, I just don't know how to set them. Sorry I didn't clarify in my call for help. I'm using the ghetto method as shown by The Real Elliot. (not the USB version)

Ah, I gotcha. (And you didn't mention which IC your using for the clock--another AVR?)

(Re: fuses--I've done more of this with uisp than avrdude, but I assume you're using avrdude.)

-- reading fuses (to verify)

I offer one example with uisp, 'cause it's easier to read fuses w/uisp:
uisp -dprog=dapa --rd_fuses

avrdude can only output fuse values to a file, and then generally only in an obtuse format, unless you just connect with verbose option:

avrdude -c dapa -p t2313 -v

The fuses will be included in the output.

I include the section on reading fuses, because:
AVR fuse bits are inverted values-- 0 == programmed, 1 == unprogrammed.

Read the fuse bits first on a stock AVR, and compare with the default values, use that as a guide. The bits should be inverted; avrdude and uisp work like that. Some GUI programmer invert the values for you (I don't know for sure what platform, etc. you are using.)

-- writing fuses

Syntax for the low fuse:
avrdude -c dapa -p t2313 -U lfuse:w:0x64:m

and the high:
avrdude -c dapa -p t2313 -U hfuse:w:0xDF:m

These values are examples only (not specific to your app.) And the part can be verbose on more recent versions of avrdude (attiny2313 vs t2313 .)

Oh by clock I meant digital clock - you know, the number type! Thanks for all your help! I'm going to start to manifest all of this information into a product soon - I just have to take it in, along with all 231 pages of the manual XX. My dad said he's going to help me with figuring out how to use interrupts, so hopefully this goes well.

One more thing about fuses:
You should set the high and low fuses together, in case one set is dependent on the other (might apply to external clocks, etc.)

Here's a decent page on interrupts, although it's for the mega8 (no biggie, just 2313 defines and you'll be cool.) And here's a IRQ article specific to the 2313.

But read the avr-libc documentation: I think the old SIG_ vector names are depreciated; there is a new macro and new vector names. You'll figure it out....

GAD! I don't think anyone reads the whole PDF manual! Good luck, have fun!

How would you set them together? as in..... on one line?

Yeah, as in: avrdude -c dapa -p t2313 -U lfuse:w:0x64:m -U hfuse:w:0xDF:m (but it looks like you've already got it working...)

Awesome! So... I figured out interrupts - it was actually pretty simple. I just have one question - why can't I write to global variables in an ISR?

I'm trying to make a counter that runs off of an interrupt, but when I do this:
int count;
toggle led1 //toggle = pseudo, too lazy to write out all of it

and then in the main
if (counter%2==0) {toggle LED2}; //toggle is pseudo

it doesn't work. It seems as if it's getting interrupted, 'cause it's toggling led1, but never toggles led2... any ideas?

Best guess: you should be able to use global variables, but like this:

volatile int count;

It's a compiler optimization thing: in the scope of normal linear execution, main() doesn't call any code that changes count.

From the avr-libc faq:

the compiler will typically access "count" only once, and optimize further accesses completely away, since its code path analysis shows that nothing inside the loop could change the value of flag anyway. To tell the compiler that this variable could be changed outside the scope of its code path analysis (e. g. from within an interrupt routine)...

If that doesn't work, post (or PM) more of the code?

so.... I read my fuses... and they're all bytes, and there's a bunch of them. I thought fuse bits were only 2 bytes long, but I guess there are actually... 6 bytes worth of them.... I'll go look up the bit values now.....

Oh! or not.... for some reason it printed out the fuses twice, so there's only 3 bytes worth of them, that makes sense!

SUCCESS! I successfully burned by fuses! hoorah! sooooo..... now for the USART.....

Setting the fuses is a usually a delicate dance between your programmer hardware and the software that drives it. If you're using AVRDUDE as your "programmer interface", it looks like you use the "'-U" option after manually calculating the values you need. Here are some examples. (I've never done this myself, mind you; I'm going by general principles.)

As for interrupts, the usual technique is to set one of the timers, or an external timer, to run continuously and generate an interrupt at an appropriate interval much less than one second, and increment a counter an appropriate amount. (for example, the arduino core code sets timer0 to interrupt every 1.024 miliseconds, and increments a "ticks" counter by one. Cisco IOS software historically uses an external timer to cause an interrupt to occur every 4 milliseconds, and adds 4 to a "clock in milliseconds" variable.) The main (non-interrupt) code can then poll the counter and do appropriate calculations to convert it to "real" time.

I'd help, but I have no clue about avr, I'm not ignoring you