chiark / gitweb /
attempt at service mode
[trains.git] / cebpic / i2c-test-reply.asm
1 ; write a byte to pic0 via the serial port, pic0 will transmit it to
2 ; pic1. 
3
4 ; pic0 will go into morse/register readout panic routine when it 
5 ; has transmitted the address byte+data byte via i2c.
6
7 ; pic1 will go into morse/register readout panic routine when it 
8 ; received address byte+data byte via i2c.
9
10 ; prints out various debugging letters via the serial port 
11 ; along the way.
12
13 ; panic routines may be all a bit confused because I can't remember 
14 ; whet the original i2c program did when panicing.
15
16 ;***************************************************************************
17 ; pin 21 (per-pic-led, RD2/PSP2/C1IN) states: 
18 ;  high H = blue (=green), low L = orange (=red), float Z = black
19
20 ;***************************************************************************
21 ;SETUP AND DEFINITIONS
22
23 ; CONVENTIONS:
24 ;
25 ; In subroutines, unless otherwise stated, W and S may have any
26 ; value on entry and will be undefined on exit.
27 ;
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)
36
37 ;---------------------------------------------------------------------------
38 ; boilerplate:
39
40         radix           dec
41
42         include common.inc
43         include morse-auto.inc
44         include ../iwjpictest/insn-aliases.inc
45         include ../iwjpictest/clockvaries.inc
46
47         extern  led_green
48         extern  led_red
49         extern  led_black
50
51         ifdef   SLOW_VERSION
52         messg   "hello this is the slow version"
53         endif
54
55         ifndef  SLOW_VERSION
56         messg   "hello this is the fast version"
57         endif
58
59         ifdef   SLOW_VERSION
60         messg   "with an if"
61         else
62         messg   "and an else"
63         endif
64
65 ;---------------------------------------------------------------------------
66
67 ; ID locations layout, in flash - see README.protocol
68
69 F_PIC_NO        equ     0x200000
70 F_I2C_CTRL      equ     0x200001
71
72 ; reserved access bank locations
73
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
79
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.
84
85
86 ; constants
87
88 MORSE_MSG_LENGTH        equ     04h     ; lenght of morse messages in bytes
89
90
91 ;---------------------------------------------------------------------------
92 ; memory location definitions
93
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.
98
99
100 ;---------------------------------------------------------------------------
101 ; RAM - ie, variables etc.
102
103 ; i2c specific stuff
104                 udata   0x400
105
106 PIC_NO          res     1
107
108 I2C_CTRL        res     1
109 I2C_CTRL_MASTER equ     7       ; bit 7 of I2C_CTRL is 1=master 0=slave
110
111 ;---------------------------------------------------------------------------
112 ; error messages
113
114 err_SOS equ     0       ; msg 0 = SOS
115
116 ;****************************************************************************
117 ; VECTORS: special locations, where the PIC starts executing
118 ; after reset and interrupts
119
120         org     0
121         goto    vector_reset
122
123         org     000008h
124         goto    vector_interrupt_high
125
126         org     000018h
127         goto    vector_interrupt_low
128
129 ;****************************************************************************
130 ; MACROS
131 ;---------------------------------------------------------------------------
132 panic macro message
133         movlw   (message - morse_messages_start)/4
134         movwf   PANIC_ADDRESS
135         goto    panic_routine
136         endm
137
138 ;----------------------------------------
139 ; debug(BYTE)
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
144 ;               Before          After
145 ;       W       any             undefined
146 ;       S       any             undefined
147
148 ; macro to call subroutine to transmit over serial port for debugging
149 ; takes 8-bit value, puts in W, invokes debug_serial_transmit
150         ifndef  SLOW_VERSION
151 debug macro debugvalue
152         endm
153         endif
154
155         ifdef   SLOW_VERSION
156 debug macro debugvalue
157         movlw   debugvalue
158         call    polling_serial_transmit
159         endm
160         endif
161
162 ;----------------------------------------
163 ; debughf(REGISTER)
164 ;       reads REGISTER once and writes it to the serial port in hex
165 ;       for conditions etc. see "debug", above
166 ;               Before          After
167 ;       W       any             undefined
168 ;       S       any             undefined
169  ifdef  SLOW_VERSION
170 DEBUGHF_VALUE   equ     0x040   ; getting on towards end of access bank
171                                 ; FIXME if all of program used udata that
172                                 ; would be very nice
173
174 debughf macro register
175         movff   register, DEBUGHF_VALUE
176         call    debughf_subroutine
177         endm
178
179 debughf_subroutine
180         call    debughf_digit
181         call    debughf_digit
182         return
183
184 ;--------------------
185 debughf_digit
186 ;       transmits top nybble of DEBUGHF_VALUE in hex
187 ;       through serial port, as above, and swaps nybbles
188 ;                       Before          After
189 ;       W               any             undefined
190 ; DEBUGHF_VALUE         BBBBaaaa        aaaaBBBB        (BBBB was sent)
191
192         swapf   DEBUGHF_VALUE,1,0
193         movf    DEBUGHF_VALUE,0,0
194         andlw   0x0f
195         sublw   10
196         sublw   0
197         bn      debughf_digit_ifnot_ge10
198         addlw   'a'-('0'+10)
199 debughf_digit_ifnot_ge10
200         addlw   '0'+10
201         goto    polling_serial_transmit
202
203  else
204 debughf macro register
205         endm
206  endif
207
208
209         
210 ;****************************************************************************
211 ; PORTMANTEAU CODE
212 ; which contains lists of checks and calls to function-specific
213 ; routines etc.
214
215 ;----------------------------------------
216 vector_reset
217
218         call    serial_setup
219
220         debug   10
221         debug   13
222         debug   'a'
223
224         call    copy_per_pic_data
225
226         debug   'b'
227
228         call    i2c_setup
229         call    enable_interrupts
230
231         debug   'c'
232
233         goto    main
234
235 ;----------------------------------------
236 main
237         debug   'J'
238         debughf SSPSTAT
239         debughf SSPCON1
240         debughf SSPCON2
241         debughf SSPADD
242
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
247
248 ;----------------------------------------
249 vector_panic
250         mov_lw          0x5a
251         mov_wf          TESTFLASH
252
253         panic   morse_TG
254
255 panic_routine
256 ; switch off interrupts and power
257 ; reconfigure timer0 for writing diagnostic msg to the LED
258
259         clrf    INTCON,0        ; disable all interrupts EVER
260         bcf     PORTC,1,0       ; switch off booster
261
262
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
267
268 ; get # bytes of morse msg, # registers in panic readout, message start addr.
269 ; back from condensed message start addr. stored in PANIC_ADDRESS
270
271 panic_loop
272         movlw   4
273         mulwf   PANIC_ADDRESS
274         movff   PRODL,TBLPTRL
275         movff   PRODH,WREG
276         add_lw  (morse_messages_start)/256
277         movwf   TBLPTRH
278         clr_f   TBLPTRU
279
280         tblrd   *+              ; read 1st byte of error message
281                                 ; (gives # bytes morse, # bytes registers)
282
283         movff   TABLAT,PANIC_MORSE
284         movlw   00001111b
285         and_wff PANIC_MORSE     ; PANIC_MORSE now contains # bytes of morse msgs
286
287         movff   TABLAT,PANIC_REGS
288         movlw   01110000b
289         and_wff PANIC_REGS
290         swap_f  PANIC_REGS      ; PANIC_REGS now contains # registers to read
291
292         call    led_black
293         call    waiting
294         call    waiting
295         call    waiting
296         call    waiting
297         call    morsemsg        ; transmit SOS in red
298         call    led_black
299         call    waiting
300         call    waiting
301         call    waiting
302         call    waiting 
303         call    registermsg     ; transmit contents of TESTFLASH in
304                                 ; red(=low) and blue(=high)
305         goto    panic_loop
306
307 ;****************************************************************************
308 ; PANIC SUBROUTINES
309
310 morsemsg
311 ; wrapper round readout to flash the per-pic led red for a
312 ; (currently 4-byte) morse msg
313
314 morse_msg_start
315         clrf    WREG3,0         ; clear loop counter (WREG3)
316
317 morse_loop
318         mov_fw          PANIC_MORSE
319         cmp_fw_ifge     WREG3           ; if loop counter >=MORSE_MSG_LENGTH,
320         return                          ; return to panic
321
322         tblrd           *+
323         mov_ff          TABLAT,WREG2
324         call            morse_readout
325         inc_f           WREG3
326         goto            morse_loop
327
328
329 ;--------------------------
330 morse_readout
331
332 ; Flashes the per-pic led red(0) in a specified pattern.
333 ;
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.
337 ;               On entry                On exit
338 ; W             any                     undefined
339 ; WREG2         flash pattern           preserved
340 ; WREG4         any                     undefined
341
342         clr_f           WREG4           ; clear loop counter (WREG4)
343         rr_f            WREG2
344
345 morse_readout_loop
346         mov_lw          8
347         cmp_fw_ifge     WREG4           ; if loop counter >=8, return
348         return
349
350         rl_f            WREG2           ; top bit goes into N, ie Negative if 1
351         bra_n           morse_readout_if_led_1
352
353 morse_readout_if_led_0 
354         call            led_black
355         bra             morse_readout_endif_led
356
357 morse_readout_if_led_1
358         call            led_red
359
360 morse_readout_endif_led
361         inc_f           WREG4           ; increment loop counter
362         call            waiting
363         bra             morse_readout_loop
364
365 ;--------------------------
366 ;--------------------------
367 registermsg
368
369 register_msg_start
370         clrf            WREG3,0         ; clear loop counter (WREG3)
371
372 register_loop
373         mov_fw          PANIC_REGS 
374         cmp_fw_ifge     WREG3           ; if loop counter >=MORSE_MSG_LENGTH,
375         return                          ; return to panic
376
377         tblrd           *+
378
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.
382
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)
389
390         mov_ff          INDF0,WREG2
391         call            register_readout
392
393         inc_f           WREG3
394
395         call            waiting
396         call            waiting
397         goto            register_loop
398
399 ;--------------------------
400 register_readout
401
402 ; Flashes the per-pic led red(0) and green(1) in a specified pattern.
403 ; (black gap between each bit)
404 ;
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.
408 ;               On entry                On exit
409 ; W             any                     undefined
410 ; WREG2         flash pattern           preserved
411 ; WREG4         any                     undefined
412
413         clrf    WREG4,0         ; clear loop counter (WREG4)
414         rrncf   WREG2,1
415
416
417 register_readout_loop
418         movlw           8
419         cpfslt          WREG4,0         ; if loop counter >=8 (register
420                                         ; length), return
421         return
422
423         movlw           4
424         cmp_fw_ifne     WREG4           ; if loop counter !=4 (nybble length),
425                                         ; skip insertion of extra black space
426         goto            not_nybble_boundary
427         call            waiting
428
429 not_nybble_boundary
430         rlncf           WREG2,1         ; top bit goes into N flag,   
431                                         ; ie Negative if 1
432         bn              register_readout_if_led_1
433
434 register_readout_if_led_0
435         call            led_red
436         bra             register_readout_endif_led
437
438 register_readout_if_led_1
439         call            led_green
440
441 register_readout_endif_led
442         incf            WREG4,1,0       ; increment loop counter
443         call            waiting
444         call            led_black
445         call            waiting
446         bra             register_readout_loop
447
448
449 ;****************************************************************************
450 vector_interrupt_low
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.
454
455 ;       btfsc   PIR1,SSPIF,0    ; check if MSSP interrupt generated, if so
456 ;       goto    i2c_isr         ; I2C ISR will check whether master or slave
457
458         btfsc   PIR1,5,0        ; check for serial receive interrupt
459         goto    serial_rx_isr   ; receive serial
460
461         debug   'L'             ; else panic - interrupt but don't know why
462         panic   morse_IL
463
464 ;----------------------------------------
465 enable_interrupts
466 ;       globally enable interrupts - p77
467 ;       etc.
468
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)
476         return
477
478 ;****************************************************************************
479 vector_interrupt_high
480         call    led_red
481         goto    vector_interrupt_high
482
483 ;***************************************************************************(
484 ; FUNCTIONALITY
485 ; these routines actually glue things together to make something that
486 ; does something
487
488 ;----------------------------------------
489 master_main
490 ;       main program for master PIC
491
492         call    led_green
493
494 master_main_loop
495         goto    master_main_loop
496
497
498 ;----------------------------------------
499 slave_main
500 ;       main program for slave PICs
501
502         bcf     PIE1,5,0        ; disable serial receive interrupt
503         bcf     PIE1,4,0        ; disable serial transmit interrupt
504         call    led_red
505         debug   'S'
506
507 slave_main_loop
508         call    wait_for_i2c_interrupt  ; wait for 1st (address) byte
509         call    led_green
510         debug   'G'
511         call    wait_for_i2c_interrupt  ; wait for 2nd (data) byte
512         call    led_black
513         debug   'B'
514         goto    vector_panic
515
516 ;----------------------------------------
517 serial_rx_isr
518         call    led_black
519
520         debug   'd'
521
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
525
526         debug   'e'
527
528         movlw   0x82                    ; transmit 1000 0010
529         movwf   SSPBUF,0                ; (ie address 1000001, read=0)
530
531         call    wait_for_i2c_interrupt
532
533         debug   'f'
534
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
539
540         debug   'g'
541
542         movff   RCREG,SSPBUF            ; copy byte from serial to i2c buffer
543         call    wait_for_i2c_interrupt
544
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
549
550         bsf     SSPCON2,PEN,0           ; i2c STOP
551         call    wait_for_i2c_interrupt
552
553         goto    vector_panic
554         retfie
555
556 ;***************************************************************************
557 ; SERIAL PORT
558
559 ;--------------------
560 serial_setup
561 ;       sets up the serial port, 9600 8N1 etc. as required by host
562 ;       interrupt is enabled for reception but not transmission
563
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
569         
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
574
575 ; set SPBRG to get correct baud rate
576         movlw_movwf_spbrg
577
578 ; interrupt set-up for serial receive
579         bcf     IPR1,5,0        ; set to low-priority interrupt
580         return
581
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
588 ;               Before          After
589 ;       W       byte to xmit    preserved
590
591         movwf   TXREG,0         ; move contents of W (i.e. debugvalue)
592                                 ;       to TXREG for transmission
593 debug_waitfortsr_loop
594         btfss   TXSTA,1,0
595         bra     debug_waitfortsr_loop
596
597         return
598
599 ;****************************************************************************
600
601         code
602
603 ;***************************************************************************
604 ; FLASH ID LOCATIONS
605
606 ;--------------------
607 copy_per_pic_data
608 ;       copies PIC-dependent info out of flash memory to RAM
609 ;       see README.protocol
610
611         debug 'P'
612
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
616         movwf   TBLPTRH
617         movlw   F_PIC_NO & 0xff
618         movwf   TBLPTRL
619
620         tblrd   *+              ; read then increment pointer 
621                                 ; (now points to i2c control byte)
622
623         banksel PIC_NO
624         movf    TABLAT,0,0      ; move pic number into normal memory
625         movwf   PIC_NO,1
626
627         debughf TABLAT
628
629         tblrd   *               ; read i2c
630
631         movf    TABLAT,0,0      ; move i2c_ctrl byte into normal memory
632         movwf   I2C_CTRL,1
633 ; now have: PIC number in 400h, i2c control byte in 401h - see
634 ; RAM variables re i2c specific stuff, above
635
636         debughf TABLAT
637
638         return
639
640 ;***************************************************************************
641 ; I2C
642
643 ;--------------------
644 i2c_setup
645 ;       sets up the I2C interface
646
647 ; see also:
648 ; p68
649 ; p314
650 ; p 275 ID locs
651
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)
655
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)
661
662         bcf     IPR1,SSPIP,0    ; make interrupt low priority
663
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
668
669 i2c_setup_if_master
670         movlw   0x08            ; clear top 2 status bits; disable SSP;
671         movwf   SSPCON1,0       ;  CKP unused, set to 0; master mode.
672
673 ; set baud rate
674         movlw   i2c_sspadd
675         movwf   SSPADD,0
676         goto    i2c_setup_endif_master_slave
677
678 i2c_setup_if_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"
683
684 ; set slave address
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)
691
692 i2c_setup_endif_master_slave
693         bsf     SSPCON1,5,0     ; enable I2C mode
694
695         return
696
697 ;----------------------------------------
698 i2c_isr
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
703
704 ;--------------------
705 i2c_master_isr
706         debug   'm'
707         goto    wait_for_i2c_interrupt
708
709 ;--------------------
710 i2c_slave_isr
711         debug   's'
712         goto    wait_for_i2c_interrupt
713
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.
719
720         debug   '.'
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
724
725         bcf     PIR1,SSPIF,0    ; clear interrupt bit
726
727         debug   'I'
728         debughf SSPSTAT
729         debughf SSPCON1
730         debughf SSPCON2
731         
732         return
733
734 ;****************************************************************************
735 ; GENERAL SUBROUTINES
736
737 ;----------------------------------------
738 waiting
739 ; waits for a fixed interval, depending on the configuration of TMR0
740
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
745 loop
746         btfss   INTCON,2,0      ; check whether timer0 interrupt has been set -
747                                 ; skip next instruction if so
748         bra     loop
749         return
750
751
752 ;****************************************************************************
753
754         org 0x2000
755         dw      0xffff
756
757         org 0x6000
758         dw      0xffff
759
760         end
761