A question of style... clarity or not?

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

Inspired by the recent discussion of video generation by AVR, I am knocking together a demo application. Basic theory is to run a counter at 64uS which triggers the line sync and output generator as an interrupt, and a match at 63uS which puts us to sleep beforehand to ensure a consitent delay between timeout and interrupt.

The polite way to do this:

// here at 63us
sleepy_head:
	sei
	sleep
	reti
	
// and here from sleep at 64us
syncs:
	// do stuff
	reti

Which, after the syncs interrupt finishes, retis back to sleep_head which retis back to the main loop.

Alternatively...

// here at 63us
sleepy_head:
	sei
	sleep
	//reti
	
// and here from sleep at 64us
syncs:
	// do stuff
	pop iarg0
	pop iarg0
	reti

Now, instead of the double reti we lose the sync return address and the syncs' reti returns to the sleepy_head's return address. It takes just as long (4 cycles per reti, two cycles per pop) but somehow it feels a shade more elegant, given that the two interrupts are so closely coupled. Note that the sleepy_head routine is *complete*; there's no processing required there except to re-enable the interrupts.

Should I be run out of town on a rail, have my programmer's license revoked, pay a fine? I really can't decide... :shock:

Neil

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

I'd do it just because it is an assembly trick that can't really be done in C :D

Regards,
Steve A.

The Board helps those that help themselves.

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

Getting to play with the stack is one of the perks of assembly language - go for it. You might even get a Samperi for it (sort of like an Academy Award, only covered in wrinkles instead of gold).

As for the "can't really be done in C" - where's Lee?

Chuck Baird

"I wish I were dumber so I could be more certain about my opinions. It looks fun." -- Scott Adams

http://www.cbaird.org

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

Quote:
As for the "can't really be done in C" - where's Lee?

I saw it, and thought about it for a bit. Given the RETIs it looks like we are in an ISR, and I'd never (or at least I've never) tried to go to sleep inside an ISR.

Now, in FORTRAN or COBOL it would be easier, right, 'cause there are facilities for multiple entry points into a function?

I can't grasp the entire context. It would seem that the same thing could be accomplished by leaving the first ISR and going to sleep in the mainline?

Now, protothreads kind of do this with Duff's device, right? But the switch/case overhead may be too much.

I don't fully grasp it. I thought that if you use a wakeup source then the IE bit for that source had to be set. So after coming out of sleep you are going to execute one instruction, the first POP above, and then take the vector, right?

Lee

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

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

Okay, the only interrupts are comp match a and b on timer 1. Timer 1 is in CTC at 64uS set through comp a and with 63uS on comp b. So at 63us we go to sleep, and at 64us we wake up again - the cpu wakes up at the interrupt but executes the interrupt before it executes the reti (original version). That shoves it across to the syncs interrupt with a constant offset from the timer CTC tick.

I can't return from the first interrupt; I'm asleep. That's the whole point - the first interrupt *gets* me asleep so the second interrupt can wake up. That saves me a whole heap of troubles having to arrange the main routine in short routines that can end in sleeps; it happens automagically.

Neil

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

Great.

What about this ?

// here at 63us 
sleepy_head: 
   disable 'unwanted' interrupts
   sei 
   NOP
   NOP
   NOP
   NOP
   NOP
   NOP
   NOP
   NOP
   NOP
   NOP
   NOP
   NOP ; min 14 NOP for 20MHz
    
// and here from sleep at 64us 
syncs: 
   // do stuff 
   enable 'unwanted' interrupts
   pop iarg0 
   pop iarg0 
   reti 

Angelu.

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

angelu wrote:

nop
... ; 14 NOPs total
nop


To delay 2 or more cycles, it's more efficient to use rjmp's since they use half the flash space. So,

; delay 14 cycles
    rjmp j1
j1: rjmp j2
j2: rjmp j3
j3: rjmp j4
j4: rjmp j5
j5: rjmp j6
j6: rjmp j7
j7:
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:
To delay 2 or more cycles, it's more efficient to use rjmp's since they use half the flash space.
Can an rjmp be interrupted during the 2 cycles? I can't remember for sure and don't feel like looking it up right now...

But I think that is the whole point of the sleep mode trick or the series of NOPs. It is to make sure the interrupt happens at the exact time required and is not delayed by potentially being in the middle a multi cycle instruction.

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

Quote:
It would seem that the same thing could be accomplished by leaving the first ISR and going to sleep in the mainline?
When I have done similar tricks in the past, that is the way I did it, just go to sleep at the end of the main loop. The only advantage I can think of for the double ISR is that you can use up as many cycles as possible while still getting perfect timing for the ISR.

As for the original question, I think I prefer the first code snippet. If there is no performance advantage to the second, why bother with the less clear stack manipulations?

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

kevin123 wrote:
Can an rjmp be interrupted during the 2 cycles? I can't remember for sure and don't feel like looking it up right now...
Good question! Information about interrupt latency is in a device's datasheet, I'm not sure if latency may vary across AVR models.

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

barnacle wrote:

... clarity or not?

Neil

Diverging from the essence of the discussion to date and returning to the title of your thread Neil, I would always vote for clarity especially with an unreliable memory and less than rigorous documentation.

However if you are intent upon securing your employment against the onslaught of competitors, obfuscation may be your best form of protection ... :roll:

Cheers,

Ross McKenzie ValuSoft Melbourne Australia

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

Quote:
Can an rjmp be interrupted during the 2 cycles?
No.

I prefer the first, since there is no advantage to the second.

I don't know if it makes any difference, but I think I would want that first irq to be of higher priority in case you are ever late for them (so they don't end up swapped around? not sure).

If you were really clever, you would change the interrupt vector table-

the first irq jumps to sleepy_head
the second irq pops 2 times (in the vector table), then jumps to syncs

if you had an 'rjmp' avr, you would need 2 unused irq vectors after the syncs vector, if a 'jmp' avr, only 1

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

I have concluded that the first one is the way to go. Though as a sneaky awkward beggar, I'd *like* to do the complicated one, I think that as the program is demoing accurate timing and not clever stack manipulation, I should stick with the more obvious, even though it *seems* more complex.

Angelu, your method doesn't work for me; there's no practical difference between that and simply hitting the interrupt on the CTC tick anyway; the timing can vary - depending on what the processor is doing - by up to four cycles and that's not acceptable. From sleep, the delay between the interrupt occurring and the routine starting is longer but always the same. There is time after the sleep starts to accommodate the variable delay.

Curtvm, there's no way the syncs interrupt can occur before the sleepy_head interrupt (without a major glitch!) since they are both triggered from a rising count on the same counter, and sleepy_head's comparison happens first.

Kevin, the idea is indeed to get as many cycles as possible in the main loop while still maintaining the accuracy.

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

I really like this idea, and if I ever get the time to return to my video project, I may well steal it. I was overlaying text on an external video source, so obviously there's going to be a bit of jitter without a PLL, but I like the idea of freeing up the foreground process.

Four legs good, two legs bad, three legs stable.

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

I'm half-way through the sync pulse processing at the moment; I can poll the serial port and save into a circular buffer in the sync pulse, so the main routine just needs to compare read and write pointers.

Alberto Riccibitti's original video source - at 4MHz, yet! - interrupted four times a line, if I recall correctly...

John, phase locking to reasonably stable video is a doddle; use a sync separator chip, a 4060 PLO, and a divide to bring your chosen frequency to 15.625kHz (64us). This works very well; in the eighties and nineties I was producing video to overlay on broadcast signals this way for the Beeb.

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

Quote:
John, phase locking to reasonably stable video is a doddle; use a sync separator chip, a 4060 PLO, and a divide to bring your chosen frequency to 15.625kHz (64us). This works very well; in the eighties and nineties I was producing video to overlay on broadcast signals this way for the Beeb.

I know, but I have to say that a half pixel jaggy was hardly noticeable (at least on the antique 9 inch Hitachi B/W monitor I was using for testing!). Also there's something deeply satisfying about minimum hardware solutions. You may recall an earlier thread where I was atempting to "pull" the crystal by various means to achieve a phase lock. I didn't have much success, but I still think it might be possible.

Four legs good, two legs bad, three legs stable.

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

Quote:

If you were really clever, you would change the interrupt vector table-

Upon further reflection, I >>do<< have the capability to roll my own vector table with my compiler, and could in fact do it in C with some ugly stuff like placing flash "constants" (in reality program words) at specific addresses.

Lee

Quote:

As for the "can't really be done in C" - where's Lee?

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.