chiark / gitweb /
reformatting, comments, etc
authorian <ian>
Sun, 13 Feb 2005 22:18:17 +0000 (22:18 +0000)
committerian <ian>
Sun, 13 Feb 2005 22:18:17 +0000 (22:18 +0000)
cebpic/i2c-test.asm

index b80dbca3cd5c8ea9b42669a04b8b98a19ebb8d4d..a7c711d3298cfad170656d35361ab4e2c0a0ce69 100644 (file)
@@ -5,43 +5,27 @@
 ; pin 21 (per-pic-led, RD2/PSP2/C1IN) states: 
 ;  high H = blue (=green), low L = orange (=red), float Z = black
 
-
+;***************************************************************************
+;SETUP AND DEFINITIONS
+
+; CONVENTIONS:
+;
+; In subroutines, unless otherwise stated, W and S may have any
+; value on entry and will be undefined on exit.
+;
+; labels ending _if_... and _endif_... are used for if ... then [... else ...]
+; labels ending _loop are for loops
+; labels ending _isr are at the start of interrupt service routines
+;                      (which must end with retfie)
+; other labels in lowercase are normal subroutines (ending in `return')
+; labels in UPPERCASE are defined addresses (in RAM or flash)
+
+;---------------------------------------------------------------------------
+; boilerplate:
 
         include         /usr/share/gputils/header/p18f458.inc
-
        radix           dec
 
-; reserved for NMRA:
-NMRACTRL       equ     0x4     ; byte 4: state relevant to NMRA control
-TRANSMITBIT    equ     0x7     ; bit 7: 0/1 bit currently being transmitted
-NEXTACTION     equ     0x6     ; bit 6: change polarity on next interrupt y/n
-
-FROMSERIAL     equ     0x1     ; byte 1: from-serial buffer location (in BSR5)
-TOTRACK                equ     0x2     ; byte 2: to-track buffer location (in BSR5)
-TOTRACKBIT     equ     0x3     ; byte 3: bit location of pointer within byte
-
-NMRA_BUFF_PAGE equ     5
-
-; flash locations for PIC-dependent info:
-
-F_PIC_NO_U     equ     20h     ; flash location of PIC number
-F_PIC_NO_H     equ     00h
-F_PIC_NO_L     equ     00h
-
-F_I2C_CTRL_U   equ     20h     ; flash location of i2c control byte
-F_I2C_CTRL_H   equ     00h
-F_I2C_CTRL_L   equ     01h
-
-; i2c specific stuff
-
-I2C_BUFF_PAGE  equ     4       ; put i2c relevant stuff into buffer page 4
-PIC_NO         equ     00h     ; pic no goes to 400h
-I2C_CTRL       equ     01h     ; i2c ctrl bit goes to 401h
-I2C_MASTER     equ     0       ; bit 0 of I2C_CTRL is 1=master 0=slave
-
-
-
-
        ifdef   SLOW_VERSION
        messg   "hello this is the slow version"
        endif
@@ -56,32 +40,51 @@ I2C_MASTER  equ     0       ; bit 0 of I2C_CTRL is 1=master 0=slave
        messg   "and an else"
        endif
 
-       org     0
-       goto    initialise
+;---------------------------------------------------------------------------
+; ID locations layout, in flash - see README.protocol
 
-;****************************************************************************
+F_PIC_NO       equ     0x200000
+F_I2C_CTRL     equ     0x200001
 
-; high priority interrupt 
+;---------------------------------------------------------------------------
+; RAM - ie, variables etc.
 
-       org     000008h
-       goto    interrupt_high
+; i2c specific stuff
+               udata   0x400
 
-; low priority interrupt 
+PIC_NO         res     1
 
-       org     000018h
-       goto    interrupt_low
+I2C_CTRL       res     1
+I2C_CTRL_MASTER        equ     0       ; bit 0 of I2C_CTRL is 1=master 0=slave
 
 ;****************************************************************************
+; VECTORS: special locations, where the PIC starts executing
+; after reset and interrupts
 
-       code
+       org     0
+       goto    vector_reset
 
-;****************************************************************************
+       org     000008h
+       goto    vector_interrupt_high
+
+       org     000018h
+       goto    vector_interrupt_low
 
-macros
+;****************************************************************************
+; MACROS
+
+;----------------------------------------
+; debugvalue(BYTE)
+;      writes BYTE through the serial port
+;      serial port hardware must be suitably initialised
+;      serial port transmit interrupts must be disabled
+;      will spin until the byte is transmitted
+;              Before          After
+;      W       any             undefined
+;      S       any             undefined
 
 ; macro to call subroutine to transmit over serial port for debugging
 ; takes 8-bit value, puts in W, invokes debug_serial_transmit
-       
        ifndef  SLOW_VERSION
 debug macro debugvalue
        endm
@@ -94,19 +97,131 @@ debug macro debugvalue
        endm
        endif
 
-debug_serial_transmit
+;--------------------
+debugvalue_serial_transmit
+;      writes W through the serial port
+;      for use by debugvalue macro only
+
        movwf   TXREG,0         ; move contents of W (i.e. debugvalue)
                                ;       to TXREG for transmission
-waitfortsr
+debugvalue_waitfortsr_loop
        btfss   TXSTA,1,0
-       bra     waitfortsr
+       bra     debugvalue_waitfortsr_loop
+
        return
 
 ;****************************************************************************
 
-initialise
+       code
+
+;****************************************************************************
+; PORTMANTEAU CODE
+; which contains lists of checks and calls to function-specific
+; routines etc.
+
+;----------------------------------------
+vector_reset
+       call    serial_setup
+       call    copy_per_pic_data
+       call    i2c_setup
+       call    enable_interrupts
+       goto    main
+
+;----------------------------------------
+main
+       banksel I2C_CTRL                ; ser BSR=i2c BSR (4)
+       btfsc   I2C_CTRL,I2C_CTRL_MASTER ; check =master?, if so
+       goto    master_main             ; goto master main routine
+       goto    slave_main              ; elso goto slave main routine
+
+;----------------------------------------
+vector_interrupt_high
+       debug   'H'     
+       goto    panic
+
+;----------------------------------------
+vector_interrupt_low
+; checks which interrupt and as soon as it finds one jumps straight
+; to the relevant ISR.  That routine will return with retfie and if
+; there was another interrupt we will re-enter, which is OK.
+
+       btfsc   PIR1,SSPIF,0    ; check if MSSP interrupt generated, if so
+;      goto    i2c_isr         ; I2C ISR will check whether master or slave
+       goto    panic           ; nothing should generate these ATM....
+
+        btfsc   PIR1,5,0        ; check for serial receive interrupt
+       goto    serial_rx_isr   ; receive serial
+
+       debug   'L'             ; else panic - interrupt but don't know why
+       goto    panic
+
+;----------------------------------------
+enable_interrupts
+;      globally enable interrupts - p77
+;      etc.
 
-; serial set-up
+       bsf     RCON,7,0        ; enable priority levels
+       bsf     INTCON,7,0      ; enable high-priority interrupts
+       bsf     INTCON,6,0      ; enable low-priority interrupts
+       bcf     PIE1,3,0        ; disable master synchronous serial port
+                               ; (MSSP; i.e. enable i2c) interrupts
+                               ; (temporary for this simple program)
+       bsf     PIE1,5,0        ; enable USART receive interrupt (p85)
+       return
+
+;***************************************************************************(
+; FUNCTIONALITY
+; these routines actually glue things together to make something that
+; does something
+
+;----------------------------------------
+master_main
+;      main program for master PIC
+
+       call    led_green
+
+master_main_loop
+       goto    master_main_loop
+
+
+;----------------------------------------
+slave_main
+;      main program for slave PICs
+
+       call    led_red
+
+slave_main_loop
+       call    wait_for_i2c_interrupt  ; wait for 1st (address) byte
+       call    wait_for_i2c_interrupt  ; wait for 2nd (data) byte
+       btg     LATD,2,0                ; toggle colour of LED
+       goto    slave_main_loop
+
+;----------------------------------------
+serial_rx_isr
+;      what we actually do here is faff with I2C to start transmitting
+       bsf     SSPCON2,SEN,0           ; i2c START
+       call    wait_for_i2c_interrupt
+       movlw   0x41                    ; transmit address 0100 0001
+       call    wait_for_i2c_interrupt
+       btfss   SSPCON2,ACKSTAT,0       ; check for ack from slave (=0), if no
+       goto    panic                   ; then panic, else
+       movff   RCREG,SSPBUF            ; copy byte from serial to i2c buffer
+       call    wait_for_i2c_interrupt
+       btfss   SSPCON2,ACKSTAT,0       ; check for ack from slave (=0), if no
+       goto    panic                   ; then panic, else
+       bsf     SSPCON2,PEN,0           ; i2c STOP
+       call    wait_for_i2c_interrupt
+
+;!!!fixme - next line is wrong, surely ?
+       goto    master_main
+
+;***************************************************************************
+; SERIAL PORT
+
+;--------------------
+serial_setup
+;      sets up the serial port, 9600 8N1 etc. as required by host
+;      interrupt is enabled for reception but not transmission
 
 ; initial config - TXSTA register p181
         bcf     TXSTA,6,0      ; p181, set 8-bit mode
@@ -124,26 +239,29 @@ initialise
        bsf     SPBRG,7,0
        bsf     SPBRG,0,0
 
-
 ; interrupt set-up for serial receive
        bcf     IPR1,5,0        ; set to low-priority interrupt
+       return
 
+;***************************************************************************
+; FLASH ID LOCATIONS
 
-;----------------------------------------------------------------------------
-
-; copy PIC-dependent info out of flash memory
+;--------------------
+copy_per_pic_data
+;      copies PIC-dependent info out of flash memory to RAM
+;      see README.protocol
 
-       movlw   F_PIC_NO_U      ; set table pointer to point to
-       movwf   TBLPTRU         ; PIC number in flash
-       movlw   F_PIC_NO_H
+       movlw   (F_PIC_NO >> 16) & 0xff ; set table pointer to point to
+       movwf   TBLPTRU                 ; PIC number in flash
+       movlw   (F_PIC_NO >> 8) & 0xff
        movwf   TBLPTRH
-       movlw   F_PIC_NO_L
+       movlw   F_PIC_NO
        movwf   TBLPTRL
 
        tblrd   *+              ; read then increment pointer 
                                ; (now points to i2c control byte)
 
-        movlb   I2C_BUFF_PAGE   ; ser BSR=i2c BSR (4)
+       banksel PIC_NO
         movf    TABLAT,0,0      ; move pic number into normal memory
         movwf   PIC_NO,1
 
@@ -151,20 +269,28 @@ initialise
 
         movf    TABLAT,0,0      ; move i2c_ctrl byte into normal memory
         movwf   I2C_CTRL,1
+; now have: PIC number in 400h, i2c control byte in 401h - see
+; RAM variables re i2c specific stuff, above
 
-; now have: PIC number in 400h, i2c control byte in 401h
-
-;----------------------------------------------------------------------------
+       return
 
-; i2c setup
+;***************************************************************************
+; I2C
 
-; NB to generate an address, take PIC_NO bits 4-0 and prepend 10
-; (i.e. all addresses are of the form 10xxxxx)
+;--------------------
+i2c_setup
+;      sets up the I2C interface
 
-       movlb   I2C_BUFF_PAGE   ; ser BSR=i2c BSR (4)
+; see also:
+; p68
+; p314
+; p 275 ID locs
 
-common_setup
+; To generate our I2C address, we take PIC_NO bits 4-0 and prepend
+; 0b10 (i.e. all addresses are of the form 0b10xxxxx)
+       banksel PIC_NO          ; ser BSR=i2c BSR (4)
 
+; common to master and slaves:
        bsf     SSPSTAT,7,0     ; disable slew rate control
        bcf     SSPSTAT,6,0     ; disable SMBus specific commands
                                ; (whatever that means)
@@ -172,16 +298,12 @@ common_setup
 
        bcf     IPR1,SSPIP,0    ; make interrupt low priority
 
+; are we master or slave ?
+       btfss   I2C_CTRL,I2C_CTRL_MASTER,1      ; test whether PIC is master
+       goto    i2c_setup_if_master
+       goto    i2c_setup_if_slave
 
-master_or_slave
-
-       btfss   I2C_CTRL,I2C_MASTER,1   ; test whether PIC is master
-       goto    pic_master_setup        ; if so, set up as master
-       goto    pic_slave_setup         ; else set up as slave
-
-
-pic_master_setup
-
+i2c_setup_if_master
        movlw   0x08
        movwf   SSPCON1,0       ; set to master mode, clear top 4 bits
 
@@ -191,172 +313,91 @@ pic_master_setup
                                ; Fosc=20MHz, currently want clock=50kHz
                                ; => SSPADD=99
 
-       goto    switch_i2c_on
-
-
-pic_slave_setup
+       goto    i2c_setup_endif_master_slave
 
+i2c_setup_if_slave
        movlw   0x06
        movwf   SSPCON1,0       ; set to 7bit slave mode, clear top 4 bits
                                ; (no extra start/stop interrupts)
        
 ; set slave address
-        movlb   I2C_BUFF_PAGE   ; set BSR=i2c BSR (4)
+       banksel PIC_NO          ; set BSR=i2c BSR (4)
        movf    PIC_NO,0,1      ; copy pic_no to W (000xxxxx)
        iorlw   0x40            ; change top 3 bits t 010 (010xxxxx)
        movwf   SSPADD,0        ; move to slave address register 
                                ; (bit 7=0, bits 6-0=address)
 
-       goto    switch_i2c_on
-
-
-switch_i2c_on
-
+i2c_setup_endif_master_slave
        bsf     SSPCON1,5,0     ; enable I2C mode
 
+       return
 
-; p68
-; p314
-; p 275 ID locs
-
-
-;----------------------------------------------------------------------------
-
-; interrupt set-up
-
-; globally enable interrupts - p77
-       bsf     RCON,7,0        ; enable priority levels
-       bsf     INTCON,7,0      ; enable high-priority interrupts
-       bsf     INTCON,6,0      ; enable low-priority interrupts
-       bcf     PIE1,3,0        ; disable master synchronous serial port
-                               ; (MSSP; i.e. enable i2c) interrupts
-                               ; (temporary for this simple program)
-       bsf     PIE1,5,0        ; enable USART receive interrupt (p85)
-
-
-;****************************************************************************
-;****************************************************************************
-
-main
-       movlb   I2C_BUFF_PAGE   ; ser BSR=i2c BSR (4)
-       btfsc   I2C_CTRL,I2C_MASTER     ; check =master?, if so
-       goto    main_master             ; goto master main routine
-       goto    main_slave              ; elso goto slave main routine
-
-
-;----------------------------------------------------------------------------
-
-main_master
-
-       call    led_green
-main_loop_led
-       goto    main_loop_led
-
-
-;----------------------------------------------------------------------------
-
-main_slave
-
-       call    led_red
-
-slave_loop
-       call    wait_for_i2c_interrupt  ; wait for 1st (address) byte
-       call    wait_for_i2c_interrupt  ; wait for 2nd (data) byte
-       btg     LATD,2,0                ; toggle colour of LED
-       goto    slave_loop
-       
-
-
-;****************************************************************************
-;****************************************************************************
-
-
-interrupt_high
-       debug   'H'     
-       goto    panic
-
-
-;****************************************************************************
-
-interrupt_low
-
-; check which interrupt.
-       btfsc   PIR1,SSPIF,0    ; check if MSSP interrupt generated, if so
-;      goto    interrupt_ms    ; check whether master or slave
-       goto    panic           ; nothing should generate these ATM....
-        btfsc   PIR1,5,0        ; check whether serial receive interrupt bit set
-                               ; if so
-       goto    serial_receive  ; receive serial
-       debug   'L'             ; else panic
-       goto    panic
-
-
-interrupt_ms
-       movlb   I2C_BUFF_PAGE   ; ser BSR=i2c BSR (4)
-       btfsc   I2C_CTRL,I2C_MASTER     ; check =master?, if so
-       goto    interrupt_master        ; goto master interrupt routine
-       goto    interrupt_slave         ; elso goto interrupt_slave
-
+;----------------------------------------
+i2c_isr
+       banksel PIC_NO                  ; ser BSR=i2c BSR (4)
+       btfsc   I2C_CTRL,I2C_CTRL_MASTER ; check =master?, if so
+       goto    i2c_master_isr          ; goto master interrupt routine
+       goto    i2c_slave_isr           ; elso goto interrupt_slave
 
-;----------------------------------------------------------------------------
-interrupt_master
+;--------------------
+i2c_master_isr
        debug   'm'
        goto    panic
 
-;----------------------------------------------------------------------------
-interrupt_slave
+;--------------------
+i2c_slave_isr
        debug   's'
        goto    panic
 
-;****************************************************************************
-
-serial_receive
-       bsf     SSPCON2,SEN,0           ; i2c START
-       call    wait_for_i2c_interrupt
-       movlw   0x41                    ; transmit address 0100 0001
-       call    wait_for_i2c_interrupt
-       btfss   SSPCON2,ACKSTAT,0       ; check for ack from slave (=0), if no
-       goto    panic                   ; then panic, else
-       movff   RCREG,SSPBUF            ; copy byte from serial to i2c buffer
-       call    wait_for_i2c_interrupt
-       btfss   SSPCON2,ACKSTAT,0       ; check for ack from slave (=0), if no
-       goto    panic                   ; then panic, else
-       bsf     SSPCON2,PEN,0           ; i2c STOP
-       call    wait_for_i2c_interrupt
-       goto    main_master
-       
-
+;----------------------------------------
 wait_for_i2c_interrupt
+;      polls the relevant bit until the I2C interrupt flag is set,
+;      then returns.  should not usually be used if I2C interrupts
+;      are enabled, clearly.
+
+wait_for_i2c_interrupt_loop
        btfss   PIR1,SSPIF,0    ; check if interrupt set, if not, loop
-       goto    wait_for_i2c_interrupt
+       goto    wait_for_i2c_interrupt_loop
+
        bcf     PIR1,SSPIF,0    ; clear interrupt bit
        return
 
+;***************************************************************************
+; PER-PIC LED
 
-;****************************************************************************
+;----------------------------------------
 led_green
         bcf     TRISD,2,0       ; make pin RD2 an output (DS100)
         bsf     LATD,2,0        ; set pin RD2 H (green)
         return
 
+;----------------------------------------
 led_black
         bsf     TRISD,2,0       ; make pin RD2 an input (i.e. set Z, black)
                                ;       (DS100)
         return
 
+;----------------------------------------
 led_red
         bcf     TRISD,2,0       ; make pin RD2 an output (DS100)
         bcf     LATD,2,0        ; set pin RD2 L (red)
         return
 
 
+;***************************************************************************
+; GENERALLY-USEFUL SUBROUTINES;
+
+;----------------------------------------
 panic
+;      stops everything, makes LED red
+
        debug   'x'
        clrf    INTCON,0        ; disable all interrupts EVER
        debug   'y'
        bcf     PORTC,1,0       ; switch off booster
        debug   'z'
        call    led_red
+
 panic_loop
        goto    panic_loop