chiark / gitweb /
undo broken deletion
[trains.git] / cebpic / i2c-test.asm
1 ; write a byte to pic0 via the serial port, pic0 will transmit it to
2 ; pic1, which will then toggle its colour (without checking the contents
3 ; of the byte)
4
5 ; pin 21 (per-pic-led, RD2/PSP2/C1IN) states: 
6 ;  high H = blue (=green), low L = orange (=red), float Z = black
7
8 ;***************************************************************************
9 ;SETUP AND DEFINITIONS
10
11 ; CONVENTIONS:
12 ;
13 ; In subroutines, unless otherwise stated, W and S may have any
14 ; value on entry and will be undefined on exit.
15 ;
16 ; labels ending _if[not_... and _endif_... are used for
17 ;    if ... then [... else ...]
18 ; labels ending _loop are for loops
19 ; labels ending _isr are at the start of interrupt service routines
20 ;                       (which must end with retfie)
21 ; labels starting vector_ are the reset and interrupt entrypoints
22 ; other labels in lowercase are normal subroutines (ending in `return')
23 ; labels in UPPERCASE are defined addresses (in RAM or flash)
24
25 ;---------------------------------------------------------------------------
26 ; boilerplate:
27
28         include         /usr/share/gputils/header/p18f458.inc
29         radix           dec
30         include         ../iwjpictest/clockvaries.inc
31
32         extern  led_green
33         extern  led_red
34         extern  led_black
35
36         ifdef   SLOW_VERSION
37         messg   "hello this is the slow version"
38         endif
39
40         ifndef  SLOW_VERSION
41         messg   "hello this is the fast version"
42         endif
43
44         ifdef   SLOW_VERSION
45         messg   "with an if"
46         else
47         messg   "and an else"
48         endif
49
50 ;---------------------------------------------------------------------------
51 ; ID locations layout, in flash - see README.protocol
52
53 F_PIC_NO        equ     0x200000
54 F_I2C_CTRL      equ     0x200001
55
56 ;---------------------------------------------------------------------------
57 ; RAM - ie, variables etc.
58
59 ; i2c specific stuff
60                 udata   0x400
61
62 PIC_NO          res     1
63
64 I2C_CTRL        res     1
65 I2C_CTRL_MASTER equ     7       ; bit 7 of I2C_CTRL is 1=master 0=slave
66
67 ;****************************************************************************
68 ; VECTORS: special locations, where the PIC starts executing
69 ; after reset and interrupts
70
71         org     0
72         goto    vector_reset
73
74         org     000008h
75         goto    vector_interrupt_high
76
77         org     000018h
78         goto    vector_interrupt_low
79
80 ;****************************************************************************
81 ; MACROS
82
83 ;----------------------------------------
84 ; ifbit1(REGISTER,BITNUMBER)
85 ;       executes the next instruction but only if bit BITNUMBER
86 ;       in REGISTER (which must be in the access bank) is set
87 ifbit1 macro REGISTER, BITNUMBER
88         btfsc   REGISTER, BITNUMBER, 0
89         endm
90
91 ;----------------------------------------
92 ; ifbit0(REGISTER,BITNUMBER)
93 ;       executes the next instruction but only if bit BITNUMBER
94 ;       in REGISTER (which must be in the access bank) is clear
95 ifbit0 macro REGISTER, BITNUMBER
96         btfss   REGISTER, BITNUMBER, 0
97         endm
98
99 ;----------------------------------------
100 ; debug(BYTE)
101 ;       writes BYTE through the serial port
102 ;       serial port hardware must be suitably initialised
103 ;       serial port transmit interrupts must be disabled
104 ;       will spin until the byte is transmitted
105 ;               Before          After
106 ;       W       any             undefined
107 ;       S       any             undefined
108
109 ; macro to call subroutine to transmit over serial port for debugging
110 ; takes 8-bit value, puts in W, invokes debug_serial_transmit
111         ifndef  SLOW_VERSION
112 debug macro debugvalue
113         endm
114         endif
115
116         ifdef   SLOW_VERSION
117 debug macro debugvalue
118         movlw   debugvalue
119         call    polling_serial_transmit
120         endm
121         endif
122
123 ;----------------------------------------
124 ; debughf(REGISTER)
125 ;       reads REGISTER once and writes it to the serial port in hex
126 ;       for conditions etc. see "debug", above
127 ;               Before          After
128 ;       W       any             undefined
129 ;       S       any             undefined
130  ifdef  SLOW_VERSION
131 DEBUGHF_VALUE   equ     0x040   ; getting on towards end of access bank
132                                 ; FIXME if all of program used udata that
133                                 ; would be very nice
134
135 debughf macro register
136         movff   register, DEBUGHF_VALUE
137         call    debughf_subroutine
138         endm
139
140 debughf_subroutine
141         call    debughf_digit
142         call    debughf_digit
143         return
144
145 ;--------------------
146 debughf_digit
147 ;       transmits top nybble of DEBUGHF_VALUE in hex
148 ;       through serial port, as above, and swaps nybbles
149 ;                       Before          After
150 ;       W               any             undefined
151 ; DEBUGHF_VALUE         BBBBaaaa        aaaaBBBB        (BBBB was sent)
152
153         swapf   DEBUGHF_VALUE,1,0
154         movf    DEBUGHF_VALUE,0,0
155         andlw   0x0f
156         sublw   10
157         sublw   0
158         bn      debughf_digit_ifnot_ge10
159         addlw   'a'-('0'+10)
160 debughf_digit_ifnot_ge10
161         addlw   '0'+10
162         goto    polling_serial_transmit
163
164  else
165 debughf macro register
166         endm
167  endif
168
169
170         
171 ;****************************************************************************
172 ; PORTMANTEAU CODE
173 ; which contains lists of checks and calls to function-specific
174 ; routines etc.
175
176 ;----------------------------------------
177 vector_reset
178
179         call    serial_setup
180
181         debug   'a'
182
183         call    copy_per_pic_data
184
185         debug   'b'
186
187         call    i2c_setup
188         call    enable_interrupts
189
190         debug   'c'
191
192         goto    main
193
194 ;----------------------------------------
195 main
196         debug   'J'
197         debughf SSPSTAT
198         debughf SSPCON1
199         debughf SSPCON2
200         debughf SSPADD
201
202         banksel I2C_CTRL                ; ser BSR=i2c BSR (4)
203         btfsc   I2C_CTRL,I2C_CTRL_MASTER,1 ; check =master?, if so
204         goto    master_main             ; goto master main routine
205         goto    slave_main              ; elso goto slave main routine
206
207 ;----------------------------------------
208 vector_interrupt_high
209         debug   'H'     
210         goto    panic
211
212 ;----------------------------------------
213 vector_interrupt_low
214 ; checks which interrupt and as soon as it finds one jumps straight
215 ; to the relevant ISR.  That routine will return with retfie and if
216 ; there was another interrupt we will re-enter, which is OK.
217
218         btfsc   PIR1,SSPIF,0    ; check if MSSP interrupt generated, if so
219 ;       goto    i2c_isr         ; I2C ISR will check whether master or slave
220         goto    panic           ; nothing should generate these ATM....
221
222         btfsc   PIR1,5,0        ; check for serial receive interrupt
223         goto    serial_rx_isr   ; receive serial
224
225         debug   'L'             ; else panic - interrupt but don't know why
226         goto    panic
227
228 ;----------------------------------------
229 enable_interrupts
230 ;       globally enable interrupts - p77
231 ;       etc.
232
233         bsf     RCON,7,0        ; enable priority levels
234         bsf     INTCON,7,0      ; enable high-priority interrupts
235         bsf     INTCON,6,0      ; enable low-priority interrupts
236         bcf     PIE1,3,0        ; disable master synchronous serial port
237                                 ; (MSSP; i.e. enable i2c) interrupts
238                                 ; (temporary for this simple program)
239         bsf     PIE1,5,0        ; enable USART receive interrupt (p85)
240         return
241
242 ;***************************************************************************(
243 ; FUNCTIONALITY
244 ; these routines actually glue things together to make something that
245 ; does something
246
247 ;----------------------------------------
248 master_main
249 ;       main program for master PIC
250
251         call    led_green
252
253 master_main_loop
254         goto    master_main_loop
255
256
257 ;----------------------------------------
258 slave_main
259 ;       main program for slave PICs
260
261         bcf     PIE1,5,0        ; disable serial receive interrupt
262         bcf     PIE1,4,0        ; disable serial transmit interrupt
263         call    led_red
264         debug   'S'
265
266 slave_main_loop
267         call    wait_for_i2c_interrupt  ; wait for 1st (address) byte
268         call    led_green
269         debug   'G'
270         call    wait_for_i2c_interrupt  ; wait for 2nd (data) byte
271         call    led_black
272         debug   'B'
273         goto    slave_main_loop
274
275 ;----------------------------------------
276 serial_rx_isr
277         call    led_black
278
279         debug   'd'
280
281 ;       what we actually do here is faff with I2C to start transmitting
282         bsf     SSPCON2,SEN,0           ; i2c START
283         call    wait_for_i2c_interrupt
284
285         debug   'e'
286
287         movlw   0x82                    ; transmit 1000 0010
288         movwf   SSPBUF,0                ; (ie address 1000001, read=0)
289
290         call    wait_for_i2c_interrupt
291
292         debug   'f'
293
294         ifbit1  SSPCON2,ACKSTAT         ; check for ack from slave (=0), if no
295         goto    panic                   ; then panic, else
296
297         debug   'g'
298
299         movff   RCREG,SSPBUF            ; copy byte from serial to i2c buffer
300         call    wait_for_i2c_interrupt
301         btfsc   SSPCON2,ACKSTAT,0       ; check for ack from slave (=0), if no
302         goto    panic                   ; then panic, else
303         bsf     SSPCON2,PEN,0           ; i2c STOP
304         call    wait_for_i2c_interrupt
305
306         retfie
307
308 ;***************************************************************************
309 ; SERIAL PORT
310
311 ;--------------------
312 serial_setup
313 ;       sets up the serial port, 9600 8N1 etc. as required by host
314 ;       interrupt is enabled for reception but not transmission
315
316 ; initial config - TXSTA register p181
317         bcf     TXSTA,6,0       ; p181, set 8-bit mode
318         bsf     TXSTA,5,0       ; transmit enable
319         bcf     TXSTA,4,0       ; asynchronous mode
320         bsc_txsta_brgh          ; set high or low baud rate
321         
322 ; initial config - RCSTA register p182
323         bsf     RCSTA,7,0       ; serial port enable (p182)
324         bcf     RCSTA,6,0       ; 8-bit reception
325         bsf     RCSTA,4,0       ; enable continuous receive
326
327 ; set SPBRG to get correct baud rate
328         movlw_movwf_spbrg
329
330 ; interrupt set-up for serial receive
331         bcf     IPR1,5,0        ; set to low-priority interrupt
332         return
333
334 ;--------------------
335 polling_serial_transmit
336 ;       writes W through the serial port
337 ;       serial port hardware must be suitably initialised
338 ;       serial port transmit interrupts must be disabled
339 ;       will spin until the byte is transmitted
340 ;               Before          After
341 ;       W       byte to xmit    preserved
342
343         movwf   TXREG,0         ; move contents of W (i.e. debugvalue)
344                                 ;       to TXREG for transmission
345 debug_waitfortsr_loop
346         btfss   TXSTA,1,0
347         bra     debug_waitfortsr_loop
348
349         return
350
351 ;****************************************************************************
352
353         code
354
355 ;***************************************************************************
356 ; FLASH ID LOCATIONS
357
358 ;--------------------
359 copy_per_pic_data
360 ;       copies PIC-dependent info out of flash memory to RAM
361 ;       see README.protocol
362
363         movlw   (F_PIC_NO >> 16) & 0xff ; set table pointer to point to
364         movwf   TBLPTRU                 ; PIC number in flash
365         movlw   (F_PIC_NO >> 8) & 0xff
366         movwf   TBLPTRH
367         movlw   F_PIC_NO & 0xff
368         movwf   TBLPTRL
369
370         tblrd   *+              ; read then increment pointer 
371                                 ; (now points to i2c control byte)
372
373         banksel PIC_NO
374         movf    TABLAT,0,0      ; move pic number into normal memory
375         movwf   PIC_NO,1
376
377         iorlw   '0'
378         call    polling_serial_transmit
379
380         tblrd   *               ; read i2c
381
382         movf    TABLAT,0,0      ; move i2c_ctrl byte into normal memory
383         movwf   I2C_CTRL,1
384 ; now have: PIC number in 400h, i2c control byte in 401h - see
385 ; RAM variables re i2c specific stuff, above
386
387         iorlw   '0'
388         call    polling_serial_transmit
389
390         return
391
392 ;***************************************************************************
393 ; I2C
394
395 ;--------------------
396 i2c_setup
397 ;       sets up the I2C interface
398
399 ; see also:
400 ; p68
401 ; p314
402 ; p 275 ID locs
403
404 ; To generate our I2C address, we take PIC_NO bits 4-0 and prepend
405 ; 0b10 (i.e. all addresses are of the form 0b10xxxxx)
406         banksel PIC_NO          ; ser BSR=i2c BSR (4)
407
408 ; common to master and slaves:
409         bsf     SSPSTAT,7,0     ; disable slew rate control
410         bcf     SSPSTAT,6,0     ; disable SMBus specific commands
411                                 ; (whatever that means)
412         bcf     SSPCON2,7,0     ; disable general call (for now)
413
414         bcf     IPR1,SSPIP,0    ; make interrupt low priority
415
416 ; are we master or slave ?
417         btfsc   I2C_CTRL,I2C_CTRL_MASTER,1      ; test whether PIC is master
418         goto    i2c_setup_if_master
419         goto    i2c_setup_if_slave
420
421 i2c_setup_if_master
422         movlw   0x08            ; clear top 2 status bits; disable SSP;
423         movwf   SSPCON1,0       ;  CKP unused, set to 0; master mode.
424
425 ; set baud rate
426         movlw   i2c_sspadd
427         movwf   SSPADD,0
428         goto    i2c_setup_endif_master_slave
429
430 i2c_setup_if_slave
431         movlw   0x16            ; clear top 2 status bits; disable SSP;
432         movwf   SSPCON1,0       ;  release clock; 7bit slave mode with
433                                 ;  no extra start/stop interrupts.
434 ;       !!fixme probably want to set SSPCON2:SEN "clock stretching"
435
436 ; set slave address
437         banksel PIC_NO          ; set BSR=i2c BSR (4)
438         movf    PIC_NO,0,1      ; copy pic_no to W (000xxxxx)
439         iorlw   0x40            ; change top 3 bits t 010 (010xxxxx)
440         rlncf   WREG,0,0        ; shift, bottom bit is r/w (10xxxxx0)
441         movwf   SSPADD,0        ; move to slave address register 
442                                 ; (bits 7-1=address, bit 0=0)
443
444 i2c_setup_endif_master_slave
445         bsf     SSPCON1,5,0     ; enable I2C mode
446
447         return
448
449 ;----------------------------------------
450 i2c_isr
451         banksel PIC_NO                  ; ser BSR=i2c BSR (4)
452         btfsc   I2C_CTRL,I2C_CTRL_MASTER,1 ; check =master?, if so
453         goto    i2c_master_isr          ; goto master interrupt routine
454         goto    i2c_slave_isr           ; elso goto interrupt_slave
455
456 ;--------------------
457 i2c_master_isr
458         debug   'm'
459         goto    panic
460
461 ;--------------------
462 i2c_slave_isr
463         debug   's'
464         goto    panic
465
466 ;----------------------------------------
467 wait_for_i2c_interrupt
468 ;       polls the relevant bit until the I2C interrupt flag is set,
469 ;       then returns.  should not usually be used if I2C interrupts
470 ;       are enabled, clearly.
471
472         debug   '.'
473 wait_for_i2c_interrupt_loop
474         btfss   PIR1,SSPIF,0    ; check if interrupt set, if not, loop
475         goto    wait_for_i2c_interrupt_loop
476
477         bcf     PIR1,SSPIF,0    ; clear interrupt bit
478
479         debug   'I'
480         debughf SSPSTAT
481         debughf SSPCON1
482         debughf SSPCON2
483         
484         return
485
486 ;***************************************************************************
487 ; GENERALLY-USEFUL SUBROUTINES;
488
489 ;----------------------------------------
490 panic
491 ;       stops everything, makes LED red
492
493         debug   'x'
494         clrf    INTCON,0        ; disable all interrupts EVER
495         debug   'y'
496         bcf     PORTC,1,0       ; switch off booster
497         debug   'z'
498         call    led_red
499
500 panic_loop
501         goto    panic_loop
502
503
504 ;----------------------------------------
505 informative_panic
506 ; switch off interrupts and power
507 ; reconfigure timer0 for writing diagnostic msg to the LED
508
509         
510         clrf    INTCON,0        ; disable all interrupts EVER
511         bcf     PORTC,1,0       ; switch off booster
512
513 ; re-initialise timer0 config
514         bcf     T0CON,6,0       ; p107 Timer0 -> 16bit mode
515         bcf     T0CON,5,0       ; timer0 use internal clock
516         bsc_morse_t0con_012     ; use prescaler? and configure it
517
518
519
520
521
522
523 ;----------------------------------------
524 waiting
525 ; wait for timer0 interrupt
526         bcf     INTCON,2,0      ; clear timer0 interrupt bit (p109)
527         clrf    TMR0H,0         ; p107 set high bit of timer0 to 0 (buffered,
528                                 ; only actually set when write to tmr0l occurs)
529         clrf    TMR0L,0         ; set low bit o timer0 - timer now set to 0000h
530 loop
531         btfss   INTCON,2,0      ; check whether timer0 interrupt has been set -
532                                 ; skip next instruction if so
533         bra     loop
534         return
535
536
537 ;****************************************************************************
538
539         end