gnupic: MACRO expanding with gpasm


Previous by date: 16 Nov 2001 09:06:28 -0000 Re: PIC programmers for Linux, James Newton. Admin 3
Next by date: 16 Nov 2001 09:06:28 -0000 Re: CUMP, James Newton. Admin 3
Previous in thread:
Next in thread: 16 Nov 2001 09:06:28 -0000 Re: MACRO expanding with gpasm, Craig Franklin

Subject: MACRO expanding with gpasm
From: Frederic Mantegazza ####@####.####
Date: 16 Nov 2001 09:06:28 -0000
Message-Id: <0111161006350F.05384@sunceng>

Hello,

For my first PIC project, I would like to make a rotary encoder interface 
based on a 12C509, which will be read via I2C bus.

So, I started with the AN541, which describes the way to implement the I2C 
slave protocol, without SSP, using a 16C54 (hope it won't be to hard to 
switch to the 12C509).

But I have some troubles with gpasm. It seems that macro expanding doesn't 
work for the BIT macro (all others work):

BIT     MACRO   label,bit,file  ;Define a bit label
label                            EQU    file<<8|bit             ;(macro)
	ENDM                    ;

Every time using this macro, the following error occurs:

i2c.asm:114:Error [113] Symbol not previously defined (B_C).
i2c.asm:55:Error [116] Value of symbol "label" differs on second pass
 pass 1=0,  pass 2=768

The line 55 is the line where the BIT macro is defined, and the 114 line 
is:

	BIT	B_C,0,STATUS	;Carry

where the B_C label is defined.

Do you have any idea why this macro doesn't expand correctly ?

-- 
    Frederic

	LIST    P=16C54, C=80, N=0, R=DEC
;
;******************************************************************************
;
;       Program:          I2C.ASM 
;       Revision Date:   
;                         12-12-95      Compatibility with MPASMWIN 1.30
;
;******************************************************************************
;
CPU     EQU     1654
SIM     EQU     0               ;Change timing constants for simulator

	IF	(CPU==1654) || (CPU==1655)
_RESVEC EQU     01FFH           ;16c54 start address
	ENDIF

	IF	CPU==1656
_RESVEC EQU     03FFH           ;16C56 start address
	ENDIF

	IF	CPU==1657
_RESVEC EQU     07FFH           ;16C57 start address
	ENDIF

;*** Reset Vector ********************************************************

	ORG     _RESVEC         ;
RESVEC  					;
	GOTO    INIT            ;

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

;**********************************************************************
;* Macros to set/clear/branch/skip on bits
;* These macros define and use synthetic "bit labels"
;* Bit labels contain the address and bit of a location
;*
;**********************************************************************
;*      Usage                    Description
;*      -----------------------  --------------------------------------
;*      BIT     label,bit,file  ;Define a bit label
;*      SEB     label           ;set bit using bit label
;*      CLB     label           ;clear bit using bit label
;*      SKBS    label           ;SKIP on bit set
;*      SKBC    label           ;SKIP on bit clear
;*      BBS     label,address   ;BRANCH on bit set
;*      BBC     label,address   ;BRANCH on bit clear
;*      CBS     label,address   ;CALL on bit set
;*      CBC     label,address   ;CALL on bit clear
;*
;**********************************************************************

BIT     MACRO   label,bit,file  ;Define a bit label
label                            EQU    file<<8|bit             ;(macro)
	ENDM                    ;

SEB     MACRO   label           ;Set bit
				 BSF    label>>8,label&7        ;(macro)
	ENDM                    ;

CLB     MACRO   label           ;Clear bit
				 BCF    label>>8,label&7        ;(macro)
	ENDM                    ;

SKBS    MACRO   label           ;Skip on bit set
				 BTFSS  label>>8,label&7        ;(macro)
	ENDM

SKBC    MACRO   label           ;Skip on bit clear
				 BTFSC  label>>8,label&7        ;(macro)
	ENDM

BBS     MACRO   label,address   ;Branch on bit set
				 BTFSC  label>>8,label&7        ;(macro)
				 GOTO   address                 ;(macro)
	ENDM                    ;

BBC     MACRO   label,address   ;Branch on bit clear
				 BTFSS  label>>8,label&7        ;(macro)
				 GOTO   address                 ;(macro)
	ENDM

CBS     MACRO   label,address   ;Call on bit set
				 CALL   label>>8,label&7        ;(macro)
	ENDM                    ;

CBC     MACRO   label,address   ;Call on bit clear
				 CALL   label>>8,label&7        ;(macro)
	ENDM


;For Assembler portability

W       EQU     0               ;For file,W
w       EQU     0               ;For file,W
F       EQU     1               ;For file,F
f       EQU     1               ;For file,F

;*******************************************************************
;* REGISTER DECLARATIONS
;*******************************************************************


	ORG     0               ;ORG for register declarations

ind     RES     1               ;0=pseudo-reg 0 for indirect (FSR)
RTCC    RES     1               ;1=real time counter
PC      RES     1               ;2=PC
STATUS  RES     1               ;3=status reg

;* Status reg bits

	BIT	B_C,0,STATUS	;Carry
	BIT	B_DC,1,STATUS	;Half carry
	BIT	B_Z,2,STATUS	;Zero
	BIT	B_PD,3,STATUS	;Power down
	BIT	B_TO,4,STATUS	;Timeout
	BIT	B_PA0,5,STATUS	;Page select (56/57 only)
	BIT	B_PA1,6,STATUS	;Page select (56/57 only)
	BIT	B_PA2,7,STATUS	;GP flag

FSR     RES     1               ;4=file select reg 0-4=indirect address
PORTA   RES     1               ;5=port A I/O register (4 bits)
PORTB   RES     1               ;6=port B I/O register

	IF      (CPU==1655)||(CPU==1657)
PORTC   RES     1               ;7=I/O port C on 16C54/56 only
	ENDIF

;registers used by this code

I2CFLG  RES     1               ;I2C flag reg
;--i2c flags-------------------------------------------------
	BIT	B_RD,0,I2CFLG	;Flag: 1=read
	BIT	B_UA,1,I2CFLG	;Flag: 0=reading unit address
	BIT	B_SA,2,I2CFLG	;Flag: 1=reading subabbress
	BIT	B_ID,3,I2CFLG	;Flag: 1=reading id
;------------------------------------------------------------
I2CREG  RES     1               ;I2C I/O register
I2CSUBA RES     1               ;Subaddress
I2CBITS RES     1               ;I2C xmit bit counter


;**********************************************************************
;* 8 Pseudo registers accessed by sub-addresses 1-8
;* (address 0 accesses the ID string)
;* these are read-write registers
;**********************************************************************


I2CR0   EQU     $               ;Sub-address 8
	RES     1               ;8 pseudo registers

I2CR1   EQU     $               ;Sub-address 1
	RES     1

I2CR2   EQU     $               ;Sub-address 2
	RES     1

I2CR3   EQU     $               ;Sub-address 3
	RES     1

I2CR4   EQU     $               ;Sub-address 4
	RES     1

I2CR5   EQU     $               ;Sub-address 5
	RES     1

I2CR6   EQU     $               ;Sub-address 6
	RES     1

I2CR7   EQU     $               ;Sub-address 7
	RES     1

;Constants used by program

DEVICE_ADDRESS EQU      0D6H            ;I2C device address (device_address+1 = read)

;*************************************************************************
;** PORTA DEFINITIONS
;** I2C interface uses PORTA
;** note SDA goes to A0 for code efficiency
;**
;*************************************************************************


TAREAD  EQU     B'11110111'     ;TRISA register for SDA read
TAWRITE EQU     B'11110110'     ;TRISA register for SDA write
TAINIT  EQU     TAREAD          ;Initial TRISA value

	BIT	B_SDA,0,PORTA	;I2C SDA (data) This must be bit 0!
	BIT	B_SCL,1,PORTA	;I2C SCL (clock)
;spare		B_???,2,PORTA	;not used
;spare		B_???,3,PORTA	;not used

;*************************************************************************
;**
;** Port B definition (Parallel out)
;**
;*************************************************************************
TBINIT  EQU     B'00000000'     ;Port B tris (all output)
PBINIT  EQU     B'11111111'     ;Port B init


;**********************************************************************
;* Macros to contain user POLL loop code.
;* These are implimented as macros to allow ease of modification,
;* especially in real-time applications. The functions could be coded as
;* in-line code or as subroutines depending on ROM/time tradeoffs.
;*
;* USER_MAIN:   Decision or code to perform at idle time
;*
;* USER_Q:      'Quick' code for use during transfer - max 8 æs for full
;*              IýC Spec. More than 4 æs may result in IýC retries (at
;*              full spec speed.
;*
;* USER_MSG:    Code to execute at receipt of IýC command.
;*
;**********************************************************************

USER_MAIN       MACRO
;*** This would be user code for idle loop
	ENDM

USER_Q          MACRO
;*** This would be quick user code
	ENDM

USER_MSG        MACRO
;*** This would be user code to process a message
	ENDM

USER_RECV       MACRO
;*** This would be user code to process a received byte
;*** example code sends sub-address 0 to port b
	BBC	B_ID,_NXI_notid ;Channel 0! Bit set if INITIAL address was 0
	MOVFW   I2CREG          ;get received byte
	MOVWF   PORTB           ;and write it on portb
	GOTO    IN_CONT
_NXI_notid
	ENDM

USER_XMIT       MACRO
;*** This would be user code to prepare an output byte
;*** example code sends id string to output
	BBC	B_ID,_NXO_notid ;Channel 0! Bit set if INITIAL address was 0
	CALL    GETID           ;get next byte from ID channel
	GOTO    OUT_CONT        ;and send it
_NXO_notid
	ENDM

;*************************************************************************
; START OF CODE
;*************************************************************************
	ORG     0
;*************************************************************************
;* Device ID Table (must be at start)
;* TABLE FOR UNIT ID returns next char in W
;**********************************************************************
GETID
	MOVFW   I2CSUBA         ;W=I2CSUBA
	ANDLW   07H             ;Limit to 8 locations
	ADDWF   PC,F

;**********************************************************************
;* Device ID text: read starting at sub-address 0
;**********************************************************************

	RETLW   'P'
	RETLW   'I'
	RETLW   'C'
	RETLW   'I'
	RETLW   '2'
	RETLW   'C'
	RETLW   0
	RETLW   0


;**********************************************************************
;* I2C Device routines
;*
;* Enable must be HIGH, else state goes to 0
;* write is to me, read is from me.
;*
;*            <============== first byte / subsequant writes =====> <end>
;*
;* SDA   --|   X-----X-----X-----X-----X-----X-----X-----X---X------|  |--
;*         |---X-----X-----X-----X-----X-----X-----X-----X---X******|--|
;* (bit)   s    7     6     5     4     3     2     1     0   ackout
;* SCL  -----|  |--|  |--|  |--|  |--|  |--|  |--|  |--|  |--|  |--|  |---
;*           |--|  |--|  |--|  |--|  |--|  |--|  |--|  |--|  |--|  |--|
;*
;* STATE: 0 1 2  3  2  3  2  3  2  3  2  3  2  3  2  3  2  4  5  6  2  3 0
;*
;*            <============== subsequant reads ===================>
;*
;* SDA     X-----X-----X-----X-----X-----X-----X-----X----X------X-----
;*       --X-----X-----X-----X-----X-----X-----X-----X----X******X-----
;* (bit)ack   7     6     5     4     3     2     1     0   ackin
;* SCL  --|  |--|  |--|  |--|  |--|  |--|  |--|  |--|  |--|  |--|  |--
;*        |--|  |--|  |--|  |--|  |--|  |--|  |--|  |--|  |--|  |--|
;*
;* STATE:  7  8  7  8  7  8  7  8  7  8  7  8  7  8  7  8  9  A  7  8
;*
;*            <============== Final READ =========================>
;*
;* SDA     X-----X-----X-----X-----X-----X-----X-----X----X-|**|-------
;*       --X-----X-----X-----X-----X-----X-----X-----X----X*|--|
;* (bit)ack   7     6     5     4     3     2     1     0   ackin
;* SCL  --|  |--|  |--|  |--|  |--|  |--|  |--|  |--|  |--|  |---------
;*        |--|  |--|  |--|  |--|  |--|  |--|  |--|  |--|  |--|
;*
;* STATE:  7  8  7  8  7  8  7  8  7  8  7  8  7  8  7  8  9  A  0  0
;*
;* STATE B is an ignore bit state for non-addressed bits
;* STATE C indicates last sample had ENA low
;* on rising edge of ENA, DATA LOW = low voltage, DATA&CLOCK low = RESET
;**********************************************************************

;I2C interface uses PORTA
;note SDA must be on PORTA,0 for code efficiency

;*************************************************************************
;** INIT
;** Hardware reset entry point
;**
;*************************************************************************
INIT    ;Power-on entry

;*************************************************************************
;** RESET
;** software reset entry point
;**
;*************************************************************************
RESET   ;Soft reset

	MOVLW   TAINIT          ;Init ports
	TRIS    PORTA
	MOVLW   TBINIT
	TRIS    PORTB
	MOVLW   PBINIT
	MOVWF   PORTB

;******************************************************
; Main wait loop while idle. POLL loop should be called here
;
;******************************************************

I2CWAIT
	CLRWDT                  ;Clear watchdog timer
	CLB	B_UA		;Init state flags
	CLB	B_SA		;Init state flags
	CLB	B_RD		;Init state flags

loop1
	CLRWDT                  ;Clear watchdog timer

	USER_MAIN       ;Call user code while in idle state

	SKBC	B_SDA		;Wait for SDA&SCL=H
loop2
	SKBS	B_SCL		;
	GOTO    loop1           ; No longer valid to wait for start!

	CLRWDT                  ;Clear watchdog timer

	USER_MAIN       ;Call user code while in idle state

;** wait for start **
	SKBC	B_SCL		;Clock has dropped
	SKBC	B_SDA		;Data dropped... Start!
	GOTO    loop2

;** START RECEIVED! --- wait for first bit!
loop3
	BBS	B_SDA,I2CWAIT	;Data raised before clock dropped -- abort
	BBS	B_SCL,loop3	;Wait for clock low


NEXTBYTE
	CLRWDT                  ;Clear watchdog timer
	MOVLW   1               ;Init receive byte so bit falls off at end!
	MOVWF   I2CREG

;** Shift bits! -- external poll may be executed during low clock cycle only!
;* ENABLE line is checked for loss of enable ONLY during HIGH CLOCK

;*** CLOCK IS LOW -- DATA MAY CHANGE HERE
;*** We have at least 4 æs before any change can occur

loop4
	USER_Q
loop4A
	BBC	B_SCL,loop4A	;Wait for clock high

;*** CLOCK IS HIGH -- SHIFT BIT - then watch for change
	RRF     PORTA,W         ;Move RA0 into C
	RLF     I2CREG,F        ;Shift in bit
	SKPNC                   ;Skip if not done
	GOTO    ACK_I2C         ;Acknowledge byte

	BTFSC   I2CREG,0        ;Skip if data bit was 0
	GOTO    ii_1            ;This bit was set
ii_0
	BBC	B_SCL,loop4	;Wait for clock  low
	SKBS	B_SDA		;Data low-high == stop
	GOTO    ii_0
I2CSTOP
	USER_MSG                ;process completed message!
	GOTO    I2CWAIT         ;back to main loop

ii_1	BBC	B_SDA,I2CWAIT	;Data high-low == start
	BBC	B_SCL,loop4	;Wait for clock  low
	GOTO    ii_1

ACK_I2C
	BBC	B_UA,ACK_UA	;Not addressed - check unit address
	BBS	B_SA,ACK_SA	;Reading secondary address

;****
;** Do what must be done with new data bytes here (before ACKloop)
;** Don't ack if byte can't be processed!
;****
;--------

	USER_RECV

	MOVLW   07H             ;Register count
	ANDWF   I2CSUBA,f       ;Limit register count
	MOVLW   I2CR0           ;Pseudo-registers
	ADDWF   I2CSUBA,W       ;Offset from buffer start
	INCF    I2CSUBA, F      ;Next sub-address
	MOVWF   FSR             ;Indirect address
	MOVFW   I2CREG
	MOVWF   ind             ;Put data into register

IN_CONT                         ;continue point for intercepted bytes

ACKloop
	BBS	B_SCL,ACKloop	;Wait for clock low

	CLB	B_SDA		;Set ACK
	MOVLW   TAWRITE
	TRIS    PORTA
	CLB	B_SDA		;Set ACK (just in case docs are wrong)


ACKloop2
	USER_Q
	BBC	B_SCL,ACKloop2	;Wait for clock high

ACKloop3
	USER_Q
	BBS	B_SCL,ACKloop3	;Wait for clock low

	MOVLW   TAREAD          ;End ACK
	TRIS    PORTA

	BBC	B_RD,NEXTBYTE	;Skip if read (we were acking address only)


;*********************************************************************
; I2C Readback (I2C read request)
; Application specific code to get bytes to send may be added here.
; This routine gets data from location pointed to by I2CSUBA and
; sends it to I2C. Subsequent reads get sequential addresses. This version
; AND's the register # with 7 to limit to 8 registers (for speed). This
; could be modified to do a comparison to an ablolute number.
;
;*********************************************************************

NEXTOUT

;*** <<< PUT NEXT BYTE INTO I2CREG HERE NOW! >>> ***

	USER_XMIT

	MOVLW   07H             ;Register count
	ANDWF   I2CSUBA,f       ;Limit register count
	MOVLW   I2CR0           ;Pseudo-registers
	ADDWF   I2CSUBA,W       ;Offset from buffer start
	INCF    I2CSUBA, F      ;Next sub-address
	MOVWF   FSR             ;Indirect address
	MOVFW   ind             ;Get data from register

OUT_CONT
	MOVWF   I2CREG
;-- add code here to init I2CREG! when B_ID is clear!
	MOVLW   8               ;Bit counter
	MOVWF   I2CBITS

;** OUT bits! -- external poll may be executed during low clock cycle, but
;                may also be executed during high cycle if necessary.

;* ENABLE line is checked for loss of enable ONLY during HIGH CLOCK

;*** CLOCK IS LOW -- CHANGE DATA HERE FIRST!

;*** loop 1: data was 1
iiOUT_loop_1
	RLF     I2CREG,F        ;Shift data out, MSB first
	SKPNC                   ;1->0: change
	GOTO    iiOUT_1         ;Output another 1!
	CLB	B_SDA		;Output 0
	MOVLW   TAWRITE
	TRIS    PORTA
	CLB	B_SDA		;Set data (just in case docs are wrong)

iiOUT_0
	CLRWDT                  ;Clear watchdog timer

	USER_Q

iiOUT_loop_02
	BBC	B_SCL,iiOUT_loop_02 ;Wait for clock high

	USER_Q

iiOUT_loop_03
	BBS	B_SCL,iiOUT_loop_03 ;Wait for clock low

	DECFSZ  I2CBITS, F      ;Count bits
	GOTO    iiOUT_loop_0    ;Loop for last bit 0
	MOVLW   TAREAD          ;Done with last bit 0... Set to 1 for ACK
	TRIS    PORTA
	GOTO    iiOUT_ack       ;Get ACK

iiOUT_loop_0
	RLF     I2CREG,F        ;Shift data out, MSB first
	SKPC                    ;0->1: change
	GOTO    iiOUT_0         ;Output another 0!

	MOVLW   TAREAD          ;Set to 1
	TRIS    PORTA

iiOUT_1
	CLRWDT                  ;Clear watchdog timer


	USER_Q

iiOUT_loop_12
	BBC	B_SCL,iiOUT_loop_12 ;Wait for clock high


	USER_Q

iiOUT_loop_13
	BBS	B_SCL,iiOUT_loop_13 ;Wait for clock low

	DECFSZ  I2CBITS, F      ;Count bits
	GOTO    iiOUT_loop_1    ;Loop for last bit 1


iiOUT_ack ;Get acknowledge
	INCF    I2CSUBA, F      ;Next sub-address

iiOUT_loop_a2
	BBC	B_SCL,iiOUT_loop_a2 ;Wait for clock high

	BBS	B_SDA,I2CWAIT	;No ACK --- wait for restart!

;-- prepare next character here!

iiOUT_loop_a3
	BBC	B_SCL,NEXTOUT	;Wait for clock low - output next char!

	BBS	B_SDA,iiOUT_loop_a3 ;Watch out for new start condition!
	GOTO    I2CWAIT             ;Stop received!
USER_READ                         ;user code to process data sent

	GOTO    I2CWAIT


;**********************************************************************
;* Unit address received - check for valid address
;*
;**********************************************************************
ACK_UA
	SEB	B_UA		;Flag unit address received
	BTFSC   I2CREG,0        ;Skip if data coming in
	SEB	B_RD		;Flag - reading from slave
	MOVF    I2CREG,W        ;Get address
	ANDLW   0FEH            ;Mask direction flage before compare
	XORLW   DEVICE_ADDRESS  ;Device address
	BNZ     I2CWAIT         ;Not for me! (skip rest of message)
	BBS	B_RD,ACKloop	;Read - no secondary address
	SEB	B_SA		;Next is secondary address
	GOTO    ACKloop         ;Yes! ACK address and continue!

;**********************************************************************
;* Secondary address received - stow it!
;* SA = 0 is converted to 128 to facilitate ID read
;**********************************************************************
ACK_SA
	CLB	B_SA		;Flag second address received
	CLB	B_ID
	MOVFW   I2CREG          ;Get subaddress
	SKPNZ                   ;Not 0
	SEB	B_ID		;Flag - id area selected
	MOVWF   I2CSUBA         ;Set subaddress
	GOTO    ACKloop


	END

Previous by date: 16 Nov 2001 09:06:28 -0000 Re: PIC programmers for Linux, James Newton. Admin 3
Next by date: 16 Nov 2001 09:06:28 -0000 Re: CUMP, James Newton. Admin 3
Previous in thread:
Next in thread: 16 Nov 2001 09:06:28 -0000 Re: MACRO expanding with gpasm, Craig Franklin


Powered by ezmlm-browse 0.20.