Continue to Site

Welcome to our site!

Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

  • Welcome to our site! Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

Software PWM for 128 led matrix + [video]

Status
Not open for further replies.

tubos

New Member
See Page 3 for latest video

I'm doing all multiplexing and pwm in a an ISR.
I can get to 16 step pwm per led with a framerate
of about 60.

How can i improve my code to get more pwm depth?

its a basic hardware setup:
-74595 for green cathodes & 74595 for red cathodes.
-8 anode rows from a PIC 8bit port buffered with transistors.
-PIC in video is PIC16F886 now I'm using an 18F14K22
PIC running at 64 Mhz (16mips) see code below

Here's a video at 8 PWM levels / pixels:


Code:
if(INTCON.TMR0IF ) // TMR0 Interrupt?  64Mhz/4/8/256 = 7812hz ~ uS
    {
     //=== 8x8 matrix Bicolor ===== Payload ISR 46% at 16 level PWM ==
     LEDRED=1;
     if(slice < (PWMdepth-1) ) slice++;
     else 
      { 
        slice=0;
        if(Irow<7) Irow++; else Irow=0;   // 8 rows
      }
     Ival<<=Irow;                      // translate row in rowvalue
     
        for(Ia=7 ; Ia!=255; Ia--)        // Send Green 8 bits to 74HC595's
         {
           if(slice>=Dgrn[Irow][Ia])  SER88=1; // PIXEL OFF
           else SER88=0;                       // PIXEL ON
           CLK88=1;                    // Send current bit to 74HC595
           asm nop
           CLK88=0;
         }
        for(Ia=7 ; Ia!=255; Ia--)        // Send Red 8 bits to 74HC595's
         {
           if(slice>=Dred[Irow][Ia])  SER88=1; // PIXEL OFF
           else SER88=0;                       // PIXEL ON
           CLK88=1;                    // Send current bit to 74HC595
           asm nop
           CLK88=0;
         }
     PORTC = ~Ival;                    // Change to next row (row on ='0')
     STC88 = 1;  STC88 = 0;            // Latch data in registers to output
     Ival=0x01;                        // Initialize for next turn
     LEDRED=0;
     INTCON.TMR0IF = 0;    // clear T0 Int flag
    }
 
Last edited by a moderator:
Which version of C are you using? How many duty cycle steps are you looking for?
 
Last edited:
How can i improve my code to get more pwm depth?
Make the periodic update more efficient so you can do more of them for your given framerate.

As a start, I would change the code to the following.. gains but a few cycles... the main problem would be the loops I guess.
Code:
if(INTCON.TMR0IF ) // TMR0 Interrupt?  64Mhz/4/8/256 = 7812hz ~ uS
{
    //=== 8x8 matrix Bicolor ===== Payload ISR 46% at 16 level PWM ==
    LEDRED = 1;

    if(++slice == PWMDepth)
    {
        slice = 0;
        Irow = (Irow + 1) & 7;      // 8 rows
    }

    Ival <<= 1;
    if(Ival == 0)
        Ival = 1;       // translate row in rowvalue

    for(Ia=7 ; Ia!=255; Ia--)        // Send Green 8 bits to 74HC595's
    {
        if(slice>=Dgrn[Irow][Ia])  SER88=1; // PIXEL OFF
        else SER88=0;                       // PIXEL ON
        CLK88=1;                    // Send current bit to 74HC595
        asm nop
        CLK88=0;
    }
    for(Ia=7 ; Ia!=255; Ia--)        // Send Red 8 bits to 74HC595's
    {
        if(slice>=Dred[Irow][Ia])  SER88=1; // PIXEL OFF
        else SER88=0;                       // PIXEL ON
        CLK88=1;                    // Send current bit to 74HC595
        asm nop
        CLK88=0;
    }
    PORTC = ~Ival;                    // Change to next row (row on ='0')
    STC88 = 1;
    STC88 = 0;            // Latch data in registers to output
    LEDRED=0;
    INTCON.TMR0IF = 0;    // clear T0 Int flag
}
 
yes indeed , the problem is the loops for sending out 16 bits
serially to the 74h595's.

Your suggestion only changes the speed slightly.
I even removed the nops for clocking serial data without much difference.

@mike I'm using mikroc compiler, I just want toi squeeze the max Depth/framerate
from what is possible. ( 8 bit depth at > 50 hz would be nice :) )

Is there a faster way to do pwm than I am aware off?
I hope there is :)
 
Aren't you already doing 8 and 16 bit soft PWM at 60 Hz? If you want more than that you might want to toss the 74HC595's and replace them with 74HC574 or similar 8-bit parallel latches.

If your target is 256 soft PWM levels, you'd need an 8-usec step time for a 60-Hz refresh rate. That's only about 128 instruction cycles with a 64-MHz clock.

While the soft PWM counter method is reasonably efficient you might want to look at other methods that use a toggle array or BAM (bit angle modulation).

Good luck on your project.

Cheerful regards, Mike
 
I am at 8 and 16 levels right now , that is 3 and 4 bit depth
I am running a 64mhz clock but on a pic that is only 16mips.
 
Last edited:
Thanks for the tips on BAM I'm looking into that one to
see if I'm smart enough to understand and code it :)
 
@mike is it possible to provide me with a link that explains the "toggle array"
method? Googling didnt make me wiser on this subject.

What are the speed improvements to expect soft PWM on an led matrix?
 
if I understand the toggle array correctly, all values are 0 (so that they have no effect when XORed against the port value)
until the cycle that you want to clear 1 or more leds - in which case you set a bit which will set the led. Each element of
the toggle array is XORed against the port for each of the levels (e.g. 256). This method requires 1 bit per led per level -
so it uses too much ram for your application, sorry.

The BAM would be the best (& simplest) bet, just note that the smallest
bit time cannot be smaller than the fastest speed of the ISR. therefore it might be advantageous to precalculate the values so that the ISR is simple.
 
Doug's assessment is basically correct. You use a toggle array with with one element for each update interval (64 levels = 64 elements, 256 levels = 256 elements, etc.), so it uses lots of RAM. You refresh the array at end-of-period by inserting 8 "toggle" bits into the array. Updating the port from the array is very fast for all but the end-of-period interval when you refresh the array (some additional info' in this forum.microchip post).

Code:
;
; K8LH "toggle array" 8-bit 8-chan soft PWM method (pseudo C code)
;
;
; unsigned char Led[] = { 0,14,37,7,50,7,42,0 }; // 0..255 range
;
; unsigned char Interval = 0;   // 0..255
; unsigned char Toggle[256];    // 256 element "toggle" array
;
; void isr_hi ()
; { if (PIR1bits.CCP1IF == 1)   // if CCP1 "special event trigger"
;   { PIR1bits.CCP1IF = 0;      // clear CCP1 interrupt flag
;     LATB ^= Toggle[Interval]; // update PWM outputs
;     Toggle[Interval] = 0;     // clear element for next period
;
;     if(++Interval == 0)       // if end of period, refresh array
;     { Toggle[Led[0]] |= 1;    // insert b0 output toggle bit
;       Toggle[Led[1]] |= 2;    // insert b1 output toggle bit
;       Toggle[Led[2]] |= 4;    // insert b2 output toggle bit
;       Toggle[Led[3]] |= 8;    // insert b3 output toggle bit
;       Toggle[Led[4]] |= 16;   // insert b4 output toggle bit
;       Toggle[Led[5]] |= 32;   // insert b5 output toggle bit
;       Toggle[Led[6]] |= 64;   // insert b6 output toggle bit
;       Toggle[Led[7]] |= 128;  // insert b7 output toggle bit
;       Toggle[0] ^= ~LATB;     // initialize 1st toggle element
;       Toggle[255] = 0;        // duty cycle 255 = digital on
;     }
;   }
; }
;
;   78.125 Hz, 256 steps, 50.0 usec interrupts
;   97.656 Hz, 256 steps, 40.0 usec interrupts
;  130.208 Hz, 256 steps, 30.0 usec interrupts
;  195.312 Hz, 256 steps, 20.0 usec interrupts
;  390.625 Hz, 256 steps, 10.0 usec interrupts
;  781.250 Hz, 256 steps,  5.0 usec interrupts
;
;  10 cycles for 255 interrupts, 30 cycles every 256th interrupt
;
        org     0x0008
v_inthi
        bcf     PIR1,TMR2IF     ; clear timer 2 interrupt flag    |
        movf    INDF0,W         ;
        xorwf   LATB,F          ; LATB ^= Toggle[Interval]
        clrf    INDF0           ; Toggle[Interval] = 0
        incfsz  FSR0L,F         ; all 256 steps? yes, skip, else
        retfie  FAST            ; exit

;       lfsr    0,Toggle        ; fsr0 = &Toggle[0]
        movf    Led+0,W         ; insert b0 output toggle bit
        bsf     PLUSW0,0        ; Toggle[Led[0]] |= 0b00000001
        movf    Led+1,W         ; insert b1 output toggle bit
        bsf     PLUSW0,1        ; Toggle[Led[1]] |= 0b00000010
        movf    Led+2,W         ; insert b2 output toggle bit
        bsf     PLUSW0,2        ; Toggle[Led[2]] |= 0b00000100
        movf    Led+3,W         ; insert b3 output toggle bit
        bsf     PLUSW0,3        ; Toggle[Led[3]] |= 0b00001000
        movf    Led+4,W         ; insert b4 output toggle bit
        bsf     PLUSW0,4        ; Toggle[Led[4]] |= 0b00010000
        movf    Led+5,W         ; insert b5 output toggle bit
        bsf     PLUSW0,5        ; Toggle[Led[5]] |= 0b00100000
        movf    Led+6,W         ; insert b6 output toggle bit
        bsf     PLUSW0,6        ; Toggle[Led[6]] |= 0b01000000
        movf    Led+7,W         ; insert b7 output toggle bit
        bsf     PLUSW0,7        ; Toggle[Led[7]] |= 0b10000000
        comf    LATB,W          ;
        xorwf   Toggle,F        ; Toggle[0] ^= ~LATB
        clrf    Toggle+255      ; duty cycle 255 = digital on
        retfie  FAST            ;
Caveats are (1) too much ram memory, and (2) you really need to use an assembly language driver because no high level language (that I'm aware of) will generate that highly optimized (18F) end-of-period code.

Cheerful regards, Mike
 
Last edited:
... The BAM would be the best (& simplest) bet, just note that the smallest
bit time cannot be smaller than the fastest speed of the ISR. therefore it might be advantageous to precalculate the values so that the ISR is simple.

I agree that a BAM (bit angle modulation) driver is probably the better choice for this application (once you've overcome the shift register bottleneck).

Your "smallest bit time" or "step interval" (1T) observation is only true if you implement a BAM driver using binary weighted 2^0 (1T), 2^1 (2T), 2^2 (4T), 2^3 (8T) ... 2^7 (128T) interrupt intervals. If instead you perform all eight interval updates each interrupt from eight precalculated update values, you can achieve 1T step times as small as 2 instruction cycles (single 8 bit port) or 4 instruction cycles (dual 8 bit ports) with approximately 50% ISR overhead. This allows for eight bit PWM duty cycle resolution at moderately high refresh rates, which is necessary if you're doing any kind of animation (since display updates should be synchronized to the frame rate to avoid visual artifacts).

So if tubos were to replace the 74HC595 drivers with 74HC574 or similar drivers, he would be looking at an 8 cycle 'step' (1T) interval (the time it takes to write 16 bits to the 74HC574's). That's a 500-nsec step time (64-MHz clock) with 128-usec interrupt intervals for 8-bit BAM, which produces a 1024-usec frame rate and a 976.5625-Hz refresh rate. Unfortunately, I'm still talking about assembly language here since I haven't figured out how to get cycle-accurate delays in any high level language. Sigh! Sorry!

Cheerful regards, Mike
 
Last edited:
While the 595s are a bottleneck, if there's some other reason to keep them, then a fair gain in speed can be obtained by using the hardware SPI port available on that PIC. From memory, fastest clock speed should be 8MHz and it'll take at least 32 cycles to transfer the red/grn data - this will be heaps faster than the software shifting (but obviously not as fast as using parallel F/Fs). This will easily fit inside a 128us interval with plenty of time to calculate the values for the next transfer (which can be done in the ISR).
 
@doug even if i used hw spi i would still need to create the 2 bytes of data to send to the 595's
realtime in my isr by checking/comparing the 2dim arrays with my slice value?
Wont the speed increase be minimal? Or am i overseeing something?

@mike your suggestion of 74HC754's would mean I need a pic with lots more pins :p
as the data needs to be sent parallel to the 754's.

If i understand correctly the BAM method requires only 8 Intcycles per frame per led
but happens at different intervals, so it seems hard to code.
Or does one still use 256 interrupts and only use 8 of them to update the led data?

I read somewhere that basic BAM has some blinking problems when fading in or out.

I've added the assembler file generated by the C compiler for my interrupt.
Could I optimize this by using inline assembler?


Code:
;bi88pwm.c,162 ::                 if(INTCON.TMR0IF ) // TMR0 Interrupt?  64Mhz/4/8/256 = 7812hz ~ uS
        BTFSS       INTCON+0, 2 
        GOTO        L_interrupt36
;bi88pwm.c,165 ::                 LEDRED=1;
        BSF         PORTA+0, 2 
;bi88pwm.c,166 ::                 if(slice < (PWMdepth-1) ) slice++;
        MOVLW       15
        SUBWF       _slice+0, 0 
        BTFSC       STATUS+0, 0 
        GOTO        L_interrupt37
        INCF        _slice+0, 1 
        GOTO        L_interrupt38
L_interrupt37:
;bi88pwm.c,169 ::                 slice=0;
        CLRF        _slice+0 
;bi88pwm.c,170 ::                 if(Irow<7) Irow++; else Irow=0;   // 8 rows
        MOVLW       7
        SUBWF       _Irow+0, 0 
        BTFSC       STATUS+0, 0 
        GOTO        L_interrupt39
        INCF        _Irow+0, 1 
        GOTO        L_interrupt40
L_interrupt39:
        CLRF        _Irow+0 
L_interrupt40:
;bi88pwm.c,171 ::                 }
L_interrupt38:
;bi88pwm.c,172 ::                 Ival<<=Irow;                      // translate row in rowvalue
        MOVF        _Irow+0, 0 
        MOVWF       R0 
        MOVF        R0, 0 
L__interrupt60:
        BZ          L__interrupt61
        RLCF        _Ival+0, 1 
        BCF         _Ival+0, 0 
        ADDLW       255
        GOTO        L__interrupt60
L__interrupt61:
;bi88pwm.c,174 ::                 for(Ia=7 ; Ia!=255; Ia--)        // Send Green 8 bits to 74HC595's
        MOVLW       7
        MOVWF       _Ia+0 
L_interrupt41:
        MOVF        _Ia+0, 0 
        XORLW       255
        BTFSC       STATUS+0, 2 
        GOTO        L_interrupt42
;bi88pwm.c,176 ::                 if(slice>=Dgrn[Irow][Ia])  SER88=1; // PIXEL OFF
        MOVLW       3
        MOVWF       R2 
        MOVF        _Irow+0, 0 
        MOVWF       R0 
        MOVLW       0
        MOVWF       R1 
        MOVF        R2, 0 
L__interrupt62:
        BZ          L__interrupt63
        RLCF        R0, 1 
        BCF         R0, 0 
        RLCF        R1, 1 
        ADDLW       255
        GOTO        L__interrupt62
L__interrupt63:
        MOVLW       _Dgrn+0
        ADDWF       R0, 1 
        MOVLW       hi_addr(_Dgrn+0)
        ADDWFC      R1, 1 
        MOVF        _Ia+0, 0 
        ADDWF       R0, 0 
        MOVWF       FSR2L 
        MOVLW       0
        ADDWFC      R1, 0 
        MOVWF       FSR2H 
        MOVF        POSTINC2+0, 0 
        SUBWF       _slice+0, 0 
        BTFSS       STATUS+0, 0 
        GOTO        L_interrupt44
        BSF         PORTB+0, 4 
        GOTO        L_interrupt45
L_interrupt44:
;bi88pwm.c,177 ::                 else SER88=0;                       // PIXEL ON
        BCF         PORTB+0, 4 
L_interrupt45:
;bi88pwm.c,178 ::                 CLK88=1;                    // Send current bit to 74HC595
        BSF         PORTB+0, 5 
;bi88pwm.c,180 ::                 CLK88=0;
        BCF         PORTB+0, 5 
;bi88pwm.c,174 ::                 for(Ia=7 ; Ia!=255; Ia--)        // Send Green 8 bits to 74HC595's
        DECF        _Ia+0, 1 
;bi88pwm.c,181 ::                 }
        GOTO        L_interrupt41
L_interrupt42:
;bi88pwm.c,182 ::                 for(Ia=7 ; Ia!=255; Ia--)        // Send Red 8 bits to 74HC595's
        MOVLW       7
        MOVWF       _Ia+0 
L_interrupt46:
        MOVF        _Ia+0, 0 
        XORLW       255
        BTFSC       STATUS+0, 2 
        GOTO        L_interrupt47
;bi88pwm.c,184 ::                 if(slice>=Dred[Irow][Ia])  SER88=1; // PIXEL OFF
        MOVLW       3
        MOVWF       R2 
        MOVF        _Irow+0, 0 
        MOVWF       R0 
        MOVLW       0
        MOVWF       R1 
        MOVF        R2, 0 
L__interrupt64:
        BZ          L__interrupt65
        RLCF        R0, 1 
        BCF         R0, 0 
        RLCF        R1, 1 
        ADDLW       255
        GOTO        L__interrupt64
L__interrupt65:
        MOVLW       _Dred+0
        ADDWF       R0, 1 
        MOVLW       hi_addr(_Dred+0)
        ADDWFC      R1, 1 
        MOVF        _Ia+0, 0 
        ADDWF       R0, 0 
        MOVWF       FSR2L 
        MOVLW       0
        ADDWFC      R1, 0 
        MOVWF       FSR2H 
        MOVF        POSTINC2+0, 0 
        SUBWF       _slice+0, 0 
        BTFSS       STATUS+0, 0 
        GOTO        L_interrupt49
        BSF         PORTB+0, 4 
        GOTO        L_interrupt50
L_interrupt49:
;bi88pwm.c,185 ::                 else SER88=0;                       // PIXEL ON
        BCF         PORTB+0, 4 
L_interrupt50:
;bi88pwm.c,186 ::                 CLK88=1;                    // Send current bit to 74HC595
        BSF         PORTB+0, 5 
;bi88pwm.c,188 ::                 CLK88=0;
        BCF         PORTB+0, 5 
;bi88pwm.c,182 ::                 for(Ia=7 ; Ia!=255; Ia--)        // Send Red 8 bits to 74HC595's
        DECF        _Ia+0, 1 
;bi88pwm.c,189 ::                 }
        GOTO        L_interrupt46
L_interrupt47:
;bi88pwm.c,190 ::                 PORTC = ~Ival;                    // Change to next row (row on ='0')
        COMF        _Ival+0, 0 
        MOVWF       PORTC+0 
;bi88pwm.c,191 ::                 STC88 = 1;  STC88 = 0;            // Latch data in registers to output
        BSF         PORTB+0, 6 
        BCF         PORTB+0, 6 
;bi88pwm.c,192 ::                 Ival=0x01;                        // Initialize for next turn
        MOVLW       1
        MOVWF       _Ival+0 
;bi88pwm.c,193 ::                 LEDRED=0;
        BCF         PORTA+0, 2 
;bi88pwm.c,194 ::                 INTCON.TMR0IF = 0;    // clear T0 Int flag
        BCF         INTCON+0, 2 
;bi88pwm.c,195 ::                 }
L_interrupt36:
;bi88pwm.c,196 ::                 }
L__interrupt59:
        RETFIE      1
; end of _interrupt
 
Last edited:
@mike your suggestion of 74HC754's would mean I need a pic with lots more pins :p
as the data needs to be sent parallel to the 754's.
I would daisy-chain the 574's which would require 9 pins. You could probably use an 18-pin PIC if you wanted.

If i understand correctly the BAM method requires only 8 Intcycles per frame per led but happens at different intervals, so it seems hard to code.
Well, it's a binary weighted interval so it's just a matter of shifting the interval value 1 bit to the left each interval. You could probably do it something like this using the CCP module "special event" interrupts;

Code:
void interrupt()           //
{ pir1.CCP1IF = 0;         // clear "special event" interrupt flag
  ccpr1 = interval;        // new "compare" interrupt value
  if(interval.14)          // if last (2^7) interval
    interval = 128;        // reset to 1T (2^0) interval (128 cycles)
  else                     //
    interval <<= 1;        //
}
Caveat! I actually tried this method (using an interrupt for each binary weighted interval) but dismissed it due to ISR overhead and relatively low performance.

I should also point out that you would use the extra time during the long T128 (2^7) interval to run the "data bender" routine to build the special eight element BAM[] array for the next column update interval.

Or does one still use 256 interrupts and only use 8 of them to update the led data?
No, you don't use 256 interrupts (yuch!).

I read somewhere that basic BAM has some blinking problems when fading in or out.
That particular visual artifact / anomaly is not an issue on multiplexed arrays because there's plenty of "off" time between each LED refresh interval.
 
Last edited:
I've added the assembler file generated by the C compiler for my interrupt.
Could I optimize this by using inline assembler?

Actually, knowledge of assembler could help you optimize even the high level language code. For example, the line below compiles to seven instructions and executes in six or seven cycles;

Code:
[FONT=monospace]
        if(Irow<7) Irow++; else Irow=0;  // 8 rows
[/FONT]
The following code performs basically the same function but it compiles to two instructions and runs in two cycles (a 71% size improvement and a 66% or 71% speed improvement);

Code:
        Irow++;              // bump "Irow"
        Irow &= 0b11110111;  // 0..7 inclusive (pseudo %7)
That compiler output listing suggests there's a lot of opportunities for improving performance.

Good luck on your project. I really have to get back to my studies.

Cheerful regards, Mike
 
That compiler output listing suggests there's a lot of opportunities for improving performance.

I thought so too but my assembler skills are too poor i guess.
Anyway thanks for your time and tips, you've helped out a lot.
 
@doug even if i used hw spi i would still need to create the 2 bytes of data to send to the 595's
realtime in my isr by checking/comparing the 2dim arrays with my slice value?
Wont the speed increase be minimal? Or am i overseeing something?
Using the hw SPI make the send run in parallel (i.e. in the background) so you can continue to do useful stuff with the CPU.

Also taking the calc/precalc out of loops will increase performance. Something like the following may work.
Code:
void interrupt isr()
{
    // setup the BAM-specific interrupt spacing
    interval >>= 1;
    if(interval == 0)
	{
            interval |= 128;
	    row = (row + 1) & 0xF7;     // 0..7
	    rowMask <<= 1;
	    if(rowMask == 0)
		rowMask++;
	}

    TMRxINTERVAL = interval;	// TMRx has an appropriate prescaler

    // send the first 8 bits
	ROWSEL_PINS = 0;
    CS_PIN = 1;     // whatever the latch of the 595 is to shift the data
    TXREG = redPrecalc;


    char *ptr = &red[row];
    if(*ptr++ & interval)
        redPrecalc |= 1;
    if(*ptr++ & interval)
        redPrecalc |= 2;
    if(*ptr++ & interval)
        redPrecalc |= 4;
    if(*ptr++ & interval)
        redPrecalc |= 8;
    if(*ptr++ & interval)
        redPrecalc |= 16;
    if(*ptr++ & interval)
        redPrecalc |= 32;
    if(*ptr++ & interval)
        redPrecalc |= 64;
    if(*ptr++ & interval)
        redPrecalc |= 128;

	// possibly wait for tx to finish here if the precalc above took < 32 cycles
    TXREG = grnPrecalc;

    ptr = &grn[row];
    if(*ptr++ & interval)
        grnPrecalc |= 1;
    if(*ptr++ & interval)
        grnPrecalc |= 2;
    if(*ptr++ & interval)
        grnPrecalc |= 4;
    if(*ptr++ & interval)
        grnPrecalc |= 8;
    if(*ptr++ & interval)
        grnPrecalc |= 16;
    if(*ptr++ & interval)
        grnPrecalc |= 32;
    if(*ptr++ & interval)
        grnPrecalc |= 64;
    if(*ptr++ & interval)
        grnPrecalc |= 128;

	// possibly wait for tx to finish here if the above precalc took < 32 cycles
	CS_PIN = 1;		// latch the data or something
	ROWSEL_PINS = rowMask;	// enable the row
}

I read somewhere that basic BAM has some blinking problems when fading in or out.
I imagine that is due to updating the intensity values part way through a cycle. If you wait until the end of a cycle before updating, I wouldn't think there'd be any flicker.
 
I read somewhere that basic BAM has some blinking problems when fading in or out.
I imagine that is due to updating the intensity values part way through a cycle. If you wait until the end of a cycle before updating, I wouldn't think there'd be any flicker.

No, that's not it at all. There's a pretty good description of the anomoly in post #3 in this PicBasicPro forum thread.
 
Last edited by a moderator:
Status
Not open for further replies.

Latest threads

New Articles From Microcontroller Tips

Back
Top