; can be tested with liberator's mic input: ; 1k1, 110k resistor divider from track gives 1/100 track ; voltage to mic input ; then ; sox -r 96000 -u -b -t ossdsp /dev/dsp t.dat ; perl -pe '$_= m/\-/ ? "_" : "~"' u ; in an xterm showing font "tiny" and then resized to eg 295x54 ; less u ; 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 radix dec clock equ mclock include ../iwjpictest/clockvaries.inc NMRACTRL equ 0x4 ; byte 4: state relevant to NMRA control TRANSMITBIT equ 0x7 ; bit 7: 0/1 bit currently being transmitted NEXTACTION equ 0x6 ; bit 6: 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 BUFFERPAGE equ 5 extern led_green extern led_red extern led_black ifdef SLOW_VERSION messg "hello this is the slow version" endif ifndef SLOW_VERSION messg "hello this is the fast version" endif ifdef SLOW_VERSION messg "with an if" else messg "and an else" endif org 0 goto initialise ;**************************************************************************** ; high priority interrupt org 000008h goto interrupt_high ; low priority interrupt org 000018h goto interrupt_low ;**************************************************************************** code ;**************************************************************************** macros ; macro to call subroutine to transmit over serial port for debugging ; takes 8-bit value, puts in W, invokes debug_serial_transmit ifndef SLOW_VERSION debug macro debugvalue endm endif ifdef SLOW_VERSION debug macro debugvalue movlw debugvalue call debug_serial_transmit endm endif debug_serial_transmit movwf TXREG,0 ; move contents of W (i.e. debugvalue) ; to TXREG for transmission waitfortsr btfss TXSTA,1,0 bra waitfortsr return ;**************************************************************************** initialise ; serial set-up ; initial config - TXSTA register p181 bcf TXSTA,6,0 ; p181, set 8-bit mode bsf TXSTA,5,0 ; transmit enable bcf TXSTA,4,0 ; asynchronous mode bsc_txsta_brgh ; initial config - RCSTA register p182 bsf RCSTA,7,0 ; serial port enable (p182) bcf RCSTA,6,0 ; 8-bit reception bsf RCSTA,4,0 ; enable continuous receive ; set SPBRG to get correct baud rate according to table top right p186 ; (Tosc = 20MHz, desired baud rate = 9600) movlw_movwf_spbrg debug 0x0A ; LF to terminak debug 'a' ; write 'a' to serial port ;---------------------------------------------------------------------------- ; timer 0 set-up ; LED pin (21) initialisation bcf TRISE,4,0 ; turn off PSPMODE (Data Sheet p100/101) ; timer0 initial config for NMRA timer ifdef SLOW_VERSION bcf T0CON,6,0 ; p107 Timer0 -> 16bit mode (testing) endif ifndef SLOW_VERSION bsf T0CON,6,0 ; p107 Timer0 -> 8bit mode (not-testing) endif bcf T0CON,5,0 ; timer0 use internal clock bcf T0CON,3,0 ; use prescaler ifndef SLOW_VERSION bcf T0CON,2,0 ; } bcf T0CON,1,0 ; } prescale value 1:2 bcf T0CON,0,0 ; } (not-testing) endif ifdef SLOW_VERSION bsf T0CON,2,0 ; } bcf T0CON,1,0 ; } prescale value 1:16 bcf T0CON,0,0 ; } (testing) endif debug 'b' ; write 'b' to serial port ;---------------------------------------------------------------------------- ; initialise buffers (for BSR5, for nmra from-serial/to-track buffers) movlw BUFFERPAGE movwf BSR,0 ; set BSR to point to buffer page clrf NMRACTRL,0 ; for bits relevant to control of nmra stream clrf FROMSERIAL,0 ; for loc'n of write-from-usart ptr in buffers clrf TOTRACK,0 ; for loc'n of send-to-track ptr in buffers ; all in access bank debug 'c' ; write 'c' to serial port ;---------------------------------------------------------------------------- ; 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 bcf TRISC,0,0 ; make pin 0 (booster direction) output bcf PORTC,0,0 ; set low initially ; set booster pwm high bsf PORTC,1,0 ; booster pwm high bcf TRISC,1,0 ; make pin 1 (booster pwm) output bcf PORTB,2,0 ; booster shutdown L bcf TRISB,2,0 ; booster shutdown not-Z bcf PORTB,0,0 ; user fault L or Z debug 'd' ; write 'd' to serial port ;---------------------------------------------------------------------------- ; 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 bcf IPR1,5,0 ; set to low-priority interrupt bsf PIE1,5,0 ; enable USART receive interrupt (p85) ; interrupt set-up for timer0 interrupt p79/80 bcf INTCON2,2,0 ; timer0 overflow low priority bsf INTCON,5,0 ; enable timer0 interrupts debug 'e' ; write 'e' to serial port ;**************************************************************************** call led_green main_loop_led goto main_loop_led ;**************************************************************************** interrupt_high debug 'H' goto panic ;**************************************************************************** interrupt_low ; check which interrupt. Branch to serial_receive or timer or return debug '*' ; write 'f' to serial port btfsc INTCON,2,0 ; check whether timer0 interrupt set goto timer0_interrupt debug 'g' ; write 'g' to serial port btfsc PIR1,5,0 ; check whether serial recv interrupt bit set goto serial_receive debug 'L' goto panic ; if 2 interrupts are set at once the 2nd will generate a new ; interrupt on leaving the interrupt routine ; *** we hope and trust -iwj ;**************************************************************************** serial_receive ; debug 'h' ; write 'h' to serial port btfsc RCSTA,FERR,0 ; if FERR set (= framing error), then panic goto panic btfsc RCSTA,OERR,0 ; if OERR set (= overrun error), then panic goto panic movff FROMSERIAL,FSR0L ; set low byte of INDF0 pointer movlw BUFFERPAGE movwf FSR0H,0 ; set high byte of INDF0 pointer ; debug '1' ; write 'h' to serial port movff RCREG,INDF0 ; copy to received register ; debug '2' ; write 'h' to serial port ; check whether bit 7 is set. If so, move to next buffer. btfsc INDF0,7,0 ; check if bit 7 is set call advance_write_buffer ; if so, move to next buffer ; debug '3' ; write 'h' to serial port ; If not, move to next byte btfss INDF0,7,0 ; check if bit 7 is set incf FROMSERIAL,1,0 ; advance FROMSERIAL pointer by 1 byte ; debug '4' ; write 'h' to serial port bcf PIR1,RCIF,0 ; unset interrupt 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 ; clear low 4 bits of FROMSERIAL and increment top 4 bits ; aaaabbbb -> bbbbaaaa -> bbbb(aaaa+1) -> 0000(aaaa+1) -> (aaaa+1)0000 debug '5' ; write 'h' to serial port swapf FROMSERIAL,1,0 incf FROMSERIAL,1,0 movlw 0xF andwf FROMSERIAL,1,0 swapf FROMSERIAL,1,0 ; clear bit 6 (will set back to buffer 0 if has overflowed to 4) debug '6' ; write 'h' to serial port bcf FROMSERIAL,6,0 return ;**************************************************************************** timer0_interrupt debug ',' ; write 'j' to serial port bcf INTCON,2,0 ; clear interrupt-set bit ifdef SLOW_VERSION movlw 0x01 ; (testing) endif ifndef SLOW_VERSION movlw 0x73 ; (not-testing) endif movwf TMR0L,0 ; set timer0 to appropriate value (so interrupt takes 58us) debug 'k' ; write 'k' to serial port ; check next action - if 0, change to 1 and return btfsc NMRACTRL,NEXTACTION,0 goto toggle_output bsf NMRACTRL,NEXTACTION,0 debug '1' ; write 'k' to serial port retfie 1 ; if next action = 1, then toggle output toggle_output debug 'l' ; write 'l' to serial port 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 debug 'm' ; write 'm' to serial port btfsc NMRACTRL,TRANSMITBIT,0 bsf NMRACTRL,NEXTACTION,0 btfss NMRACTRL,TRANSMITBIT,0 bcf NMRACTRL,NEXTACTION,0 debug '2' ; write 'k' to serial port retfie 1 decide_next_bit debug 'n' ; write 'n' to serial port ; check whether current to-track buffer = current from-serial buffer ; if yes, transmit 1s (set transmitbit=1, nextaction=1 and return) movff FROMSERIAL,WREG xorwf TOTRACK,0,0 andlw 0x30 bnz read_from_buffer bsf NMRACTRL,TRANSMITBIT,0 bsf NMRACTRL,NEXTACTION,0 debug '3' bsf TRISB,0,0 ; user fault Z (red) retfie 1 read_from_buffer bcf TRISB,0,0 ; user fault L (purple) debug 'o' ; if currently on bit 7, want to skip to bit 6 ;*** wouldn't it be easier to start on bit 6 ? :-) -iwj btfsc TOTRACKBIT,7,0 rrncf TOTRACKBIT,1,0 ; rotate mask right ; 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 debug 'p' movff TOTRACK,FSR1L ; set low byte of IND1 pointer movlw BUFFERPAGE movwf FSR1H,0 ; set high byte of IND1 pointer movff INDF1,WREG andwf TOTRACKBIT,0,0 ; select bit to be transmitted bz zero_bit_to_track bra one_bit_to_track zero_bit_to_track debug '_' ; write 'q' to serial port debug '0' ; write 'q' to serial port debug '_' ; write 'q' to serial port bcf NMRACTRL,TRANSMITBIT,0 bcf NMRACTRL,NEXTACTION,0 goto advance_bit one_bit_to_track debug '_' ; write 'q' to serial port debug '1' ; write 'r' to serial port debug '_' ; write 'q' to serial port bsf NMRACTRL,TRANSMITBIT,0 bsf NMRACTRL,NEXTACTION,0 goto advance_bit advance_bit ; rotate transmitbit to next position debug 's' ; write 's' to serial port rrncf TOTRACKBIT,1,0 ; rotate mask right ;*** surely rrnc (`rotate right not through carry' I assume) ;*** will leave a copy of the top bit in the N flag ? Then you ;*** can use branch if negative. -iwj btfsc TOTRACKBIT,7,0 call advance_pointer debug '5' ; write 's' to serial port retfie 1 advance_pointer debug 't' ; write 't' to serial port ; 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 BUFFERPAGE movwf FSR1H,0 ; if set, move to next buffer btfsc INDF1,7,0 call advance_read_buffer ; if not set, move to next byte of samebuffer (increment TOTRACK) ; (will be on bit 7 at this point anyway so no need to change TOTRACKBIT) btfss INDF1,7,0 incf TOTRACK,1,0 return advance_read_buffer ; move pointer to next buffer ; clear low 4 bits of TOTRACK and increment top 4 bits ; aaaabbbb -> bbbbaaaa -> bbbb(aaaa+1) -> 0000(aaaa+1) -> (aaaa+1)0000 debug '7' ; write 'v' to serial port swapf TOTRACK,1,0 incf TOTRACK,1,0 movlw 0xF andwf TOTRACK,1,0 swapf TOTRACK,1,0 debug '8' ; write 'v' to serial port ; clear bit 6 (will set back to buffer 0 if has overflowed to 4) bcf TOTRACK,6,0 debug '9' ; write 'v' to serial port return ;**************************************************************************** panic debug 'x' clrf INTCON,0 ; disable all interrupts EVER debug 'y' bcf PORTC,1,0 ; switch off booster debug 'z' call led_red panic_loop goto panic_loop ;**************************************************************************** end