Questions about AVR sleep mode, interrupts and wake up - Page 1
Forum section: electronics / general

author: MathWizard
author_rank: Super Contributor
timestamp: October 04, 2024, 10:57:14 pm
content: I'm bare metal programming an ATtiny13A. So I'm making assembly, then the opcodes, then the intel hex. And for now running it in SimulIDE 1.1.0I made a basic program that should setup the ADC to auto-trigger when the Timer/Counter gets Compare Match A. And I'm trying to put the system into IDLE mode right after starting the counter, and I'm setting the MCUCR reg for idle mode, including the enable bit. And then I'm giving the SLEEP command.Except for maybe the ADC INT Flag, ADIF, I think the rest are setup right, and the Global int flag is set 1. It says in the datasheet, that you can clear ADIF, by setting 1. But looking in the ADCSRA reg in SimulIDE, it gets set to 0, even though my code was right. Maybe that's fine and not an issue.So after the sleep command, I'm expecting the CPU to powerdown, but the ADC and T/C will keep running. Then the T/C should count up to MATCH the value in OCR0A. The T/C is set to Clear Timer on Compare. The output registers OC0A,B are set to toggle. I put nothing in any timer interrupt vector location, besides RJMP to main prgm.The ADC is set to auto-trigger on Compare Match A, so I'm guessing it watches OC0A for a state change, and ADIF is set low, and ADIE is high for allowing the interrupt. I didn't see an explanation of how the T/C tells the ADC to trigger, or anything that says to set more interrupts. If I get it, the WGM and COM0x settings handle that.So at the ADC INT vector, I put an RJMP to a routine, word 40 ATM (but the code in not working so never mind the exact end section). And I put a RETI at the end of it, expecting then the RETI would lead to the instruction after SLEEP.Maybe I'm supposed to be doing PUSH/POP with the stack for those return instruction addresses ?But I'm not sure the timer is running, I don't see the TCNT0 counter reg getting incremented, and the ADC never gets trigger as far as I can tell. It never gives any result. In the sim, the main osc is only set to ~1MHz, and only 1 instruction/sec.But also for the SLEEP command, I get an error, saying it's not being fully implemented. The timer should count up ~83ms in real life, in the sim IDK, I have it slowed way down. But the PC goes to the next command, and carry's on. But I get the errorQuoteNow for the sleep command, am I supposed to be storing in the stack, the location of the SLEEP ( or 1 after it) ? Or is that done automatically by the SLEEP command ? I don't see anything in the stack tho, I did set the top as 0x9F. Looking this up on the web, I just get the same old pages over and over, and usually only in C, not assembly. So IDK what PUSH or POP commands might be going on.But the PC is jumping right to the next command after sleep, I had a NOP there, then I tried loading the code for disabling sleep-enable. And whatever the T/C is really doing, the ADC never seems to do anything. I've never seen the PC go to the ADC INT vector at 0x09, or to the little routine a few steps ahead of SLEEP. I had RJMP before it too, so it really never got there.The end code and some rmps and branch aren't finished since it's not working. But all I was trying to do, is read a sine-wave with the ADC, and if the count was under 256, ADCH would be 0, and then I would do a CPI, and Branch IF Carry flag Set, and light up an LED. Otherwise, it would jump back to enabling sleep modes, reset the counter and SLEEP again, and count up and read the ADC again.Here's a look at the main I/O reg's on PC36, so the NOP right before the sleep command. I added some of them so it would be easy to change the final intelhex in the spreadsheet. Besides ADIF in the ADCSRA set to 0, so it's 0xAB, not 0xBB, everything is as I set as I think it should be. I also had LED's on OC0A/B. They toggle some, but something wrong, certainly with the ADC not triggering, and the SLEEP.The SLEEP on PC37, definitely takes longer, but then it just goes up to W39 and RJMP's to W34 and loops forever.0 RJMP 91 RJMP 82 RJMP 73 RJMP 64 RJMP 55 RJMP 46 RJMP 37 RJMP 28 RJMP 19 RJMP 30 ;ADC interrupt leads to W4010 EOR R0,R011 LDI R16,64 ; loads 0100 0000 for ADMUX12 OUT 7,R16 ;sets ADMUX use 1V1ref and PB5=ADC013 LDI R17,187 :loads 1011 1011 for ADCSRA14 OUT 6,R17 ;enables ADC, ADCinterrupts, /8 prescaler15 LDI R18,3 ;loads 0000 0011 for ADCSRB16 OUT 3,R18 ;sets ADC to trigger on T/C CompareMatchA17 LDI R19,63 ;loads 0011 1111 for DIDR018 OUT 20,R19 ;disables DigitalData buffers for all 6 ports19 LDI R20,129 ;loads 1000 0001 for GTCCR20 OUT 40,R20 ;holds the T/C in reset while setting up21 LDI R21,82 ;loads 0101 0010 for TCCR0A22 OUT 47,R21 ;set OC0x to toogle on CompareMatch, WGM to ClearTimer on CompareMatch23 LDI R22,5 ;loads 0000 0101 for TCCR0B24 OUT 51,R22 ;does not Force CompareMatch, also sets a bit of WGM25 LDI R23,100 ;loads 100d for OCR0A26 OUT 54,R23 ;uses to compare with TCNT0 count27 LDI R24,11 ;loads 0000 1011 for DDRB28 OUT 23,R24 ;sets PB0,1,2 as outputs29 OUT 63,R0 ;Clears SREG30 SEI ;enable Global Interrupts31 LDI R25,159 ;load 0x9F for SPL32 OUT 61,R25 ;sets SPL to top of SRAM33 LDI R26,32 ;loads 00010 0000 for MCUCR34 OUT 53,R26 ;chooses IDLE sleep and enables SleepMode35 OUT 40,R0 ;clears GTCCR so the T/C should start running36 RJMP 037 SLEEP38 OUT 53,R0 ;disables SleepMode39 RJMP -640 OUT 53,R0 ;disables SleepMode41 IN 4,30 ;loads ADCH42 IN 5,31 ;loads ADCL43 CPI R31,1 ;ADCH-1 might set CarryFlag44 BRCS 2 ;rjmp +2 if Cflag set , ADC count <25645 RETI46 NOP47 SBI 24,348 NOP49 OUT 40,R20

author: westfw
author_rank: Super Contributor
timestamp: October 05, 2024, 03:23:49 am
content: QuoteToo unreadable for me.What do you have against using a real assembler, with, like, labels and symbols and such?

author: T3sl4co1l
author_rank: Super Contributor
timestamp: October 05, 2024, 06:41:13 am
content: Doing it is completely bare assembly, you also need to set stack pointer.It's possible to do interrupts without register push/pop if you use exclusive sets of registers vs. main(), but you still need to save and restore SREG.Maybe you're doing that, I don't know, I don't remember the addresses. Using symbols is so much more descriptive.The sleep instruction is broken when an interrupt occurs; if your ADC source is set to do this, then the next instruction executed is the interrupt (RJMP and so on), and main() resumes on RETI. The timer either doesn't break sleep mode at all, or triggers the interrupt -- it's the same action. But you said that interrupt is RJMP to init? So it just resets the program. Maybe that's intended for such a short program, but it would be very unusual for anything more substantial.Tim

author: MathWizard
author_rank: Super Contributor
timestamp: October 05, 2024, 11:30:36 am
content: Yeah I should have added some comments, I've used ArduinoIDE, but I'm trying to see more what the lower levels are doing, so it's not just a void in my mind, but yeah I want to learn more semiconductor physics too.But really tho, taxcodes are some complicated, I'm worried people might be trying to hide them in my codes, or do their taxes in a shady way, using my MCU.OK I'll try and get just the ADC working, or the T/C, or the sleep command, before trying them together. And try something with the stack.I do see bytes getting written into RAM tho, I need to watch in the simulator, I'm not sure what would be doing that behind the scenes. None of it was around the top for the stack tho.

author: westfw
author_rank: Super Contributor
timestamp: October 06, 2024, 06:58:00 am
content: QuoteThat's going to make the simulator pretty useless for evaluating what you're trying to do, unless it does a really good job of documented what "fully" means...

author: MathWizard
author_rank: Super Contributor
timestamp: October 06, 2024, 01:11:05 pm
content: For the T/C interrupt, I don't get what the TIFR0 reg is doing. I'm mainly just using the ATTiny13A datasheet, not following guides. And it says the default is 0x00.But on the 2nd instruction, so the MCU starts in the sim, and RJMPS to W10 the EOR, and ALREADY, the OCF0A and OCF0B flags for CompareMatch A,B, are getting set HIGH. But not the TOVF.So later in the program I set GTCCR to hold reset, TCCR0A,B , OCR0A=100d, and TIMSK0 to only enable ISR for OCF0A.But then as soon as I enable Interrupts Globally, the TIFR0 already has OCF0A,B set high, so the PC jumps to W6 for the TIM0_COMPA ISR.So I added a line to set TIFR0 to 0x00, and the sim says it's 0 afterwards, yet again, as soon as do the SEI, even tho TIFR0 is all 0, AND THE GTCCR is still 1000 0001 for holding reset if I understand it correctly....the T/C isn't even running yet.....it still immediately jumps to TIM0_COMPA.I don't quite get what the datasheet says about setting flags high is the TIFR0. Everything I've read, I think they are active HIGH. Like in this page.https://web.ics.purdue.edu/~jricha14/Timer_Stuff/TIMSK.htmYet the datasheet saysQuoteBut an interrupt happens, leading to W6=TIM0_COMPA, when the MCU on it's own, sets both OCF0A/B HIGH on startup for some reason, or when I've set it them to 0, it still happens, while the T/C is held in reset, as soon as I allow interrupts globally.Now I'm still setting up the ADC for auto-triggering from COMP_A, before setting up the T/C, there I'm setting ADIEnable HIGH, and ADIFlag LOW. I'll try version without all that now.There has to be datasheets that explain all of this, I'll start checking some of the other ones I have just on the Timer.But what can be going on ??But another observation, in the sim, once the interrupt has happened after a SEI on Word35 in my current program, 0x24=36d gets stored to 0x9F, without me doing a PUSH.Ok I see if I write the TIFR0 flags all high, then they get reset to all low, right after, so I don't have that interrupt problem now. So I'll check the other flags for that issue too.Now to try getting the SLEEP working.

author: westfw
author_rank: Super Contributor
timestamp: October 06, 2024, 07:10:26 pm
content: QuoteYou should certainly set up the stack BEFORE you enable interrupts.But the tiny13 is one of the chips that automatically sets the SP to the last memory location, so you don't NEED to set it at all.(Old Datasheet (7/10) Page 11, section 4.5 "Stack Pointer"):This Stack space in the data SRAM is automaticall defined to the last address in SRAM during power on reset.QuoteInterrupts work like "rcall", and automatically push the (old) PC at the time of the interrupt (that's why the stack setup should happen before SEI)

author: MathWizard
author_rank: Super Contributor
timestamp: October 10, 2024, 08:12:18 pm
content: OK so when this SimulIDE version says SLEEP is not fully IMPLEMENTED, they mean the program/developers, have not finished making the SLEEP simulation, part of their program.I went off and fleshed out some stuff I'm doing with the ADC, and tried the sleep again last night, and started having a deja-vu about some other time, and some other problem where it was the sim or hardware that can't do want I want.I actually bought the Oshon AVR simulator, and it just stops at the sleep command, and never goes to an interrupt. I need to check the sim settings, and their documentation. Otherwise I'll just change the SLEEP to some count down or whatever, while waiting the few cycles for the ADC.But now I'm pretty sure I get the basics of the interrupts and returns from them, so I'm going to try my ADC program on a real chip. In the ADC ISR, I'm storing data each time, then once I get enough, it also calculates a bunch of averages. So I'll add an LED on/off and I should know.Otherwise, I'll get use sleep in a real C IDE like Arduino, and see whats in the resultant assembly code.I want to try outputting some data for 7-segment LED's, either doing it directly with multiplexing a few port pins, or outputting serial data to shift register's or a CD4026. I might even try doing basic I2C, and send LED data that way.But yeah, I really don't know how much memory all that would take, or how much RAM it would take.Soon enough I'll move back to C and those IDE's, and use library's for complex stuff like I2C.