-
Notifications
You must be signed in to change notification settings - Fork 5
/
grenade.asm
2715 lines (2444 loc) · 63.8 KB
/
grenade.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
; *****************************************************************************
; Recoil Gun Grenade code for SkyRocket Toys 2017
; Based on TR4K-IDE Demo Code by TRITAN Technology Inc.
;
; Note that the TR4K-IDE uses 8 character tabs.
; TR4P153CT = new hardware (emulator, otp chips)
; as TR4P153BT but supports ADC
; TR4P153BT = new hardware (grenade)
; 14 pins (11 input/output, 1 input, vcc, gnd)
; 1536 instructions (12 bit words)
; 256 nybbles of RAM (4 bit nybbles) in banks of 32 nybbles
; 2.2V to 5.5V
; For pinout and GPIO usage see pinout.inc
; For protocol timing see protocol.inc
; *****************************************************************************
;
; Resource usage
; Green mode (low speed oscillator) is not used - just normal and halt
; Internal high speed oscillator is 32MHz +/- 2%
; CPU clock is osc/4 = 8MHz
; Scaler2 = MCLK/8 = 1MHz
; Timer1 = Unused
; Timer2 = 100uS for protocol output
; RTC = Unused (1 second)
;
; *****************************************************************************
; Notes about assembly language
; jc = jump if less than
; jnc = jump if greater or equal
; *****************************************************************************
; -----------------------------------------------------------------------------
; Defines ONLY WORK if they are defined here rather than in the include files
; Must be BEFORE include blocks
; "BOARD_MARCH" fails to compile so we use "BOARD_8LEDS"
; -----------------------------------------------------------------------------
; -----------------------------------------------------------------------------
; Define one of these boards.
#define BOARD_8LEDS ; PCB with 8 single infrared LEDs on individual pins
;#define BOARD_STEPHEN ; Initial prototype board from stephen with 4 pairs of infrared LEDs
;#define BOARD_DEVELOP ; PCB with 8 single infrared LEDs on a 3 to 8 demuxer
; -----------------------------------------------------------------------------
; Choose an appropriate protocol from protocol.inc, and its subdefines
; since the assembler does not get them correctly.
#define PROTOCOL_MAN20A
#define PROTOCOL_MAN
#define PROTOCOL_20A
#define PROTOCOL_OUTSTATE ; Output the outstate instead of the state
;#define PROTOCOL_NEC12
;#define PROTOCOL_NEC
;#define PROTOCOL_12
;#define PROTOCOL_NEC4
;#define PROTOCOL_NEC
;#define PROTOCOL_4
;#define PROTOCOL_EXPLODE_PULSE
; Note that the explode pulse happens during the explosion state
; -----------------------------------------------------------------------------
#define USE_FIXED_SERIAL 0 ; Use a fixed serial number instead of unique serial number
; -----------------------------------------------------------------------------
; Special versions for testing explosions - these all require PROTOCOL_MAN20A, PROTOCOL_OUTSTATE
;#define SPECIAL_TEST2 ; 5s of 0000, 5s of FFFF, 5s of 5555, 5s of AAAA
;#define SPECIAL_TEST ; 20s of state 1, 20s of state 14
#define SPECIAL_RC1 ; 30s detonation of state 1
;#define SPECIAL_RC2 ; 10s detonation of state 1
;#define SPECIAL_RC3 ; 5s detonation of state 1
;#define SPECIAL_RC4 ; 30s detonation of state 14
;#define SPECIAL_RC5 ; 10s detonation of state 14
;#define SPECIAL_RC6 ; 5s detonation of state 14
;#define SPECIAL_RC7 ; 60s detonation of state 1..12
; -----------------------------------------------------------------------------
; Special simon demo for analysing power supply
; 1. ADDRESS_MASK is always 0 (use LED 1 only)
; 2. OUTPUT_POWER is always 0 (power levels off)
; 3. 38kHz constantly - no modulation (IR_OnOff is assumed to be 1)
; 4. long delay on reset (no 38khz output) 500ms+
; 5. do not go to sleep
;#define SPECIAL_SIMON 1
; -----------------------------------------------------------------------------
; Special sam demo for testing range
; Keeps looping trigger
;#define SPECIAL_SAM 1
; -----------------------------------------------------------------------------
; Include Block
; -----------------------------------------------------------------------------
; Include one of these three only
#include "tr4p153ct.inc" ; Emulator (same as grenade)
;#include "tr4p153bt.inc" ;Grenade (same as emulator)
;#include "tr4p151af.inc" ; Beacon (lacks portD)
#include "protocol.inc"
#include "pinout.inc"
; -----------------------------------------------------------------------------
; grenade logic equates (internal logic)
state_unarmed equ 0
state_cancelled equ 1
state_priming equ 2
state_primed equ 3
state_10 equ 4
state_9 equ 5
state_8 equ 6
state_7 equ 7
state_6 equ 8
state_5 equ 9
state_4 equ 10
state_3 equ 11
state_2 equ 12
state_1 equ 13
state_explode equ 14
state_waiting equ 15 ; On start up, wait for a while to decide if priming or armed
; Output "state" as requested on 27 jun 2017 (and made sensible by including primed/cancelled)
outstate_none equ 0 ; Do not output packets
outstate_explode0 equ 1 ; Old cancelled button - may be more visible
outstate_explode5 equ 2
outstate_explode10 equ 3
outstate_explode15 equ 4
outstate_explode20 equ 5
outstate_explode25 equ 6
outstate_explode30 equ 7
outstate_explode35 equ 8
outstate_explode40 equ 9
outstate_explode45 equ 10
outstate_explode50 equ 11
outstate_explode55 equ 12
outstate_cancelled equ 13
outstate_priming equ 14
outstate_primed equ 15
; In these units with 16 bits we can reach 5 seconds (5000ms)
TIME_TICK equ 100*25/2 ; (16 bits) Size of normal grenade ticks in ms->interrupt units
TIME_EXPLODE equ 100*25/2 ; (16 bits) Size of explosion ticks in ms->interrupt units (assumed to be <=65535)
TIME_CANCELLED equ 100*25/2 ; (16 bits) Size of cancelled ticks in ms->interrupt units (assumed to be <=65535)
TIME_PRIMING equ 50*25/2 ; (16 bits) Size of priming ticks
TIME_PRIMED equ 50*25/2 ; (16 bits) Size of primed ticks (must match TIME_PRIMING)
TIME_WAITING equ 750*25/2 ; (16 bits) Time to wait to see if priming or armed (0.75s) first time
TIME_REWAITING equ 1500*25/2 ; (16 bits) Time to wait to see if priming or armed (2.00s) second time
COUNT_PRIMING equ 10 ; (8 bits) Number of priming ticks between packets (assumed to be even) (assumed to be <255)
;;COUNT_EXPLODE equ 20 ; (8 bits) Number of explosion ticks before going to sleep (assumed to be <=255)
COUNT_EXPLODE equ 50 ; (8 bits) Number of explosion ticks before changing explosion counter (assumed to be <=255)
COUNT_TICK equ 10 ; (4 bits) Number of update ticks before going to next state (assumed to be even) (assumed to be <15)
COUNT_CANCELLED equ 20 ; (8 bits) Number of cancelled ticks before going to sleep (assumed to be <=255)
COUNT_PRIMEDTX equ 10 ; (4 bits) Number of primed ticks between sending 8 packets
COUNT_PRIMED equ 40 ; (8 bits) Number of primed ticks to stay visible in the primed mode? (2 seconds)
#ifdef SPECIAL_SIMON
ADDRESS_MASK equ 0
#else
#ifdef BOARD_STEPHEN
ADDRESS_MASK equ 3
#endif
#ifdef BOARD_DEVELOP
ADDRESS_MASK equ 7
#endif
#ifdef BOARD_8LEDS
ADDRESS_MASK equ 7
#endif
#endif
; -----------------------------------------------------------------------------
; User defined "registers" (SRAM variables)
; -----------------------------------------------------------------------------
;#define Optimal_MAH ; System MAH Optimal (Only optimal MAH)
#define Optimal_MAH_PCH ; System MAH + PCH Optimal (Optimal MAH and PCH)
; This means that ldpch commands are not required since they will be ignored and regenerated by the compiler
; So I only put them in the header so we can see how they affect the padding
; This means that ldmah commands are not required since they will be generated by the compiler when variables in this struct are used
; So I only put them in where they are needed to override the assembler
VARRM = {
; -------------------------------------
; System variables
A_SRT ; Save the A register during an interrupt
SramChk0_IN ; Canary byte for checking SRAM corruption
SramChk1_IN ; ^
; The 16 bit payload data
; In hover racer this was the MCU unique ID read from OTP flash (set on startup)
Payload0 ; 16 bit packet data
Payload1 ; ^
Payload2 ; ^
Payload3 ; ^
; -------------------------------------
; Infrared packet (output)
; (up to) 32 bit data packet for output (set on each packet output; destroyed during transmission)
IR_PktData0 ; (was IR_CRC_Byte0) First bit sent is the low bit of this nybble
IR_PktData1 ; (was IR_CRC_Byte1)
IR_PktData2 ; (was IR_Data_Byte0)
IR_PktData3 ; (was IR_Data_Byte1)
IR_PktData4 ; (was IR_Data_Byte2)
IR_PktData5 ; (was IR_Data_Byte3)
IR_PktData6 ; (was IR_User_Byte0)
IR_PktData7 ; (was IR_User_Byte1) Last bit sent is the high bit of this nybble
; -------------------------------------
; CRC variables (first bank)
Dat_Len_Num ; Number of bits that have been processed via CRC
IR_CRC_Buf0 ; Calculated CRC output buffer
IR_CRC_Buf1 ; ^
; -------------------------------------
; Packet timing variables
Tim_SendPkt1 ; 12 bit counter (incremented once per Timer2 interrupt)
Tim_SendPkt2 ; ^ Used for determining timing of sending packets
Tim_SendPkt3 ; ^ SHARED between main thread and interrupt thread! Be careful!
IR_Group0 ; 12 bit counter (incremented every packet) for checking fast vs slow packets
IR_Group1 ; ^ For main thread
IR_Group2 ; ^ For main thread
IR_Enable_Flag ; Zero = Do not touch infrared, One = allow infrared
IR_Flag ; Bit0=header pulse has been sent.
; Bit1=header gap has been sent
; Bit2=payload has been sent
; Bit3=stop bit has been sent
IR_Num0 ; 8 bits: the number of payload bits that have been sent in this packet
IR_Num1 ; ^ For interrupt thread
IR_BaseTim0 ; 8 bit counter incremented every timer2 (100uS) "Do basic time waveform used"
IR_BaseTim1 ; ^ this is reset between phases (e.g. header, gap, each payload bit)
IR_BIT_OK_FLAG ; True iff IR_Bit is valid. False if a new payload bit should be extracted from the packet.
IR_Bit ; The value of the current transmitting payload bit (0 or 1)
; (would be a bank boundary if this was handled manually)
LastTim1 ; Used for checking that multi nybble comparisons have not been invalidated
g_poweroff ; Flag to turn the power off (no sleep mode in this project)
g_quiet ; In primed mode, this means we are quiet
; CRC variables (second bank)
CRC_DATA0 ; Calculated 16 bit CRC input buffer
CRC_DATA1 ; ^
CRC_DATA2 ; ^
CRC_DATA3 ; ^
; Grenade logic variables
g_update ; true when we want to update the output packet (Payload0 has changed)
g_send ; true when we want to keep on sending a group of packets
g_timer0 ; Increments every 100us
g_timer1 ; Increments every 1.6ms
g_timer2
g_timer3
g_state
g_substate0
g_substate1
g_outi ; Which port to use for output
g_tmp ; For masking
g_random ; Increments fast when the button is pressed
; The MCU unique ID read from OTP flash (set on startup)
Mcu_ID0 ; 16 bit packet data
Mcu_ID1 ; ^
Mcu_ID2 ; ^
Mcu_ID3 ; ^
; The processed payload (gggggg01) = mangled serial of chip + 11 for grenade
Weapon0 ; Goes to Payload2
Weapon1 ; Goes to Payload3
; Pressing button
BtnTimer ; For spacing out the read (debouncing)
BtnLast ; Last button was pressed? (active high)
BtnNow ; Button is pressed? (active high)
BtnSmooth ; Button value 0 (off) ... 15 (on) for debouncing the other variables
; Fast explosion logic
SendExplode ; 0=normal, 1=Explosion enabled
ExplodePhase ; 0=off phase, 1=on phase during explosion
OutState ; outstate_xxx for output
; (would be a bank boundary if this was handled manually)
g_btntimer0 ; For counting when the button is held during primed mode
g_btntimer1
g_btntimer2
g_btntimer3
; Special value for primed counter
g_primedcnt ; Counts up on each substate - 10 make it to trigger flashes
; Initial delay timer
CntDelay0
CntDelay1
CntDelay2
CntDelay3
CntDelay4
}
IR_FLAG_HDR_MARK equ 1 ; Bit0=header pulse has been sent.
IR_FLAG_HDR_SPACE equ 2 ; Bit1=header gap has been sent
IR_FLAG_PAYLOAD equ 4 ; Bit2=payload has been sent
IR_FLAG_STOP equ 8 ; Bit3=stop bit has been sent
IR_FLAG_PACKET equ 15; All bits set
; This is cached to reduce interrupt jitter on the infrared output enable
IR_OnOff equ USER1 ; set nonzero for on (copy to RTC register at next timer2 interrupt)
; -----------------------------------------------------------------------------
; General Parameters for the program
Ram_chk_Dat equ 5AH ; Canary value for SRAM sanity checking
VINT_MAH equ 00 ; The SRAM bank we want to use inside the interrupt [Mind you, Optima overrides this]
DELAY_MAH equ 03 ; The SRAM bank we want to use for delays
BIT_PWR_BTN equ 1<<PIN_PWR_BTN
; -----------------------------------------------------------------------------
; PROGRAM Entry points
; -----------------------------------------------------------------------------
; (0) Entry point for program start
org 0
ldpch PGMSRT
jmp PGMSRT
nop
nop
; (4) Entry point for wakeup
ldpch WakeUp
jmp WakeUp
nop
nop
; (8) Entry point for interrupt start (Timer1, Timer2, RTC)
ldpch INT_Start
jmp INT_Start
; -----------------------------------------------------------------------------
; Main Interrupt routine for Timer1, Timer2, RTC
; Hardware will store the following registers and restore them on RETI
; MAH = Memory address high
; PCH = Program counter high
; PCL = Program counter low
; CZ = Carry and Zero flags of the status register
; ENINT = ENINT flag of the SYS0 register
; Cannot call subroutines; must preserve other registers
; -----------------------------------------------------------------------------
INT_Start:
ldmah #VINT_MAH ; (Optima will do this anyway)
ld (A_SRT),A ; Preserve the A register over the interrupt
; Despatch the interrupt
; Is this interrupt from the real time clock? (once per second)
ld a,(RTC)
and A,#1000B;RTCFG/F38K/RTCS1/RTCS0
jz RTC_Acked
; This interrupt is from the real time clock (not important)
clr #3,(RTC) ; Clear the real time clock overflow flag
RTC_Acked:
; Is this interrupt from Timer1? (should not happen)
ld A,(STATUS);TM2IFG/TM1IFG/CF/ZF
and A,#0100B
jz Timer1_Acked
clr #2,(STATUS) ; Clear the timer1 interrupt flag
Timer1_Acked:
; Is this interrupt from Timer2?
ld a,(STATUS)
and A,#1000B
jnz Tim2_Int_Prc
; No timer2 interrupt this time round
jmp INT_End_NoInc
; This interrupt is from Timer2
Tim2_Int_Prc:
clr #3,(STATUS) ; Clear the timer2 interrupt flag
; Update timer for grenade logic
inc (g_timer0)
adr (g_timer1)
adr (g_timer2)
adr (g_timer3)
; Update timer for primed logic
inc (g_btntimer0)
adr (g_btntimer1)
adr (g_btntimer2)
adr (g_btntimer3)
; Support special grenade explosion
ld a,(SendExplode)
cmp a,#1 ; Just in case this is set to a bad value
jz IR_SendExplode
; Are we sending IR data?
ld a,(IR_Enable_Flag)
jz INT_End
; Where are we in the transmission?
inc (IR_BaseTim0) ; Increment 8 bit timer
adr (IR_BaseTim1)
; CPM: output high or low here at fixed location instead of all over the IRQ routine causing jitter
#ifdef SPECIAL_SIMON
ld a,#1 ; Always on (38kHz carrier)
#else
ld a,(IR_OnOff)
#endif
jz IrIsOff
set #2,(RTC) ; PA1 output infrared beam
jmp IrIsDone
IrIsOff:
clr #2,(RTC) ; PA1 no output infrared beam
IrIsDone:
ld a,(IR_Flag)
and a,#IR_FLAG_HDR_MARK
jnz IR_9MS_OK_Prc ; Have we sent the initial header?
; Code for outputting the header pulse
Head_9ms_Prc:
set #2,(IR_OnOff) ; PA1 output 38kHz infrared beam
; Are we still in the header pulse (first "9ms")?
ld a,(IR_BaseTim0)
cmp a,#Tim_9ms.n0
ld a,(IR_BaseTim1)
sbc a,#Tim_9ms.n1
jc INT_End
; We have just finished the header pulse
ld a,(IR_Flag)
or a,#IR_FLAG_HDR_MARK ; Flag the header pulse as having been sent
ld (IR_Flag),a
; Reset the phase timer
ld a,#0
ld (IR_BaseTim0),a
ld (IR_BaseTim1),a
jmp INT_End
IR_9MS_OK_Prc:
Ir_45ms_Chk_Prc:
; Have we sent the header gap?
ld a,(IR_Flag)
and a,#IR_FLAG_HDR_SPACE
jnz IR_45MS_Ok_Prc
; Have we finished the gap?
ld a,(IR_BaseTim0)
cmp a,#tim_45ms.n0
ld a,(IR_BaseTim1)
sbc a,#tim_45ms.n1
jc IR_StartGap
#ifdef PROTOCOL_MAN
; Do we want a start bit?
ld a,(IR_BaseTim0)
cmp a,#tim_gapms.n0
ld a,(IR_BaseTim1)
sbc a,#tim_gapms.n1
jc IR_StartBit
#endif
; Just finished the header gap (and maybe start bit)
ld a,#0
ld (IR_BaseTim0),a
ld (IR_BaseTim1),a
ld a,(IR_Flag)
or a,#IR_FLAG_HDR_SPACE
ld (IR_Flag),a
jmp INT_End
IR_StartGap:
; Send the header gap
clr #2,(IR_OnOff) ; PA1 no output infrared beam
jmp INT_End
#ifdef PROTOCOL_MAN
IR_StartBit:
; Send the Manchester start bit
set #2,(IR_OnOff) ; PA1 no output infrared beam
jmp INT_End
#endif
IR_45MS_Ok_Prc:
Data_rx_Prc:
ld A,(IR_Flag)
and A,#IR_FLAG_PAYLOAD
jnz DATA_RX_OK_Prc
; ====================================
; Send the payload bits (originally 32 bits; now can also be 20, 16, 12, 9 or 4 bits)
Data_32bit_RX_Prc:
ld a,(IR_Num0)
cmp a,#IR_BitNum_Dat.n0
ld a,(IR_Num1)
sbc a,#IR_BitNum_Dat.n1
jnc RX_Data_32Bit_OK_Prc
; Do we need to grab a new payload bit from the packet?
ld a,(IR_BIT_OK_FLAG)
jnz Rx_Ir_01_Prc
ld a,#01
ld (IR_BIT_OK_FLAG),a
; Grab the next payload bit from the packet (destructively)
ld a,#0
ld (IR_Bit),a ; Default payload bit is zero
clr C
rrc (IR_PktData7)
rrc (IR_PktData6)
rrc (IR_PktData5)
rrc (IR_PktData4)
rrc (IR_PktData3)
rrc (IR_PktData2)
rrc (IR_PktData1)
rrc (IR_PktData0)
jnc Rx_Ir_01_Prc ; Are we a one or zero? Jump if zero
ld a,#01
ld (IR_Bit),a ; This payload bit is a one bit
Rx_Ir_01_Prc:
ld a,(IR_Bit)
jnz Bit_1_RX_Prc
; ====================================
; Transmit a zero payload bit
Bit_0_RX_Prc:
Bit_0_1_RX_Prc:
; Are we transmitting the first or second half of a zero bit?
ld a,(IR_BaseTim0)
cmp a,#IR_0a_Dat.n0
ld a,(IR_BaseTim1)
sbc a,#IR_0a_Dat.n1
jnc Bit_0_0_RX_Prc
; First half of a zero bit
#ifdef PROTOCOL_MAN
clr #2,(IR_OnOff) ; PA1 no output infrared beam
#else
set #2,(IR_OnOff) ; PA1 output 38kHz infrared beam
#endif
jmp INT_End
Bit_0_0_RX_Prc:
; Have we finished transmitting the zero bit?
ld a,(IR_BaseTim0)
cmp a,#IR_0ab_Dat.n0
ld a,(IR_BaseTim1)
sbc a,#IR_0ab_Dat.n1
jnc RX_0_OK_Prc
; Second half of a zero bit
#ifdef PROTOCOL_MAN
set #2,(IR_OnOff) ; PA1 output 38kHz infrared beam
#else
clr #2,(IR_OnOff) ; PA1 no output infrared beam
#endif
jmp INT_End
RX_0_OK_Prc:
; Completed transmitting a zero bit
ld a,#0
ld (IR_BaseTim0),a
ld (IR_BaseTim1),a
ld (IR_BIT_OK_FLAG),a
; New payload bit
inc (IR_Num0)
adr (IR_Num1)
jmp INT_End
; ====================================
; Transmit a one payload bit
Bit_1_RX_Prc:
Bit_1_1_RX_Prc:
; Are we transmitting the first or second half of a one bit?
ld a,(IR_BaseTim0)
cmp a,#IR_1a_Dat.n0
ld a,(IR_BaseTim1)
sbc a,#IR_1a_Dat.n1
jnc Bit_1_0_RX_Prc
; First half of a one bit
set #2,(IR_OnOff) ; PA1 output 38kHz infrared beam
jmp INT_End
Bit_1_0_RX_Prc:
; Have we finished transmitting the one bit?
ld a,(IR_BaseTim0)
cmp a,#IR_1ab_Dat.n0
ld a,(IR_BaseTim1)
sbc a,#IR_1ab_Dat.n1
jnc RX_1_OK_Prc
; Second half of a one bit
clr #2,(IR_OnOff) ; PA1 no output infrared beam
jmp INT_End
RX_1_OK_Prc:
; Completed transmitting a one bit
ld a,#0
ld (IR_BaseTim0),a
ld (IR_BaseTim1),a
ld (IR_BIT_OK_FLAG),a
; New payload bit
inc (IR_Num0)
adr (IR_Num1)
jmp INT_End
; Have just transmitted all payload bits
RX_Data_32Bit_OK_Prc:
ld a,#0
ld (IR_Num0),a
ld (IR_Num1),a
ld a,(IR_Flag)
or a,#IR_FLAG_PAYLOAD
ld (IR_Flag),a
; Transmit the stop bit (don't delay 100us!)
set #2,(IR_OnOff) ; PA1 output 38kHz infrared beam
jmp INT_End
DATA_RX_OK_Prc:
; ====================================
; Transmit the stop bit (all payload has been sent)
ld a,(IR_Flag)
and a,#IR_FLAG_STOP
jnz Ir_Last_data_Rx_Ok_Prc
IR_Last_Dat_RX_Prc:
; Send the stop bit - have we finished sending it?
ld a,(IR_BaseTim0)
cmp a,#IR_Last_Tim.n0
ld A,(IR_BaseTim1)
sbc a,#IR_Last_Tim.n1
jnc Last_Dat_RX__OK_Prc
; Nope, still sending the stop bit
set #2,(IR_OnOff) ; PA1 output 38kHz infrared beam
jmp INT_End
Last_Dat_RX__OK_Prc:
; Idle period after complete packet has been sent
ld a,#0
ld (IR_BaseTim0),a
ld (IR_BaseTim1),a
ld a,(IR_Flag)
or a,#IR_FLAG_STOP ; If not already true
ld (IR_Flag),a
jmp INT_End
; The complete packet has been sent
Ir_Last_data_Rx_Ok_Prc:
ld a,(IR_Flag)
cmp a,#IR_FLAG_PACKET
jnz INT_End
clr #2,(IR_OnOff) ; PA1 no output infrared beam
#ifdef SPECIAL_SIMON
#else
clr #2,(RTC) ; PA1 no output infrared beam
#endif
ld A,#00
ld (IR_Enable_Flag),A
; End of interrupt for timer2
INT_End:
inc (Tim_SendPkt1) ; Increment the 12 bit timer counter
adr (Tim_SendPkt2)
adr (Tim_SendPkt3)
; End of interrupt for timer1, timer2, RTC
INT_End_NoInc:
ld a,(A_SRT) ; Restore the A register
reti
; Interrupt Routine to send special grenade explosion pulse instead of normal packet
IR_SendExplode:
; Where are we in the transmission?
inc (IR_BaseTim0) ; Increment 8 bit timer
adr (IR_BaseTim1)
ld a,(IR_BaseTim0)
cmp a,#tim_explode_pulse.n0
ld a,(IR_BaseTim1)
sbc a,#tim_explode_pulse.n1
jc INT_End
; Pulse has changed phase
ld a,#0
ld (IR_BaseTim0),a
ld (IR_BaseTim1),a
inc (ExplodePhase)
ld A,(ExplodePhase)
and A,#3
jz XIrIsOn
cmp A,#1
jz XIrIsOff
; Reduce duty cycle on pulses to give receiver a chance to see them
clr #2,(RTC) ; PA1 no output infrared beam
jmp INT_End
XIrIsOn:
set #2,(RTC) ; PA1 output infrared beam
jmp INT_End
XIrIsOff:
clr #2,(RTC) ; PA1 no output infrared beam
; Duplicate of code in Grenade_update_outi
; Since on the Tritan chip an interrupt cannot call a subroutine (safely)
inc (g_outi)
ld a,(g_outi)
and a,#ADDRESS_MASK
#ifdef BOARD_STEPHEN
#error
#endif
#ifdef BOARD_DEVELOP
#error
#endif
#ifdef BOARD_8LEDS
and a,#7
jz igou_0
cmp a,#1
jz igou_1
cmp a,#2
jz igou_2
cmp a,#3
jz igou_3
cmp a,#4
jz igou_4
cmp a,#5
jz igou_5
cmp a,#6
jz igou_6
igou_7:
clr #PIN_EN7,(PORT_EN7)
set #PIN_EN8,(PORT_EN8)
jmp INT_End
igou_6:
clr #PIN_EN6,(PORT_EN6)
set #PIN_EN7,(PORT_EN7)
jmp INT_End
igou_5:
clr #PIN_EN5,(PORT_EN5)
set #PIN_EN6,(PORT_EN6)
jmp INT_End
igou_4:
clr #PIN_EN4,(PORT_EN4)
set #PIN_EN5,(PORT_EN5)
jmp INT_End
igou_3:
clr #PIN_EN3,(PORT_EN3)
set #PIN_EN4,(PORT_EN4)
jmp INT_End
igou_2:
clr #PIN_EN2,(PORT_EN2)
set #PIN_EN3,(PORT_EN3)
jmp INT_End
igou_1:
clr #PIN_EN1,(PORT_EN1)
set #PIN_EN2,(PORT_EN2)
jmp INT_End
igou_0:
clr #PIN_EN8,(PORT_EN8)
set #PIN_EN1,(PORT_EN1)
#endif
jmp INT_End
; -----------------------------------------------------------------------------
; MAIN PROGRAM entry point
PGMSRT:
;ERR_PC_ADR:
;PGM_Delay:
ld A,#0
ld (SYS0),A ; Disable interrupts
ld (USER1),A ; This nybble could be used by user code (and is)
ld (USER2),A ; This nybble could be used by user code (but isn't)
; Initialise input/output (in powered down state)
call PODY_IO_Init
; Delay loop (uses SRAM before it is cleared)
; Should be 11 cycles * (0x100000-0xF5000) / 2 Mhz = about 0.25 seconds
ldmah #DELAY_MAH
ld A,#0
ld (CntDelay0),A
ld (CntDelay1),A
ld (CntDelay2),A
ld A,#05H ; Short delay
ld (CntDelay3),A
ld A,#0FH ; Short delay
ld (CntDelay4),A ; 20 bit timer 0xF5000
DELAY1:
ld A,#05H
ld (WDT),A ; Kick the watchdog
ld A,(CntDelay0)
clr C
adc A,#1
ld (CntDelay0),A
adr (CntDelay1)
adr (CntDelay2)
adr (CntDelay3)
adr (CntDelay4)
jnc DELAY1
; Initialise input/output again
ld A,#0
ld (SYS0),A ; Disable interrupts
call PODY_IO_Init
; Check that the button is pressed
ld a,(PORT_PWR_BTN)
and a,#BIT_PWR_BTN ; PD0 = user button
jz SkipLongDelay
; Delay loop (uses SRAM before it is cleared)
; Should be 11 cycles * (0x100000-0xE0000) / 2 Mhz = about 0.72 seconds
ldmah #DELAY_MAH
ld A,#0
ld (CntDelay0),A
ld (CntDelay1),A
ld (CntDelay2),A
ld (CntDelay3),A
#ifdef SPECIAL_SIMON
ld A,#09h ; Longer delay
#else
ld A,#0DH ; Short delay
#endif
ld (CntDelay4),A ; 20 bit timer 0xD0000
DELAY2:
ld A,#05H
ld (WDT),A ; Kick the watchdog
ld A,(CntDelay0)
clr C
adc A,#2
ld (CntDelay0),A
adr (CntDelay1)
adr (CntDelay2)
adr (CntDelay3)
adr (CntDelay4)
jnc DELAY2
SkipLongDelay:
; Lets ensure these are cleared
ld A,#0
ld (SYS0),A ; Disable interrupts
ld (USER1),A ; This nybble could be used by user code (and is)
ld (USER2),A ; This nybble could be used by user code (but isn't)
; Power up
set #PIN_PWR_EN,(PORT_PWR_EN)
; Clear Banks 0..3 of SRAM
ldmah #3
call Clear_SRAM_INIT
ldmah #2
call Clear_SRAM_INIT
ldmah #1
call Clear_SRAM_INIT
ldmah #0
call Clear_SRAM_INIT
; Setup timer2 interrupt every 100uS
ldmah #0
call Timer2_Init
; Read the unique ID from OTP
Call Read_Mcu_ID
call SetWeapon
; Initialise the grenade logic
call Grenade_init_button
call Grenade_init_logic
; Create the CRC for the data packet
call CRC_Chk_Code
; Setup a packet
call Data_Int_Code
; Set the canary value for checking SRAM has not been modified
ld A,#Ram_chk_Dat.N0
ld (SramChk0_IN),A
ld A,#Ram_chk_Dat.N1
ld (SramChk1_IN),A
; Set the group counter to be the start value, but dont trigger it yet
ld A,#0
ld (IR_Group0),A
ld (IR_Group1),A
ld (IR_Group2),A
; -----------------------------------------------------------------------------
; Where wakeup code would return to
WakeUp:
nop
nop
; We want the RTC interrupt to be every 1s instead of 125ms to avoid disruption
set #1,(RTC)
set #0,(RTC)
; Initialise output to be sure
ld a,#0
ld (IR_Enable_Flag),A
ld (SendExplode),A
ld (g_send),a
ld (g_update),a
ld (Payload0),a
ld (Payload1),a
ld (Payload2),a
ld (Payload3),a
ld (IR_CRC_Buf0),A
ld (IR_CRC_Buf1),A
call Data_Int_Code
; -----------------------------------------------------------------------------
; Main loop for background tasks
; The call stack is too short to implement routines but these tasks are effectively subroutines
; They can call subroutines themselves.
MAIN_LOOP:
; Task 1 - system sanity check
jmp SYS_Check_Prc
SYS_Check_RP:
; Task 2 - check for sending packets
jmp Tim_SendPkt_Chk_Prc
Tim_SendPkt_Chk_RP:
; Task 3 - check for sleep
jmp Chk_Halt_Tim_Prc
Chk_Halt_Tim_RP:
nop
nop
nop
nop
jmp MAIN_LOOP
; -----------------------------------------------------------------------------
; Main loop task 1/3
; System sanity check
SYS_Check_Prc:
; Setup i/o ports (relevant if we have woken up recently)
ldmah #0
; Set ports for input/output
#ifdef BOARD_STEPHEN
ld a,#0111b
ld (IOC_PA),a ; Port A direction (0=input/1=output)
ld a,#1111b
ld (IOC_PB),a ; Port B direction (0=input/1=output)
ld a,#1110b
ld (IOC_PD),a ; Port D direction (0=input/1=output)
#endif
#ifdef BOARD_DEVELOP
ld a,#0110b
ld (IOC_PA),a ; Port A direction (0=input/1=output)
ld a,#1111b
ld (IOC_PB),a ; Port B direction (0=input/1=output)
ld a,#1110b
ld (IOC_PD),a ; Port D direction (0=input/1=output)
#endif
#ifdef BOARD_8LEDS
ld a,#0111b
ld (IOC_PA),a ; Port A direction (0=input/1=output)
ld a,#1111b
ld (IOC_PB),a ; Port B direction (0=input/1=output)
ld a,#1111b
ld (IOC_PD),a ; Port D direction (0=input/1=output)
#endif
; Kick the watchdog
ld a,#05h
ld (WDT),a
set #1,(SYS0) ; Enable interrupts
nop ; paranoid
; Check the SRAM canary to see if it has been corrupted
ld a,#Ram_chk_Dat.n0
cmp a,(SramChk0_IN)
jnz PGMSRT
ld a,#Ram_chk_Dat.n1
cmp a,(SramChk1_IN)
jnz PGMSRT
; Return to the next task in the main loop
jmp SYS_Check_RP