1 ;======================================================================
2 ; NMRA DATA TO TRACK - also, initially deals with all incoming RS232
4 ;======================================================================
7 ; can be tested with liberator's mic input:
8 ; 1k1, 110k resistor divider from track gives 1/100 track
11 ; sox -r 96000 -u -b -t ossdsp /dev/dsp t.dat
12 ; perl -pe '$_= m/\-/ ? "_" : "~"' <t.dat | fold -290 | perl -pe 's/$/\n\n\n/' >u
13 ; in an xterm showing font "tiny" and then resized to eg 295x54
16 ;======================================================================
18 clock equ mclock ; this part runs really only on master
24 nmractrl res 1 ; state relevant to NMRA control
25 transmitbit equ 7 ; bit 7: 0/1 bit currently being transmitted
26 nextaction equ 6 ; bit 6: change polarity on next interrupt y/n
27 ; nmractrl is a bitmask, and only the bits above are used
29 fromserial res 1 ; from-serial buffer location (in buffer bank)
30 totrack equ FSR2L ; to-track buffer location (in buffer bank)
31 totrackbit res 1 ; bit location of pointer within byte
33 ; buffers are each 16 bytes (this is hardwired)
34 ; and there are four of them starting at 0x500, 0x510, 0x520, 0x530.
36 ; fromserial and totrack are pointers into the buffer page
38 ; fromserial points to the first empty byte, where we will put new
39 ; data provided by the host; this means that (fromserial & 0xf0) is
40 ; the first buffer which fails to contain a complete nmra message.
41 ; fromserial is updated only by the (low priority) serial receive
42 ; interrupt handler. Furthermore, it always maintains a correct
43 ; and valid value for use by the high-priority nmra readout ISR.
45 ; totrack points to the first remaining full byte, which is currently
46 ; being transmitted; if nothing is currently being transmitted
47 ; because there is no nmra data at all then totrack points to the
48 ; start of the same buffer as fromserial
50 ; We maintain the following properties, notionally:
52 ; totrack <= fromserial < totrack
55 ; \ `- equal would mean overrun
57 ; `- equal if we have nothing but
63 buffer_section udata bufferpage << 8
71 ;****************************************************************************
75 ; macro to call subroutine to transmit over serial port for debugging
76 ; takes 8-bit value, puts in W, invokes debug_serial_transmit
79 debug macro debugvalue
84 debug macro debugvalue
86 call debug_serial_transmit
91 mov_wfa TXREG ; move contents of W (i.e. debugvalue)
92 ; to TXREG for transmission
98 ;****************************************************************************
102 ; initial config - TXSTA register p181
103 bc_fa TXSTA,6 ; p181, set 8-bit mode
104 bs_fa TXSTA,5 ; transmit enable
105 bc_fa TXSTA,4 ; asynchronous mode
108 ; initial config - RCSTA register p182
109 bs_fa RCSTA,7 ; serial port enable (p182)
110 bc_fa RCSTA,6 ; 8-bit reception
111 bs_fa RCSTA,4 ; enable continuous receive
113 ; set SPBRG to get correct baud rate according to table top right p186
114 ; (Tosc = 20MHz, desired baud rate = 9600)
117 mov_lw ~((1<<RCIP) | (1<<TXIP))
118 and_wff IPR1 ; serial interrupts: low priority
119 mov_lw (1<<RCIE) | (1<<TXIE)
120 ior_wff PIE1 ; serial interrupt: interrupt enable
124 ;----------------------------------------------------------------------------
128 ; timer0 initial config for NMRA timer
131 bc_fa T0CON,6 ; p107 Timer0 -> 16bit mode (testing)
135 bs_fa T0CON,6 ; p107 Timer0 -> 8bit mode (not-testing)
138 bc_fa T0CON,5 ; timer0 use internal clock
139 bc_fa T0CON,3 ; use prescaler
143 bc_fa T0CON,1 ; } prescale value 1:2
144 bc_fa T0CON,0 ; } (not-testing)
149 bc_fa T0CON,1 ; } prescale value 1:16
150 bc_fa T0CON,0 ; } (testing)
153 debug 'b' ; write 'b' to serial port
154 ;----------------------------------------------------------------------------
156 ; initialise buffers (for bank 5, for nmra from-serial/to-track buffers)
161 clr_fa nmractrl ; for bits relevant to control of nmra stream
162 clr_fa fromserial ; for loc'n of write-from-usart ptr in buffers
163 clr_fa totrack ; for loc'n of send-to-track ptr in buffers
167 debug 'c' ; write 'c' to serial port
168 ;----------------------------------------------------------------------------
171 ; initialise next action/transmit bit
172 bs_fa nmractrl,nextaction
173 bs_fa nmractrl,transmitbit
175 nmra_restartmessage ; Entrypoint from power_polarising_tick, at end
176 ; of settle time. Goes back to beginning of
177 ; current message (if any) and retransmits it.
178 ; Also, enables booster PWM and Timer 0 interrupts.
182 ; initialise totrackbit bitmask
184 mov_wfa totrackbit ; make bit mask be 1000 0000
186 ; initialise booster direction
187 bc_fa TRISC,0 ; make pin 0 (booster direction) output
188 bc_fa PORTC,0 ; set low initially
190 ; set booster pwm high
191 bs_fa PORTC,1 ; booster pwm high
192 bc_fa TRISC,1 ; make pin 1 (booster pwm) output
194 debug 'd' ; write 'd' to serial port
195 ;----------------------------------------------------------------------------
199 ; interrupt set-up for timer0 interrupt p79/80
200 bs_fa INTCON2,2 ; timer0 overflow high priority
201 bs_fa INTCON,5 ; enable timer0 interrupts
204 debug 'e' ; write 'e' to serial port
208 ;****************************************************************************
211 bt_f_if0 PIR1,RCIF ; check whether serial recv interrupt bit set
216 ; debug 'h' ; write 'h' to serial port
217 bt_fa_if1 RCSTA,FERR ; if FERR set (= framing error), then panic
219 bt_fa_if1 RCSTA,OERR ; if OERR set (= overrun error), then panic
222 mov_ff fromserial,FSR0L ; set low byte of INDF0 pointer
224 mov_wfa FSR0H ; set high byte of INDF0 pointer
226 mov_fw RCREG ; get received byte
227 mov_wf INDF0 ; copy to received register
229 ; check whether bit 7 is clear.
230 ; If so, move to next buffer (or process other kind of message)
231 bra_nn end_message ; (STATUS N still from mov_fw RCREG)
234 ; If not, move to next byte
235 inc_fa fromserial ; advance fromserial pointer by 1 byte
240 bra_z receive_message_too_long
242 intrl_handled_nostack
244 receive_too_much_nmra panic morse_HN
245 receive_message_too_long panic morse_HW
247 ; *** I *think* the interrupt bit is cleared by reading out of RCREG
248 ; but this may be something to try in debugging if stuff doesn't work
251 ; so what's the first byte then ?
254 and_wff fromserial ; fromserial := 00BB0000
255 com_fw INDF0 ; where BB is this buffer
256 bra_nz not_nmra_message
258 ; so, first byte is FF (since complement of it is zero)
259 ; so, move to next buffer
262 ; increment top 4 bits of fromserial (already cleared low 4 bits)
264 mov_fw fromserial ; W = 00BB0000
265 add_lw 0x10 ; W = 0?CC0000
266 mov_wf t ; t = 0?CC0000
267 ; where BB is this buffer
268 ; and CC is next buffer
270 xor_wfw totrack ; W = 0?DD????
271 and_lw 0x30 ; ..DD....
272 bra_z receive_too_much_nmra ; where DD is (fromserial buffer)
273 ; xor (totrack buffer)
275 mov_wf t ; W = 0?CC0000
276 bc_w 6 ; W = 00CC0000
279 bra serial_receive_done
282 ; we've already set FSR0 and fromserial to point
283 ; back to beginning of the same buffer
284 call serialrx_generalmsg
285 bra serial_receive_done
287 ;****************************************************************************
289 near_interrupt_high code
291 master_interrupt_high_notnmra
294 master_interrupt_high
295 bt_f_if0 INTCON,TMR0IF ; check whether timer0 interrupt set
296 bra master_interrupt_high_notnmra
299 debug ',' ; write 'j' to serial port
300 bc_fa INTCON,TMR0IF ; clear interrupt-set bit
303 mov_lw 0x01 ; (testing)
307 mov_lw 0x73 ; (not-testing)
310 mov_wfa TMR0L ; set timer0 to appropriate value (so interrupt takes 58us)
313 debug 'k' ; write 'k' to serial port
314 ; check next action - if 0, change to 1 and return
315 bt_fa_if1 nmractrl,nextaction
317 bs_fa nmractrl,nextaction
318 debug '1' ; write 'k' to serial port
322 ; if next action = 1, then toggle output
325 debug 'l' ; write 'l' to serial port
326 btg_fa PORTC,0 ; toggle booster output pin
330 ; if transition was 0->1 then we are mid-bit, so copy transmitbit to
331 ; nextaction in preparation for 2nd half of bit and then return
333 debug 'm' ; write 'm' to serial port
334 bc_fa nmractrl,nextaction
335 bt_fa_if1 nmractrl,transmitbit
336 bs_fa nmractrl,nextaction
337 debug '2' ; write 'k' to serial port
343 debug 'n' ; write 'n' to serial port
344 ; check whether current to-track buffer = current from-serial buffer
345 ; if yes, transmit 1s (set transmitbit=1, nextaction=1 and return)
350 bra_nz read_from_buffer
351 bs_fa nmractrl,transmitbit
352 bs_fa nmractrl,nextaction
354 bs_fa TRISB,0 ; user fault Z (red)
359 bc_fa TRISB,0 ; user fault L (purple)
362 ; if currently on bit 7, want to skip to bit 6
363 ;*** wouldn't it be easier to start on bit 6 ? :-) -iwj
365 bt_fa_if1 totrackbit,7
366 rr_fa totrackbit ; rotate mask right
369 ; set na=cb=bit value, advance bit (i.e. rotate transmitbit right),
370 ; check if bit7, if so, advance byte, return
374 and_wfwa totrackbit ; select bit to be transmitted
376 bra_z zero_bit_to_track
380 debug '_' ; write 'q' to serial port
381 debug '0' ; write 'q' to serial port
382 debug '_' ; write 'q' to serial port
383 bc_fa nmractrl,transmitbit
384 bc_fa nmractrl,nextaction
388 debug '_' ; write 'q' to serial port
389 debug '1' ; write 'r' to serial port
390 debug '_' ; write 'q' to serial port
391 bs_fa nmractrl,transmitbit
392 bs_fa nmractrl,nextaction
398 ; rotate transmitbit to next position
400 debug 's' ; write 's' to serial port
401 rr_fa totrackbit ; rotate mask right
402 ;*** surely rrnc (`rotate right not through carry' I assume)
403 ;*** will leave a copy of the top bit in the N flag ? Then you
404 ;*** can use branch if negative. -iwj
405 bt_fa_if1 totrackbit,7
406 rcall advance_pointer
407 debug '5' ; write 's' to serial port
415 debug 't' ; write 't' to serial port
417 ; currently on bit 7 of the byte, after having read rest of byte to
418 ; track; check whether it is 1 or 0
420 ; if set, move to next buffer
422 rcall advance_read_buffer
424 ; if not set, move to next byte of samebuffer (increment totrack)
425 ; (will be on bit 7 at this point anyway so no need to change totrackbit)
433 ; move pointer to next buffer
434 ; clear low 4 bits of totrack and increment top 4 bits
435 ; aaaabbbb -> bbbbaaaa -> bbbb(aaaa+1) -> 0000(aaaa+1) -> (aaaa+1)0000
436 debug '7' ; write 'v' to serial port
442 debug '8' ; write 'v' to serial port
444 ; clear bit 6 (will set back to buffer 0 if has overflowed to 4)
446 debug '9' ; write 'v' to serial port
449 bs_f PIE1, TXIE ; ensure we tell host to send us more
457 ;****************************************************************************
459 panic_oerr panic morse_HO
460 panic_ferr panic morse_HF
462 ;****************************************************************************