PIC16F628A Rotate Left Thru Carry & Loop Around

Status
Not open for further replies.

EvilGenius

Member
Hello
I have been doing a lot of searches and study of codes and can't seem to find what I am looking for.
I have two Ports (A & B). I want to be able to shift left from Port B thru carry and into Port A until data reaches A3.
Once I shift left one more time, I like the data to loop back to B0 (the begining).
I have seen setting up leftbit and rightbit and I know how to shift thru carry. If I shift left once again will the last bit (MSB) automatically fall into B0 (LSB)?

Leftbit equ 3
Rightbit equ 0
clrf C
set bits for port A and B
rlf ....
 
To begin, with the regular 16Fxxx series, you should use a shadow register for all PORT writes to avoid reading back incorrect pin values as caused by the read-modify-write behaviour of the ports.
With the newer 16Fxxxx series and 18F you can rely on LATch instructions to sidestep RMW.

So to answer your query as I understand it, you may need to add a delay loop if this is some sort of LED display:
Code:
ShadA equ 0x20
ShadB equ 0x21
Data     equ 0x22; keeps original dataset

PORTSHIFT;
movf Data,w; fetch original data
movwf ShadB,w; update shadow register
clrf ShadA

call UPDATE; refresh PORTS
rlf ShadB,f
rlf ShadA,f; A0 = B7
call UPDATE
rlf ShadB,f
rlf ShadA,f; A1 =B7, A0=b6
call UPDATE
rlf ShadB,f
rlf ShadA,f; A2=B7,A1=B6,A0=B5
call UPDATE
rlf ShadB,f
rlf ShadA,f; A3=B7,A2=B6,A1=B5, A0=B4
call UPDATE
return

UPDATE; port refresh.
movf ShadB,w
movwf PORTB
movf ShadA,w
movwf PORTA
clrc
return
 
You need to give some more details.

Do you want to cyclycally rotate the same 12 bits of data through the PORTA[3..0] and PORTB[7..0] over and over again?

Or do you want to read data from PORTB and then shift them bit by bit into PORTA[3..0]?
 
Code:
;
;  12-bit ring counter spanning RA3..RA0..RB7..RB0
;
        clrc                    ; C = 0 (assume RA3 = 0)
        btfsc   PORTA,3         ; is RA3 = 0? yes, skip, else
        setc                    ; C = 1
        rlf     PORTB,F         ; shift lower 8 bits
        rlf     PORTA,W         ; shift upper 4 bits
        andlw   b'00001111'     ; just RA3..RA0 bits please
        movwf   PORTA           ; update PORTA
Code:
;
;  12-bit ring counter spanning RA3..RA0..RB7..RB0
;  preserve RA7..RA4 bits
;
        clrc                    ; C = 0 (assume RA3 = 0)
        btfsc   PORTA,3         ; is RA3 = 0? yes, skip, else
        setc                    ; C = 1
        rlf     PORTB,F         ; shift lower 8 bits
        rlf     PORTA,W         ; shift upper 4 bits
        xorwf   PORTA,W         ; delta new & old bits
        andlw   b'00001111'     ; preserve RA7-RA4 bits
        xorwf   PORTA,F         ; update PORTA
 
Thank you for your responses.
Here is in details what I am doing:
Place value for A7,A6,A5,A4 (say 1101xxxx ) in a Variable called "Color" (to preserve the value)
Place initial values in ValB and ValA (First 4-bit). Say A:xxxx1011 B:11001110
Start Routine Here
Rotate Left values of ValB and ValA (During rotate Left A3 drops into B0, B7 drops into A0)
Add value of "Color" back into ValA
Call Output (ValB-> PORTB, ValA->PORTA
Loop the above routine 11 times so that at the end original B0 becomes A3, and original A3 become A2 (full rotate of 12 bits)

In a sense we are preserving the values of 12 bits and rotating them after initializing them. Also preserving value of "Color" to be added on before sending it to output.
Mike: You are very close to the concept. But what I am not seeing is moving A3 into B0 during rotate Left!
 
I am thinking let A3 drop in A4, test A4 (set or not), accordingly set B0, then AND PortA with 00001111 as you suggested and save it back in PortA, add color and send it to Output. In a sense we are creating an artificial carry after A3 and using original Carry to transfer data from PortB to PortA.
 
... what I am not seeing is moving A3 into B0 during rotate Left!

The first three instructions copy A3 into Carry before rotating PORTB. What are you "not seeing"?

Code:
        clrc                    ; C = 0 (assume RA3 = 0)
        btfsc   PORTA,3         ; is RA3 = 0? yes, skip, else
        setc                    ; C = 1
        rlf     PORTB,F         ; shift lower 8 bits

Perhaps you could simulate the code if it's unclear. Here's another way to do same thing;

Code:
;
;  12-bit ring counter spanning RA3..RA0..RB7..RB0
;  preserve RA7..RA4 'color' bits
;
        swapf   PORTA,W         ; copy A3 bit to WREG bit 7
        addlw   0x80            ; copy it into Carry (C = A3)
        rlf     PORTB,F         ; shift lower 8 bits
        rlf     PORTA,W         ; shift upper 4 bits
        xorwf   PORTA,W         ; delta new & old bits, but,
        andlw   b'00001111'     ; preserve RA7-RA4 'color' bits
        xorwf   PORTA,F         ; update RA3..RA0 ring ctr bits
 
Last edited:
The first three instructions copy A3 into Carry before rotating PORTB. What are you "not seeing"?

[/code]

ah-ha I think I see it now. So we are testing A3 first and setting Carry. At this point content of Carry is shifted into B0 as the result of first rlf-PortB and at the same time B7 drops into Carry. Now when we rotate PortA the new value of Carry (B7) drops into A0. By AND you get rid of rotated bit in A4. I see in your first code you moved the content of w into PortA which I get. Is this where you add "Color" to PortA. If so do I need another variable here so that content of PortA are preserved? What is the function of end xor?
 
I just thought of something else. Do we need to worry about carry being cleared after rlf-PortA or will the second pass override it after testing for A3.
To avoid another variable at the end, once we move w into PortA, add "color" to w (not PortA) and send it to Output from there.
 
I see in your first code you moved the content of w into PortA which I get. Is this where you add "Color" to PortA?
That code assumes "color" already occupies RA7..RA4 bit positions, thus the need to preserve RA7..RA4 bits when updating the ring counter RA3..RA0 bits.

If so do I need another variable here so that content of PortA are preserved?
Do you need to preserve the contents of port A?

What is the function of end xor?
The first XOR finds the differences between two values. The AND instruction filters out the bits that you don't want to change. The second XOR instruction writes the new A3..A0 values to PORTA. If PORTA contains color info in bits 7-4 and the four most significant bits of the 12-bit ring counter in bits 3-0, then you could use the routine I posted to advance the ring counter without disturbing the color bits. Likewise, when you want to update the four color bits without disturbing the four ring counter bits, you might use code like this;

Code:
;
;  update four color bits in PORTA RA7..RA4
;  preserve ring counter bits in RA3..RA0
;
        movlw   b'10110000'     ; new color value
        xorwf   PORTA,W         ; delta new and old bits
        xorwf   PORTA,F         ; update RA7..RA4 color bits

Take time to learn how to use the MPLAB Simulator and Watch Window to single step through code and see the results.

Modify the code as necessary to support separate color and ring counter variables which can combined when needed for port updates.

Cheerful regards, Mike
 
Last edited:
Code:
Code (text):
 
;
;  12-bit ring counter spanning RA3..RA0..RB7..RB0
;
     cblock     0x20
                      copyPORTA
                      copyPORTB
                      Color
                      Count
     endc
;---------------------------------------------------------------
     movlw    b'11000000'        ;value for color
     movwf    Color
     movlw    b'10010001'         ;value for PortB
     movwf    copyPORTB
     movlw    b'00001001'         ;value for PortA
     movwf    copyPORTA
;--------------------------------------------------------------
C0                                               
     movlw     d'11'
     movwf    Count
C1
     clrc                                         ; C = 0 (assume RA3 = 0)
     btfsc        copyPORTA,3      ; is RA3 = 0? yes, skip, else
     setc                                        ; C = 1
     rlf             copyPORTB,F       ; shift lower 8 bits
     rlf             copyPORTA,W     ; shift upper 4 bits
     andlw      b'00001111'        ; just RA3..RA0 bits please
     movwf    copyPORTA          ; update PORTA
     addwf     Color, 0
     call          Output
     decfsz     Count
     goto        C1
     goto        C0
;----------------------------------------------------
Output
     movwf    PORTA
     movfw    copyPORTB
     movwf    PORTB
     return
 
Is there some timing on this? In the original Mike's code there are 4 cycles between setting PORTA and PORTB, while in yours it's 2. Does this matter? How fast are you going to do this? Are you trying to do this as fast as possible? Or do you want some fixed intervals (delays?) between changes?
 
I also wonder if speed is an issue since this seems to be some kind of LED code. If so, then should the ring counter bits be updated during a blanking interval (LEDs turned off)? Also, if speed is important than I would save four cycles by putting the output instructions in-line.

Got a schematic so we can see what you're doin'?
 
North: I need to do this as fast as possible. This is part of the engine for another program. In addition to copyPORTA and CopyPORTB, I will have 11 more set of 2 variables for total of 12 sets (of 2). The main program will set 12 colors for 12 RGB array. Each 12 sets of variables helps me create one frame of picture. Rotating the variables allows me to rotate all 12 colors across the 12 RGB LED's (12 Frames). There will not be a delay used in any part of the main program. To sustain colors each pass will modulate colors 60 times a second and each frame will be repeated 255 times a second to maintain all colors across 12 channels without flickering. The goal is to create a 12 channel RGB controller without use of PWM to achieve 33% duty cycle with much more vivid colors. 12 bits are your anodes while 3 color bits are your common R,G,B (12 Mux 3). The rotations happens between each frame so it has to be as fast as possible. In the example I am rotating 11 times rapidly, but in reality each rotate happens after each Frame is created so the timing between rotations is controlled by main program and is not like how it appears in the example in rapid succession.
 
Here is a schematic layout and color timeline.
 

Attachments

  • 12 Channel RGB Controller2.jpg
    221.6 KB · Views: 365
  • 12 CHANNEL RGB COLOR MORPH TIMELINE2.jpg
    144 KB · Views: 287
So you're trying to do software PWM for twelve RGB LEDs? If so, how many duty cycle steps per R, G, and B LED and what is the PWM period, please?

<added>
What are the bottom and right scales on your "color timeline", please?
 
Last edited:
So you're trying to do software PWM for twelve RGB LEDs? If so, how many duty cycle steps per R, G, and B LED and what is the PWM period, please?

<added>
What are the bottom and right scales on your "color timeline", please?
Just an FYI. I have written the functional code already, but it does not look pretty and is very repetetive. That is why I am redoing it to simplify it completely. So I know the concept works!
Yes, it is software PWM. It is to take control of the timing and functions completely. This allows for much more control of brightness and also allows additional functions to be implemented as a stand-alone device. Believe it or not I have not sat down to calculate cycles. It has been by gutt feeling and trial & eror. I know to sustain colors I need to modulate each color minimum of 60Hz (my safe zone). But I am modulating much faster and refreshing much faster. Original code there are 12 frames. (not a timing consideration as I can speed up or slow down) Each Frame is looped 50 times. Each Frame calls on 3 sections (R,G,B color sets) and pushed them to Output. (7 instructions). each Section is looped 25 times, each loop has 10 instruction sets. So I would say total cycle time for one frame is: 50x3x25x10= 3750 cycles per second. The beauty is within the Frame which calls 3 Sections (R,G,B) so that I can get the maximum 33% duty cycle.
Top: Your port assignment, Bottom is your time scale, right side is your y-axis scale (number of times each color is repeated). The idea is to run x-asix 252 to 0. Your y-axis will be how many times each section is repeated. To achieve Full Red you loop that section 84 times in B0 at x-axis=0 while the other two colors are zero. At x-axis=84 your red becomes zero, while your green peaks at 84, and blue is zero. Continue the logic for the other two points... Your x-axis is your main loop variable decrementing from 252 to 0. Within that loop you have a 3 train signals that have line forumlas for triangles. As you change x-axis, your y-values for each color changes incresing or decreasing intensity of each color (number of times it is looped). What you see in the graph is one entire frame. Rotate the variables where peaks and valleys are and repeate the same x-axis timeline and all your colors will rotate slightly. Do this over and over until your last frame will have the color red in it and then repeat the whole process.
In this example since we are morphing from red to green to blue, my initial color sets are 0001xxxx, 0100xxxx, 1000xxxx. But you are not limited to these colors. You can set your initial colors to red (0001xxxx), yellow (0101xxxx), green (0100xxxx) and loop thru these colors only without use of blue. (xmas colors) and so on.....
 
Last edited:
You lost me. I realize you'd like to move ahead on your project but I'd really like to figure out what you're doing. If you have time, could you tell me what is a "frame", please?

Regards, Mike
 
Status
Not open for further replies.
Cookies are required to use this site. You must accept them to continue using the site. Learn more…