2 ; can be tested with liberator's mic input:
3 ; 1k1, 110k resistor divider from track gives 1/100 track
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
11 ; pin 21 (per-pic-led, RD2/PSP2/C1IN) states:
12 ; high H = green, low L = red, float Z = black
16 include /usr/share/gputils/header/p18f458.inc
20 include ../iwjpictest/clockvaries.inc
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
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
38 messg "hello this is the slow version"
42 messg "hello this is the fast version"
54 ;****************************************************************************
56 ; high priority interrupt
61 ; low priority interrupt
66 ;****************************************************************************
70 ;****************************************************************************
74 ; macro to call subroutine to transmit over serial port for debugging
75 ; takes 8-bit value, puts in W, invokes debug_serial_transmit
78 debug macro debugvalue
83 debug macro debugvalue
85 call debug_serial_transmit
90 movwf TXREG,0 ; move contents of W (i.e. debugvalue)
91 ; to TXREG for transmission
97 ;****************************************************************************
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
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
114 ; set SPBRG to get correct baud rate according to table top right p186
115 ; (Tosc = 20MHz, desired baud rate = 9600)
118 debug 0x0A ; LF to terminak
119 debug 'a' ; write 'a' to serial port
120 ;----------------------------------------------------------------------------
124 ; LED pin (21) initialisation
125 bcf TRISE,4,0 ; turn off PSPMODE (Data Sheet p100/101)
128 ; timer0 initial config for NMRA timer
131 bcf T0CON,6,0 ; p107 Timer0 -> 16bit mode (testing)
135 bsf T0CON,6,0 ; p107 Timer0 -> 8bit mode (not-testing)
138 bcf T0CON,5,0 ; timer0 use internal clock
139 bcf T0CON,3,0 ; use prescaler
143 bcf T0CON,1,0 ; } prescale value 1:2
144 bcf T0CON,0,0 ; } (not-testing)
149 bcf T0CON,1,0 ; } prescale value 1:16
150 bcf T0CON,0,0 ; } (testing)
153 debug 'b' ; write 'b' to serial port
154 ;----------------------------------------------------------------------------
156 ; initialise buffers (for BSR5, for nmra from-serial/to-track buffers)
159 movwf BSR,0 ; set BSR to point to buffer page
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
167 debug 'c' ; write 'c' to serial port
168 ;----------------------------------------------------------------------------
171 ; initialise next action/transmit bit
172 bsf NMRACTRL,NEXTACTION,0
173 bsf NMRACTRL,TRANSMITBIT,0
175 ; initialise TOTRACKBIT bitmask
177 movwf TOTRACKBIT,0 ; make bit mask be 1000 0000
179 ; initialise booster direction
180 bcf TRISC,0,0 ; make pin 0 (booster direction) output
181 bcf PORTC,0,0 ; set low initially
183 ; set booster pwm high
184 bsf PORTC,1,0 ; booster pwm high
185 bcf TRISC,1,0 ; make pin 1 (booster pwm) output
187 bcf PORTB,2,0 ; booster shutdown L
188 bcf TRISB,2,0 ; booster shutdown not-Z
190 bcf PORTB,0,0 ; user fault L or Z
192 debug 'd' ; write 'd' to serial port
193 ;----------------------------------------------------------------------------
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
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)
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
211 debug 'e' ; write 'e' to serial port
212 ;****************************************************************************
219 ;****************************************************************************
225 ;****************************************************************************
229 ; check which interrupt. Branch to serial_receive or timer or return
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
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
245 ;****************************************************************************
248 ; debug 'h' ; write 'h' to serial port
249 btfsc RCSTA,FERR,0 ; if FERR set (= framing error), then panic
251 btfsc RCSTA,OERR,0 ; if OERR set (= overrun error), then panic
254 movff FROMSERIAL,FSR0L ; set low byte of INDF0 pointer
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
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
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
271 bcf PIR1,RCIF,0 ; unset interrupt
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
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
290 ; clear bit 6 (will set back to buffer 0 if has overflowed to 4)
291 debug '6' ; write 'h' to serial port
297 ;****************************************************************************
301 debug ',' ; write 'j' to serial port
302 bcf INTCON,2,0 ; clear interrupt-set bit
305 movlw 0x01 ; (testing)
309 movlw 0x73 ; (not-testing)
312 movwf TMR0L,0 ; set timer0 to appropriate value (so interrupt takes 58us)
315 debug 'k' ; write 'k' to serial port
316 ; check next action - if 0, change to 1 and return
317 btfsc NMRACTRL,NEXTACTION,0
319 bsf NMRACTRL,NEXTACTION,0
320 debug '1' ; write 'k' to serial port
324 ; if next action = 1, then toggle output
327 debug 'l' ; write 'l' to serial port
328 btg PORTC,0,0 ; toggle booster output pin
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
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
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)
353 movff FROMSERIAL,WREG
357 bsf NMRACTRL,TRANSMITBIT,0
358 bsf NMRACTRL,NEXTACTION,0
360 bsf TRISB,0,0 ; user fault Z (red)
365 bcf TRISB,0,0 ; user fault L (purple)
368 ; if currently on bit 7, want to skip to bit 6
369 ;*** wouldn't it be easier to start on bit 6 ? :-) -iwj
372 rrncf TOTRACKBIT,1,0 ; rotate mask right
375 ; set na=cb=bit value, advance bit (i.e. rotate TRANSMITBIT right),
376 ; check if bit7, if so, advance byte, return
379 movff TOTRACK,FSR1L ; set low byte of IND1 pointer
381 movwf FSR1H,0 ; set high byte of IND1 pointer
383 andwf TOTRACKBIT,0,0 ; select bit to be transmitted
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
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
407 ; rotate transmitbit to next position
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
416 debug '5' ; write 's' to serial port
424 debug 't' ; write 't' to serial port
426 ; currently on bit 7 of the byte, after having read rest of byte to
427 ; track; check whether it is 1 or 0
432 ; if set, move to next buffer
434 call advance_read_buffer
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)
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
454 debug '8' ; write 'v' to serial port
456 ; clear bit 6 (will set back to buffer 0 if has overflowed to 4)
458 debug '9' ; write 'v' to serial port
463 ;****************************************************************************
468 clrf INTCON,0 ; disable all interrupts EVER
470 bcf PORTC,1,0 ; switch off booster
476 ;****************************************************************************