SparkFun Forums 

Where electronics enthusiasts find answers.

Have questions about a SparkFun product or board? This is the place to be.
By Tomasu
#40476
I have a good feeling my little blips of brightness are coming from the fact that the timer interupts the update code multiple times. I've managed to get the blips to all sync up by making sure the timer never updates the shift register while the main code is updating the data.

After looking at the math and the generated code, I've realized that my timer code is way to large. The timer is set to go off after about 390 instruction cycles, each time. And I'm pretty sure the timer code itself is longer than that after its all done updating all 8 bits of the shift register.

I can tell you one thing, even in release extended instruction mode, the code C18 generates seems to be a little verbose.

So far I've implemented my software PWM in two parts, the pwm code itself it run from a timer interupt every MCU_IPS/PWM_PERIOD (390) instruction cycles (timer ticks). And the main() loop updates the pwm data on a delay.

What would be the recommended way of doing this? The way I've come up with isn't working as well as I'd hope. Does anyone here have any recommendations?
By mpanetta
#40480
saipan59 wrote:
No, the AVR is pipelined (so it's fetching the next instruction as the current one is executing) to get higher throughput per clock. Regardless of how they do it - whether it's pipelining or an internal multiplier - the lower frequency you have on your PCB, the more forgiving it will be to lay out (which is something important when you're starting out).
Mid-range PICs have a two-stage pipeline described in their docs. So again, I'm saying that there's not a heck of a lot of difference between the brands, unless we get specific about some detailed requirements. It's not adequate to say "an AVR does 12 MIPS", and draw any real conclusions from that. You have to look at real throughput doing whatever your application requires. For example, blinking LEDs (as discussed in this thread) may use resources that are largely unrelated to a "MIPS" rating.
I am admittedly a PIC bigot because that's where I've got my experience and investment.
I do agree with you about the lower frequencies on the board, but I'm thinking that any of the major MCU brands will let you achieve that.

BTW, it seems unlikely that this LED-blinking application requires particularly high processing speeds. So it might be more useful to choose an MCU based on things like on-board PWM controllers and general-purpose I/O pins and such.

Pete
As an Anti-PIC bigot (I hate them and would rather use an 8051! :P) I believe your conclusions are false. AVR's are faster then PICs in general because it takes less instructions to do the same thing on an AVR as it does on a PIC. Main reason is the PIC only has one (general purpose) working register, and the AVR has 16. Manipulating anything in the PICs memory is a real *****, and just multiplying 2 numbers in RAM together take several loads and stores, where on an AVR it would take 3. Just look at the assembly listing of some simple C statements on PIC vs AVR and you will see what I mean. Even the hand coded PIC 16 and 32 bit multiply routines I have seen are larger then the ones for the AVR (MEGA AVRs at least). AVR's really do have a single clock instruction cycle, and there are no PLL's or whatever in them (if there are then all the AVR datasheets lie about instruction cycle time!).

Basically PIC's are extremely inefficient at running C code because of design. This is understandable, as they were created in the 70's as an IO/support processor for larger computers, and they were designed to do limited tasks that were more then likely written in assembly.

The only real alternative to a PIC I have seen from Microchip has been the dsPIC, which really is not a PIC at all, its been optimized for C compilers like the AVR was (it has multiple working registers, C compilers work best when there are more working regs available, look at all the hoops they had to jump through to get GCC to work on the Motorola/Freescale HC11/12 series), and the ISA seems to be completely different.

Actually the dsPIC looks like a pretty nice chip, but I, just as a self imposed thing because I am a 'Cheap Ba$tard' (TM) and I don't want to buy a compiler, won't use them until GCC is ported.

Oh, and as for the processor speed thing, it looks like he wants to do the LED PWM in software, so yes it will require quite a bit of processor speed.
User avatar
By leon_heller
#40482
There is a free student version of the Microchip C30 compiler for the dsPIC, it's only missing some optimisations and large memory models.

Leon
By oPossum
#40484
mpanetta wrote:Main reason is the PIC only has one (general purpose) working register, and the AVR has 16.
The 18F series PICs have a 256 register window. Any two 128 register banks out of the entire register space can be selected. This is generally much more efficient than having to shuffle data between a few registers and RAM. On the PIC registers and RAM are the same, on the AVR they are not.
Manipulating anything in the PICs memory is a real *****, and just multiplying 2 numbers in RAM together take several loads and stores, where on an AVR it would take 3.
8 bit multiply of any two registers (x and y) in two instructions...
Code: Select all
movf X,W
mulwf Y
Even the hand coded PIC 16 and 32 bit multiply routines I have seen are larger then the ones for the AVR (MEGA AVRs at least).
So how fast do they run? Can they be optimized? An unrolled loop is larger, but also faster!
AVR's really do have a single clock instruction cycle, and there are no PLL's or whatever in them
They can do this because they are pipelined. Consider what happens when the pipeline is purged!
Basically PIC's are extremely inefficient at running C code because of design.
They are as capable as the C compiler. Unfortunatly there are many bad C comilers for the PIC.
The only real alternative to a PIC I have seen from Microchip has been the dsPIC, which really is not a PIC at all
There are also PIC with a MIPS core and GCC support. The range of PICs is very diverse, much more so than the AVR.
By oPossum
#40485
Tomasu wrote:After looking at the math and the generated code, I've realized that my timer code is way to large. The timer is set to go off after about 390 instruction cycles, each time. And I'm pretty sure the timer code itself is longer than that after its all done updating all 8 bits of the shift register.
Can you use the hardware SPI? It runs at osc/4 - much faster than software SPI.
I can tell you one thing, even in release extended instruction mode, the code C18 generates seems to be a little verbose.
The Microchip C18 compiler is quite bad at optimization. At least is generates good code (unlike some others).
What would be the recommended way of doing this? The way I've come up with isn't working as well as I'd hope. Does anyone here have any recommendations?
Double buffer the data. Have the main code put data in one buffer, set a flag, and wait for the flag to be cleared. The ISR will output the other buffer and then check the flag. If the flag is set, it will copy one buffer to the other and clear the flag.
By Tomasu
#40494
oPossum wrote:
Tomasu wrote:After looking at the math and the generated code, I've realized that my timer code is way to large. The timer is set to go off after about 390 instruction cycles, each time. And I'm pretty sure the timer code itself is longer than that after its all done updating all 8 bits of the shift register.
Can you use the hardware SPI? It runs at osc/4 - much faster than software SPI.
Not witht he dev board I have. one or more of the SPI ports are "borrowed" for something else, pics like to share pins with different peripherals.
oPossum wrote:
I can tell you one thing, even in release extended instruction mode, the code C18 generates seems to be a little verbose.
The Microchip C18 compiler is quite bad at optimization. At least is generates good code (unlike some others).
True, the code runs fine,
oPossum wrote:
What would be the recommended way of doing this? The way I've come up with isn't working as well as I'd hope. Does anyone here have any recommendations?
Double buffer the data. Have the main code put data in one buffer, set a flag, and wait for the flag to be cleared. The ISR will output the other buffer and then check the flag. If the flag is set, it will copy one buffer to the other and clear the flag.
I'll give it a shot, its a minor change, but may help. And is clearly better than the flag I have set and unset around the main loop...

.... (some time later)

I've done that now, It's helped a little, but I still get "blips" in the brightness once in a while. And I can still see the "refresh". It should be running at near 30khz (120hz update * 256 levels of brightness - however long it takes to update itself).

... (more time later)

I think the blips may be caused by small surges in voltage. but the visible (albeit slightly) refresh is annoying.
By winston
#40525
oPossum wrote: There are also PIC with a MIPS core and GCC support. The range of PICs is very diverse, much more so than the AVR.
That's not really a PIC though, is it: that's a MIPS core in a microcontroller package, which is a completely different beast. There's also a 32 bit AVR. But we're discussing the 8 bit MCUs specifically here. Intel also has the Itanic, but we don't consider that when comparing the merits of, say, Intel's ia32 offerings vs AMD's ia32 offerings.