Changing interupt vectors

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

When I'm using interrupts the vector table is in the very beginning of code and from that point I think the vectors are hard coded. But is there any possibility to change the interrupts vectors on the fly with software? I think it could be possible to create one common interrupt and then hi could jump on different addresses, but I'm trying to create as fast and accurate sw PWM as I'm able to.

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

The vectors are hard coded, but there is no reason for your ISR() to not have indirect jumps.

Since the AVR is quite well suited to creating PWM with its own hardware, why do you want a software PWM?

If you require more PWM channels, then presumably the "motor-control" AVRs would be your best choice.

David.

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

This seems like a case that may benefit from stepping back to look at the final application for a moment. First, what is the PWM used for? Is it motor control, LED dimming, signaling? How fast does the PWM need to be and of what resolution? Once such questions are answered, given those answer, is there still a need to do interrupt redirection?

In my software PWM code I have optimized everything I could think of ( algorithmic only, I could shave a bit off by making an ASM interrupt ) and it did not include attempting such redirection. So the question is, is there some other requirement that you have?

Martin Jay McKee

As with most things in engineering, the answer is an unabashed, "It depends."

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

You can switch to a second set of interrupt vectors inside the boot section.

Peter

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

Quote:
I'm trying to create as fast and accurate sw PWM as I'm able to.

How is adding extra jumps going to make the code faster?

Regards,
Steve A.

The Board helps those that help themselves.

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

I'm controlling LEDs, I want to make it faster so I will be able to make higher resolution, I would to go near 16bits, perhaps I will got to 12bits, but it could be much acceptable than 8bits. And get to great refresh rate on 30chanells on Mega16 at 16Mhz.

I want to change vector because I don't want to make jumps (to save every possible cpu tick as possible).

Now I got to 292 950 cpu clocks per second needed for 8bit 8 channel pwm running at refresh 1953Hz (almost 2Khz with 500Khz base frequency) with variable duty. That is 1.830% cpu usage. And the cpu usage is almost the same with more channels.

The problem is I'm using different algorithm and it's not dependant on channels etc.. but I'm challenging different problems. In some points I need get very fast from the interrupt, at that place now I got in 21 clocks but if I could get it much faster I could get another benefits from it and move more goodies in it (better resolution at good refresh and more channels).

I want have the best channel/price ratio, if somebody know very cheap widely available pwm chip I could scrap the project.

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

Cheap widely available PWM chip for LED's is the TLC5940. 16 channels $4.73 in single piece quantities from Digikey. It is 12bit, and has a maximum clock of 30MHz, so it could be easily used in a multiplexed configuration.

If you must do it via software BCM (bit code modulation) [also known as BAM - Bit Angle Modulation] is a good method, though the LSB's can be tricky, if you need a very high PWM rate, and high precision. At 16Mhz 12 bit is very doable, 16bits is pushing it. But there is no need to change vectors, as the display ISR runs exactly the same, no matter what bit you are outputting. The only thing that changes on each pass, is the time to the next interrupt.

Writing code is like having sex.... make one little mistake, and you're supporting it for life.

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

Thanks for the tlc5940 i saw it on the forum already, but I tried to get som on ebay but I could not get it. So then I tried the sw pwm. I'm in irealnd and here is absolutely weakest background and business for hobby electronics, I'm Slovak by origin and this was absolutely disappointing for me. I will try to get them from the UKs digikey.

Exactly I'm doing it with bcm and I'm fighing with the LSBs to save every cpu cycle I could.

What you are describing is to calculate things on every bit and do the ISR almost the same calculation. First it's doing lot of necesary work on every bit and testing something that will be true just on the last bit etc...
I premade rutines for every bit, for example bit 6 pushes 64 to CTM already, when you calculate that you first loads the CTM the shifts to left then stores CTM then every single bit you are checking if the CTM needs to reset to 1 again etc... now I'm doing just the necesary minimum for every bit and i got to 20 cycles for bits 0-6 and 24 cycles for bit 7 if the duty is the same and 43 cycles if the duty is changing. because the LSB is 20cycles i'm using DIV 32 on timer so I have 500kHz base frq., but if I could skip the jumps I could go under the 8cycles to have 2Mhz base frq. Most of the 20cycles are just things around the jump and return from the interupt, storing registers etc... and the real work is just fraction of the 20 cycles. So I'm looking to get rid of the overhead from the 20cycles routine and the jump could help very much.

If somebody know how I could swap the whole irq table for different copy (with diferent vector for my timer) I would be very thankful.

I would like to try the changing of vectors first, then as the alternative I will join couple of LSBs into one interupt and time them manualy.

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

I fail to see how vectors play a part in this.

If timing is so mega critical you should use assembly for your ISR so you have absolute control over what's done.

What about not using interrupts at all and just using the interrupt flag to synchronize things?

I once had an application (not on an AVR) where the interrupt handling overhead was so big the system spent more time handling interrupts then doing useful work. I went with polling interrupt flags and spin locks and that worked much better.

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

Yes that the another way to make own irq system but it won't work under 20 cycles, at least not with BCM.

It's already made in asm, the C code produced about 100cycle ISR and I shrieked it to 20 so now I can use DIV32 and now I'm pushing it to the limits even more. To get it working on perhaps DIV8.

Sorry for my english, I'm not able to explain exactly why it's so important for me. I need to get 20cycles routine get even smaller and the option to change vector could that. I don't want to do it with different aproach wich will take much more thatn 20 cycles.

Just please tell how I could swap the irq table. :)

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

If you don't use the adjacent interrupts vectors you can start your ISR right at the interrupt vector, this will save a jmp.

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

truhlik_fredy wrote:

If somebody know how I could swap the whole irq table for different copy (with diferent vector for my timer) I would be very thankful.

As you were told before, you cannot swap interrupt vectors on the fly. You could create a dynamic interrupt, but this will happen at the cost of an additional jump.

There is one exception to the above. If the AVR you are using supports self-programming (most models do now), then you could twiddle the IVSEL bit to flip between the normal vector table at 0x0000, and the bootloader interrupt table at the start of the bootloader block (as defined by your fuses). This will work fine, as long as you don't have a bootloader installed.

Writing code is like having sex.... make one little mistake, and you're supporting it for life.

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

truhlik_fredy wrote:
Yes that the another way to make own irq system but it won't work under 20 cycles, at least not with BCM.

A mainline routine with a polling loop is going to have less overhead than an interrupt.

Also note that for the LSB's you can run hard-coded code sequence to output those bits, and then once the bit time is long enough enter into a normal single interrupt per bit mode.

consider something like this:

interrupt:
  if bit<4
    output data[0];
    wait delay 1x;
    output data[1];
    wait delay 2x;
    output data[2];
    wait delay 4x;
    output data[3];
    bit = 4;
    timer_value = delay 8x;
  else
    output data[bit];
    bit++;
    timer_value *= 2;
  end if;
end interrupt;

the above code outputs the first 4 bits through a hardcoded timed sequence, all other bits are output as normal. The effect is that you get one single long interrupt for the first 4 bits, instead of 4 short ones. By doing this you any and all the interrupt overhead associated with 3/4 of those bits.

Also, as you said this is for LED's... don't be so concerned with exact timing. The human eye is very tolerant to slight deviations. So even if the LSB's run a bit longer than they should, the eye will likely never perceive the error.

And finally there is no reason this cannot be done in C, especially when considering my approach of hardcoding the "fast" sequence, and the fact that a few cycles of deviation is not going to matter.

Writing code is like having sex.... make one little mistake, and you're supporting it for life.

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

jayjay1974 wrote:
If you don't use the adjacent interrupts vectors you can start your ISR right at the interrupt vector, this will save a jmp.

That is not so bad idea :)

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

glitch wrote:
truhlik_fredy wrote:
Yes that the another way to make own irq system but it won't work under 20 cycles, at least not with BCM.

Also note that for the LSB's you can run hard-coded code sequence to output those bits, and then once the bit time is long enough enter into a normal single interrupt per bit mode.

And finally there is no reason this cannot be done in C, especially when considering my approach of hardcoding the "fast" sequence, and the fact that a few cycles of deviation is not going to matter.

Yes I mentioned before that perhaps I should try to join couple LSBs and time them maualy. (when i fail to change the vector)

And when I'm looking on the discussion joining the LBSs is much better and easier than very tricky change of vector.

Thanks you very much, I will try it today, I will let you know with update. :)

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

I got update.
I joined first 4 LSB bits, in assembler timed.
Then the whole day tried to debug it :)
But it's working on DIV 8, so on 16Mhz mega it's 2Mhz base frq and with 8bits 16 leds on 7.8Khz refresh.

Next I will try to move from 8bit timer2 to 16bit timer1 and rise the resolution.

First when I was reading documentation on Megas CTC timmer I thought that the timer is zeroed imieadetly when compare match occurs, but when I was debuging it, it looked like the zeroing happens just right next timer clock after that, so in this case 8 cpu cycles away, it's realy so?

Now it's working nicely (observation by eye), but I think it makes 1 timer tick more than it should. Perhaps I should decrement the top value by 1 to compensate it.

And second thing, when the compare match occurs, how long takes to execute the 1st instruction in ISR? I think it's takes little bit to finish actual instruction and the just 3 cycles for JUMP in vector table. I'm right?

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

Quote:

Now it's working nicely (observation by eye), but I think it makes 1 timer tick more than it should. Perhaps I should decrement the top value by 1 to compensate it.

That's a common "gotcha" with CTC - if you want 500 "ticks" you set OCR to 499 and so on.

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

clawson wrote:

That's a common "gotcha" with CTC - if you want 500 "ticks" you set OCR to 499 and so on.

Thanks.

BTW I have new update, "couple hours" more spend with asm and debuging but now the base frequency is 8Mhz and it's doing 10bit on 16channels with almost 8Khz, and now I was able to put multiplexing to play, 48channels (multiplexion between 3) still on 2Khz. So now the mega16 can control array of 4x4 RGB leds and every led has 2Khz refresh. The cpu usage it's much much higgher, but it's funny now because when I raise resolution then I have much lower cpu usage (it's because the 7 LSB are joined and just the rest of bits leavening some time to do CPU something else).

Now it's time to play little bit of multiplexing and resolutions. I made table in excel what refresh on how many leds on witch resolution I will get.
For example 8x4=32 leds=96 channels multiplexing on 11bits will have 558Hz refresh
But 8x8=64leds=192channels multiplexing on 10 bits is 601Hz almost the same like 8x4 on better resolution.

I wanted to have 12bit but on desirable numbers of LEDs it have usually about 200Hz.

Guys do you know minimal acceptable refreshes for stationary leds, then for moving objects? And how the multiplexing will affect the refresh requirements? I think when the led will be off for 11/12 of the time it will have different effect on leds not multiplexed on same refreshes.

But it think the fundamentals are done, just I need the best ratio of resolution and channels (on both apply:more is better). Already have done some effects processing inside, but later I want there HSV and RGB controls. Gamma and white balancing already done. Just left to do some communication routines (prehaps SPI) and moving it on Mega8 HW. Lot of work to do, but lot of work already done. :) Wish me luck :)