chiark / gitweb /
m% does not include loc labels and bars
[trains.git] / cebpic / nmra-stream.asm
1
2 ; can be tested with liberator's mic input:
3 ;   1k1, 110k resistor divider from track gives 1/100 track
4 ;   voltage to mic input
5 ; then
6 ;   sox -r 96000 -u -b -t ossdsp /dev/dsp t.dat
7 ;   perl -pe '$_= m/\-/ ? "_" : "~"' <t.dat | fold -290 | perl -pe 's/$/\n\n\n/' >u
8 ; in an xterm showing font "tiny" and then resized to eg 295x54
9 ;   less u
10
11 ; pin 21 (per-pic-led, RD2/PSP2/C1IN) states: 
12 ;  high H = green, low L = red, float Z = black
13
14
15
16         include         /usr/share/gputils/header/p18f458.inc
17         radix           dec
18
19 clock equ mclock
20         include         ../iwjpictest/clockvaries.inc
21
22
23 NMRACTRL        equ     0x4     ; byte 4: state relevant to NMRA control
24 TRANSMITBIT     equ     0x7     ; bit 7: 0/1 bit currently being transmitted
25 NEXTACTION      equ     0x6     ; bit 6: change polarity on next interrupt y/n
26
27 FROMSERIAL      equ     0x1     ; byte 1: from-serial buffer location (in BSR5)
28 TOTRACK         equ     0x2     ; byte 2: to-track buffer location (in BSR5)
29 TOTRACKBIT      equ     0x3     ; byte 3: bit location of pointer within byte
30
31 BUFFERPAGE      equ     5
32
33         extern  led_green
34         extern  led_red
35         extern  led_black
36
37         ifdef   SLOW_VERSION
38         messg   "hello this is the slow version"
39         endif
40
41         ifndef  SLOW_VERSION
42         messg   "hello this is the fast version"
43         endif
44
45         ifdef   SLOW_VERSION
46         messg   "with an if"
47         else
48         messg   "and an else"
49         endif
50
51         org     0
52         goto    initialise
53
54 ;****************************************************************************
55
56 ; high priority interrupt 
57
58         org     000008h
59         goto    interrupt_high
60
61 ; low priority interrupt 
62
63         org     000018h
64         goto    interrupt_low
65
66 ;****************************************************************************
67
68         code
69
70 ;****************************************************************************
71
72 macros
73
74 ; macro to call subroutine to transmit over serial port for debugging
75 ; takes 8-bit value, puts in W, invokes debug_serial_transmit
76         
77         ifndef  SLOW_VERSION
78 debug macro debugvalue
79         endm
80         endif
81
82         ifdef   SLOW_VERSION
83 debug macro debugvalue
84         movlw   debugvalue
85         call    debug_serial_transmit
86         endm
87         endif
88
89 debug_serial_transmit
90         movwf   TXREG,0         ; move contents of W (i.e. debugvalue)
91                                 ;       to TXREG for transmission
92 waitfortsr
93         btfss   TXSTA,1,0
94         bra     waitfortsr
95         return
96
97 ;****************************************************************************
98
99 initialise
100
101 ; serial set-up
102
103 ; initial config - TXSTA register p181
104         bcf     TXSTA,6,0       ; p181, set 8-bit mode
105         bsf     TXSTA,5,0       ; transmit enable
106         bcf     TXSTA,4,0       ; asynchronous mode
107         bsc_txsta_brgh
108         
109 ; initial config - RCSTA register p182
110         bsf     RCSTA,7,0       ; serial port enable (p182)
111         bcf     RCSTA,6,0       ; 8-bit reception
112         bsf     RCSTA,4,0       ; enable continuous receive
113
114 ; set SPBRG to get correct baud rate according to table top right p186
115 ; (Tosc = 20MHz, desired baud rate = 9600)
116         movlw_movwf_spbrg
117
118         debug   0x0A    ; LF to terminak
119         debug   'a'     ; write 'a' to serial port
120 ;----------------------------------------------------------------------------
121
122
123 ; timer 0 set-up
124 ; LED pin (21) initialisation
125         bcf     TRISE,4,0       ; turn off PSPMODE (Data Sheet p100/101)
126
127
128 ; timer0 initial config for NMRA timer
129
130         ifdef   SLOW_VERSION
131         bcf     T0CON,6,0       ; p107 Timer0 -> 16bit mode (testing)
132         endif
133
134         ifndef  SLOW_VERSION
135         bsf     T0CON,6,0       ; p107 Timer0 -> 8bit mode (not-testing)
136         endif
137
138         bcf     T0CON,5,0       ; timer0 use internal clock
139         bcf     T0CON,3,0       ; use prescaler
140
141         ifndef  SLOW_VERSION
142         bcf     T0CON,2,0       ; }
143         bcf     T0CON,1,0       ; } prescale value 1:2
144         bcf     T0CON,0,0       ; } (not-testing)
145         endif
146
147         ifdef   SLOW_VERSION
148         bsf     T0CON,2,0       ; }
149         bcf     T0CON,1,0       ; } prescale value 1:16
150         bcf     T0CON,0,0       ; } (testing)
151         endif
152         
153         debug   'b'     ; write 'b' to serial port
154 ;----------------------------------------------------------------------------
155
156 ; initialise buffers (for BSR5, for nmra from-serial/to-track buffers)
157
158         movlw   BUFFERPAGE
159         movwf   BSR,0           ; set BSR to point to buffer page
160
161         clrf    NMRACTRL,0      ; for bits relevant to control of nmra stream
162         clrf    FROMSERIAL,0    ; for loc'n of write-from-usart ptr in buffers
163         clrf    TOTRACK,0       ; for loc'n of send-to-track ptr in buffers
164                                 ; all in access bank
165
166
167         debug   'c'     ; write 'c' to serial port
168 ;----------------------------------------------------------------------------
169
170
171 ; initialise next action/transmit bit
172         bsf     NMRACTRL,NEXTACTION,0
173         bsf     NMRACTRL,TRANSMITBIT,0
174
175 ; initialise TOTRACKBIT bitmask
176         movlw   0x80
177         movwf   TOTRACKBIT,0    ; make bit mask be 1000 0000
178
179 ; initialise booster direction
180         bcf     TRISC,0,0       ; make pin 0 (booster direction) output
181         bcf     PORTC,0,0       ; set low initially
182
183 ; set booster pwm high
184         bsf     PORTC,1,0       ; booster pwm high
185         bcf     TRISC,1,0       ; make pin 1 (booster pwm) output
186
187         bcf     PORTB,2,0       ; booster shutdown L
188         bcf     TRISB,2,0       ; booster shutdown not-Z
189
190         bcf     PORTB,0,0       ; user fault L or Z
191
192         debug   'd'     ; write 'd' to serial port
193 ;----------------------------------------------------------------------------
194
195 ; interrupt set-up
196
197 ; globally enable interrupts - p77
198         bsf     RCON,7,0        ; enable priority levels
199         bsf     INTCON,7,0      ; enable high-priority interrupts
200         bsf     INTCON,6,0      ; enable low-priority interrupts
201
202 ; interrupt set-up for serial receive
203         bcf     IPR1,5,0        ; set to low-priority interrupt
204         bsf     PIE1,5,0        ; enable USART receive interrupt (p85)
205
206 ; interrupt set-up for timer0 interrupt p79/80
207         bcf     INTCON2,2,0     ; timer0 overflow low priority
208         bsf     INTCON,5,0      ; enable timer0 interrupts
209
210
211         debug   'e'     ; write 'e' to serial port
212 ;****************************************************************************
213
214         call    led_green
215 main_loop_led
216         goto    main_loop_led
217
218
219 ;****************************************************************************
220
221 interrupt_high
222         debug   'H'     
223         goto    panic
224
225 ;****************************************************************************
226
227 interrupt_low
228
229 ; check which interrupt. Branch to serial_receive or timer or return
230
231         debug   '*'     ; write 'f' to serial port
232         btfsc   INTCON,2,0      ; check whether timer0 interrupt set
233         goto    timer0_interrupt
234         debug   'g'     ; write 'g' to serial port
235         btfsc   PIR1,5,0        ; check whether serial recv interrupt bit set
236         goto    serial_receive
237         debug   'L'     
238         goto    panic
239
240 ; if 2 interrupts are set at once the 2nd will generate a new
241 ; interrupt on leaving the interrupt routine
242 ; *** we hope and trust -iwj
243
244
245 ;****************************************************************************
246
247 serial_receive
248 ;       debug   'h'     ; write 'h' to serial port
249         btfsc   RCSTA,FERR,0            ; if FERR set (= framing error), then panic
250         goto    panic
251         btfsc   RCSTA,OERR,0            ; if OERR set (= overrun error), then panic
252         goto    panic
253
254         movff   FROMSERIAL,FSR0L        ; set low byte of INDF0 pointer
255         movlw   BUFFERPAGE
256         movwf   FSR0H,0                 ; set high byte of INDF0 pointer
257 ;       debug   '1'     ; write 'h' to serial port
258         movff   RCREG,INDF0             ; copy to received register
259 ;       debug   '2'     ; write 'h' to serial port
260
261 ; check whether bit 7 is set. If so, move to next buffer.
262         btfsc   INDF0,7,0               ; check if bit 7 is set
263         call    advance_write_buffer    ; if so, move to next buffer
264 ;       debug   '3'     ; write 'h' to serial port
265
266 ; If not, move to next byte
267         btfss   INDF0,7,0               ; check if bit 7 is set
268         incf    FROMSERIAL,1,0          ; advance FROMSERIAL pointer by 1 byte
269 ;       debug   '4'     ; write 'h' to serial port
270
271         bcf     PIR1,RCIF,0     ; unset interrupt
272         retfie  1
273
274 ; *** I *think* the interrupt bit is cleared by reading out of RCREG
275 ; but this may be something to try in debugging if stuff doesn't work
276
277
278
279 advance_write_buffer
280
281 ; clear low 4 bits of FROMSERIAL and increment top 4 bits
282 ; aaaabbbb -> bbbbaaaa -> bbbb(aaaa+1) -> 0000(aaaa+1) -> (aaaa+1)0000
283         debug   '5'     ; write 'h' to serial port
284         swapf   FROMSERIAL,1,0
285         incf    FROMSERIAL,1,0
286         movlw   0xF
287         andwf   FROMSERIAL,1,0
288         swapf   FROMSERIAL,1,0
289
290 ; clear bit 6 (will set back to buffer 0 if has overflowed to 4)
291         debug   '6'     ; write 'h' to serial port
292         bcf     FROMSERIAL,6,0
293         
294         return
295
296
297 ;****************************************************************************
298
299 timer0_interrupt
300         
301         debug   ','     ; write 'j' to serial port
302         bcf     INTCON,2,0      ; clear interrupt-set bit
303         
304         ifdef   SLOW_VERSION
305         movlw   0x01    ; (testing)
306         endif
307
308         ifndef  SLOW_VERSION
309         movlw   0x73    ; (not-testing)
310         endif
311
312         movwf   TMR0L,0         ; set timer0 to appropriate value (so interrupt takes 58us)
313
314
315         debug   'k'     ; write 'k' to serial port
316 ; check next action - if 0, change to 1 and return
317         btfsc   NMRACTRL,NEXTACTION,0
318         goto    toggle_output
319         bsf     NMRACTRL,NEXTACTION,0
320         debug   '1'     ; write 'k' to serial port
321         retfie  1
322
323
324 ; if next action = 1, then toggle output
325
326 toggle_output
327         debug   'l'     ; write 'l' to serial port
328         btg     PORTC,0,0       ; toggle booster output pin
329         btfss   PORTC,0,0       
330         goto    decide_next_bit
331         goto    mid_bit
332
333
334 ; if transition was 0->1 then we are mid-bit, so copy transmitbit to 
335 ; nextaction in preparation for 2nd half of bit and then return
336
337 mid_bit         
338         debug   'm'     ; write 'm' to serial port
339         btfsc   NMRACTRL,TRANSMITBIT,0
340         bsf     NMRACTRL,NEXTACTION,0
341         btfss   NMRACTRL,TRANSMITBIT,0
342         bcf     NMRACTRL,NEXTACTION,0
343         debug   '2'     ; write 'k' to serial port
344         retfie  1
345
346
347 decide_next_bit
348
349         debug   'n'     ; write 'n' to serial port
350 ; check whether current to-track buffer = current from-serial buffer
351 ; if yes, transmit 1s (set transmitbit=1, nextaction=1 and return)
352
353         movff   FROMSERIAL,WREG
354         xorwf   TOTRACK,0,0
355         andlw   0x30
356         bnz     read_from_buffer
357         bsf     NMRACTRL,TRANSMITBIT,0
358         bsf     NMRACTRL,NEXTACTION,0
359         debug   '3'
360         bsf     TRISB,0,0       ; user fault Z (red)
361         retfie  1
362
363
364 read_from_buffer
365         bcf     TRISB,0,0       ; user fault L (purple)
366         debug   'o'
367
368 ; if currently on bit 7, want to skip to bit 6
369 ;*** wouldn't it be easier to start on bit 6 ? :-)  -iwj
370
371         btfsc   TOTRACKBIT,7,0
372         rrncf   TOTRACKBIT,1,0          ; rotate mask right
373
374 ; if not on bit 7 , 
375 ; set na=cb=bit value, advance bit (i.e. rotate TRANSMITBIT right), 
376 ; check if bit7, if so, advance byte, return
377
378         debug   'p'
379         movff   TOTRACK,FSR1L           ; set low byte of IND1 pointer
380         movlw   BUFFERPAGE
381         movwf   FSR1H,0                 ; set high byte of IND1 pointer
382         movff   INDF1,WREG
383         andwf   TOTRACKBIT,0,0          ; select bit to be transmitted
384
385         bz      zero_bit_to_track 
386         bra     one_bit_to_track
387         
388 zero_bit_to_track
389         debug   '_'     ; write 'q' to serial port
390         debug   '0'     ; write 'q' to serial port
391         debug   '_'     ; write 'q' to serial port
392         bcf     NMRACTRL,TRANSMITBIT,0
393         bcf     NMRACTRL,NEXTACTION,0
394         goto    advance_bit
395         
396 one_bit_to_track
397         debug   '_'     ; write 'q' to serial port
398         debug   '1'     ; write 'r' to serial port
399         debug   '_'     ; write 'q' to serial port
400         bsf     NMRACTRL,TRANSMITBIT,0
401         bsf     NMRACTRL,NEXTACTION,0
402         goto    advance_bit
403
404
405
406 advance_bit
407 ; rotate transmitbit to next position 
408
409         debug   's'     ; write 's' to serial port
410         rrncf   TOTRACKBIT,1,0          ; rotate mask right
411 ;*** surely rrnc (`rotate right not through carry' I assume)
412 ;*** will leave a copy of the top bit in the N flag ?  Then you
413 ;*** can use branch if negative.  -iwj
414         btfsc   TOTRACKBIT,7,0
415         call    advance_pointer
416         debug   '5'     ; write 's' to serial port
417
418         retfie  1
419
420
421
422 advance_pointer
423
424         debug   't'     ; write 't' to serial port
425
426 ; currently on bit 7 of the byte, after having read rest of byte to
427 ; track; check whether it is 1 or 0
428         movff   TOTRACK,FSR1L   
429         movlw   BUFFERPAGE
430         movwf   FSR1H,0         
431
432 ; if set, move to next buffer
433         btfsc   INDF1,7,0
434         call    advance_read_buffer
435
436 ; if not set, move to next byte of samebuffer (increment TOTRACK)
437 ; (will be on bit 7 at this point anyway so no need to change TOTRACKBIT)
438         btfss   INDF1,7,0
439         incf    TOTRACK,1,0
440         return
441
442
443 advance_read_buffer
444
445 ; move pointer to next buffer 
446 ; clear low 4 bits of TOTRACK and increment top 4 bits
447 ; aaaabbbb -> bbbbaaaa -> bbbb(aaaa+1) -> 0000(aaaa+1) -> (aaaa+1)0000
448         debug   '7'     ; write 'v' to serial port
449         swapf   TOTRACK,1,0
450         incf    TOTRACK,1,0
451         movlw   0xF
452         andwf   TOTRACK,1,0
453         swapf   TOTRACK,1,0
454         debug   '8'     ; write 'v' to serial port
455         
456 ; clear bit 6 (will set back to buffer 0 if has overflowed to 4)
457         bcf     TOTRACK,6,0
458         debug   '9'     ; write 'v' to serial port
459         return
460
461
462
463 ;****************************************************************************
464
465
466 panic
467         debug   'x'
468         clrf    INTCON,0        ; disable all interrupts EVER
469         debug   'y'
470         bcf     PORTC,1,0       ; switch off booster
471         debug   'z'
472         call    led_red
473 panic_loop
474         goto    panic_loop
475         
476 ;****************************************************************************
477
478         end