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
+bits 6-0 contain the data to be sent to the track
+bit 7 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)
+(i.e. the first two complete bytes should be 01111111 01111111)
(packets beginning with some other sequence are reserved for non-NMRA messages)
Maximum NMRA message length = 16 bytes (i.e. 112 bits).
-;ERRORS:
-
-; 1red = high interrupt bit set
-; 2red = low interrupt bit set by something which isn't timer0 or the USART
-
-
; 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
initialise
-; 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
-
-; interrupt set-up for serial receive
- bsf PIE1,5,0 ; enable USART receive interrupt (p85)
- bsf IPR1,5,0 ; set to low-priority interrupt
-
-; interrupt set-up for timer0 interrupt p79/80
- bsf INTCON,5,0 ; enable timer0 interrupts
- bcf INTCON2,2,0 ; timer0 overflow low priority
-
-
-;-----------------------------------------------------------------------------------------
-
-
; serial set-up
; initial config - TXSTA register p181
;-----------------------------------------------------------------------------------------
-; timer set-up
+; timer 0 set-up
; LED pin (21) initialisation
bcf TRISE,4,0 ; turn off PSPMODE (Data Sheet p100/101)
; initialise buffers (for BSR5, for nmra from-serial/to-track buffers)
movlw 5
- movwf BSR,0 ; set BRS to 5
+ movwf BSR,0 ; set BSR 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
+
;-----------------------------------------------------------------------------------------
+
+; initialise next action/transmit bit
+ bsf NMRACTRL,NEXTACTION,0
+ bsf NMRACTRL,TRANSMITBIT,0
+
+; initialise TOTRACKBIT bitmask
+ movlw 0x80
+ movwf TOTRACKBIT,0 ; make bit mask be 1000 0000
+
+; initialise booster direction
+ bsf TRISC,0,0 ; make pin 0 (booster direction) output
+ bcf PORTC,0,0 ; set low initially
+
; 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
+; 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
+
+; interrupt set-up for serial receive
+ bsf PIE1,5,0 ; enable USART receive interrupt (p85)
+ bsf IPR1,5,0 ; set to low-priority interrupt
+
+; interrupt set-up for timer0 interrupt p79/80
+ bsf INTCON,5,0 ; enable timer0 interrupts
+ bcf INTCON2,2,0 ; timer0 overflow low priority
;*****************************************************************************************
main_loop_led
call led_green
- call waiting
- call led_black
- call waiting
- goto main_loop_led
+ goto main_loop_led
;*****************************************************************************************
interrupt_high
- call led_red
- call waiting
- retfie 1
+ goto panic
;*****************************************************************************************
goto serial_receive
btfss INTCON,2,0 ; check whether timer0 interrupt set
goto timer0_interrupt
- call led_red
- call waiting
- call led_red
- retfie 1 ; return from interrupt to main if spurious interrupt
+ goto panic
+
+; if 2 interrupts are set at once the 2nd will generate a new interrupt on leaving
+; the interrupt routine
+
;*****************************************************************************************
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
+ btfss RCREG,7,0 ; check if bit 7 is set
call advance_write_buffer ; if so, move to next buffer
- call led_red
- call waiting
- return
+ retfie 1
+; *** I *think* the interrupt bit is cleared by reading out of RCREG
+; but this may be something to try in debugging if stuff doesn't work
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
+ movf FROMSERIAL,0,0 ; copy FROMSERIAL pointer location to W
andlw 0xF ; investigate last 4 bits
; if zero (i.e. overflowed to next buffer), branch to overflow check
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
; check next action - if 0, change to 1 and return
btfsc NMRACTRL,NEXTACTION,0
goto toggle_output
- bsf
+ bsf NMRACTRL,NEXTACTION,0
retfie 1
read_from_buffer
-; if no, find current to-track byte and bit
-; (and TRANSMITBIT with 0x1)
-
- movff TOTRACKBIT,W,0
- andlw 0x1
+; if currently on bit 7, want to skip to bit 6
-; checking whether TRANSMITBIT (bit mask) is at bit 0
-; (i.e. whether andlw 0x1 is 1 (on bit 0) or 0 (not on bit 0)
+ btfss TOTRACKBIT,7,0
+ rrncf TOTRACKBIT,1,0 ; rotate mask right
- bnz advance_pointer
-
-; if not on bit 0 (i.e. if the and above results in 0),
-; set na=cb=bit value, advance bit (i.e. rotate TRANSMITBIT left), return
+; if not on bit 7 ,
+; set na=cb=bit value, advance bit (i.e. rotate TRANSMITBIT right),
+; check if bit7, if so, advance byte, return
movff TOTRACK,FSR1L ; set low byte of IND1 pointer
movlw 5
zero_bit_to_track
bcf NMRACTRL,TRANSMITBIT,0
bcf NMRACTRL,NEXTACTION,0
- call advance_bit
- retfie 1
+ goto advance_bit
one_bit_to_track
bsf NMRACTRL,TRANSMITBIT,0
bsf NMRACTRL,NEXTACTION,0
- call advance_bit
+ goto advance_bit
+
+
+
+advance_bit
+; rotate tranmitbit to next position
+
+ rrncf TOTRACKBIT,1,0 ; rotate mask right
+
+ btfss TOTRACKBIT,7,0
+ call advance_pointer
+
retfie 1
advance_pointer
-; if currently on the last bit of the byte (bit 0), then check whether it is 1 or 0
+; currently on bit 7 of the byte, after having read rest of byte to track; check whether it is 1 or 0
movff TOTRACK,FSR1L
movlw 5
movwf FSR1H,0
movff INDF1,W,0
- andlw 0x1
+ andlw 0x80
- bnz advance_write_buffer
- bra advance_write_byte
+ bnz advance_read_buffer
+ bra advance_read_byte
-advance_write_buffer
+advance_read_buffer
-; move pointer to next buffer byte 0
+; move pointer to next buffer
; check if on 1st byte of new buffer anyway (i.e. last 4 bits = 0)
movff TOTRACK,W ; copy TOTRACK pointer location to W
totrack_overflow
; clear bit 6 (will set back to buffer 0 if has overflowed to 4)
bcf TOTRACK,6,0
-
-; advance to bit7
-
- movlw 0x1
- movwf TOTRACKBIT,0
; write na=cb=1 and return
-advance_write_byte
+advance_read_byte
; advance to next byte of buffer (increment TOTRACK)
+; (will be on bit 7 at this point anyway so no need to change TOTRACKBIT)
incf TOTRACK,1,0
-; advance to bit7
-
- movlw 0x1
- movwf TOTRACKBIT,0
; set na=cb=new bit value
-advance_bit
-; rotate tranmitbit to next position
-
- rlncf TOTRACKBIT,1,0 ; rotate mask left
-
-
-
-; 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.)
-
-
;*****************************************************************************************
-waiting
-; change - timer0 now for NMRA timer; run this off timer0+counter
-
- 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
-
-
led_green
bcf TRISD,2,0 ; make pin RD2 an output (DS100)
return
+panic
+ bcf INTCON,7,0 ; disable high-priority interrupts
+ bcf INTCON,6,0 ; disable low-priority interrupts
+ bcf PORTC,1,0 ; switch off booster
+panic_loop
+ call led_red
+ goto panic_loop
+
;*****************************************************************************************
end
-;ERRORS:
-
-; 1red = high interrupt bit set
-; 2red = low interrupt bit set by something which isn't timer0 or the USART
-
-
; 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
initialise
-; 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
-
-; interrupt set-up for serial receive
- bsf PIE1,5,0 ; enable USART receive interrupt (p85)
- bsf IPR1,5,0 ; set to low-priority interrupt
-
-; interrupt set-up for timer0 interrupt p79/80
- bsf INTCON,5,0 ; enable timer0 interrupts
- bcf INTCON2,2,0 ; timer0 overflow low priority
-
-
-;-----------------------------------------------------------------------------------------
-
-
; serial set-up
; initial config - TXSTA register p181
;-----------------------------------------------------------------------------------------
-; timer set-up
+; timer 0 set-up
; LED pin (21) initialisation
bcf TRISE,4,0 ; turn off PSPMODE (Data Sheet p100/101)
; initialise buffers (for BSR5, for nmra from-serial/to-track buffers)
movlw 5
- movwf BSR,0 ; set BRS to 5
+ movwf BSR,0 ; set BSR 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
+
;-----------------------------------------------------------------------------------------
+
+; initialise next action/transmit bit
+ bsf NMRACTRL,NEXTACTION,0
+ bsf NMRACTRL,TRANSMITBIT,0
+
+; initialise TOTRACKBIT bitmask
+ movlw 0x80
+ movwf TOTRACKBIT,0 ; make bit mask be 1000 0000
+
+; initialise booster direction
+ bsf TRISC,0,0 ; make pin 0 (booster direction) output
+ bcf PORTC,0,0 ; set low initially
+
; 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
+; 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
+
+; interrupt set-up for serial receive
+ bsf PIE1,5,0 ; enable USART receive interrupt (p85)
+ bsf IPR1,5,0 ; set to low-priority interrupt
+
+; interrupt set-up for timer0 interrupt p79/80
+ bsf INTCON,5,0 ; enable timer0 interrupts
+ bcf INTCON2,2,0 ; timer0 overflow low priority
;*****************************************************************************************
main_loop_led
call led_green
- call waiting
- call led_black
- call waiting
- goto main_loop_led
+ goto main_loop_led
;*****************************************************************************************
interrupt_high
- call led_red
- call waiting
- retfie 1
+ goto panic
;*****************************************************************************************
goto serial_receive
btfss INTCON,2,0 ; check whether timer0 interrupt set
goto timer0_interrupt
- call led_red
- call waiting
- call led_red
- retfie 1 ; return from interrupt to main if spurious interrupt
+ goto panic
+
+; if 2 interrupts are set at once the 2nd will generate a new interrupt on leaving
+; the interrupt routine
+
;*****************************************************************************************
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
+ btfss RCREG,7,0 ; check if bit 7 is set
call advance_write_buffer ; if so, move to next buffer
- call led_red
- call waiting
- return
+ retfie 1
+; *** I *think* the interrupt bit is cleared by reading out of RCREG
+; but this may be something to try in debugging if stuff doesn't work
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
+ movf FROMSERIAL,0,0 ; copy FROMSERIAL pointer location to W
andlw 0xF ; investigate last 4 bits
; if zero (i.e. overflowed to next buffer), branch to overflow check
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
; check next action - if 0, change to 1 and return
btfsc NMRACTRL,NEXTACTION,0
goto toggle_output
- bsf
+ bsf NMRACTRL,NEXTACTION,0
retfie 1
read_from_buffer
-; if no, find current to-track byte and bit
-; (and TRANSMITBIT with 0x1)
-
- movff TOTRACKBIT,W,0
- andlw 0x1
+; if currently on bit 7, want to skip to bit 6
-; checking whether TRANSMITBIT (bit mask) is at bit 0
-; (i.e. whether andlw 0x1 is 1 (on bit 0) or 0 (not on bit 0)
+ btfss TOTRACKBIT,7,0
+ rrncf TOTRACKBIT,1,0 ; rotate mask right
- bnz advance_pointer
-
-; if not on bit 0 (i.e. if the and above results in 0),
-; set na=cb=bit value, advance bit (i.e. rotate TRANSMITBIT left), return
+; if not on bit 7 ,
+; set na=cb=bit value, advance bit (i.e. rotate TRANSMITBIT right),
+; check if bit7, if so, advance byte, return
movff TOTRACK,FSR1L ; set low byte of IND1 pointer
movlw 5
zero_bit_to_track
bcf NMRACTRL,TRANSMITBIT,0
bcf NMRACTRL,NEXTACTION,0
- call advance_bit
- retfie 1
+ goto advance_bit
one_bit_to_track
bsf NMRACTRL,TRANSMITBIT,0
bsf NMRACTRL,NEXTACTION,0
- call advance_bit
+ goto advance_bit
+
+
+
+advance_bit
+; rotate tranmitbit to next position
+
+ rrncf TOTRACKBIT,1,0 ; rotate mask right
+
+ btfss TOTRACKBIT,7,0
+ call advance_pointer
+
retfie 1
advance_pointer
-; if currently on the last bit of the byte (bit 0), then check whether it is 1 or 0
+; currently on bit 7 of the byte, after having read rest of byte to track; check whether it is 1 or 0
movff TOTRACK,FSR1L
movlw 5
movwf FSR1H,0
movff INDF1,W,0
- andlw 0x1
+ andlw 0x80
- bnz advance_write_buffer
- bra advance_write_byte
+ bnz advance_read_buffer
+ bra advance_read_byte
-advance_write_buffer
+advance_read_buffer
-; move pointer to next buffer byte 0
+; move pointer to next buffer
; check if on 1st byte of new buffer anyway (i.e. last 4 bits = 0)
movff TOTRACK,W ; copy TOTRACK pointer location to W
totrack_overflow
; clear bit 6 (will set back to buffer 0 if has overflowed to 4)
bcf TOTRACK,6,0
-
-; advance to bit7
-
- movlw 0x1
- movwf TOTRACKBIT,0
; write na=cb=1 and return
-advance_write_byte
+advance_read_byte
; advance to next byte of buffer (increment TOTRACK)
+; (will be on bit 7 at this point anyway so no need to change TOTRACKBIT)
incf TOTRACK,1,0
-; advance to bit7
-
- movlw 0x1
- movwf TOTRACKBIT,0
; set na=cb=new bit value
-advance_bit
-; rotate tranmitbit to next position
-
- rlncf TOTRACKBIT,1,0 ; rotate mask left
-
-
-
-; 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.)
-
-
;*****************************************************************************************
-waiting
-; change - timer0 now for NMRA timer; run this off timer0+counter
-
- 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
-
-
led_green
bcf TRISD,2,0 ; make pin RD2 an output (DS100)
return
+panic
+ bcf INTCON,7,0 ; disable high-priority interrupts
+ bcf INTCON,6,0 ; disable low-priority interrupts
+ bcf PORTC,1,0 ; switch off booster
+panic_loop
+ call led_red
+ goto panic_loop
+
;*****************************************************************************************
end