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.

Can't Set Bit <0> in Register -- ASM

Status
Not open for further replies.

jpanhalt

Well-Known Member
Most Helpful Member
Previous related thread: https://www.electro-tech-online.com/threads/stimulus-for-software-uart.139345/
Language: MPASM
Tool: MPLab SIM
Chip: 12F683
Code source:

Decided to just set the register flags in code so I could follow the simulation. Albeit clumsy, but simple. (BTW, I am using an asynchronous stimulus to initiate receive.)

Problem: Can't set the zero bit in PROC232. I am able to set every other bit. Here are snippets of the modified code for debugging. I have tried a few things, but to keep this short, I won't go into those details. Note: PROC232 is clear prior to the first NOP.

Capture.PNG
Capture1.PNG

As you can see (Left = modified program; Right = Watch window), when I load w with FF and move it to PROC232, the zero bit is not changed. Tries some other values, such as 0x03 and 0x04, and they work, except for the zero bit.

What sort of things can prevent one from setting a single bit in MPASM?

John
 
Are you sure your interrupt isn't clearing it? I'm not sure what the simulator does with interrupts, especially in the new version of MPLAB.

Mike.
 
I had not looked into that. I figured that stepping through would avoid that as a factor. I just disabled interrupts as shown here:
upload_2013-12-16_12-47-5.png


and got the same result. The zero bit does not set.

Thanks for the suggestion. This is my first time using interrupts. Mike's (K8LH) program runs and it is easy to follow on paper. I just want to see how it works in simulation.

John
 
Here's an additional piece:
1) Uncommented all the interrupt stuff to return to the original.
2) Rearranged the bit assignments to avoid the zero bit:
upload_2013-12-16_13-20-29.png


(For the flag bits, I tried the #define change from equate awhile back to see if it made a difference. As expected, it didn't.) The original flag bit assignments are commented out. However, with the changed bit assignments, all three flag bits can be set to "1." BUT, the zero bit, which is not defined as anything now, still won't set using the code I posted originally.

John
 
PROBLEM SOLVED
I forget to set the device in "Configure" . The default was a 12F509, and I got a warning about retfie being a label and not in column 1. Once that got fixed, the rest is working too.

Dumb.

John
 
Similar things have got me more than once, and they'll get me again!
 
Hi John.

I have a more recent version of that half-duplex demo as well as a full-duplex demo, if you're interested.

Cheerful regards, Mike

Code:
;******************************************************************
;                                                                 *
;   Filename: 12F683 Half-Duplex 9600 Demo.asm                    *
;     Author: Mike McLaren, K8LH                                  *
;       Date: 02-Jun-05  (last revision 02-Dec-05)                *
;                                                                 *
;    Half Duplex Bit-Banged 9600 Baud Serial I/O Demo             *
;    (with 16-byte circular receive character buffer)             *
;                                                                 *
;   ·Uses 12F683 INTOSC running at 8-MHz                          *
;   ·Bit rate error 0.16% plus or minus 1.0% for INTOSC           *
;   ·Bit-banged 9600 baud serial I/O                              *
;     ·Half Duplex (should not TX and RX simultaneously)          *
;     ·TMR2 interrupts at 104-usec intervals (every 208           *
;      instruction cycles) and IOC (interrupt on change)          *
;      for RX start bit leading edge detection on RXPIN           *
;     ·Circular 16-byte RX character buffer                       *
;     ·Inverted TX and RX signals (MAX232A or similar             *
;      inverting RS-232 interface required)                       *
;   ·Relatively small - the ISR and the support routines          *
;    Init232, Put232, and Get232 use 102 words of code            *
;    space at locations 0x04 through 0x69                         *
;   ·Worst case 23% ISR 'overhead' (24-usecs) when a              *
;    complete RX character is added to the circular               *
;    buffer once every 1.04-msecs while receiving                 *
;                                                                 *
;      MPLab: 7.21    (tabs=8)                                    *
;      MPAsm: 4.02                                                *
;                                                                 *
;******************************************************************
 
Last edited:
Mike,

Yes, I am absolutely interested in the newer version. I think the half-duplex will suffice for what I am doing. It is very well done.

Regards,

John
 
Here it is, John...

Happy Holidays...

Code:
;******************************************************************
;                                                                 *
;   Filename: 12F683 Half-Duplex 9600 Demo.asm                    *
;     Author: Mike McLaren, K8LH   (k8lh_at_arrl.net)             *
;       Date: 02-Jun-05  (last revision 02-Dec-05)                *
;                                                                 *
;    Half Duplex Bit-Banged 9600 Baud Serial I/O Demo             *
;    (with 16-byte circular receive character buffer)             *
;                                                                 *
;   ·Uses 12F683 INTOSC running at 8-MHz                          *
;   ·Bit rate error 0.16% plus or minus 1.0% for INTOSC           *
;   ·Bit-banged 9600 baud serial I/O                              *
;     ·Half Duplex (should not TX and RX simultaneously)          *
;     ·TMR2 interrupts at 104-usec intervals (every 208           *
;      instruction cycles) and IOC (interrupt on change)          *
;      for RX start bit leading edge detection on RXPIN           *
;     ·Circular 16-byte RX character buffer                       *
;     ·Inverted TX and RX signals (MAX232A or similar             *
;      inverting RS-232 interface required)                       *
;   ·Relatively small - the ISR and the support routines          *
;    Init232, Put232, and Get232 use 102 words of code            *
;    space at locations 0x04 through 0x69                         *
;   ·Worst case 23% ISR 'overhead' (24-usecs) when a              *
;    complete RX character is added to the circular               *
;    buffer once every 1.04-msecs while receiving                 *
;                                                                 *
;      MPLab: 7.21    (tabs=8)                                    *
;      MPAsm: 4.02                                                *
;                                                                 *
;******************************************************************

        #include        <p12f683.inc>
        errorlevel      -302

        __config        _FCMEN_OFF & _IESO_OFF & _MCLRE_OFF & _WDT_OFF & _INTRC_OSC_NOCLKOUT
;
; file register variables
;
IPROC   equ     h'20'           ; ISR Process Latch
TXCNT   equ     h'21'           ; TX-232 bit count
TXVAR   equ     h'22'           ; TX-232 data byte
RXCNT   equ     h'23'           ; RX-232 bit count
;
RDPTR   equ     h'24'           ; RX buffer Rd pointer
WRPTR   equ     h'25'           ; RX buffer Wr pointer
;
PTRL    equ     h'26'           ; PutString
PTRH    equ     h'27'           ; PutString
TEMP    equ     h'28'           ; PutByte

RXBUFF  equ     0xA0            ; 16 byte RX buffer, A0h-AFh
;
; IPROC flag bit constants
;
RXFLG   equ     h'00'           ; 1=rx in progress
TXFLG   equ     h'01'           ; 1=tx in progress
flag2   equ     h'02'           ; spare
flag3   equ     h'03'           ; spare
flag4   equ     h'04'           ; spare
flag5   equ     h'05'           ; spare
flag6   equ     h'06'           ; spare
flag7   equ     h'07'           ; spare
;
; RXPIN and TXPIN constants
;
RXPIN   equ     h'01'           ; RS-232 RX (GP1)
TXPIN   equ     h'00'           ; RS-232 TX (GP0)
BAUDX   equ     .208            ; 208 for 9600 baud
;
; file locations used by ISR for saving and restoring the stack
;
W_ISR   equ     h'70'           ; ISR 'W'
S_ISR   equ     h'71'           ; ISR 'STATUS'
P_ISR   equ     h'72'           ; ISR 'PCLATH'
F_ISR   equ     h'73'           ; ISR 'FSR'

;******************************************************************
;
;  _Title macro - home cursor, clear screen, print a string
;{
_Title  macro   str             ;
        local   String, Print
        movlw   low String      ;
        movwf   PTRL            ;
        movlw   high String     ;
        movwf   PTRH            ;
        goto    Print           ;
String  dt      0x1b,"[2J"      ; home cursor, clear screen
        dt      str,0
Print   call    PutString       ; print string
        endm
;}
;******************************************************************
;
;  _Print macro - print a string to the RS-232 port
;
_Print  macro   str             ;
        local   String, Print
        movlw   low String      ;
        movwf   PTRL            ;
        movlw   high String     ;
        movwf   PTRH            ;
        goto    Print           ;
String  dt      str,0
Print   call    PutString       ; print string
        endm

;
; Hardware notes:
;
; <1> INTOSC 8-MHz, 500-nsec instruction cycle
; <2> GP3 (pin 4) > 'bit banged' serial input
; <3> GP0 (pin 7) > 'bit banged' serial output
; <4> RS-232 signals inverted with MAX232 or 2N7000 drivers
; <5> Using 2700 ohm pull-up resistor on GP3
; <6>
; <7>
;
;
;  This program simply prints a text string to Hyperterminal
;  and echos typed characters back to Hyperterminal...
;
;  Setup Hyperterminal for 9600, 8, 1, none...  Use a MAX232 or
;  similar level shifting circuit (I use a pair of 2N7000s) for
;  connection between the 12F683 and PC...
;

;******************************************************************
;                                                                 *
;                                                                 *
;                                                                 *
;                                                                 *
;                                                                 *
;******************************************************************

        org     0x0000

Start   clrf    STATUS          ;                                 |B0
        goto    Main            ;                                 |B0

;******************************************************************
;                                                                 *
;     Interrupt Service Routine for Half Duplex Serial I/O        *
;                                                                 *
;     Interrupts are generated every 104-us by TMR2 for 9600      *
;     baud shift operations and by IOC (interrupt on change)      *
;     on the RX start bit leading edge on RXPIN GP3...            *
;                                                                 *
;     On detecting the RX start bit leading edge, GP3 IOC is      *
;     turned off, RXFLG is set to indicate rx-in-progress,        *
;     RXCNT bit count variable is set, and TMR2 is advanced       *
;     by 1/2 bit (52-usec)...  Note - advancing TMR2 could        *
;     mess up a transmit-in-progress, so you shouldn't send       *
;     and receive at the same time...                             *
;                                                                 *
;******************************************************************

        org     0x0004
;
;  save MAIN program context
;
ISR     movwf   W_ISR           ; save W-reg                      |B?
        swapf   STATUS,W        ; doesn't change STATUS bits      |B?
        movwf   S_ISR           ; save STATUS reg                 |B?
        clrf    STATUS          ; bank 0                          |B0
        movf    PCLATH,W        ; get PCLATH                      |B0
        movwf   P_ISR           ; save PCLATH                     |B0
        movf    FSR,W           ; get FSR                         |B0
        movwf   F_ISR           ; save FSR                        |B0
;
;  test for GP3 (RXPIN) start bit leading edge IOC interrupt
;
;{
        btfss   INTCON,GPIF     ; IOC "start bit" interrupt?      |B0
        goto    ISR_TX          ; no, branch                      |B0
        movf    GPIO,W          ; yes, read GPIO                  |B0
        bcf     INTCON,GPIF     ; clear IOC interrupt flag        |B0
        bsf     IPROC,RXFLG     ; indicate RX in progress         |B0
        movlw   d'10'           ; 10 bits (start, 8 data, stop)   |B0
        movwf   RXCNT           ; initialize RX bit counter       |B0
        movlw   BAUDX/2         ;                                 |B0
        movwf   TMR2            ; inc TMR2 by 1/2 bit (52-usec)   |B0
;       bsf     INTCON,PEIE     ; enable peripheral (tmr2) ints   |B0
        goto    ISR_X           ; turn off GP3 IOC & exit         |B0
;}
;  bit banged transmit
;
ISR_TX  btfss   IPROC,TXFLG     ; TX in progress?                 |B0
        goto    ISR_RX          ; no, branch                      |B0
        movf    TXCNT,W         ; TX bit count initialized?       |B0
        bnz     ISR_TX0         ; yes, branch, send bit           |B0
        movlw   d'11'           ; else,                           |B0
        movwf   TXCNT           ; initialize TX bit count         |B0
        goto    ISR_TX1         ; send the start bit              |B0
ISR_TX0 rrf     TXVAR,f         ; shift lsb into C                |B0
        bsf     TXVAR,7         ; set bit 7 for stop bits         |B0
        btfsc   STATUS,C        ; skip if C=0                     |B0
        bsf     GPIO,TXPIN      ; set TX pin                      |B0
        btfss   STATUS,C        ; skip if C=1                     |B0
ISR_TX1 bcf     GPIO,TXPIN      ; clear TX pin                    |B0
        decfsz  TXCNT,f         ; last bit?                       |B0
        goto    ISR_RX          ; no, branch                      |B0
        bcf     IPROC,TXFLG     ; yes, indicate end of TX         |B0
;
;  bit banged receive with 16 byte circular RX buffer
;
ISR_RX  btfss   IPROC,RXFLG     ; RX in progress?                 |B0
        goto    ISR_XIT         ; no, branch                      |B0
        movf    WRPTR,W         ; RX buffer Wr Pointer            |B0
        movwf   FSR             ; RXBUFF[WRPTR] (sort of)         |B0
        bcf     STATUS,C        ; assume bit=0                    |B0
        btfsc   GPIO,RXPIN      ; is it a 0?                      |B0
        bsf     STATUS,C        ; no, bit=1                       |B0
        rrf     INDF,f          ; shift bit into our char         |B0
        decfsz  RXCNT,f         ; all 10 bits?                    |B0
        goto    ISR_XIT         ; no, branch, else                |B0
        rlf     INDF,f          ; get rid of the stop bit         |B0
        bcf     IPROC,RXFLG     ; clear RX-in-progress flag       |B0
        incf    WRPTR,W         ; W=WRPTR+1                       |B0
        andlw   RXBUFF+h'0F'    ; keep in range of A0..AF         |B0
        xorwf   RDPTR,W         ; buffer full (WRPTR+1=RDPTR)?    |B0
        bz      ISR_X           ; yes, ignore new char, else      |B0
        xorwf   RDPTR,W         ; restore WRPTR + 1 value         |B0
        movwf   WRPTR           ; update RXBUFF WRPTR             |B0
;
;  toggle RXPIN (GP3) IOC on or off
;
ISR_X   bsf     STATUS,RP0      ; select bank 1                   |B1
        movlw   1<<RXPIN        ; mask for RXPIN                  |B1
        xorwf   IOC,f           ; toggle GP3 IOC                  |B1
        bcf     STATUS,RP0      ; select bank 0                   |B0
;
;  clear TMR2 interrupt flag and restore MAIN program context
;
ISR_XIT bcf     PIR1,TMR2IF     ; clear TMR2 irq flag first       |B0
        movf    F_ISR,W         ;                                 |B0
        movwf   FSR             ; restore FSR                     |B0
        movf    P_ISR,W         ;                                 |B0
        movwf   PCLATH          ; restore PCLATH                  |B0
        swapf   S_ISR,W         ;                                 |B0
        movwf   STATUS          ; restore STATUS                  |B?
        swapf   W_ISR,f         ; don't screw up STATUS           |B?
        swapf   W_ISR,W         ; restore W-reg                   |B?
        retfie                  ; return from interrupt           |B?

;******************************************************************
;                                                                 *
;   Companion Put232 and Get232 subroutines                       *
;                                                                 *
;******************************************************************
;
;  Put232 - enter with character to be sent in W
;
Put232  btfsc   IPROC,TXFLG     ; TX in progress?                 |B0
        goto    Put232          ; yes, branch and wait            |B0
        movwf   TXVAR           ; else, stuff character           |B0
        bsf     IPROC,TXFLG     ; initiate TX                     |B0
        return                  ;                                 |B0
;
;  Get232 - exit with received character in W
;         - RXBUFF "pull" operation
;
Get232  movf    RDPTR,W         ;                                 |B0
        movwf   FSR             ; setup for indirect access       |B0
        xorwf   WRPTR,W         ; buffer empty (RDPTR=WRPTR)?     |B0
        bz      Get232          ; yes, loop (wait), else          |B0
        incf    RDPTR,W         ; increment RDPTR                 |B0
        andlw   RXBUFF+h'0F'    ; keep it in range of A0..AF      |B0
        movwf   RDPTR           ; update RXBUFF RDPTR             |B0
        movf    INDF,W          ; pull character                  |B0
        return                  ;                                 |B0

;******************************************************************
;                                                                 *
;   Companion Init232 subroutine                                  *
;                                                                 *
;******************************************************************
;
;  initialize RS-232 variables before turning on interrupts
;
Init232 clrf    IPROC           ; clear ISR process latch var     |B0
        clrf    TXCNT           ; clear TX bit count var          |B0
        movlw   RXBUFF          ; init circular buffer pointers   |B0
        movwf   RDPTR           ; set RX buffer Rd pointer        |B0
        movwf   WRPTR           ; set RX buffer Wr pointer        |B0
;
;  put TXPIN latch in the stop condition and setup TRISIO data
;  direction for TXPIN output and RXPIN input
;
        bsf     GPIO,TXPIN      ; put TXPIN latch in STOP state   |B0
        bsf     STATUS,RP0      ; select Bank 1                   |B1
        bcf     TRISIO,TXPIN    ; set TXPIN as an output          |B1
        bsf     TRISIO,RXPIN    ; set RXPIN as an input           |B1
;
        bsf     IOC,RXPIN       ; RXPIN 'Interrupt On Change'     |B1
;
;  configure TIMER2 for 104-usec interrupts (8-MHz clock)
;
;  note: INTCON is 00000000 after any reset
;         T2CON is 00000000 after any reset (pre=1, post=1)
;          PIE1 is 000-0000 after any reset
;          PIR1 is 000-0000 after any reset
;
        bsf     PIE1,TMR2IE     ; enable TMR2 interrupts          |B1
        movlw   BAUDX-1         ; number of 500-nsec ticks        |B1
        movwf   PR2             ; 104-usec interrupts             |B1
        bcf     STATUS,RP0      ; select Bank 0                   |B0
        bsf     INTCON,GIE      ; enable global interrupts        |B0
        bsf     INTCON,PEIE     ; enable peripheral interrupts    |B0
        bsf     INTCON,GPIE     ; enable IOC interrupts           |B0
        bsf     T2CON,TMR2ON    ; start TMR2                      |B0
        return                  ;                                 |B0

;******************************************************************
;
;  PutString sends a character string through the RS232 port
;
;  Entry: setup PTRL and PTRH to string address before entry
;         string must be terminated with a 00 byte
;
PutString
        call    GetTable        ; get a table character           |B0
        andlw   b'11111111'     ;                                 |B0
        skpnz                   ; 00 byte, last character?        |B0
        return                  ; yes, return                     |B0
        call    Put232          ; else,output character           |B0
        incfsz  PTRL,F          ; increment pointer               |B0
        goto    PutString       ;                                 |B0
        incf    PTRH,F          ;                                 |B0
        goto    PutString       ;                                 |B0
;
GetTable
        movf    PTRH,W          ;                                 |B0
        movwf   PCLATH          ;                                 |B0
        movf    PTRL,W          ;                                 |B0
        movwf   PCL             ;                                 |B0

;******************************************************************
;
;  Print byte in W as two ASCII nybbles
;
PutByte movwf   TEMP            ; save byte                       |B0
        swapf   TEMP,W          ; swap nybbles in W               |B0
        call    Hex2Asc         ; process left nybble             |B0
        movf    TEMP,W          ; process right nybble            |B0
Hex2Asc andlw   b'00001111'     ; mask off left nybble            |B0
        addlw   a'6'            ; 0-9>36-3F, A-F>40-45            |B0
        btfsc   STATUS,DC       ; A..F?  no, skip, else           |B0
        addlw   h'07'           ; A-F (40-45) > 47-4C             |B0
        addlw   0-6             ; '0'..'9' or 'A'..'F'            |B0
        goto    Put232          ; print ASCII nybble              |B0

;******************************************************************
;                                                                 *
;                                                                 *
;                                                                 *
;                                                                 *
;                                                                 *
;******************************************************************
;
;  12F683 specific peripheral initialization
;
Main    movlw   b'00000111'     ;                                 |B0
        movwf   CMCON0          ; turn off comparator             |B0
        bsf     STATUS,RP0      ; bank 1                          |B1
        clrf    ANSEL           ; turn off A2D, digit I/O         |B1
        movlw   b'00001000'     ;                                 |B1
        movwf   TRISIO          ; setup TRISIO as desired         |B1
;
;  setup 8-MHz INTOSC
;
        movlw   b'01110000'     ;                                 |B1
        movwf   OSCCON          ; 8-MHz INTOSC system clock       |B1
Stable  btfss   OSCCON,HTS      ; oscillator stable?              |B1
        goto    Stable          ; no, branch                      |B1
        bcf     STATUS,RP0      ; bank 0                          |B0
;
;  initialize RS-232 Serial I/O
;
        call    Init232         ;                                 |B0
;
;  _Title macro - home cursor, clear screen, and print a string
;
        _Title  "K8LH 12F683 Half Duplex 9600 Demo\r\n\n"
        _Print  "Test 1\r\n"
        _Print  "Test 2\r\n\n"
;
;  Echo characters coming from Hyperterminal
;
Test    call    Get232          ; receive character               |B0
        call    Put232          ; echo character                  |B0
        goto    Test            ;                                 |B0

;
        end
 
Thanks, Mike

I took your earlier code and flowcharted it to see how you got it into the 104 uS interrupt interval. I look forward to doing the same for this.

Just curious, when you write something as integrated as this, do you draw a plan or do a flowchart? I often flow chart, but I get the feeling that real programmers don't use such crutches.

John
 
Status
Not open for further replies.

Latest threads

New Articles From Microcontroller Tips

Back
Top