Well, I've hit yet another problem. Everything was going great...until I tried to run all PWM channels at the same value. Apparently, that wasn't such a great idea :) I'm running the older version of the code, what's posted on the web, not the new suggestions Scott has made below. I'm sorry the post is so long, but I felt it was somewhat important to leave Scott's comments attached. Basically what I think is happening is that when all the counters roll over at the same time, each bit in the mask needs to be set, and it adds too many cycles to the ISR. So when I set all PWMs to 0xFF, instead of looking like almost a perfect 100% duty cycle, instead I see about a 50% duty cycle. And yes, it happens with 0xFE too, so it's not just a wacky end of range thing. So...the question is, what do I do now? I was thinking of perhaps splitting the channels up. Instead of having them all on 1 main counter, I could have 4 counters. They'd all increment in the ISR, but I'd preload them at the start with different values, and offset them. This would make my ISR much longer, but it would be a uniform longness, not based (as much) on concurrent roll overs. I guess another option would be to try Scott's updated 18F code below, but I think I'll run into similar problems as long as there are 8 roll overs occuring at once. I can't quite figure out exactly why this is all happening, my ideas above are educated guesses at best. The problem doesn't seem to occur as much with lower PWM values, but once I get significantly above 0x80 (halfway) things start to go odd. Below that, I'm getting the right pulse widths on most channels, but have some values that cause wierd things to happen with some channels and not others. That's why I leaning towards the seperate, offset main counters. Any comments? Am I even on the right track? Or am I so horribly wrong that it doesn't even make sense? Thanks :) Josh -- A common mistake that people make when trying to design something completely foolproof is to underestimate the ingenuity of complete fools. -Douglas Adams Scott Dattalo wrote: > > On Sun, 15 Dec 2002, Josh Koffman wrote: > > > Ok, sorry to dig up this old thread, but now that I actually go to > > integrate it into a project, I seem to have forgotten that perfect view > > of the solution I had a month ago :) > > > > I am looking to use the code at > > http://www.dattalo.com/technical/software/pic/pwm8.asm > > to do multiple PWMs on one chip. My basic question is...where and when > > do I update the PWM counters? I plan on putting the timer checking and > > updating in an ISR, and triggering it with a TMR0 interrupt. This will > > work on the first iteration, but once a counter has hit zero, doesn't it > > just start again at 255? Therefore, I would need to reload the value I > > want in the counter so that it will start to count down again. What if > > after: > > DECFSZ pwm0,F ;If the first counter has not reached 0 > > IORLW 00000001b ;then we don't want to turn it off. > > I add something to the effect of: > > check pwm0 for zero > > if zero, reload pwm0 with proper value > > This would still be in the ISR. How does this sound? Plausible? Am I on > > the right track? I'm using an 18f252 chip, so I was thinking about using > > the BZ (Branch if Zero) operand. I guess I would have to do a movf > > pwm0,f in order to trigger the zero bit. If only there was an > > instruction similar to TSTFSZ (Test f, skip if 0), but skip if not zero. > > Can having the branch operand in an ISR cause a stack overflow if I run > > too many of them? > > If you're using the 18F series then you can save an instruction: > > Instead of doing this (at the end of the routine) > > XORLW 11111111b ;Toggle the current state. > INCFSZ rising_edge,F ;If the rising edge counter has not > XORLW 11111111b ;rolled over then toggle them again. > ;Double toggle == no effect. However, > ;if the rising edge counter does roll > ;over then a single toggle will turn > ;the pwm bits on, unless of course the > ;pwm counter has just rolled over too. > > You save the instruction by: > > INFSNZ rising_edge,F > BRA UpdatePWMs ;When the rising edge counter rolls over > ; then update everything. > > MOVWF pwm_state ;Save the state > MOVWF PWM_PORT ;update the outputs > > RETURN > > Then: > > UpdatePWMs: > > ; (note the reversed order from above - this ensures the > ; pwm_port is written isochronously). > > MOVWF PWM_PORT ;update the outputs > MOVWF pwm_state ;Save the state > > ; copy the current duty cycles into counters > > MOVFF pwm0DC,pmw0 > ... > > RETURN > > Everytime the "rising_edge" counter rolls over, 17 extra cycles are spent > updating the PWM counters. However, the counters don't need to be updated > if nothing has changed (they just roll over). So you could save 15 > instructions by adding a flag: > > UpdatePWMs: > > ; (note the reversed order from above - this ensures the > ; pwm_port is written isochronously). > > MOVWF PWM_PORT ;update the outputs > MOVWF pwm_state ;Save the state > > BTFSS ShouldUpdate,bitn > return > > BCF ShouldUpdate,bitn > > ; copy the current duty cycles into counters > > MOVFF pwm0DC,pmw0 > ... > > ---- > > You can also dynamically adjust the PWM. However, this runs the risk of > creating an abrupt discontinuity. See the comments in the code (on my web > page) on how this can be done. > > ---- > > BTW, If you're using the 18F there's a way to save many instructions: > > DCFSNZ pwm0,F ;When the pwm counter reaches 0 > BTG PWM_LATCH,0 ;toggle it's output > > .... > > DCFSNZ pwm7,F > BTG PWM_LATCH,7 > > DCFSNZ rising_edge,F > NEGF PWM_LATCH,F ; tricky - drive all ouput highs. > > 18 cycles versus 23. > > The NEGF works because all of the outputs are cleared by executing a > single BTG (bit toggle) instruction every 256 iterations. At the end of > 256 cycles, all 8 outputs are cleared and the NEGF will turn them all back > on. Of course, this assumes that when the PWM engine was started that the > output latch was initialized to all ones. > > A slightly better ending: > > DECFSZ rising_edge,F > RETURN > > NEGF PWM_LATCH,F > > ; update the PWM's: > > BTFSS ShouldUpdate,bitn > return > > BCF ShouldUpdate,bitn > > MOVFF pwm0DC, pwm0 > ... > > RETURN -- http://www.piclist.com hint: The PICList is archived three different ways. See http://www.piclist.com/#archives for details.