# Tiny ASM: PWM LED brightness

#### Mosaic

##### Well-Known Member
Code:
Brightness; S'ware PWM (uses 3 GPRs) on a 3 bit (8 step)  base, LEDdrive GPR bits 0,2 are the common anodes in this case. At about a 1.37ms prg loop speed (my app. prg)  100% DC period is  11mSec or 90Hz refresh.
incf LUXCTRL,w; 100% DC timebase. GPR register
andlw .7; lower 3 bits
movwf LUXCTRL; range 0-7.
subwf LUX_setpt,w; Brightness PWM setting, GPR register. Range = 0 (12.5%) thru 7 (100%) for dimmest to brightest.
movf LEDdrive,w; buffer GPR register for common anodes avoids Read Modify Write issues.
iorlw b'00000101'; set B0 & B2 as hi by default
skpc
andlw  b'11111010'; disable active common anodes if no carry.
movwf  LEDport; mapped to actual pic PORT, eg #define LEDport    PORTB
return
So for the first bit of code to stand alone I am adding an instruction to preset the b0 & b2 to high by default...which drives the LED anodes.

#### NorthGuy

##### Well-Known Member
Only the first 'slow' PWM code changes B0,B2.
It only changes the bits of the actual port, but it doesn't modify LEDdrive. Therefore, bits #0 and #2 in LEDdrive never change. The fast code copies these 2 bits from LEDdrive to LEDport every 10us.

When u say that the first bit of code sets b0,2 high, no it doesn't.
I din't say that. I said it only works if you set them to 1. I see you fixed this with the new code.

However, your new code still doesn't modify LEDdrive, but the fast code overwrites LEDport's bits with the bits from LEDdrive. So the bits set by slow code in LEDport won't stick for longer than 12us.

#### Mosaic

##### Well-Known Member
Yes that's true, for this code to 'stick' there needs to be a 'movwf LEDdrive' to keep the buffer updated. If that is the concern. The write to LEDdrive needs to be included otherwise it won't work with other LEDdrive updates. Like this:
Code:
Brightness; S'ware PWM (uses 3 GPRs) on a 3 bit (8 step)  base, LEDdrive GPR bits 0,2 are the common anodes in this case. At about a 1.37ms prg loop speed (my app. prg)  100% DC period is  11mSec or 90Hz refresh.
incf LUXCTRL,w; 100% DC timebase. GPR register
andlw .7; lower 3 bits
movwf LUXCTRL; range 0-7.
subwf LUX_setpt,w; Brightness PWM setting, GPR register. Range = 0 (12.5%) thru 7 (100%) for dimmest to brightest.
movf LEDdrive,w; buffer GPR register for common anodes avoids Read Modify Write issues.
iorlw b'00000101'; set B0 & B2 as hi by default
skpc
andlw  b'11111010'; disable active common anodes if no carry.
movwf  LEDport; mapped to actual pic PORT, eg #define LEDport    PORTB
movwf LEDdrive; keep buffer updated.
return
That is another artifact of the LEDdrive was updated with the anode bits before entering this routine. That is moot now since the anode bits are only changed to low based on the slow PWM.

It seems I left out two instructions that made the difference. So I see the issue now. It wasn't a global issue with the buffer approach it is a local one with the code snippet? Is that right?

Last edited:

#### NorthGuy

##### Well-Known Member
It seems I left out two instructions that made the difference. So I see the issue now. It wasn't a global issue with the buffer approach it is a local one with the code snippet? Is that right?
I think so.

It also would be nice to safeguard it against interrupts happening in the middle of the operation (somewhere around skpc instruction), but I don't think it's feasible in PIC16.

#### NorthGuy

##### Well-Known Member
It seems I left out two instructions that made the difference. So I see the issue now. It wasn't a global issue with the buffer approach it is a local one with the code snippet? Is that right?
I think so.

It also would be nice to safeguard it against interrupts happening in the middle of the operation (somewhere around skpc instruction), but I don't think it's feasible in PIC16.