chiark / gitweb /
added serial receive stuff
authorceb <ceb>
Mon, 20 Dec 2004 00:58:10 +0000 (00:58 +0000)
committerceb <ceb>
Mon, 20 Dec 2004 00:58:10 +0000 (00:58 +0000)
started on transmit to track stuff
changed timer to NMRA timer
done initialisation of output pins
not quite decided on packet format

cebpic/README.protocol [new file with mode: 0644]
cebpic/nmra-stream.asm
cebpic/nmra-test.asm [new file with mode: 0644]
detpic/nmra-stream.asm

diff --git a/cebpic/README.protocol b/cebpic/README.protocol
new file mode 100644 (file)
index 0000000..87fb3ab
--- /dev/null
@@ -0,0 +1,12 @@
+NMRA packets from the computer to the PIC should consist of 8-bit bytes.
+
+bits 7-1 contain the data to be sent to the track
+bit 0 is 1 if the byte is the last in the packet and 0 otherwise
+The first 14 data bits in the NMRA packet should be 1s.
+(i.e. the first two complete bytes should be 11111110 11111110)
+(packets beginning with some other sequence are reserved for non-NMRA messages)
+
+baud rate 9600
+most significant bit first
+8n1
index 69f0e151ef2c564aad28e10b6d2be05d969a1d07..7ef179411875c4523bcfc5b64485bf007077e803 100644 (file)
@@ -7,8 +7,28 @@
 
 ; pin 21 (per-pic-led, RD2/PSP2/C1IN) states: high H = green, low L = red, float Z = black
 
+
+; *******will need to deal with initial short circuit first
+
+
+
+
+
+
         include         /usr/share/gputils/header/p18f458.inc
 
+
+NMRACTRL       equ     0x0     ; byte 0: state relevant to NMRA control
+TRANSMITBIT    equ     0x7     ; bit 7: 0/1 bit currently being transmitted
+NEXTACTION     equ     0x6     ; bit 7: 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
+
+
+
+
        org     0
        goto    initialise
 
@@ -74,27 +94,42 @@ initialise
         bcf     TRISE,4,0       ; turn off PSPMODE (Data Sheet p100/101)
 
 
-; timer0 initial config for led flash
-;        bcf     T0CON,6,0       ; p107 Timer0 -> 16bit mode
-;        bcf     T0CON,5,0       ; timer0 use internal clock
-;        bcf     T0CON,3,0       ; use prescaler
-;        bcf     T0CON,2,0       ; }
-;        bsf     T0CON,1,0       ; } prescale value 1:8 (13ms x 8)
-;        bcf     T0CON,0,0       ; }
-
-; *** setup for timer0 for nmra bits
+; timer0 initial config for NMRA timer
+        bsf     T0CON,6,0       ; p107 Timer0 -> 8bit mode
+        bcf     T0CON,5,0       ; timer0 use internal clock
+        bcf     T0CON,3,0       ; use prescaler
+        bcf     T0CON,2,0       ; }
+        bcf     T0CON,1,0       ; } prescale value 1:2
+        bcf     T0CON,0,0       ; }
 
        
 ;-----------------------------------------------------------------------------------------
 
-; initialise buffers
+; initialise buffers (for BSR5, for nmra from-serial/to-track buffers)
+
+       movlw   5
+       movwf   BSR,0           ; set BRS to 5
+
+       clrf    NMRACTRL,0      ; for bits relevant to control of nmra stream
+       clrf    FROMSERIAL,0    ; for location of write-from-usart pointer within BSR5
+       clrf    TOTRACK,0       ; for location of send-to-track pointer within BSR5
+                               ; all in access bank
+
+;-----------------------------------------------------------------------------------------
+
+; set booster pwm high
+       bsf     TRISC,1,0       ; make pin 1 (booster pwm) output
+       bsf     PORTC,1,0       ; booster pwm high
+
+; *** also need to deal with initial short circuit state ***
+
+; initialise booster direction
+       bsf     TRISC,0,0       ; make pin 0 (booster direction) output
+
+; initialise next action/transmit bit
+       bsf     NMRACTRL,NEXTACTION,0
+       bsf     NMRACTRL,TRANSMITBIT,0
 
-       movlw   5       
-       movwf   FSR0H,0
-       clrf    FSR0L,0         ; set next empty buffer to 500h
-       movlw   5       
-       movwf   FSR1H,0
-       clrf    FSR1L,0         ; set current buffer to 500h
 
 ;*****************************************************************************************
 
@@ -117,7 +152,7 @@ interrupt_high
 
 interrupt_low
 
-; *** check which interrupt. Branch to serial_receive or timer or return
+; check which interrupt. Branch to serial_receive or timer or return
 
         btfss   PIR1,5,0        ; check whether serial receive interrupt bit set
        goto    serial_receive
@@ -126,13 +161,46 @@ interrupt_low
        call    led_red
        call    waiting
        call    led_red
-        retfie                  ; return from interrupt to main if spurious interrupt
+        retfie  1               ; return from interrupt to main if spurious interrupt
 
 ;*****************************************************************************************
 
 serial_receive
+       movff   FROMSERIAL,FSR0L        ; set low byte of IND0 pointer
+       movlw   5
+       movwf   FSR0H,0                 ; set high byte of IND0 pointer
+       movff   RCREG,IND0              ; copy to received register
+       incf    FROMSERIAL,1,0          ; advance FROMSERIAL pointer by 1 byte
+       btfss   RCREG,0,0               ; check if bit 0 is set
+       call    advance_write_buffer    ; if so, move to next buffer
+       call    led_red
+       call    waiting
+       return
+
 
 
+advance_write_buffer
+
+; check if on 1st byte of new buffer anyway (i.e. last 4 bits = 0)
+       movff   FROMSERIAL,W    ; copy FROMSERIAL pointer location to W
+       andlw   0xF             ; investigate last 4 bits
+
+; if zero (i.e. overflowed to next buffer), branch to overflow check
+       bz      fromserial_overflow
+       
+; if not zero, clear low 4 bits of FROMSERIAL and increment top 4 bits
+; aaaabbbb -> bbbbaaaa -> bbbb(aaaa+1) -> 0000(aaaa+1) -> (aaaa+1)0000
+       swapf   FROMSERIAL,1,0
+       incf    FROMSERIAL,1,0
+       movlw   0xF
+       andwf   FROMSERIAL,1,0
+       swapf   FROMSERIAL,1,0
+       
+fromserial_overflow
+; clear bit 6 (will set back to buffer 0 if has overflowed to 4)
+       bcf     FROMSERIAL,6,0
+       
+       return
 
 
 ;*****************************************************************************************
@@ -140,12 +208,72 @@ serial_receive
 timer0_interrupt
        
        bcf     INTCON,2,0      ; clear interrupt-set bit
+       movlw   0x6E
+       movwf   W,TMR0L         ; set timer0 to 0x6E (so that interrupt takes 58us)
+
+
+; check next action - if 0, change to 1 and return
+       btfsc   NMRACTRL,NEXTACTION,0
+       goto    toggle_output
+       bsf     
+       retfie  1
+
+
+; if next action = 1, then toggle output
+
+toggle_output
+       btg     PORTC,0,0       ; toggle booster output pin
+       btfss   PORTC,0,0       
+       goto    decide_next_bit
+       goto    mid_bit
+
+
+; if transition was 0->1 then we are mid-bit, so copy transmitbit to 
+; nextaction in preparation for 2nd half of bit and then return
+
+mid_bit                
+       btfsc   NMRACTRL,TRANSMITBIT,0
+       bsf     NMRACTRL,NEXTACTION,0
+       btfss   NMRACTRL,TRANSMITBIT,0
+       bcf     NMRACTRL,NEXTACTION,0
        retfie  1
+
+
+decide_next_bit
+
+; check whether current to-track buffer = current from-serial buffer
+; if yes, transmit 1s (set transmitbit=1, nextaction=1 and return)
+
+       movff   FROMSERIAL,W,0
+       xorwf   TOTRACK,0,0
+       andlw   0x30
+       bnz     read_from_buffer
+       bsf     NMRACTRL,TRANSMITBIT,0
+       bsf     NMRACTRL,NEXTACTION,0
+       retfie  1
+
+
+read_from_buffer
+
+; if no, find current to-track byte and bit
        
+; if bit=0, check value of current byte+bit
+; set = last byte&bit, so move pointer to next buffer byte 0
+; write na=cb=1 and return
+
+; if bit=0 not set, advance to bit7 of next byte in buffer
+; set na=cb=new bit value, return
 
+; if bit=/=0, 
+; set na=cb=bit value, advance bit, return
+       
+       retfie  1
+       
 
-nmra_transmit
 
+; use rotate through carry?
+; rotate mask register for anding? would also provide easy check for which bit I'm on
+; use top bit for last byte? signed integer arithmetic possible (branch if -ve etc.)
 
 
 
diff --git a/cebpic/nmra-test.asm b/cebpic/nmra-test.asm
new file mode 100644 (file)
index 0000000..76dfc59
--- /dev/null
@@ -0,0 +1,126 @@
+
+; general initialisation
+; set up serial port
+; set up 58us timer loop (actually longer for 1st test version
+
+; receive bytes from computer
+; send when computer has sent complete stream (wait for stop, or for 9x1?)
+;
+~
+
+
+; pin 21 (per-pic-led, RD2/PSP2/C1IN) states: high H = green, low L = red, float Z = black
+
+        include         /usr/share/gputils/header/p18f458.inc
+
+       org     0
+       goto    initialise_serial
+
+; interrupt routine call - this needs to be at 00008h (high priority interrupt)
+
+       org     000008h
+       goto    interrupt_high
+
+; interrupt routine call - this needs to be at 000018h (low priority interrupt)
+
+       org     000018h
+       goto    interrupt_low
+
+
+       code
+
+initialise_serial
+
+; 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
+
+; initial config - RCSTA register p182
+        bsf    RCSTA,7,0       ; serial port enable (p182)
+       bsf     RCSTA,6,0       ; 8-bit reception
+       bsf     RCSTA,4,0       ; enable continuous receive
+
+       bcf     TXSTA,4,0       ; asynchronous mode
+
+; set SPBRG to get correct baud rate according to table top right p186
+; (Tosc = 20MHz, desired baud rate = 9600)
+       bsf     TXSTA,2,0       ; set high baud rate
+       bsf     SPBRG,7,0
+       bsf     SPBRG,0,0
+
+; interrupt set-up for serial receive
+       bsf     PIE1,5,0        ; enable USART receive interrupt (p85)
+       bsf     IPR1,5,0        ; set to low-priority interrupt
+
+
+; LED pin (21) initialisation
+        bcf     TRISE,4,0       ; turn off PSPMODE (Data Sheet p100/101)
+
+
+; timer0 (main loop LED flash) initial config
+        bcf     T0CON,6,0       ; p107 Timer0 -> 16bit mode
+        bcf     T0CON,5,0       ; timer0 use internal clock
+       bcf     INTCON,5,0      ; clear TMR0IE => mask interrupt
+        bcf     T0CON,3,0       ; use prescaler
+        bcf     T0CON,2,0       ; }
+        bsf     T0CON,1,0       ; } prescale value 1:8 (13ms x 8)
+        bcf     T0CON,0,0       ; }
+
+; timer2 (nmra 58us period) initial config (p115)
+
+
+
+main
+       call    led_green
+        call    waiting
+       call    led_black
+        call    waiting
+       goto    main
+
+
+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
+
+
+waiting
+        bcf     INTCON,2,0      ; clear timer0 interrupt bit (p109)
+        clrf    TMR0H,0         ; p107 set high bit of timer0 to 0 (buffered,
+                                ; so only actually set when write to tmr0l occurs)
+        clrf    TMR0L,0         ; set low bit o timer0 - timer now set to 0000h
+loop
+        btfss   INTCON,2,0      ; check whethr tiomer0 interrupt has been set -
+                                ; skip next instruction if so
+        bra     loop
+        return
+
+
+interrupt_high
+; needed?
+
+interrupt_low
+       btfss   PIR1,5,0        ; check whether serial receive interrupt bit set
+       
+       btfss   PIR1,5,0        ; check whether timer interrupt bit set
+       call    led_red
+       clrf    WREG            ; clear working register
+       movff   RCREG,WREG      ; read data out of serial receive buffer -> WREG
+       incf    WREG            ; increment WREG
+       movff   WREG,TXREG      ; write data out of WREG -> serial transmit buffer
+       retfie
+; *** retfie 1 or 0?
+; *** also need to clear specific interrupt bits in software
+
+
+       end
index 69f0e151ef2c564aad28e10b6d2be05d969a1d07..7ef179411875c4523bcfc5b64485bf007077e803 100644 (file)
@@ -7,8 +7,28 @@
 
 ; pin 21 (per-pic-led, RD2/PSP2/C1IN) states: high H = green, low L = red, float Z = black
 
+
+; *******will need to deal with initial short circuit first
+
+
+
+
+
+
         include         /usr/share/gputils/header/p18f458.inc
 
+
+NMRACTRL       equ     0x0     ; byte 0: state relevant to NMRA control
+TRANSMITBIT    equ     0x7     ; bit 7: 0/1 bit currently being transmitted
+NEXTACTION     equ     0x6     ; bit 7: 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
+
+
+
+
        org     0
        goto    initialise
 
@@ -74,27 +94,42 @@ initialise
         bcf     TRISE,4,0       ; turn off PSPMODE (Data Sheet p100/101)
 
 
-; timer0 initial config for led flash
-;        bcf     T0CON,6,0       ; p107 Timer0 -> 16bit mode
-;        bcf     T0CON,5,0       ; timer0 use internal clock
-;        bcf     T0CON,3,0       ; use prescaler
-;        bcf     T0CON,2,0       ; }
-;        bsf     T0CON,1,0       ; } prescale value 1:8 (13ms x 8)
-;        bcf     T0CON,0,0       ; }
-
-; *** setup for timer0 for nmra bits
+; timer0 initial config for NMRA timer
+        bsf     T0CON,6,0       ; p107 Timer0 -> 8bit mode
+        bcf     T0CON,5,0       ; timer0 use internal clock
+        bcf     T0CON,3,0       ; use prescaler
+        bcf     T0CON,2,0       ; }
+        bcf     T0CON,1,0       ; } prescale value 1:2
+        bcf     T0CON,0,0       ; }
 
        
 ;-----------------------------------------------------------------------------------------
 
-; initialise buffers
+; initialise buffers (for BSR5, for nmra from-serial/to-track buffers)
+
+       movlw   5
+       movwf   BSR,0           ; set BRS to 5
+
+       clrf    NMRACTRL,0      ; for bits relevant to control of nmra stream
+       clrf    FROMSERIAL,0    ; for location of write-from-usart pointer within BSR5
+       clrf    TOTRACK,0       ; for location of send-to-track pointer within BSR5
+                               ; all in access bank
+
+;-----------------------------------------------------------------------------------------
+
+; set booster pwm high
+       bsf     TRISC,1,0       ; make pin 1 (booster pwm) output
+       bsf     PORTC,1,0       ; booster pwm high
+
+; *** also need to deal with initial short circuit state ***
+
+; initialise booster direction
+       bsf     TRISC,0,0       ; make pin 0 (booster direction) output
+
+; initialise next action/transmit bit
+       bsf     NMRACTRL,NEXTACTION,0
+       bsf     NMRACTRL,TRANSMITBIT,0
 
-       movlw   5       
-       movwf   FSR0H,0
-       clrf    FSR0L,0         ; set next empty buffer to 500h
-       movlw   5       
-       movwf   FSR1H,0
-       clrf    FSR1L,0         ; set current buffer to 500h
 
 ;*****************************************************************************************
 
@@ -117,7 +152,7 @@ interrupt_high
 
 interrupt_low
 
-; *** check which interrupt. Branch to serial_receive or timer or return
+; check which interrupt. Branch to serial_receive or timer or return
 
         btfss   PIR1,5,0        ; check whether serial receive interrupt bit set
        goto    serial_receive
@@ -126,13 +161,46 @@ interrupt_low
        call    led_red
        call    waiting
        call    led_red
-        retfie                  ; return from interrupt to main if spurious interrupt
+        retfie  1               ; return from interrupt to main if spurious interrupt
 
 ;*****************************************************************************************
 
 serial_receive
+       movff   FROMSERIAL,FSR0L        ; set low byte of IND0 pointer
+       movlw   5
+       movwf   FSR0H,0                 ; set high byte of IND0 pointer
+       movff   RCREG,IND0              ; copy to received register
+       incf    FROMSERIAL,1,0          ; advance FROMSERIAL pointer by 1 byte
+       btfss   RCREG,0,0               ; check if bit 0 is set
+       call    advance_write_buffer    ; if so, move to next buffer
+       call    led_red
+       call    waiting
+       return
+
 
 
+advance_write_buffer
+
+; check if on 1st byte of new buffer anyway (i.e. last 4 bits = 0)
+       movff   FROMSERIAL,W    ; copy FROMSERIAL pointer location to W
+       andlw   0xF             ; investigate last 4 bits
+
+; if zero (i.e. overflowed to next buffer), branch to overflow check
+       bz      fromserial_overflow
+       
+; if not zero, clear low 4 bits of FROMSERIAL and increment top 4 bits
+; aaaabbbb -> bbbbaaaa -> bbbb(aaaa+1) -> 0000(aaaa+1) -> (aaaa+1)0000
+       swapf   FROMSERIAL,1,0
+       incf    FROMSERIAL,1,0
+       movlw   0xF
+       andwf   FROMSERIAL,1,0
+       swapf   FROMSERIAL,1,0
+       
+fromserial_overflow
+; clear bit 6 (will set back to buffer 0 if has overflowed to 4)
+       bcf     FROMSERIAL,6,0
+       
+       return
 
 
 ;*****************************************************************************************
@@ -140,12 +208,72 @@ serial_receive
 timer0_interrupt
        
        bcf     INTCON,2,0      ; clear interrupt-set bit
+       movlw   0x6E
+       movwf   W,TMR0L         ; set timer0 to 0x6E (so that interrupt takes 58us)
+
+
+; check next action - if 0, change to 1 and return
+       btfsc   NMRACTRL,NEXTACTION,0
+       goto    toggle_output
+       bsf     
+       retfie  1
+
+
+; if next action = 1, then toggle output
+
+toggle_output
+       btg     PORTC,0,0       ; toggle booster output pin
+       btfss   PORTC,0,0       
+       goto    decide_next_bit
+       goto    mid_bit
+
+
+; if transition was 0->1 then we are mid-bit, so copy transmitbit to 
+; nextaction in preparation for 2nd half of bit and then return
+
+mid_bit                
+       btfsc   NMRACTRL,TRANSMITBIT,0
+       bsf     NMRACTRL,NEXTACTION,0
+       btfss   NMRACTRL,TRANSMITBIT,0
+       bcf     NMRACTRL,NEXTACTION,0
        retfie  1
+
+
+decide_next_bit
+
+; check whether current to-track buffer = current from-serial buffer
+; if yes, transmit 1s (set transmitbit=1, nextaction=1 and return)
+
+       movff   FROMSERIAL,W,0
+       xorwf   TOTRACK,0,0
+       andlw   0x30
+       bnz     read_from_buffer
+       bsf     NMRACTRL,TRANSMITBIT,0
+       bsf     NMRACTRL,NEXTACTION,0
+       retfie  1
+
+
+read_from_buffer
+
+; if no, find current to-track byte and bit
        
+; if bit=0, check value of current byte+bit
+; set = last byte&bit, so move pointer to next buffer byte 0
+; write na=cb=1 and return
+
+; if bit=0 not set, advance to bit7 of next byte in buffer
+; set na=cb=new bit value, return
 
+; if bit=/=0, 
+; set na=cb=bit value, advance bit, return
+       
+       retfie  1
+       
 
-nmra_transmit
 
+; use rotate through carry?
+; rotate mask register for anding? would also provide easy check for which bit I'm on
+; use top bit for last byte? signed integer arithmetic possible (branch if -ve etc.)