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
5 ; pin 21 (per-pic-led, RD2/PSP2/C1IN) states:
6 ; high H = blue (=green), low L = orange (=red), float Z = black
8 ;***************************************************************************
13 ; In subroutines, unless otherwise stated, W and S may have any
14 ; value on entry and will be undefined on exit.
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)
25 ;---------------------------------------------------------------------------
28 include /usr/share/gputils/header/p18f458.inc
30 include ../iwjpictest/clockvaries.inc
37 messg "hello this is the slow version"
41 messg "hello this is the fast version"
50 ;---------------------------------------------------------------------------
51 ; ID locations layout, in flash - see README.protocol
54 F_I2C_CTRL equ 0x200001
56 ;---------------------------------------------------------------------------
57 ; RAM - ie, variables etc.
65 I2C_CTRL_MASTER equ 7 ; bit 7 of I2C_CTRL is 1=master 0=slave
67 ;****************************************************************************
68 ; VECTORS: special locations, where the PIC starts executing
69 ; after reset and interrupts
75 goto vector_interrupt_high
78 goto vector_interrupt_low
80 ;****************************************************************************
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
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
99 ;----------------------------------------
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
109 ; macro to call subroutine to transmit over serial port for debugging
110 ; takes 8-bit value, puts in W, invokes debug_serial_transmit
112 debug macro debugvalue
117 debug macro debugvalue
119 call polling_serial_transmit
123 ;----------------------------------------
125 ; reads REGISTER once and writes it to the serial port in hex
126 ; for conditions etc. see "debug", above
131 DEBUGHF_VALUE equ 0x040 ; getting on towards end of access bank
132 ; FIXME if all of program used udata that
135 debughf macro register
136 movff register, DEBUGHF_VALUE
137 call debughf_subroutine
145 ;--------------------
147 ; transmits top nybble of DEBUGHF_VALUE in hex
148 ; through serial port, as above, and swaps nybbles
151 ; DEBUGHF_VALUE BBBBaaaa aaaaBBBB (BBBB was sent)
153 swapf DEBUGHF_VALUE,1,0
154 movf DEBUGHF_VALUE,0,0
158 bn debughf_digit_ifnot_ge10
160 debughf_digit_ifnot_ge10
162 goto polling_serial_transmit
165 debughf macro register
171 ;****************************************************************************
173 ; which contains lists of checks and calls to function-specific
176 ;----------------------------------------
183 call copy_per_pic_data
188 call enable_interrupts
194 ;----------------------------------------
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
207 ;----------------------------------------
208 vector_interrupt_high
212 ;----------------------------------------
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.
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....
222 btfsc PIR1,5,0 ; check for serial receive interrupt
223 goto serial_rx_isr ; receive serial
225 debug 'L' ; else panic - interrupt but don't know why
228 ;----------------------------------------
230 ; globally enable interrupts - p77
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)
242 ;***************************************************************************(
244 ; these routines actually glue things together to make something that
247 ;----------------------------------------
249 ; main program for master PIC
254 goto master_main_loop
257 ;----------------------------------------
259 ; main program for slave PICs
261 bcf PIE1,5,0 ; disable serial receive interrupt
262 bcf PIE1,4,0 ; disable serial transmit interrupt
267 call wait_for_i2c_interrupt ; wait for 1st (address) byte
270 call wait_for_i2c_interrupt ; wait for 2nd (data) byte
275 ;----------------------------------------
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
287 movlw 0x82 ; transmit 1000 0010
288 movwf SSPBUF,0 ; (ie address 1000001, read=0)
290 call wait_for_i2c_interrupt
294 ifbit1 SSPCON2,ACKSTAT ; check for ack from slave (=0), if no
295 goto panic ; then panic, else
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
308 ;***************************************************************************
311 ;--------------------
313 ; sets up the serial port, 9600 8N1 etc. as required by host
314 ; interrupt is enabled for reception but not transmission
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
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
327 ; set SPBRG to get correct baud rate
330 ; interrupt set-up for serial receive
331 bcf IPR1,5,0 ; set to low-priority interrupt
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
341 ; W byte to xmit preserved
343 movwf TXREG,0 ; move contents of W (i.e. debugvalue)
344 ; to TXREG for transmission
345 debug_waitfortsr_loop
347 bra debug_waitfortsr_loop
351 ;****************************************************************************
355 ;***************************************************************************
358 ;--------------------
360 ; copies PIC-dependent info out of flash memory to RAM
361 ; see README.protocol
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
367 movlw F_PIC_NO & 0xff
370 tblrd *+ ; read then increment pointer
371 ; (now points to i2c control byte)
374 movf TABLAT,0,0 ; move pic number into normal memory
378 call polling_serial_transmit
382 movf TABLAT,0,0 ; move i2c_ctrl byte into normal memory
384 ; now have: PIC number in 400h, i2c control byte in 401h - see
385 ; RAM variables re i2c specific stuff, above
388 call polling_serial_transmit
392 ;***************************************************************************
395 ;--------------------
397 ; sets up the I2C interface
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)
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)
414 bcf IPR1,SSPIP,0 ; make interrupt low priority
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
422 movlw 0x08 ; clear top 2 status bits; disable SSP;
423 movwf SSPCON1,0 ; CKP unused, set to 0; master mode.
428 goto i2c_setup_endif_master_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"
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)
444 i2c_setup_endif_master_slave
445 bsf SSPCON1,5,0 ; enable I2C mode
449 ;----------------------------------------
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
456 ;--------------------
461 ;--------------------
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.
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
477 bcf PIR1,SSPIF,0 ; clear interrupt bit
486 ;***************************************************************************
487 ; GENERALLY-USEFUL SUBROUTINES;
489 ;----------------------------------------
491 ; stops everything, makes LED red
494 clrf INTCON,0 ; disable all interrupts EVER
496 bcf PORTC,1,0 ; switch off booster
504 ;----------------------------------------
506 ; switch off interrupts and power
507 ; reconfigure timer0 for writing diagnostic msg to the LED
510 clrf INTCON,0 ; disable all interrupts EVER
511 bcf PORTC,1,0 ; switch off booster
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
523 ;----------------------------------------
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
531 btfss INTCON,2,0 ; check whether timer0 interrupt has been set -
532 ; skip next instruction if so
537 ;****************************************************************************