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.

ASM programming problem

Status
Not open for further replies.

ChriX

Member
I've been trying to add more NMEA sentences stored as data tables to the program for my GPS project, but am getting strange results. I can only describe the problem - don't really want to post my full code as it's a bit messy at the moment and you will all laugh :p

Right, so previously I had the following two sentences stored:
Code:
gpgga	addwf PCL, F				
	DT "$PSRF103,00,01,00,00", 0

gpvtg	addwf PCL, F				
	DT "$PSRF103,05,01,00,00", 0

This works fine, and im using a simple loop to retreive each character and send it. However, if I try to add another sentence above these two, when the bottom one is due to be sent, it only sends half of the string, and then the PIC resets - it's like i've used all the memory or something, which shouldn't be the case as i'm using a 16F628 and when programming the software states 850 ish words. I get the same result when I make one of the above two strings a lot longer, the loop only sends part of it and then the PIC resets. I have tried putting all of the data tables on a different page in memory but then it doesn't send anything (apart from the CR/LF at the end of the send loop).

This is the loop i'm using to send each character:
Code:
messgga	
	clrf loop					
msgloop	movf loop,W
	call gpgga					
	addlw 0	
	btfsc STATUS,Z
	goto msgdone				
	call send					
        incf loop,F					
	goto msgloop				
msgdone 
	movlw  0x0D ; CR
        call send
        movlw  0x0A ; LF
        call send 
	return

Thanks for any help!
 
It sounds like your table is crossing a 256 byte boundary?, a BIG problem if you don't know about it - assuming your tables aren't too large?, easiest solution is to move them to the start of memory (ensure you have a 'goto' to jump past them though). Next easiest, is to move them to their own 256 byte boundary, but you have to set bit's correctly before you call the table. The more complicated option is to write the table routine so it automatically compensates for the boundary - and code for this has been posted here many times.
 
You legend Nigel! Put my tables at the beginning of memory and it works fine.

I can't believe in all the work i've done with PICs before that i've never even heard about this boundary limitation. I now understand why there is such a limitation though, but never found it mentioned in any of the tutorials I started with years ago - granted i've not fully been through yours so it might be in there. ;)

Thanks :)
 
ChriX said:
You legend Nigel! Put my tables at the beginning of memory and it works fine.

I can't believe in all the work i've done with PICs before that i've never even heard about this boundary limitation. I now understand why there is such a limitation though, but never found it mentioned in any of the tutorials I started with years ago - granted i've not fully been through yours so it might be in there. ;)

We've all been caught that way, and probably will be in the future, the reason is simple, you're adding to an 8 bit PCL, so it can only address 256 bytes, and the addition doesn't affect the extra PCL bits which allow it to address the rest of the memory.
 
May I suggest an alternative that allows in-line code strings which can be longer than 256 bytes and can straddle 256 byte boundaries (by correctly manipulating PCLATH along with PCL)?

Regards, Mike

Code:
;
;  example usage of the _Print macro in your program
;
        _Print  "$PSRF103,00,01,00,00\r\n"
        _Print  "$PSRF103,05,01,00,00\r\n"
;
Code:
;******************************************************************
;
;  _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
;
;******************************************************************
Code:
;******************************************************************
;
;  PutStr - 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
        btfsc   STATUS,Z        ; a 00 byte, last character?      |B0
        return                  ; yes, return                     |B0
        call    Put232          ; output char                     |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
;
;******************************************************************
 
Last edited:
Mike said:
May I suggest an alternative which allows in-line code strings which can be longer than 256 bytes and can straddle 256 byte boundaries (by correctly manipulating PCLATH along with PCL)?

Regards, Mike

Code:
;
;  example usage of the _Print macro in your program
;
        _Print  "$PSRF103,00,01,00,00\r\n"
        _Print  "$PSRF103,05,01,00,00\r\n"
;
Code:
;******************************************************************
;
;  _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
;
;******************************************************************
Code:
;******************************************************************
;
;  PutStr - 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
        btfsc   STATUS,Z        ; a 00 byte, last character?      |B0
        return                  ; yes, return                     |B0
        call    Put232          ; output char                     |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
;
;******************************************************************

As I mentioned above!, thanks Mike, I knew someone would post it again ;)
 
You're very welcome Nigel. And for PIC18 (16-bit instruction core), there's another very tight and clean method I like that uses the return address from the stack and TBLPTR registers.

A nice feature on the PIC18's is that two ASCII characters are stored in each 'word' of memory in the DB tables.

Regards, Mike

Code:
;
;  macro usage examples
;
        _Print  "K8LH Az/El Controller 1.041123\n\n\r"
        _Print  "Satellite AOS:\n\r"
        _Print  "Satellite LOS:\n\r"
;
Code:
;******************************************************************
;
;  _Print macro
;
_Print  MACRO   str             ; print in-line string macro
        call    PutString       ;
        db      str,0
        ENDM
;
Code:
;******************************************************************
;
;  PutString - print in-line string via Stack and TBLPTR
;
;  string must be terminated with a 00 byte and does not need
;  to be word aligned
;
PutString
        movff   TOSH,TBLPTRH    ; copy return address to TBLPTR
        movff   TOSL,TBLPTRL    ;
        clrf    TBLPTRU         ; assume PIC with < 64-KB
PutNext
        tblrd   *+              ; get in-line string character
        movf    TABLAT,W        ; last character (00)?
        bz      PutExit         ; yes, exit, else
        rcall   Put232          ; print character
        bra     PutNext         ; and do another
PutExit
        btfsc   TBLPTRL,0       ; odd address?
        tblrd   *+              ; yes, make it even (fix PC)
        movf    TBLPTRH,W       ; setup new return address
        movwf   TOSH            ; 
        movf    TBLPTRL,W       ;
        movwf   TOSL            ;
        return                  ;
;
;******************************************************************
 
Last edited:
Status
Not open for further replies.

Latest threads

Back
Top