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.

Dissassembled TRISC inst. question

Status
Not open for further replies.

Mosaic

Well-Known Member
Hello:
Here is a code snip of the 16f690 assembly followed by the same as disassembled from the (MPLAB) hex file.

Assembly:

Code:
;Input PORTA setup (RA3)
Banksel TRISA
BSF TRISA,3 ; Set RA3 as an input


;PORTC  setup
	BankSel TRISC 
	movlw	b'11110000'
	movwf	TRISC	; MAKE I/O PIN C0,c1,c2,c3 AN OUTPUT, BY SETTING PINS 0,1,2,3 LOW.
	CLRF PORTC; init PORTC
	BankSel Clicks ; back to general variable bank

Disassembly:

Code:
	BSF STATUS,RP0
	BCF STATUS,RP1
	BSF PORTA,3
	BSF STATUS,RP0
	BCF STATUS,RP1
	MOVLW 0xF0
	MOVWF 0x07
	CLRF 0x07
	BCF STATUS,RP0
	BCF STATUS,RP1

The question is I don't understand why the 'MOVWF TRISC' instruction disassembles as a ' MOVWF 0x07'. Since you note that the CLR PORTC instruction is disassembled as a 'CLR 0x07'. It appears that the TRISC register is considered the SAME as the PORTC register, which can't be.

Now the TRISC register is 0x87 in the 16f690 which is 0x07 with bit 7 set. Is it that the MOVWF 0x07 instruction is actually using address 0x87 as a result of the previous bankselect setting? I suspect this maybe so as there are only 7 bits reserved for addressing in the 14 bit opcode, limiting the high address to 0x7F, thus requiring bank switching and the use of the RP0 / RP1 to make up 9 bits of addressing = 512 bytes.

If so then the CLR 0x07 (PORTC) needs a bankselect PORTC before it, otherwise it is overwriting the TRISC register? I observe that since TRISA and TRISC are in the same bank, bank switching between them does nothing.

Thanks.
 
Last edited:
hi
The way I read this part.
BankSel TRISC
movlw b'11110000'
movwf TRISC ; MAKE I/O PIN C0,c1,c2,c3 AN OUTPUT, BY SETTING PINS 0,1,2,3 LOW.
CLRF PORTC; init PORTC
BankSel Clicks ;
The TRISC selects Bank1 and the CLRF will occur in Bank1, so the dissembled code is showing what the assembly language is setting.

BSF STATUS,RP0
BCF STATUS,RP1
MOVLW 0xF0
MOVWF 0x07
CLRF 0x07
BCF STATUS,RP0
BCF STATUS,RP1
 
Last edited:
Now the TRISC register is 0x87 in the 16f690 which is 0x07 with bit 7 set. Is it that the MOVWF 0x07 instruction is actually using address 0x87 as a result of the previous bankselect setting? I suspect this maybe so as there are only 7 bits reserved for addressing in the 14 bit opcode, limiting the high address to 0x7F, thus requiring bank switching and the use of the RP0 / RP1 to make up 9 bits of addressing = 512 bytes.

TRISC isn't 0x87, it's 0x07 exactly as PORTC - the only difference is they are in different banks.

If so then the CLR 0x07 (PORTC) needs a bankselect PORTC before it, otherwise it is overwriting the TRISC register? I observe that since TRISA and TRISC are in the same bank, bank switching between them does nothing.

Yes, you need to switch banks back - TRIS and PORT are just the same address in different banks.
 
Nigel, thx for the reply.
I have started to use the PIC16 Sim from Oshon and I find its displays and functions to be excellent.
It has allowed me to detect the bank selection issue and by direct injection into any of the registers on the fly, I could tell which registers were being written to and in which bank.
Further, I have been able to optimize my code based on simultaneously watching the gp registers, the Special registers, The virtual LED output, the PIC hardware Pin I/O display and the assembly code stepping execution pointer all at once.
By Activating Virtual LEDs I could exactly simulate the LPC board and achieve pressing the switch with a duty cycle square wave feeding RA3. The duty cycle period of the wave permitted an easy way to tell how long the debounce delay was (25ms) for the delay variable in use. Smart breakpoints which occur based on a register's value permit faster simulation and better feedback.

I feel empowered.

One caveat, the assembler doesn't like MPLAB shortcuts like the BC instruction nor does it like Relocatable code and variables, and u must be explicit on all the commands. Also, u must clear memory between compiles or u can be testing the wrong hex.


I think everyone should give the Oshonsoft trial a try, super stuff there.
 
We're happy for you. And now you should recognize the bank select error I mentioned on your other thread, yes, no?

Regards...
 
Forgive me for not explaining further on the other thread but it seemed (to me) that you were not open to advice or suggestions.

Anyway as you've already figured out the assembly language instruction for movwf PORTC and movwf TRISC is the exact same instruction because there's only room in each PIC instruction for 7-bits of an SFR or GPR address.

Have fun on your projects.

Kind regards, Mike

<added>

Are you open to discussing alternate switch debouncing methods on your other thread?
 
Last edited:
Mike, I can't understand why you felt I was not open to advice as I posted asking for it. Insofar as the debouncer, its my very first independent PIC prg attempt, I am open to more efficient ways. I will admit though, that i purposely did not research it in order to see if i could do it on my own.
thx
 
Mike, I can't understand why you felt I was not open to advice as I posted asking for it.
I apologize for the misunderstanding then. It seemed to me that you dismissed Mike's (Pommie's) comments about being able to assemble the program "as is" and you dismissed my comment on the banking problem.

Insofar as the debouncer, its my very first independent PIC prg attempt, I am open to more efficient ways. I will admit though, that i purposely did not research it in order to see if i could do it on my own.
Then I think you did a very good job. I was impressed that you had the insight to use a switch state latch. If you update the latch bit after each sample then it's relatively easy to detect a "new press" (new = 1, old = 0), a "new release" (new = 0, old = 1), a "still open" (new = 0, old = 0), or a "still closed" (new = 1, old = 1) switch state.

If you're open to suggestions or if you'd like to discuss some other switch debounce & management methods (on the other thread?) then I'd be happy to participate.

As an example, here's another way, out of hundreds of different ways, that you might have accomplished the same program (using a switch state latch and debouncing both "press" and "release" switch states);

Code:
        code    0x000
init
        banksel ANSEL           ; bank 2                          |B2
        clrf    ANSEL           ; turn off analog pin functions   |B2
        clrf    ANSELH          ;                                 |B2
        banksel TRISA           ; bank 1                          |B1
        movlw   b'00001000'     ;                                 |B1
        movwf   TRISA           ; RA3 input, others outputs       |B1
        movlw   b'11110000'     ;                                 |B1
        movwf   PORTC           ; RC7-RC4 inputs, RC3-RC0 outputs |B1
        banksel PORTC           ; bank 0                          |B0
        clrf    PORTC           ; clear PORTC output latches      |B0
        clrf    latch           ; clear switch state latch        |B0
        clrf    click           ; clear click counter             |B0
;
;         ____---____-----_____   new switch sample (press = 1)
;  latch  _____---____-----____   switch state latch
;         ____-__-___-____-____   w = changes, press or release
;         ____-______-_________   filter out "new release" bits
;  swnew  ____-______-_________   leaving "new press" bits
;
getkey
        movlw   32              ; reset debounce timer            |B0
        movwf   dbctr           ; dbctr = 32                      |B0
dbounce
        DelayCy(1*msecs)        ; 1 msec sample intervals         |B0
        comf    PORTA,W         ; sample active lo switches       |B0
        andlw   b'00001000'     ; on RA3 pin                      |B0
        xorwf   latch,W         ; changes (press or release)?     |B0
        skpnz                   ; yes, skip, else                 |B0
        goto    getkey          ; branch (no change detected)     |B0
        decfsz  dbctr,F         ; debounced? yes, skip, else      |B0
        goto    dbounce         ; branch (sample again)           |B0
        xorwf   latch,F         ; update switch state latch       |B0
        andwf   latch,W         ; filter out "new release" bits   |B0
        skpnz                   ; a new press? yes, skip, else    |B0
        goto    getkey          ; branch (a "new release")        |B0
        movwf   swnew           ; save "new press" bits           |B0
upsw
        btfsc   swnew,3         ; a "new press"? no, skip, else   |B0
        incf    click,F         ; increment 'click'               |B0
disp
        movf    click,W         ; wreg = 'click' value            |B0
        movwf   PORTC           ; display on RC3-RC0 LEDs         |B0
        goto    getkey          ;                                 |B0
;
A few years ago Mike (Pommie) suggested there's no real advantage sampling switches at short intervals and that under-sampling them at the full "debounce" interval, typically 16 to 32 msecs, would work just as well and simplify the code. I've come to agree with him. What happens is that if you happen to sample the switch while it's bouncing you'll detect "no change" but you'll certainly catch it 32-msecs later after it has stopped bouncing. That said, here's another shorter version of your main program loop;

Code:
;
;         ____---____-----_____   new switch sample (press = 1)
;  latch  _____---____-----____   switch state latch
;         ____-__-___-____-____   w = changes, press or release
;         ____-______-_________   filter out "new release" bits
;  swnew  ____-______-_________   leaving "new press" bits
;
getkey
        DelayCy(25*msecs)       ; 25-msec sample intervals        |B0
        comf    PORTA,W         ; sample active low switches      |B0
        andlw   b'00001100'     ; on RA3 and RA2 pins             |B0
        xorwf   latch,W         ; changes (press or release)      |B0
        xorwf   latch,F         ; update switch state latch       |B0
        andwf   latch,W         ; filter out "new release" bits   |B0
        skpnz                   ; a new press? yes, skip, else    |B0
        goto    getkey          ; (no change or a new release)    |B0
        movwf   swnew           ; save "new press" bits           |B0
upsw
        btfsc   swnew,3         ; up sw (RA3) press? no, skip     |B0
        incf    click,F         ; else, increment 'click'         |B0
dnsw
        btfsc   swnew,2         ; dn sw (RA2) press? no, skip     |B0
        decf    click,F         ; else, decrement 'click'         |B0
disp
        movf    click,W         ;                                 |B0
        movwf   PORTC           ; display on RC3..RC0 pins        |B0
        goto    getkey          ; loop                            |B0
;
Have fun. Be open to suggestions. And good luck sorting out the good ones from the bad ones (lol)...

Cheerful regards, Mike
 
Last edited:
Debounce flavour

I presume the DelayCY (25*msecs) is a macro?

I think most modern N.O. microswitches and keypads will work well with the second approach. I rather like the use of simple logic combinations to produce an elegant result.. I suppose that comes with experience.

The one feature that my approach had that i don't see in these samples is the dynamic adjustment to a really bouncy switch. The debounce counter here increments when switch is 'on' and decrements when 'off' to provide bidirectional debounce. This means if the switch keeps bouncing the code will delay making a decision until its stops bouncing. Also, if the switch stops bouncing soon the code will force a quick response by eliminating the delay loop before outputting the result.

BTW, I still can't see the problem with Org that Pommie mentioned, I figure mebbe its the compiler differences /rules. Both 'Org' & "Code' compile just fine with relocatable variables on MPLAB 8.5x, no complaints. Although I have noticed in the Oshonsoft compile that org requires EQU static variables. But then it does not accept "Code" at all.

So I guess this code is good for high vibration or 'industrial' applications. But not as efficient for say a calculator app or password app.


Code:
GETSWITCH ;debounce routine of Switch on RA3
	BTFSS PORTA,3 ; test RA3, skip if HI (SW is OPEN)
	CALL CLOSED
	BTFSC PORTA,3 ; test RA3, skip if lo (SW is CLOSED)
	CALL OPEN
	RETURN
	
OPEN ; When Switch is Open
	DECFSZ Switch,F; Debounce Countdown if switch is open.
	Return ; return if switch value is non zero
	Incf Switch,f ; make switch minimum 1
	CLRF Latch ; clear onlatch as Switch has reached lowest count.
	RETURN
	
CLOSED: ; When switch is closed
	INCF Switch,F ; Debounce count up if switch is on/closed
	MOVF Switch,w
	SUBLW .32 ; 32-w
	BTFSC STATUS,C ; DO NOT RETURN IF CARRY CLR
	GOTO RET ; RETURN on carry set (w<32) =>return as count not high enough.
	BSF Latch,1 ; set onlatch,1 to 1 if Switch =33
	CALL CLIK	
	DECF Switch,F ; keep Switch from rising past 33.
RET	RETURN
	
CLIK	; Track number of switch clicks
	BTFSC Latch,0 ;skip next inst. if latch,0 is CLR. (if latch is 0)
	GOTO NOCOUNT
	INCF Clicks,f ; If Latch,0 is clear,then this is a state change from switch open => increment clicks
	MOVLW .1
	MOVWF Delay2 ; SET Delay2 to .1 to force update of portC.
NOCOUNT	BCF STATUS,C ; clear the carry
		RRF Latch,f ; make bit 1 into bit 0 to update Latch status for switch open/closed testing.
		RETURN
 
I presume the DelayCY (25*msecs) is a macro?
Yes, it's the macro portion of a general purpose fixed delay or constant delay subsystem that produces "cycle accurate" delays in "msecs", "usecs", or "cycles" using almost any clock (4,8,12,16, or 20 MHz). There's a 9-word subroutine that goes along with the macro.

I think most modern N.O. microswitches and keypads will work well with the second approach. I rather like the use of simple logic combinations to produce an elegant result.. I suppose that comes with experience.
Yes, experience and research and recognizing there may be a better way to do something.

The one feature that my approach had that i don't see in these samples is the dynamic adjustment to a really bouncy switch. The debounce counter here increments when switch is 'on' and decrements when 'off' to provide bidirectional debounce. This means if the switch keeps bouncing the code will delay making a decision until its stops bouncing. Also, if the switch stops bouncing soon the code will force a quick response by eliminating the delay loop before outputting the result.
Unfortunately, your "dynamic" debounce counter approach isn't really fully debouncing both the "press" and "release" states. For example, when you release the switch your code will decrement the counter from 32 to 31 but if your "really bouncy switch" is bouncing and reads low on the next sample then the counter will increment from 31 to 32 and your code will pronounce it a "new press".

You really need a full 16 to 32 msecs after detecting a state change, including a "bounce", before calling a switch "debounced".

So you avoided doing any research in order to come up with a solution on your own and it's a reasonably good attempt but now it's time for you to do some research.

BTW, I still can't see the problem with Org that Pommie mentioned, I figure mebbe its the compiler differences /rules. Both 'Org' & "Code' compile just fine with relocatable variables on MPLAB 8.5x, no complaints. Although I have noticed in the Oshonsoft compile that org requires EQU static variables. But then it does not accept "Code" at all.
When I tested your program on MPLAB 8.5 in absolute mode (no linker file) I got the same assembler error Mike (Pommie) did. Mike's (Pommie's) analysis is correct. We're just not sure what you were doing that makes you think it's not a problem.

So I guess this code is good for high vibration or 'industrial' applications. But not as efficient for say a calculator app or password app.
I'm not sure I'm following you here.

Have fun.

Cheerful regards, Mike
 
Cumulative debounce

Unfortunately, your "dynamic" debounce counter approach isn't really fully debouncing both the "press" and "release" states. For example, when you release the switch your code will decrement the counter from 32 to 31 but if your "really bouncy switch" is bouncing and reads low on the next sample then the counter will increment from 31 to 32 and your code will pronounce it a "new press".

Mike, have a closer look at the Latching subroutine. For a keypress to be accepted the count must go from 1 to 33, for a key up to be accepted that count must go from 32 to 0. Anything in between does not make for a state change. In fact let's say that the switch bounces continuously every millisec, on - off. The net count will not ever achieve either a key up or key down latch.

Now, what's interesting and useful is that the counter calculates the net result. For a switch that bounces a lot the counter will eventually net a final result based on the duty cycle of the bounces. So if the switch is overall more on than off, the code will eventually make an 'on' decision and the converse. Of course, there is no time limit to the code making this decision, it depends on the mechanical properties of the switch. So the code will compensate for a very bouncy switch by taking LONGER to decide and will take a minimum of about 25ms for a very good switch.

The key difference is the code I wrote is not entirely time based as it considers each bounce event and makes a cumulative decision that is time coupled.

This is why I think it is more suitable for conditions that lead to significant switch bounce such as mechanical vibration as in a moving vehicle or heavy industry.
 
Last edited:
Ok, I see it (where you don't clear "Latch" in the "OPEN" subroutine until "Switch" equals 0). Sorry.

Your code is so fragmented with so many subroutines and your method of using the Latch variable is so obscure that I couldn't quite figure out what you were doing until I created a project and simulated it. Whew!

Honestly, now that I see what you're doing, I don't see any advantage to your "dynamic" (time coupled cumulative decision) debounce method. It still takes 32 cumulative samples at the same state to debounce a new press or a new release and a user won't perceive the small time savings you think you might get. I can imagine why you think a cumulative decision might be handy but in practice you can use a pair of bare wires in place of a switch and get spectacular results with less complicated methods (LOL).

Anyway, I would very much like to see how you might build on this method for multiple switches.

Kind regards, Mike
 
Last edited:
The cumulative sampling is only good for very bouncy conditions. If u simulate it with a 50% duty PWM injected into RA3 with say a base duration of 4ms the latch will never set. With the other method of testing twice using the 25 ms fixed time period, a 4 ms PWM may very well appear debounced if it happens to be 'on' or 'off' at both tests.
If u alter the duty to say 75%, the cumulative method will solve the switch condition after sampling sufficiently, giving a workable solution based on the switches 'on'time vs 'off' time. The regular method will almost randomly get it right or wrong with these conditions.

There are 'new' switches out there with up to 157 millisec bounces, which far exceeds the 25 ms fixed debounce rroutine. I think this cumulative method would be a better handler for such switches.

http://www.ganssle.com/debouncing.htm

I think because of the subroutine separations, it would be relatively easy to do multiple switches by simply correctly initializing the variables to match the particular switch before calling the routines, much like saving & restoring the registers before/after an interrupt service. But, I'd have to attempt it to be certain. If efficient RAM usage became an issue, then some bitwise operations to have multiple variables within a single byte would have to be considered.

I'm sure if i spend some time studying the calls there would be some gains with better coding.

Having said that, I'll prob use yours for most all debounce, its too efficient to resist.
 
Last edited:
Status
Not open for further replies.

Latest threads

New Articles From Microcontroller Tips

Back
Top