Scott, again, thanks for your replies. I do understand the phase shifted counters idea. Thank you for the pointer to your webpage. I think I might be running into problems based on speed. I'm running an 18F252 at 10MHz, multiplied to 40MHz. I'm doing the PWM updating in the ISR, triggered by TMR0, which is running with no prescaler (ie as fast as possible). I though I had the problem narrowed down to the extra instructions created by all the counters rolling over at once. But I just tried using 0xC0 instead of 0xFF, and the same thing isn't happening. I honestly don't understand exactly what is happening. If I posted my adaptation of your code, would you be willing to look at it and see if I've made any big mistakes? I am updating the PWM counters only when the edge counter rolls over. In fact, I tried taking the updating code out, and replacing it with NOPs (to maintain time), and the problem still occurs. So I know it's in my counting/outputting, not my updating. I'd appreciate any help you, or anyone else can give me. I think my idea about having more than one edge counter is a bit flawed too, because (although extremely unlikely), if one selected the right values for each PWM channel, you could get them to roll over at the same time, and could give me the same problem. I will likely try this to be sure though. 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 Fri, 20 Dec 2002, Josh Koffman wrote: > > > 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 :) > > It should work just fine! > > > 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. > > There are a couple of enhancements to that code. Probably the biggest one > is that I suggested a "NEGF" instruction when I meant a "COMF" > instruction. I bet that is what's causing you the problems. Sorry about > that. > > > > > 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. > > It sounds like these roll-over counters are throwing you through a > while(1) loop. You may wish to read a brief description of the pwm > algorithm here: > > http://www.dattalo.com/technical/theory/pwm.html > > > > > 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? > > In the original routine there are 8 counters for the 8 pwms, 1 counter for > the rising edge and there's one variable for the current state of the pwm > outputs. None of these should be changed while the program is running! The > other day we discussed a method by which the 8 pwm counters could be > dynamically changed. Recall that this require 8 new variables that get > copied to the 8 pwm counters when the rising edge counter rolls over. > > Let's look at the roll over issue in a little more detail. From my web > page I write: > > RE |---------|---------|---------|---------|--------- > 01234567890123456789012345678901234567890123456789 > > FE ----|---------|---------|---------|---------|----- > 67890123456789012345678901234567890123456789012345 > > PWM ----______----______----______----______----______ > > RE = Rising Edge counter > > FE = Falling Edge counter > > PWM = PWM output > > In this example, the counters roll over after 10 counts. In the beginning, > the rising edge counter is cleared and the output is driven high. Also, > the duty cycle is 4 so the falling edge counter is initialized to (10 - 4) > = 6. When the rising edge counter counts from 9 to 10, it is "rolled over" > back to zero and the output is driven high. Similarly, the falling edge > counter drives the output low when it rolls over. > > Perhaps one thing to notice is that the difference (modulo 10) between the > two counters is always equal to the duty cycle. That's no coincidence. In > fact that's why this technique is called the "Phase Shifted Counters". > > -------------- > > You describe the boundary condition of the pwm counters = 0xff. Let's look > at that for one pwm. This table illustrates what happens: > > rising pwm > edge counter output > ------------------------- > 0 ff 1 > 1 fe 1 > 2 fd 1 > ... > fe 1 1 > ff 0 0 > 0 ff 1 > > Can you try this in a simulator to verify that it's true? > > Now for code. You've got the routine on my web page. Here's a version that > saves an instruction (and still works for the 14-bit core devices): > > MOVF pwm_state,W ;Get the current state of the pwms. > ;We assume that the PWMs are not changed > ;on this cycle > ; > ; > DECFSZ pwm0,F ;If the first counter has not reached 0 > ANDLW 11111110b ;then we don't want to turn it off. > ; > DECFSZ pwm1,F ;Same for the second one > ANDLW 11111101b ; > ; > DECFSZ pwm2,F ;and so on... > ANDLW 11111011b ; > ; > DECFSZ pwm3,F ; > ANDLW 11110111b ; > ; > DECFSZ pwm4,F ; > ANDLW 11101111b ; > ; > DECFSZ pwm5,F ; > ANDLW 11011111b ; > ; > DECFSZ pwm6,F ; > ANDLW 10111111b ; > ; > DECFSZ pwm7,F ; > ANDLW 01111111b ; > ;At this point, W contains a bit > ;mask of all PWMs that need to be > ;cleared > ; > ; > INCFSZ rising_edge,F ;If the rising edge counter has not > GOTO drive_pwms ;reached zero then drive the next state > ; > MOVLW 11111111b ;Drive all pwms high > MOVWF pwm_state ;Save the state > MOVWF PWM_PORT ;update the outputs > > ; update the pwm counters here. > > RETURN > ; > drive_pwms: ; > XORWF pwm_state,W ;Clear the outputs that have changed > MOVWF pwm_state ;Save the state > MOVWF PWM_PORT ;update the outputs > > RETURN > > ---------- > > The code I posted for the 18f instruction set last time directly modifies > the output latch. This is bad because it means that there's a skew in the > pulse widths of the PWMs. So here is a correction: > > PWM_LATCH EQU LATB ; assume port b is the output port. > > COMF PWM_LATCH,W ;Get the complement of the current state > ;of the pwms. We assume the pwms will > ;change this iteration. > ; > ; > DECFSZ pwm0,F ;If the first counter has not reached 0 > ANDLW 11111110b ;then don't turn it off. > ; > DECFSZ pwm1,F ;Same for the second one > ANDLW 11111101b ; > ; > DECFSZ pwm2,F ;and so on... > ANDLW 11111011b ; > ; > DECFSZ pwm3,F ; > ANDLW 11110111b ; > ; > DECFSZ pwm4,F ; > ANDLW 11101111b ; > ; > DECFSZ pwm5,F ; > ANDLW 11011111b ; > ; > DECFSZ pwm6,F ; > ANDLW 10111111b ; > ; > DECFSZ pwm7,F ; > ANDLW 01111111b ; > ;At this point, W contains a bit > ;mask of all PWMs that need to be > ;cleared > ; > ; > INFSNZ rising_edge,F ;If the rising edge counter has rolled > COMF PWM_LATCH,W ;over, grab a complement of the current > ;state of the outputs > ; > XORWF PWM_LATCH ;update the outputs > > TSTFSZ rising_edge > RETURN > ; > > ; update PWM counters here. > > RETURN > -- http://www.piclist.com hint: The PICList is archived three different ways. See http://www.piclist.com/#archives for details.