-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathds1wire-1pin.asm
1116 lines (951 loc) · 31.7 KB
/
ds1wire-1pin.asm
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
;; ############################################################
;;
;; Dallas 1-wire routines
;;
;; Requirements:
;;
;; Uses Timer 0 (TMR0), configred with no prescaler (running
;; at 1:1 freq). User program can utilize TMR0 in hook functions
;; to measure short intervals of time but should not change
;; prescaler and other settings of TMR0.
;;
;; Uses interrupt-on-change, this feature is not available
;; in the user's code using these 1-wire routines. User's code
;; should not modify IOC register.
;;
;; Uses WDT, WDT should be enabled in configuration word
;; Assigns prescaler to WDT, sets it to 1:32 which yields WDT
;; timeout of 0.57 sec
;;
;; Completely owns OPTION_REG register and resets it periodically
;; to restore WDT prescaler. Specifically controls bits
;; PS0-2, PSA, T0SE, T0CS, GPPU of OPTION_REG . Only bit
;; INTEDG can be controlled by user program; control
;; word can be passed via set_option_reg_bits function.
;;
;; 1-wire bus is connected to a single GPIO port,
;; which is dynamically switched between input and output
;; modes. Port number should be passed in W in call to ds1init.
;;
;; Weak pull-up for this port is turned on if user calls
;; function enable_wpu, this makes
;; device stable in case it becomes disconnected from the 1-wire bus.
;; User's code should not reload WPU and IOC registers completely,
;; can only set or clear individual bits. Note that weak pull-up
;; may interfere with other devices on 1-wire bus; test before you use
;; it. In my experiments it broke things when device was connected
;; to 1-wire hub based on DS2409 but worked fine when device was
;; connected directly to the master.
;;
;; To initialize:
;;
;; movlw GPIO4
;; call ds1init
;; ; optionally pass value of INTEDG bit (default is '0')
;; clrw ; OPTION_REG bit INTEDG == 0
;; call set_option_reg_bits
;; ; optionally enable weak pull-up on 1-wire port
;; call enable_wpu
;; ; optionally use one GPIO port for 'activity' LED
;; movlw GPIO5
;; call set_activity_led_port
;; ; optionally use one GPIO port for 'error' LED
;; movlw GPIO2
;; call set_error_led_port
;; call ds1main ; this loops forever
;;
;; ============= API sunctions ==================================
;;
;; Setup:
;;
;; ds1init: pass GPIO port used for 1-wire in W
;;
;; set_option_reg_bits: pass bits for OPTION_REG in W
;; ds1wire module controls bits PS0-2, PSA, T0SE, T0CS, GPPU
;; only bit INTEDG is passed by user program using set_option_reg_bits
;;
;; set_activity_led_port: pass GPIO port used for activity LED in W
;;
;; set_error_led_port: pass GPIO port used for error indic. LED in W
;;
;;
;; User functions are implemeted in three 'hook' functions:
;; read_register_hook, write_to_register_hook, idle_hook
;;
;; read_register_hook: called in MATCH_ROM, function 0xF5 right before
;; register contents is sent to the master
;;
;; write_register-hook: called in MATCH_ROM, function 0x5A after
;; data has been written to the register
;;
;; idle_hook: called while waiting for reset pulse
;;
;; Controlling indicator LEDs:
;;
;; actled_on, actled_off: turn activity LED on / off
;; errled_on, errled_off: turn error indicator LED on / off
;;
;; Main loop:
;;
;; ds1main: main loop
;;
;; ############################################################
;;
;; How to put device to 'sleep' while wating for the reset pulse:
;; This requires modifications to the code in this module. Since
;; device is in 'sleep' mode most of the time, idle-hook function
;; will not be called. All user code operations should be performed
;; in read_register_hook and write_to_register_hook functions.
;;
;; Note that ds1init enables interrupt-on-change - sets IOC
;; and clears GPIF bit
;;
;; Add the following in ds1wait or right before call to it in ds1main.
;;
; bsf INTCON,GPIE ; enable GPIO change interrupt
; sleep
; nop
; bcf INTCON,GPIE ; disable Interrupt on GPIO port change
; call ds1wait
;
IFDEF __12F675
include p12f675.inc
#define OPTION_BITS b'00001101' ; assign prescaler to WDT, prescaler 1:32
; prescaler 1:32 -> WDT timeout 0.57sec
; weak pull-ups enabled
;; timer0 constants
;; it looks like tmr0 runs at 1:1 rate when prescaler is
;; assigned to WDT, this does not match datasheet
#define T0_50us 0xCD
#define T0_160us 0x5F
#define T0_250us 0x05
#define LONG_TIMER_FACTOR 4
ENDIF
IFDEF __12F683
include p12f683.inc
#define OPTION_BITS b'00000000' ; assign prescaler to TMR0,
; TMR0 runs with prescaler 1:2
; use WDTCON prescaler for WDT
#define WDTCON_BITS b'00010011' ; WDT on, prescaler 1:16384
;; timer0 constants
;; tmr0 runs at 1:2 rate
#define T0_50us 0xF5
#define T0_160us 0xBE
#define T0_250us 0x82
#define LONG_TIMER_FACTOR 2
ENDIF
errorlevel -302 ; suppress message 302 from list file
DS1WIRE_CODE set 1
include ds1_address.inc
include ds1.inc
DS1W_VARS UDATA 0x40
dsstat RES 1
bitctr RES 1
indat RES 1
indat1 RES 1
indat2 RES 1
indat3 RES 1
indat4 RES 1
outdat RES 1
addr_idx RES 1
byte_true RES 1
byte_compl RES 1
bcntr RES 1
tmpbit RES 1
tmpind RES 1
long_timeout1 RES 1
rx_byte_count RES 1
long_timer_val RES 1
long_timer_cntr RES 1
;;; 1-wire I/O bit
ds1iobit RES 1
ds1iobit_c RES 1
;;; activity LED bit
actledbit RES 1
actledbit_c RES 1
;;; Error indicator bit
errledbit RES 1
errledbit_c RES 1
option_reg_bits RES 1
wpu_reg_bits RES 1
dlyctr RES 1
REGISTERS RES 8 ; 8 1-byte registers
DS1W_C CODE
DA "Copyright 2007, Vadim Kurland"
DA "v1.2"
;; check 1-wire line and skip next if line is low
;; note that since we ue bit Z, we actually skip when
;; Z is set (hence btfss)
TEST1WSC macro
movfw GPIO
andwf ds1iobit,w
btfss STATUS,Z
endm
;; check 1-wire line and skip next if line is high
TEST1WSS macro
movfw GPIO
andwf ds1iobit,w
btfsc STATUS,Z
endm
SR_1_BIT_OP macro
TEST1WSS
goto $-3
;; send the bit
rrf byte_true,f
call ds1wr
;; ~32us from this moment till the beginning of the next slot
;; send the same bit, complemented, bit is still in C
call ds1wr_r
;; read bit back from the master
;;
;; bit GPIF indicates mismatch between current value of
;; the GPIO bit and its value on the last read.
;; Last read was inside ds1wr where we waited for the line to
;; become high. Now we wait for the line to come low. No need
;; to read GPIO to clear mismatch, in fact, if for some reason
;; line has already come low and mismatch occured, we need to know.
;; In that case bit GPIF will be set immediately after we clear it,
;; and that is good for us.
bcf INTCON,GPIF
btfss INTCON,GPIF
goto $-1
;; the line is low at this time
rlf byte_true,f ; put the bit back
bcf STATUS,C
call delay12us
TEST1WSC
bsf STATUS,C ; line is high == '1'
rlf tmpbit,w
;; bit that was sent by the master is in W (W=0 or W=1)
;; my own bit is in byte_true (also as 0 or 1)
xorwf byte_true,f
btfsc byte_true,0
goto sr_no_match ; *** NO MATCH ***
rrf byte_true,f
endm
MR_1_BIT_OP macro
TEST1WSS
goto $-3
bcf INTCON,GPIF
btfss INTCON,GPIF
goto $-1
bcf STATUS,C
call delay12us
TEST1WSC
bsf STATUS,C ; line is high == '1'
rrf tmpbit,f
endm
owin:
movfw ds1iobit
BANKSEL TRISIO
iorwf TRISIO,f
BANKSEL GPIO
return
owout_line_low:
movfw ds1iobit_c
BANKSEL TRISIO
andwf TRISIO,f
BANKSEL GPIO
andwf GPIO,f
return
actled_on:
;; 'activity' LED on
movfw actledbit
BANKSEL GPIO
iorwf GPIO,f
return
actled_off:
;; 'activity' LED off
movfw actledbit_c
BANKSEL GPIO
andwf GPIO,f
return
errled_on:
;; 'error' LED on
movfw errledbit
BANKSEL GPIO
iorwf GPIO,f
return
errled_off:
;; 'error' LED off
movfw errledbit_c
BANKSEL GPIO
andwf GPIO,f
return
delay12us:
call delay4us
call delay4us
delay4us:
return
;; ################################################################
;; convert bit number to bit mask
;; bit number passed in W, bit mask returned in W
getbitmask:
movwf tmpind
incf tmpind,f
bsf STATUS,C
clrf tmpbit
rlf tmpbit,f
decfsz tmpind,f
goto $-2
movfw tmpbit
return
reset:
movlw REGISTERS
movwf FSR
movlw D'8'
movwf bcntr
clrf INDF
incf FSR,f
decfsz bcntr,f
goto $-3
clrf actledbit
clrf actledbit_c
comf actledbit_c,f
clrf errledbit
clrf errledbit_c
comf errledbit_c,f
clrw
call set_option_reg_bits
return
;; Clear WDT and reset prescaler (prescaler is cleared
;; by clrwdt command)
clearwdt:
BANKSEL OPTION_REG
clrwdt
movfw option_reg_bits
movwf OPTION_REG
BANKSEL GPIO
return
;;------------------------------------------------------
;; We use interrupt-on-change to quickly detect changes in
;; 1-wire line state. We enable interrupt-on-change only
;; for the GPIO port used for 1-wire communication. This
;; feature is disabled for all other GPIO ports to avoid
;; interference.
ds1init:
call getbitmask
movwf ds1iobit
movwf ds1iobit_c
comf ds1iobit_c,f
;; turn weak pull-up on for the 1-wire port
movfw ds1iobit
BANKSEL IOC
movwf IOC ; enable interrupt-on-change for the given gpio
IFDEF __12F683
BANKSEL WDTCON
movlw WDTCON_BITS
movwf WDTCON ; enable WDT
ENDIF
BANKSEL GPIO
;; if NOT_POR bit is '0', this means WDT timeout occured
btfsc STATUS, NOT_TO
call reset ; clear registers and other things on power-on
call clearwdt ; clrwdt cleats NOT_TO bit in STATUS
BANKSEL STATUS
btfss STATUS, NOT_TO
call errled_on ; err led on if WDT reset
ds1close:
call actled_off
call owin
movfw GPIO ; clear GPIF mismatch condition, if any
bcf INTCON,GPIF
return
enable_wpu:
movfw ds1iobit
movwf wpu_reg_bits
BANKSEL WPU
iorwf WPU
BANKSEL GPIO
return
;; pass control word for the OPTION_REG
;; ds1wire module controls bits PS0-2, PSA, T0SE, T0CS
;; other bits are passed by user program using set_option_reg_bits
;;
set_option_reg_bits:
movwf option_reg_bits
movlw b'01000000'
andwf option_reg_bits,f
movlw OPTION_BITS
iorwf option_reg_bits,f
return
;; use GPIO channel passed in W as 'activity' indicator
set_activity_led_port:
call getbitmask
movwf actledbit
movwf actledbit_c
comf actledbit_c,f
return
;; use GPIO channel passed in W as 'error' indicator
set_error_led_port:
call getbitmask
movwf errledbit
movwf errledbit_c
comf errledbit_c,f
return
;;------------------------------------------------------
;; ds1 main loop
wait_reset_end:
call clearwdt
call ds1wait_short
goto wait_cmd
gen_error:
call errled_on
ds1main:
call ds1wait
wait_cmd:
;;; Need to wait a little bit for slow chips to get in sync with protocol.
;;; Since different devices can generate presence pulse of different length,
;;; line can possibly still be low when we get to this point. Usually there
;;; is a pause of 1-3 ms between reset-presence pulses and the command
;;; sent by the master so it is safe to wait a little before we start reading
;;; command.
movlw T0_50us ; 50 us
movwf TMR0
bcf INTCON,T0IF
btfss INTCON,T0IF
goto $-1
call ds1rec_open_ended
btfsc dsstat,1
goto wait_reset_end
cmd:
movlw SEARCH_ROM
subwf indat,w
btfss STATUS,Z
goto mr
;; SEARCH ROM command
call actled_on
call ds1_search_rom
call actled_off
;; we do not support any subcommands after SEARCH_ROM at this time
goto ds1main
mr: movlw MATCH_ROM
subwf indat,w
btfss STATUS,Z
goto gen_error
;; MATCH ROM command
call ds1_match_rom
btfsc dsstat,1
goto ds1main ; match_rom did not match our address
;call actled_on
;; Perform operations specific to MATCH_ROM
call ds1rec
;call actled_off
movlw 0xF5
subwf indat,w
btfss STATUS,Z
goto reg_write
;; Command 0xF5: read content of the register N
;; register number follows (1 byte)
call ds1rec
;; call hook so that user's program can make changes in registers
;; right before they are read
call read_register_hook
movfw indat
addlw REGISTERS
movwf FSR
movfw INDF
movwf outdat
call ds1sen
goto ds1main
reg_write:
movlw 0x5A
subwf indat,w
btfss STATUS,Z
goto gen_error ; illegal command
;; Command 0x5A: write two bytes into the register N
;; register number follows (1 byte)
;; receive 3 bytes from the master (indat1, indat2, indat3)
call ds1_rx3
movfw indat1
addlw REGISTERS
movwf FSR
;; check data integrity
movlw 0xAA
movwf outdat
comf indat3,w
xorwf indat2,w
btfss STATUS,Z
goto reg_wr_err
movfw indat2
movwf INDF
call ds1sen
send_reg:
movfw INDF
movwf outdat
call ds1sen
call write_to_register_hook
goto ds1main
reg_wr_err:
call errled_on
movlw 0xA0
movwf outdat
call ds1sen
clrf outdat
call ds1sen
call errled_off
goto ds1main
;; block and wait for 1wire reset pulse, then send presence pulse
;;
;; How to put device to 'sleep' while wating for the reset pulse:
;;
;; (note that ds1init enables interrupt-on-change - sets IOC
;; and clears GPIF bit)
;;
; movlw GPIO4
; call ds1init
; bsf INTCON,GPIE ; enable GPIO change interrupt
; sleep
; nop
; bcf INTCON,GPIE ; disable Interrupt on GPIO port change
; call ds1wait
;
;;; Wait for the line to go low, then wait for it to go high,
;;; making sure it stays low long enough to be reset.
;;; Timer constant for the timeout is in W on entry
;;;
;;; Just block and wait for reset, then return
;;; in case of error returns with bit C set
ds1wait:
movlw d'100' ; start 400 us timer
movwf tmpbit
call idle_loop
measure_reset_pulse:
movfw tmpbit
call long_timer_init
_while_line_low:
TEST1WSC ; test line, skip if low
goto ds1wait ; line went high too soon
call long_timer_check
btfss INTCON,T0IF
goto _while_line_low
TEST1WSS ; Timeout, line was low long enough.
goto $-3 ; Wait till it is high again.
call ds1pres ; got reset, send presence
return
;;; Wait for the reset pulse but start with line low
;;; and use short timeout. Use after ds1rec_open_ended
;;; detected start of the reset pulse (hense short timeout)
ds1wait_short:
movlw d'40' ; start 150 us timer
movwf tmpbit
goto measure_reset_pulse
idle_loop:
call clearwdt
call actled_off
call errled_off
call idle_hook
TEST1WSC
goto idle_loop
return
;;-------------------------------------------------------
;; sends presence pulse
ds1pres:
;; pause ~20us
call delay4us
call delay4us
call delay4us
call delay4us
call delay4us
call owout_line_low ; dq low
movlw T0_160us ; wait ~160 us
movwf TMR0
bcf INTCON,T0IF
btfss INTCON,T0IF
goto $-1
call owin
return
;; ****************************************************************
;; Receive one byte. In the end wait for the line to come high
;;;
;;; This function is used to read command sent by the master after
;;; reset pulse. Problem: master sends reset pulse when SEARCH_ROM sequence
;;; is complete, we detect this pulse in the main loop and proceed waiting
;;; for the command in ds1rec, which never comes. Instead, another reset pulse
;;; comes some time later. This means it is possible that this function
;;; can receive reset pulse instead of a byte of data. If this happens,
;;; return with bit dsstat set in dareset variable.
ds1rec: movlw 0x08
movwf bitctr
bcf dsstat,dareset
call ds1rec1
TEST1WSS
goto $-3
return
;;; ****************************************************************
;;; Receive one byte.
;;; Do not wait for the line to become high in the end.
;;; Note that timeout measured while waiting for the line to be released
;;; after each bit still applies. If this fuction gets control after
;;; reset pulse sent after the SEARCH_ROM command is completed, it will
;;; time out after the first attempt to read a bit and return with
;;; bit dsstat set in dareset variable.
ds1rec_open_ended:
movlw 0x08
movwf bitctr
bcf dsstat,dareset
call ds1rec1
return
;; ****************************************************************
;; Core routine to read 1 byte:
;; waits for the line to go low, reads 8 bits, in the end
;; does not wait for the line to go high after 8 bits have been read
;;;
ds1rec1:
movfw GPIO
bcf INTCON,GPIF
btfss INTCON,GPIF
goto $-1
;bsf GPIO, GPIO2
ds1rec2:
get_bit:
;bsf GPIO, GPIO5
call delay12us
TEST1WSC ; test line, skip if low
goto got_1 ; line is high == '1'
bcf STATUS,C ; line is low == '0'
rrf indat,f
;bcf GPIO, GPIO5
decfsz bitctr,f
goto ds1rec_wait_high
return
;; wait till line goes high or timeout
ds1rec_wait_high:
movlw T0_250us ; 250 us - timeout
movwf TMR0
bcf INTCON,T0IF
wait_0:
TEST1WSC ; test line, skip if low
goto ds1rec1
btfss INTCON,T0IF
goto wait_0
;; timeout, set error bit and exit
bsf dsstat,dareset
;bcf GPIO, GPIO5
;bcf GPIO, GPIO2
return
got_1: bsf STATUS,C
rrf indat,f
;bcf GPIO, GPIO5
decfsz bitctr,f
goto ds1rec1
;bcf GPIO, GPIO2
return
;; ****************************************************************
;; read 2 bytes, put them in indat1, indat2
;;
;; Using delayed initialization to conserve time at the beginning
;; This routine may be used when there is very little time gap,
;; next to none, between chip-specific subcommand and following
;; data bytes. E.g. this is the case for subcommand 0x5A for DS2413
;; (command MATCH_ROM, subsommand 0x5A "PIO access write")
;; This command sends two bytes from the master immediately after
;; the command code. We need to move into waiting for the line to
;; go low as soon as possible after we matched command code.
;; ****************************************************************
ds1_rx2:
clrf bitctr
_rx_rec1:
;; wait for the line to go low
movfw GPIO
bcf INTCON,GPIF
btfss INTCON,GPIF
goto $-1
movf bitctr,f
btfss STATUS,Z
goto _rx_cont
;; bitctr==0, delayed initialization
movlw 2
movwf rx_byte_count
movlw indat1
movwf FSR
movlw 0x08
movwf bitctr
bcf dsstat,dareset
_rx_cont:
call delay12us
TEST1WSC
goto _rx_got_1 ; line is high == '1'
bcf STATUS,C ; line is low == '0'
rrf INDF,f
decfsz bitctr,f
goto _rx_wait_high
goto _rx_ds1rec_byte_done
;; wait till line goes high or timeout
_rx_wait_high:
movlw T0_250us ; 250 us - timeout
movwf TMR0
bcf INTCON,T0IF
_rx_wait_0:
TEST1WSC
goto _rx_rec1
btfss INTCON,T0IF
goto _rx_wait_0
;; timeout, set error bit and exit
bsf dsstat,dareset
return
_rx_got_1:
bsf STATUS,C
rrf INDF,f
_rx_ds1rec_loop:
decfsz bitctr,f
goto _rx_rec1
_rx_ds1rec_byte_done:
incf FSR,f
movlw 0x08
movwf bitctr
decfsz rx_byte_count,f
goto _rx_wait_high
return
;; ****************************************************************
;; read 3 bytes, put them in indat1, indat2, indat3
;; Just like ds1_rx2 but three bytes
;; ****************************************************************
ds1_rx3:
clrf bitctr
;; wait for the line to go low
movfw GPIO
bcf INTCON,GPIF
btfss INTCON,GPIF
goto $-1
movf bitctr,f
btfss STATUS,Z
goto _rx_cont
;; bitctr==0, delayed initialization
movlw 3
movwf rx_byte_count
movlw indat1
movwf FSR
movlw 0x08
movwf bitctr
bcf dsstat,dareset
goto _rx_cont
;; ****************************************************************
;; read 4 bytes, put them in indat1, indat2, indat3, indat4
;; Just like ds1_rx2 but four bytes
;; ****************************************************************
ds1_rx4:
clrf bitctr
;; wait for the line to go low
movfw GPIO
bcf INTCON,GPIF
btfss INTCON,GPIF
goto $-1
movf bitctr,f
btfss STATUS,Z
goto _rx_cont
;; bitctr==0, delayed initialization
movlw 4
movwf rx_byte_count
movlw indat1
movwf FSR
movlw 0x08
movwf bitctr
bcf dsstat,dareset
goto _rx_cont
;;;-----------------------------------------------------
;;; sends 1 bit
;;; bit to be sent is passed via carry
;;; assumes master has sent reset pulse
;;; This function is used only in SEARCH_ROM (macro SR_1_BIT_OP)
;;;
;;; In the end waits for the line to go high with no timeout.
;;; WDT provides protection against situations when line
;;; gets stuck low.
;;;
ds1wr: bcf dsstat,dareset
movfw GPIO
bcf INTCON,GPIF
btfss STATUS,C
goto ds1wr_0 ; send '0'
ds1wr_1:
;; wait for the line to go low
btfss INTCON,GPIF
goto $-1
goto ds1wr_hold
;;;----------------------------------------------------
;;; second entry point: send 1 bit, reversed
;;; bit to be sent is passed via carry
;;; assumes master has sent reset pulse
;;; This function is used only in SEARCH_ROM (macro SR_1_BIT_OP)
;;;
ds1wr_r:
movfw GPIO
bcf INTCON,GPIF
btfss STATUS,C
goto ds1wr_1
;; sending 0
ds1wr_0:
;; wait for the line to go low
btfss INTCON,GPIF
goto $-1
call owout_line_low
ds1wr_hold:
call delay12us
call delay12us
call owin
TEST1WSS
goto $-3
return
;;; -----------------------------------------------------
;;; Send one byte
;;;
;;; Master drives line low to indicate beginning of a slot, however
;;; line stays low for just a few microseconds so TEST1WSC is too slow.
;;; Use interrupt on change bit.
;;;
ds1sen: movlw 0x08
movwf bitctr
movfw GPIO
bcf INTCON,GPIF
;;; master drives line low and then releases it right away, line stays
;;; low for only about 3us. It then senses the line level to check what
;;; is being transmitted by slave, 0 or 1. It senses the line
;;; within about 10us after it releases the line. Prepare the bit to be
;;; sent before we go into the loop waiting for the beginning of the slot.
;;; Splitting the loop into two parts (for '0' and '1') allows for minimal
;;; delay between detection of the beginning of the slot and setting line
;;; level low to send '0'.
ds1sen1:
rrf outdat,f
btfsc STATUS,C
goto ds1sen_1
ds1sen_0:
btfss INTCON,GPIF
goto $-1
call owout_line_low
ds1sen_hold:
call delay12us
call delay12us
call owin ; does not touch GPIO
; so it does not clear IOC condition
movfw GPIO ; to clear IOC condition
bcf INTCON,GPIF
decfsz bitctr,f
goto ds1sen1
return
ds1sen_1:
btfss INTCON,GPIF
goto $-1
goto ds1sen_hold
;; ****************************************************************
;; SEARCH_ROM
;; Performs SEARCH_ROM command (0xF0)
;; ****************************************************************
ds1_search_rom:
clrf tmpbit
movlw D'8'
movwf addr_idx
sr_loop:
movfw addr_idx
call get_addr_byte
;; byte of the address is in W
movwf byte_true
SR_1_BIT_OP
SR_1_BIT_OP
SR_1_BIT_OP
SR_1_BIT_OP
SR_1_BIT_OP
SR_1_BIT_OP
SR_1_BIT_OP
SR_1_BIT_OP