1 ; write a byte to pic0 via the serial port, pic0 will transmit it to
4 ; pic0 will go into morse/register readout panic routine when it
5 ; has transmitted the address byte+data byte via i2c.
7 ; pic1 will go into morse/register readout panic routine when it
8 ; received address byte+data byte via i2c.
10 ; prints out various debugging letters via the serial port
13 ; panic routines may be all a bit confused because I can't remember
14 ; whet the original i2c program did when panicing.
16 ;***************************************************************************
17 ; pin 21 (per-pic-led, RD2/PSP2/C1IN) states:
18 ; high H = blue (=green), low L = orange (=red), float Z = black
20 ;***************************************************************************
21 ;SETUP AND DEFINITIONS
25 ; In subroutines, unless otherwise stated, W and S may have any
26 ; value on entry and will be undefined on exit.
28 ; labels ending _if[not_... and _endif_... are used for
29 ; if ... then [... else ...]
30 ; labels ending _loop are for loops
31 ; labels ending _isr are at the start of interrupt service routines
32 ; (which must end with retfie)
33 ; labels starting vector_ are the reset and interrupt entrypoints
34 ; other labels in lowercase are normal subroutines (ending in `return')
35 ; labels in UPPERCASE are defined addresses (in RAM or flash)
37 ;---------------------------------------------------------------------------
43 include morse-auto.inc
44 include ../iwjpictest/insn-aliases.inc
45 include ../iwjpictest/clockvaries.inc
52 messg "hello this is the slow version"
56 messg "hello this is the fast version"
65 ;---------------------------------------------------------------------------
67 ; ID locations layout, in flash - see README.protocol
70 F_I2C_CTRL equ 0x200001
72 ; reserved access bank locations
74 WREG2 equ 00h ; a 2nd working reg :-)
75 WREG3 equ 01h ; a 3rd working reg :-)
76 WREG4 equ 02h ; a 4th working reg :-)
77 BLANK equ 03h ; register full of zeros
78 TESTFLASH equ 04h ; test LED flash pattern
80 ; used in panic macro for temporary storage
81 PANIC_MORSE equ 05h ; stores # bytes of morse msg in panic readout
82 PANIC_REGS equ 06h ; stores # registers in panic readout
83 PANIC_ADDRESS equ 07h ; stores condensed form of message start addr.
88 MORSE_MSG_LENGTH equ 04h ; lenght of morse messages in bytes
91 ;---------------------------------------------------------------------------
92 ; memory location definitions
94 ERROR_BUF_PAGE equ 3 ; error codes on flash p3
95 F_ERROR_U equ 00h ; upper part of error memory locations
96 F_SOS_H equ 40h ; high (middle) part of SOS error memory loc.
97 F_SOS_L equ 00h ; lower part of SOS error memory loc.
100 ;---------------------------------------------------------------------------
101 ; RAM - ie, variables etc.
109 I2C_CTRL_MASTER equ 7 ; bit 7 of I2C_CTRL is 1=master 0=slave
111 ;---------------------------------------------------------------------------
114 err_SOS equ 0 ; msg 0 = SOS
116 ;****************************************************************************
117 ; VECTORS: special locations, where the PIC starts executing
118 ; after reset and interrupts
124 goto vector_interrupt_high
127 goto vector_interrupt_low
129 ;****************************************************************************
131 ;---------------------------------------------------------------------------
133 movlw (message - morse_messages_start)/4
138 ;----------------------------------------
140 ; writes BYTE through the serial port
141 ; serial port hardware must be suitably initialised
142 ; serial port transmit interrupts must be disabled
143 ; will spin until the byte is transmitted
148 ; macro to call subroutine to transmit over serial port for debugging
149 ; takes 8-bit value, puts in W, invokes debug_serial_transmit
151 debug macro debugvalue
156 debug macro debugvalue
158 call polling_serial_transmit
162 ;----------------------------------------
164 ; reads REGISTER once and writes it to the serial port in hex
165 ; for conditions etc. see "debug", above
170 DEBUGHF_VALUE equ 0x040 ; getting on towards end of access bank
171 ; FIXME if all of program used udata that
174 debughf macro register
175 movff register, DEBUGHF_VALUE
176 call debughf_subroutine
184 ;--------------------
186 ; transmits top nybble of DEBUGHF_VALUE in hex
187 ; through serial port, as above, and swaps nybbles
190 ; DEBUGHF_VALUE BBBBaaaa aaaaBBBB (BBBB was sent)
192 swapf DEBUGHF_VALUE,1,0
193 movf DEBUGHF_VALUE,0,0
197 bn debughf_digit_ifnot_ge10
199 debughf_digit_ifnot_ge10
201 goto polling_serial_transmit
204 debughf macro register
210 ;****************************************************************************
212 ; which contains lists of checks and calls to function-specific
215 ;----------------------------------------
224 call copy_per_pic_data
229 call enable_interrupts
235 ;----------------------------------------
243 banksel I2C_CTRL ; ser BSR=i2c BSR (4)
244 btfsc I2C_CTRL,I2C_CTRL_MASTER,1 ; check =master?, if so
245 goto master_main ; goto master main routine
246 goto slave_main ; elso goto slave main routine
248 ;----------------------------------------
256 ; switch off interrupts and power
257 ; reconfigure timer0 for writing diagnostic msg to the LED
259 clrf INTCON,0 ; disable all interrupts EVER
260 bcf PORTC,1,0 ; switch off booster
263 ; re-initialise timer0 config
264 bcf T0CON,6,0 ; p107 Timer0 -> 16bit mode
265 bcf T0CON,5,0 ; timer0 use internal clock
266 bsc_morse_t0con_012 ; use prescaler? and configure it
268 ; get # bytes of morse msg, # registers in panic readout, message start addr.
269 ; back from condensed message start addr. stored in PANIC_ADDRESS
276 add_lw (morse_messages_start)/256
280 tblrd *+ ; read 1st byte of error message
281 ; (gives # bytes morse, # bytes registers)
283 movff TABLAT,PANIC_MORSE
285 and_wff PANIC_MORSE ; PANIC_MORSE now contains # bytes of morse msgs
287 movff TABLAT,PANIC_REGS
290 swap_f PANIC_REGS ; PANIC_REGS now contains # registers to read
297 call morsemsg ; transmit SOS in red
303 call registermsg ; transmit contents of TESTFLASH in
304 ; red(=low) and blue(=high)
307 ;****************************************************************************
311 ; wrapper round readout to flash the per-pic led red for a
312 ; (currently 4-byte) morse msg
315 clrf WREG3,0 ; clear loop counter (WREG3)
319 cmp_fw_ifge WREG3 ; if loop counter >=MORSE_MSG_LENGTH,
320 return ; return to panic
329 ;--------------------------
332 ; Flashes the per-pic led red(0) in a specified pattern.
334 ; The pattern is specified as the state for 8 identically-long time
335 ; periods each as long as a morse `dot', encoded into a byte with
336 ; most significant bit first.
339 ; WREG2 flash pattern preserved
340 ; WREG4 any undefined
342 clr_f WREG4 ; clear loop counter (WREG4)
347 cmp_fw_ifge WREG4 ; if loop counter >=8, return
350 rl_f WREG2 ; top bit goes into N, ie Negative if 1
351 bra_n morse_readout_if_led_1
353 morse_readout_if_led_0
355 bra morse_readout_endif_led
357 morse_readout_if_led_1
360 morse_readout_endif_led
361 inc_f WREG4 ; increment loop counter
363 bra morse_readout_loop
365 ;--------------------------
366 ;--------------------------
370 clrf WREG3,0 ; clear loop counter (WREG3)
374 cmp_fw_ifge WREG3 ; if loop counter >=MORSE_MSG_LENGTH,
375 return ; return to panic
379 mov_fw TABLAT ; TABLAT has the 8-bit version
380 mov_wf FSR0L ; of the address. So, 8 bits
381 ; go straight into FSR0L.
383 mov_lw 0x0f ; For FSR0H, we see if the
384 mov_fw FSR0H ; address XX is >=0x60.
385 ; If it is then we meant 0xfXX;
386 mov_lw 0x5f ; if not then we meant 0x0XX.
387 cmp_fw_ifle FSR0L ; (This is just like PIC does
388 clr_f FSR0H ; for insns using Access Bank)
391 call register_readout
399 ;--------------------------
402 ; Flashes the per-pic led red(0) and green(1) in a specified pattern.
403 ; (black gap between each bit)
405 ; The pattern is specified as the state for 8 identically-long time
406 ; periods each as long as a morse `dot', encoded into a byte with
407 ; most significant bit first.
410 ; WREG2 flash pattern preserved
411 ; WREG4 any undefined
413 clrf WREG4,0 ; clear loop counter (WREG4)
417 register_readout_loop
419 cpfslt WREG4,0 ; if loop counter >=8 (register
424 cmp_fw_ifne WREG4 ; if loop counter !=4 (nybble length),
425 ; skip insertion of extra black space
426 goto not_nybble_boundary
430 rlncf WREG2,1 ; top bit goes into N flag,
432 bn register_readout_if_led_1
434 register_readout_if_led_0
436 bra register_readout_endif_led
438 register_readout_if_led_1
441 register_readout_endif_led
442 incf WREG4,1,0 ; increment loop counter
446 bra register_readout_loop
449 ;****************************************************************************
451 ; checks which interrupt and as soon as it finds one jumps straight
452 ; to the relevant ISR. That routine will return with retfie and if
453 ; there was another interrupt we will re-enter, which is OK.
455 ; btfsc PIR1,SSPIF,0 ; check if MSSP interrupt generated, if so
456 ; goto i2c_isr ; I2C ISR will check whether master or slave
458 btfsc PIR1,5,0 ; check for serial receive interrupt
459 goto serial_rx_isr ; receive serial
461 debug 'L' ; else panic - interrupt but don't know why
464 ;----------------------------------------
466 ; globally enable interrupts - p77
469 bsf RCON,7,0 ; enable priority levels
470 bsf INTCON,7,0 ; enable high-priority interrupts
471 bsf INTCON,6,0 ; enable low-priority interrupts
472 bcf PIE1,3,0 ; disable master synchronous serial port
473 ; (MSSP; i.e. enable i2c) interrupts
474 ; (temporary for this simple program)
475 bsf PIE1,5,0 ; enable USART receive interrupt (p85)
478 ;****************************************************************************
479 vector_interrupt_high
481 goto vector_interrupt_high
483 ;***************************************************************************(
485 ; these routines actually glue things together to make something that
488 ;----------------------------------------
490 ; main program for master PIC
495 goto master_main_loop
498 ;----------------------------------------
500 ; main program for slave PICs
502 bcf PIE1,5,0 ; disable serial receive interrupt
503 bcf PIE1,4,0 ; disable serial transmit interrupt
508 call wait_for_i2c_interrupt ; wait for 1st (address) byte
511 call wait_for_i2c_interrupt ; wait for 2nd (data) byte
516 ;----------------------------------------
522 ; what we actually do here is faff with I2C to start transmitting
523 bsf SSPCON2,SEN,0 ; i2c START
524 call wait_for_i2c_interrupt
528 movlw 0x82 ; transmit 1000 0010
529 movwf SSPBUF,0 ; (ie address 1000001, read=0)
531 call wait_for_i2c_interrupt
535 ifbit0 SSPCON2,ACKSTAT ; check for ack from slave (=0), if no
536 bra serial_rx_isr_ifnot_noack1
537 panic morse_SA ; then panic, else
538 serial_rx_isr_ifnot_noack1
542 movff RCREG,SSPBUF ; copy byte from serial to i2c buffer
543 call wait_for_i2c_interrupt
545 ifbit0 SSPCON2,ACKSTAT ; check for ack from slave (=0), if no
546 bra serial_rx_isr_ifnot_noack2
547 panic morse_SD ; then panic, else
548 serial_rx_isr_ifnot_noack2
550 bsf SSPCON2,PEN,0 ; i2c STOP
551 call wait_for_i2c_interrupt
556 ;***************************************************************************
559 ;--------------------
561 ; sets up the serial port, 9600 8N1 etc. as required by host
562 ; interrupt is enabled for reception but not transmission
564 ; initial config - TXSTA register p181
565 bcf TXSTA,6,0 ; p181, set 8-bit mode
566 bsf TXSTA,5,0 ; transmit enable
567 bcf TXSTA,4,0 ; asynchronous mode
568 bsc_txsta_brgh ; set high or low baud rate
570 ; initial config - RCSTA register p182
571 bsf RCSTA,7,0 ; serial port enable (p182)
572 bcf RCSTA,6,0 ; 8-bit reception
573 bsf RCSTA,4,0 ; enable continuous receive
575 ; set SPBRG to get correct baud rate
578 ; interrupt set-up for serial receive
579 bcf IPR1,5,0 ; set to low-priority interrupt
582 ;--------------------
583 polling_serial_transmit
584 ; writes W through the serial port
585 ; serial port hardware must be suitably initialised
586 ; serial port transmit interrupts must be disabled
587 ; will spin until the byte is transmitted
589 ; W byte to xmit preserved
591 movwf TXREG,0 ; move contents of W (i.e. debugvalue)
592 ; to TXREG for transmission
593 debug_waitfortsr_loop
595 bra debug_waitfortsr_loop
599 ;****************************************************************************
603 ;***************************************************************************
606 ;--------------------
608 ; copies PIC-dependent info out of flash memory to RAM
609 ; see README.protocol
613 movlw (F_PIC_NO >> 16) & 0xff ; set table pointer to point to
614 movwf TBLPTRU ; PIC number in flash
615 movlw (F_PIC_NO >> 8) & 0xff
617 movlw F_PIC_NO & 0xff
620 tblrd *+ ; read then increment pointer
621 ; (now points to i2c control byte)
624 movf TABLAT,0,0 ; move pic number into normal memory
631 movf TABLAT,0,0 ; move i2c_ctrl byte into normal memory
633 ; now have: PIC number in 400h, i2c control byte in 401h - see
634 ; RAM variables re i2c specific stuff, above
640 ;***************************************************************************
643 ;--------------------
645 ; sets up the I2C interface
652 ; To generate our I2C address, we take PIC_NO bits 4-0 and prepend
653 ; 0b10 (i.e. all addresses are of the form 0b10xxxxx)
654 banksel PIC_NO ; ser BSR=i2c BSR (4)
656 ; common to master and slaves:
657 bsf SSPSTAT,7,0 ; disable slew rate control
658 bcf SSPSTAT,6,0 ; disable SMBus specific commands
659 ; (whatever that means)
660 bcf SSPCON2,7,0 ; disable general call (for now)
662 bcf IPR1,SSPIP,0 ; make interrupt low priority
664 ; are we master or slave ?
665 btfsc I2C_CTRL,I2C_CTRL_MASTER,1 ; test whether PIC is master
666 goto i2c_setup_if_master
667 goto i2c_setup_if_slave
670 movlw 0x08 ; clear top 2 status bits; disable SSP;
671 movwf SSPCON1,0 ; CKP unused, set to 0; master mode.
676 goto i2c_setup_endif_master_slave
679 movlw 0x16 ; clear top 2 status bits; disable SSP;
680 movwf SSPCON1,0 ; release clock; 7bit slave mode with
681 ; no extra start/stop interrupts.
682 ; !!fixme probably want to set SSPCON2:SEN "clock stretching"
685 banksel PIC_NO ; set BSR=i2c BSR (4)
686 movf PIC_NO,0,1 ; copy pic_no to W (000xxxxx)
687 iorlw 0x40 ; change top 3 bits t 010 (010xxxxx)
688 rlncf WREG,0,0 ; shift, bottom bit is r/w (10xxxxx0)
689 movwf SSPADD,0 ; move to slave address register
690 ; (bits 7-1=address, bit 0=0)
692 i2c_setup_endif_master_slave
693 bsf SSPCON1,5,0 ; enable I2C mode
697 ;----------------------------------------
699 banksel PIC_NO ; ser BSR=i2c BSR (4)
700 btfsc I2C_CTRL,I2C_CTRL_MASTER,1 ; check =master?, if so
701 goto i2c_master_isr ; goto master interrupt routine
702 goto i2c_slave_isr ; elso goto interrupt_slave
704 ;--------------------
707 goto wait_for_i2c_interrupt
709 ;--------------------
712 goto wait_for_i2c_interrupt
714 ;----------------------------------------
715 wait_for_i2c_interrupt
716 ; polls the relevant bit until the I2C interrupt flag is set,
717 ; then returns. should not usually be used if I2C interrupts
718 ; are enabled, clearly.
721 wait_for_i2c_interrupt_loop
722 btfss PIR1,SSPIF,0 ; check if interrupt set, if not, loop
723 goto wait_for_i2c_interrupt_loop
725 bcf PIR1,SSPIF,0 ; clear interrupt bit
734 ;****************************************************************************
735 ; GENERAL SUBROUTINES
737 ;----------------------------------------
739 ; waits for a fixed interval, depending on the configuration of TMR0
741 bcf INTCON,2,0 ; clear timer0 interrupt bit (p109)
742 clrf TMR0H,0 ; p107 set high byte of timer0 to 0 (buffered,
743 ; only actually set when write to tmr0l occurs)
744 clrf TMR0L,0 ; set timer0 low byte - timer now set to 0000h
746 btfss INTCON,2,0 ; check whether timer0 interrupt has been set -
747 ; skip next instruction if so
752 ;****************************************************************************