forked from eeeschwartz/voltage
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Wundernoise041306.asm
executable file
·1523 lines (1268 loc) · 43.5 KB
/
Wundernoise041306.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
; --WunderNoise--
; TMB
; Original: 10/31/05
; Rebuilt to be more better for Spring 2006 Tour-
; 4/2/06
; Still EEpromless but tour ready with five programs that drop bombs.
4/13/06 -TB
; The following is the code for the 12f683 which drives the "Who Got A Big
Ol' Butt" kit made for the Voltage
;tour, fall 2005. Fundamentally it is a ghetto dsp device which makes a lot
of "guesses" about an incoming
;analog signal using the a/d and comparator and outputs different gibberish,
waveforms and whatnot.
;It reminds me of a little accountant, hiring and firing. Cutting checks on
the spot.
;The idea is that with the one button you can engage / disengage the circuit
from the world (turn the output into an input)
;But if you hold said magic button the circuit will change to a different
program. This program gets stored in EEPROM so that
;each particular circuit remembers what it's supposed to be after power off.
Maybe the PWM to the LED is different for each one
;in some artsy way.
;The concepts for some of the routines:
;-------See notes in MoreWunderNoise.txt
;-------------------------------------------------------------------------------------------------------
;-------------------------------------------------------------------------------------------------------
;Compiler Setup
;-------------------------------------------------------------------------------------------------------
;-------------------------------------------------------------------------------------------------------
WunderNoise_setup
processor 12f683
include <p12f683.inc>
__config _CP_OFF & _WDT_OFF & _PWRTE_ON & _BOD_OFF & _MCLRE_OFF &
_INTRC_OSC_NOCLKOUT
org 0
cblock h'20'
randomval4
randomval3
randomval2
randomval1
debounce_counter
switch_held_counter
switch_register
program_selector
output_state
ADresult
LEDchase
currentDelay
delayCounter
loopCounter
comparatorReg
IIRL
IIRH
timer_start_valueL
timer_start_valueH
times_through_loop
current_timer_readingL
current_timer_readingH
tempL
tempH
temp1L
temp1H
step_timer_counter
debugCounter
endc
;-------------------------------------------------------------------------------------------------------
;-------------------------------------------------------------------------------------------------------
;Device Pinout:
;-------------------------------------------------------------------------------------------------------
;-------------------------------------------------------------------------------------------------------
;Device =
;12F683
; -----------------
; | * |
; VDD VSS
; | |
; Output Comparator In
; | |
; Analog In Comparator Reference
; | |
; Switch LED Drive
; | |
; -----------------
;-------------------------------------------------------------------------------------------------------
;-------------------------------------------------------------------------------------------------------
;Defines:
;-------------------------------------------------------------------------------------------------------
;-------------------------------------------------------------------------------------------------------
#define SWITCH_INPUT GPIO,3
#define OUTPUT_PIN GPIO,5
#define DEBOUNCE_TIME d'255'
#define HOLD_TIME d'255'
#define ALREADY_PRESSED switch_register,0
#define VALID_SWITCH switch_register,1
#define TIMER_FLIPPED_FLAG switch_register,2
#define RESET_PROGRAM_FLAG switch_register,3
#define CHANGE_PROGRAM_FLAG switch_register,4
#define OUTPUT_STATE_FLAG output_state,0
#define NOISE_BIT randomval1,0
#define NOISE_THRESHOLD d'175'
#define DELAY_CONSTANT d'8' ; This is the loop multiplier to
determine noise freq. Greater = lower f.
#define STEP_TIME_CONSTANT d'30' ; This value determines the speed of
the stepped tone generator. Lower = faster.
;-------------------------------------------------------------------------------------------------------
;-------------------------------------------------------------------------------------------------------
;Initialization on Powerup.
;-------------------------------------------------------------------------------------------------------
;-------------------------------------------------------------------------------------------------------
;Get your options, input interrupts, tris, A/D setup and the like going.
;Clear your I/Os and get your banks straight.
power_on_routine
bcf STATUS, RP0 ;bank 0
clrf INTCON ;Turns interrupts off.
movlw b'00000010'
movwf CMCON0 ;Comparator is on, taking input from the pins, and
non-inverted. No external O/P.
movlw b'0001101'
movwf ADCON0 ;A/D on, left justified, referenced to VDD, channel 3 (pin
3).
clrf CMCON1 ;Comparator runs asyncronously.
clrf GPIO ;clears outputs.
bsf STATUS, RP0 ;bank1
movlw b'00111011'
movwf TRISIO ;GP0,1,3,4,5 = inputs, GP2 = outputs.
;Remember to turn 5 back into an output when it's time to flip it!
movlw b'01110111' ;Sets the system clock to the internal oscillator and
;ratchets it up to 8MHz.
movwf OSCCON ;Osccon is in bank 1.
movlw b'01011000'
movwf ANSEL ;AN3 to analog input, conversion clock = Fosc / 16.
clrf VRCON ;Voltage reference powered down.
movlw b'10000000'
movwf OPTION_REG ;sets pullups off.
bcf STATUS, RP0 ;bank 0
clrf GPIO ;clear O/Ps again because I'm paranoid.
call init_PWM ;Get the LED poppin.
movf TMR0,W ;Seed the random number generator.
movwf randomval4
movwf randomval3
movwf randomval2
movwf randomval1
;Initialize your variables
movlw DEBOUNCE_TIME
movwf debounce_counter
clrf switch_held_counter
clrf switch_register
clrf program_selector
; movlw b'11111111' ;Why did I do this?
; movwf output_state
bcf ALREADY_PRESSED ;Switch isn't already pressed.
bcf VALID_SWITCH ;Switch isn't valid.
bcf RESET_PROGRAM_FLAG
bcf CHANGE_PROGRAM_FLAG
clrf output_state
movlw d'128'
movwf ADresult
movwf ADRESH
clrf LEDchase
movlw d'127' ;initialize to low frequency.
movwf currentDelay
movlw DELAY_CONSTANT
movwf delayCounter
clrf comparatorReg
; call readprom ;Get the hot shit from EEPROM.
goto program_selector_tree
;-------------------------------------------------------------------------------------------------------
;-------------------------------------------------------------------------------------------------------
;Program Selector Loop
;-------------------------------------------------------------------------------------------------------
;-------------------------------------------------------------------------------------------------------
next_program
incf program_selector
bcf CHANGE_PROGRAM_FLAG
bcf RESET_PROGRAM_FLAG
bsf OUTPUT_STATE_FLAG ;Always start with the shit killin'.
;This is also set in the "switch held" routine immediately
previously.
program_selector_tree
;The main loop just shuttles us off to whichever program we dug out of
eeprom in Setup,
;or puts us in a new program after the button is held.
movlw b'00000000' ;Was it program 0?
clrz
xorwf program_selector,W
skpnz
goto program_0_setup
movlw b'00000001' ;Was it program 1?
clrz
xorwf program_selector,W
skpnz
goto program_1_setup
movlw b'00000010' ;Was it program 2?
clrz
xorwf program_selector,W
skpnz
goto program_2_setup
movlw b'00000011' ;Was it program 3?
clrz
xorwf program_selector,W
skpnz
goto program_3_setup
movlw b'00000100' ;Was it stepped tone?
clrz
xorwf program_selector,W
skpnz
goto stepped_tone_program
;And so on and so forth....
clrf program_selector
goto program_0_setup ;In case some weird number gets in here, or you
increment over the number of programs,
;just go to program 0.
;-------------------------------------------------------------------------------------------------------
;-------------------------------------------------------------------------------------------------------
;Synth Programs:
;-------------------------------------------------------------------------------------------------------
;-------------------------------------------------------------------------------------------------------
program_0_setup
bsf STATUS,RP0 ;Bank 1
bsf TRISIO,5 ;Turn the OP into a high impedance input.
movlw b'01110111' ;Sets the system clock to the internal oscillator and
;ratchets it up to 8MHz.
movwf OSCCON ;Osccon is in bank 1.
movlw b'01011000'
movwf ANSEL ;AN3 to analog input, conversion clock = Fosc / 16.
bcf STATUS,RP0 ;Bank 0
movlw b'00001100' ;CCP set to PWM.
movwf CCP1CON
bcf RESET_PROGRAM_FLAG ;If we've comeback from an idle time this is the
flag that we reset.
;(45 commands long when the button is not pressed, so the loop time is based
on the A/D
;cycle, and therefore around 56 commands or so.)
;The first of the shit-kickers:
;This program reads the A/D and if the level in is outside of a certain
range (ie, the signal's amplitude is
;greater than a threshold) it turns on the output pin and sends it the PSRB.
It must read lower than the threshold for
;a millisecond (or so, about 36 complete A/D cycles) before it turns off the
PSRB -- since there's no averaging on the signal this
;is just a sort of hysteresis or attempt to make sure that a chance read
near the zero point doesn't turn off the signal.
program_0
btfss SWITCH_INPUT
goto un_pressed
call debounce
call on_off_switch_handler
goto switch_hooey_finished
un_pressed
movlw DEBOUNCE_TIME
movwf debounce_counter
bcf ALREADY_PRESSED
clrf switch_held_counter
switch_hooey_finished
call random32 ;Keep it random while you're waiting.
btfss OUTPUT_STATE_FLAG ;If the thing is supposed to be inactive, go to
another loop which just turns off the OP, diddles the LED and waits on
switches.
call bide_your_time
btfsc RESET_PROGRAM_FLAG ;If we return from a bide_your_time call to this
point, this flag tells us to re-init everything.
goto program_0_setup
btfsc CHANGE_PROGRAM_FLAG ;If the Change flag got tripped, break out of
this program to the next_program section.
goto next_program
;Wait for the conversion now, since eveything is done.
btfsc ADCON0,GO
goto $-1
;In 7 cycles, start the A/D again.
movf ADRESH,W
movwf ADresult
; If the AD reading is less than 128, complement it -- a software
absolute value above the reference voltage.
movlw d'128'
clrc
subwf ADresult,W
skpc
comf ADresult
bsf ADCON0,GO
;And they're off! The A/D should be done roughly 48 commands from now, and
ready to
;go again in 8 after that. So it'd be nice to catch the end of the
conversion so I know
;where to count 8 from -- it'll be fastest that way. (see above)
;(the switch checking and RNG at the top of the loop take 12-20 cycles.
Try and be done in another 28 from here)
;Next is the compare section. If the result is higher than a threshold,
bring tha noise.
movlw NOISE_THRESHOLD
bsf STATUS,C ; Set the C bit so that subtracting through zero causes it
to clear.
subwf ADresult,W ; ADresult minus W.
skpc ; If the ADresult is bigger, there's no borrow, nothing changes.
C remains set.
goto input_less_than_threshold ; Therefore, if the C bit is still set,
make some noise. If it is now clear, the reading was lower than the
threshold -- don't do shit.
input_greater_than_threshold
;Turn on the OP port and LED. If you have the cycles, debounce, but
whatever.
bsf STATUS,RP0 ;Bank 1
bcf TRISIO,5 ;Turn the OP into an OP.
bcf STATUS,RP0 ;Bank 0
btfss NOISE_BIT ;Check the bit on the RNG and put it on the output pin.
bcf OUTPUT_PIN
btfsc NOISE_BIT
bsf OUTPUT_PIN
movlw b'11111111' ;Turn up the LED all the way.
movwf CCPR1L
goto program_0 ;You're done, start the loop again.
input_less_than_threshold
bsf STATUS,RP0 ;Bank 1
bsf TRISIO,5 ;Turn the OP into a high impedance input.
bcf STATUS,RP0 ;Bank 0
rrf ADresult,W ;LED shit:
clrf CCPR1L ; A test to see if the input always stays less than the
threshold.
; movwf CCPR1L ; If the noise is off, make the led correspond to input
amplitude, but half max brightness.
goto program_0 ;You're done, start the loop again.
;------------------------------
program_1_setup
bsf STATUS,RP0 ;Bank 1
movlw b'01110111' ;Sets the system clock to the internal oscillator and
;ratchets it up to 8MHz.
movwf OSCCON ;Osccon is in bank 1.
movlw b'01011000'
movwf ANSEL ;AN3 to analog input, conversion clock = Fosc / 16.
bcf STATUS,RP0 ;Bank 0
movlw b'00001100' ;CCP set to PWM.
movwf CCP1CON
;2.) Amplitude-dependent filtered white noise
;Lil' Blood looks at the A/D value and adjusts the frequency of the PSRB,
which is always
;on. With small or no signal in, There are a lot of DC pops. As the
amplitude pins out,
;the shit gets hissy.
;Check the button, like before.
;When the program is engaged, keep the OP an OP.
;Take the AD reading, figure absolute value via complement-
;if A/D - 128 flips the Carry, complement.
;So then a reading of: 0 = 255 and 255 = 255 and 127=128 and 128=128.
;Complement this again.
;Now: 255 = 0 and 128=127.
;This means that we'll get a number back from 0-127 or so where 0 equals the
greatest input amplitude, and
;127 equals the smallest input amplitude.
;Now use this to delay moving the Noise bit to the O/P.
;Basically, this program shoots out random bits.
;It changes the time until the next random bit based on the input magnitude.
;The greater the input magnitude (amplitude), the faster the bits go out.
;So:
;Run the A/D full speed.
;Turn the a/d into a delay time. Something like ((0-127)*32) = cycles
through a 56 command program per noise bit check.
;Compare the Delay calculated from the A/D reading to the current delay
counter.
;If the calculated delay is shorter, reload the delay counter with the new
delay.
;If the calculated delay is longer, (ie, the amplitude is smaller than it
was) keep the old delay counter and
;re-calculate at the next A/D reading.
;First thing, turn on the OP so you don't waste these cycles every loop --
this stays on as long as the
;program is active.
bsf STATUS,RP0 ;Bank 1
bcf TRISIO,5 ;Turn the OP into an OP.
bcf STATUS,RP0 ;Bank 0
bcf RESET_PROGRAM_FLAG
program_1_loop
decf currentDelay ; A carryover from the OP state / freq evaluation at the
end of the loop.
btfss SWITCH_INPUT
goto un_pressed_a
call debounce
call on_off_switch_handler
goto switch_hooey_finished_a
un_pressed_a
movlw DEBOUNCE_TIME
movwf debounce_counter
bcf ALREADY_PRESSED
clrf switch_held_counter
switch_hooey_finished_a
btfss OUTPUT_STATE_FLAG ;If the thing is supposed to be inactive, go to
another loop which just turns off the OP, diddles the LED and waits on
switches.
call bide_your_time
btfsc RESET_PROGRAM_FLAG ;If we return from a bide_your_time call to this
point, this flag tells us to re-init everything.
goto program_1_setup
btfsc CHANGE_PROGRAM_FLAG ;If the Change flag got tripped, break out of
this program to the next_program section.
goto next_program
btfsc ADCON0,GO ;Are we done yet?
goto $-1
;Get the data. In 7 cycles, you're clear to start the A/D again.
; If the AD reading is less than 128, complement it -- a software absolute
value above the reference voltage.
movf ADRESH,W
movwf ADresult
movlw d'128'
bsf STATUS,C
subwf ADresult,W
skpc
comf ADresult
comf ADresult
; clrc
; subwf ADresult,W
; skpc
; comf ADresult
;ADresult should = 128-255 now.
; comf ADresult
;Adresult should = 0-127 now.
;ADresult will = 127 ADresultwith no signal in.
;ADresult is basically a seven bit number now, inversely proportional
to the signal amplitude.
bsf ADCON0,GO ;Restart that ish. Get a new reading.
;Now compare the AD result to the currentDelay. If the ADresult is smaller
(meaning that amplitude at the input is is
;greater than it was last read, or greater than the equivalent current
delay frequency) then load the ADresult into the
;current delay value. If the ADresult is greater, keep the currentDelay.
movf currentDelay,W
bsf STATUS,C
subwf ADresult,W ; This command is ADresult (f) minus currentDelay (W).
skpnc ;(NB:skpc Locks the OP high.) ; If the C bit is still set, W was
less than f, so the ADresult was greater. So if C is set don't change the
delay register.
currentDelayLessThanAD
; If we're here, the ADresult (ie, the inverse of the signal magnitude) is
greater than the value of the decay as it stands
; Don't update the delay, just keep it moving.
goto calculationDone
currentDelayGreaterThanAD
;This means the frequency of the output should increase, because the delay
period is greater (longer) than what the
;magnitude in would dictate. Move ADresult into currentDelay and reset the
delayCounter as well.
movf ADresult,W
movwf currentDelay
; movlw DELAY_CONSTANT ;Don't reset the delay counter here, because if the
input stays at the same value, (like 0)
; movwf delayCounter ;OR if the AD value steadily increases, this keeps
getting reloaded and never getting to the OP.
calculationDone
;Okay, now decrement the delay counter. When it gets to zero, decrement the
currentDelay. When that gets to zero,
;update the bitstream and output. Reset currentDelay to the default value
of 127 or whatever it was.
;Keep it random:
call random32
clrz
decf delayCounter
skpz ;When the delay counter hits zero, reset it and worry about
currentDelay. Otherwise, don't mess -- return to the beginning of the loop.
goto program_1_loop
movlw DELAY_CONSTANT
movwf delayCounter
clrw
clrz
iorwf currentDelay ; Inclusive or 0 with currentDelay. A result of zero
means that currentDelay was zero. Move to the OP section.
skpz ; Otherwise, return to the loop. IOR used because currentDelay
can be loaded with 0 if the AD returns a 255,
; in which case using DEC then SKPZ would lead to a LONG delay with
the input pinned.
goto program_1_loop ; Decrement currentDelay 1st thing in the loop now, to
save another case evaluation here.
;If we're here, the counters have all gotten to zero. Now worry about
putting the random bit on the OP.
btfss NOISE_BIT ;Check the bit on the RNG and put it on the output pin.
goto bitLow
bitHigh
bsf OUTPUT_PIN
movlw b'11111111' ;Turn up the LED all the way.
movwf CCPR1L
goto program_1_loop ;You're done, start the loop again.
bitLow
bcf OUTPUT_PIN
clrf CCPR1L ;Turn down the LED all the way.
goto program_1_loop ;You're done, start the loop again.
;---------------------------------------
;---------------------------------------
program_2_setup
;This program is easy. It looks at the comparator, and if the O/P of the
comparator is high, it sets the O/P bit
;high. If the comparator is low, the O/P goes low. Easy.
;***** -- In here now is the comp XORED with TMR0. It's not bad.
;***** -- See if you can't make the button (or something) somehow select the
TMR0 freq.
;First thing, turn on the OP so you don't waste these cycles every loop --
this stays on as long as the
;program is active.
bsf STATUS,RP0 ;Bank 1
bcf TRISIO,5 ;Turn the OP into an OP.
bcf STATUS,RP0 ;Bank 0
bsf STATUS,RP0 ;Bank 1
movlw b'11000111' ;Pullups off, timer0 driven by internal clock, prescaler
to timer0, prescaler = 1:256.
movwf OPTION_REG
bcf STATUS,RP0 ;Bank 0
movlw b'00110101' ;Free run Timer 1 with max prescale (1/8) -- this gives
us a frequency = (2Mhz) / 8 = 250kHz. Hmmm.
movwf T1CON ;Both of these registers are in Bank 0.
bsf CMCON1,CMSYNC ;Sync the comparator with the falling edge of Timer1
Clock.
bcf RESET_PROGRAM_FLAG
;I think that's all there is to it. But I don't think this'll matter much,
audio-wise, as the T1 Clock is so fast. You could ratchet down the CPU
freq...
program_2_loop
btfss SWITCH_INPUT
goto un_pressed_b
call debounce
call on_off_switch_handler
goto switch_hooey_finished_b
un_pressed_b
movlw DEBOUNCE_TIME
movwf debounce_counter
bcf ALREADY_PRESSED
clrf switch_held_counter
switch_hooey_finished_b
btfss OUTPUT_STATE_FLAG ;If the thing is supposed to be inactive, go to
another loop which just turns off the OP, diddles the LED and waits on
switches.
call bide_your_time
btfsc RESET_PROGRAM_FLAG ;If we return from a bide_your_time call to this
point, this flag tells us to re-init everything.
goto program_2_setup
btfsc CHANGE_PROGRAM_FLAG ;If the Change flag got tripped, break out of
this program to the next_program section.
goto next_program
clrf comparatorReg ;Set a bit based on the comparator OP.
btfsc CMCON0,COUT
bsf comparatorReg,4 ;Change this bit to change the "frequency" of the
"oscillator" you're logically XORing with the comparator.
movf comparatorReg,W
xorwf TMR0,W ;Effectively just XORing the comparator output with (bit 4*)
of TMR0 -- ***MAKE SURE NOT TO WRITE TO TMR0 HERE***
;The (bit 4*) of W is now what we want on the O/P.
;* If we've anded the comparator w/ a different bit in TMR0, make sure
to check that bit for the O/P.
;NB -- try using a different logical operator than XOR. Or, try just
doing a logical operation on the result of
;the A/D instead of TMR0 -- don't hang up the operation waiting on the
A/D, just free run that nasty nas.
;You could use the noise source instead of TMR0 or the A/D, too.
movwf comparatorReg ;You didn't need that register, did you?
btfss comparatorReg,4 ;Test the bit and rock it.
goto XORLow
bsf OUTPUT_PIN
movlw b'11111111'
movwf CCPR1L
goto program_2_loop
XORLow
bcf OUTPUT_PIN
clrf CCPR1L
goto program_2_loop
;The loop below totally works, and sounds like a RAT pedal or something.
Fun for shredding, but not winning any art awards.
; movlw d'10' ;Run this part of the loop this many times before
bothering to check the switches again. Make sure your debouncing works okay
with this program.
; movwf loopCounter
;
;square_wave_loop
;
; btfss CMCON0,COUT ;Test the comparator and rock it.
; bcf OUTPUT_PIN
; btfsc CMCON0,COUT
; bsf OUTPUT_PIN
; clrz
; decf loopCounter
; skpz
; goto square_wave_loop
; goto program_2_loop
;--------------------------------
;---------------------------------------
;---------------------------------------
program_3_setup
;Program 3 examines square wave generation in a different way, by taking an
A/D reading and using the most significant bit to
;set the square wave. Mess with conversion speed to get this to sound
different (aliasing vs max conversion rate violation)
;Right now the clock is scaled down to 4MHz and the A/D conversion speed is
way slowed down.
bsf STATUS,RP0 ;Bank 1
bcf TRISIO,5 ;Turn the OP into an OP.
movlw b'01100111' ;Slows down the internal oscillator like screwed and
chopped.
movwf OSCCON ;Osccon is in bank 1. (4Mhz sounds pretty good)
;The switches in this program are all kind of fucked up -- run the
oscillator back up for the
;waiting period.
movlw b'01101000' ; 0110 is = 1/64, 0000 (MSBs)= 1/2.
movwf ANSEL ;AN3 to analog input, conversion clock optimal = Fosc / 16.
(now f/64)
bcf STATUS,RP0 ;Bank 0
bcf RESET_PROGRAM_FLAG
program_3_loop
btfss SWITCH_INPUT
goto un_pressed_c
call debounce
call on_off_switch_handler
goto switch_hooey_finished_c
un_pressed_c
movlw DEBOUNCE_TIME
movwf debounce_counter
bcf ALREADY_PRESSED
clrf switch_held_counter
switch_hooey_finished_c
btfss OUTPUT_STATE_FLAG ;If the thing is supposed to be inactive, go to
another loop which just turns off the OP, diddles the LED and waits on
switches.
call bide_your_time
btfsc RESET_PROGRAM_FLAG ;If we return from a bide_your_time call to this
point, this flag tells us to re-init everything.
goto program_3_setup
btfsc CHANGE_PROGRAM_FLAG ;If the Change flag got tripped, break out of
this program to the next_program section.
goto next_program
;Wait for the conversion now, since eveything is done.
btfsc ADCON0,GO
goto $-1
;In 7 cycles, start the A/D again.
movf ADRESH,W
movwf ADresult
btfss ADresult,7 ;Test the bit and rock it.
goto goLow
bsf OUTPUT_PIN
movlw b'11111111'
movwf CCPR1L
bsf ADCON0,GO
goto program_3_loop
goLow
bcf OUTPUT_PIN
clrf CCPR1L
bsf ADCON0,GO
goto program_3_loop
;------------------------------
stepped_tone_program
;See notes. This one's complicated.
;Initialize TMR1 and TMR0. Set tmr0 and its counters to get the time
between the steps (1/8th second, say)
;Initialize CCP to Compare -- You won't be able to PWM the LED in this
program.
;Start the first routine and run it once:
;
;Note_one:
;Start TMR0 and any counters associated with it.
;Wait for the comparator to flip.
;Start TMR1.
;Wait for the comparator to flip again.
;When it does, get the value of TMR1, and reset the timer.
;Load this value into an IIR averaging filter like so: newAverage =
(average + currentValue) / 2
;Keep waiting for comparator flips, and averaging the time between them
UNTIL
;TMR0 counts off the step length. Now:
;Take the average from the IIR and put it into the CCP module. Keep
IIR_average.
;
;Now run the following loop forever:
;
;N_notes:
;Clear TMR0. Clear TMR1.
;clear a variable "timer_start_value" to zero.
;clear a variable "times_through_loop" to zero.
;clear a "tmr_flipped" flag.
;Wait for TMR0 to flip again. While you are:
;
;Run TMR1. When TMR1 matches CCP, flip the OP and reset TMR1.
; Check the TMR_flipped flag. If it is clear, set the "tmr_flipped_flag".
; If it is set, increment times_through_loop.
;
;Tracking the incoming frequency--
;We know TMR1 is resetting is dependent on the frequency being output, and
independent of the input frequency.
;When the comparator flips, take the value of TMR1. Call it
current_tmr1_reading or something. Reset TMR1 and keep it moving.
;Now operate on the results.
;Check the tmrflipped flag:
; If it is clear, tmr1 hasn't flipped since the last comparator change.
; Get the new period by simply taking (currentReading -
timer_start_value).
; If it is set, then tmr1 has reset to zero while the new frequency was
being counted.
; The new period is then (times_through_loop * (CCP_value)) + (CCP_value
- timer_start_value) + (current_timer_reading)
;From this we get the new period between comparator changes.
;Now:
;Clear the times_through_loop variable and tmr_flipped flag.
;set timer_start_value to current_tmr1_reading.
;Run the IIR averaging filter on the new period.
;Wait for the next comparator flip or TMR1 flip and handle it as above.
;
;When TMR0 flips, take the Average from the IIR and put it in the CCP.
Leave IIR loaded. Restart the loop.
;Registers
;IIRL, IIRH
;timer_start_valueL
;timer_start_valueH
;times_through_loop (I think you only need 8 bits here)
;TIMER_FLIPPED_FLAG (just one bit in some other register)
;current_timer_readingL
;current_timer_readingH
;tempL
;tempH
;step_timer_counter
init_stepped_tone
;Setup TMR0, TMR1, and the CCP.
bsf STATUS,RP0 ;Bank 1
movlw b'01110111' ;Sets the system clock to the internal oscillator and
;ratchets it up to 8MHz.
movwf OSCCON ;Osccon is in bank 1.
movlw b'11000111' ;Pullups off, timer0 driven by internal clock, prescaler
to timer0, prescaler = 1:256.
movwf OPTION_REG ;This means that TMR0 rolls over 30.5 times a second,
with internal clock = 8Mhz.
bcf TRISIO,5 ;Turn the OP into an OP.
bcf STATUS,RP0 ;Bank 0
movlw b'00110100' ;Set Timer 1 with max prescale (1/8) -- this gives us a
frequency = (2Mhz) / 8 = 250kHz.
movwf T1CON ;All the TMR1 stuff is in Bank 0.
;NOTE: TMR1 isn't on yet until we tell it to be.
clrf CMCON1 ;The comparator won't start unless it's unsynced with TMR1.
;The CCP stuff is in bank 0 also.
movlw b'00001010' ;Set the CCP to compare mode, and have it generate a
software interrupt when the match happens.
movwf CCP1CON ;The TMR1 registers should be unaffected.
;You know, you could use this to do A/D timing in the background
elsewhere...
bsf GPIO,2 ;turn on the LED.
bcf RESET_PROGRAM_FLAG
clrf IIRL
clrf IIRH
clrf timer_start_valueL
clrf timer_start_valueH
clrf times_through_loop
bcf TIMER_FLIPPED_FLAG
clrf current_timer_readingL
clrf current_timer_readingH
clrf tempL
clrf tempH
clrf temp1L
clrf temp1H
movlw STEP_TIME_CONSTANT
movwf step_timer_counter
bcf PIR1,CMIF
;Now that the timers and interrupts are reset, wait for the first comparator
flip. When it happens, start your
;routines and start TMR1. Then do the real loop.
;This'll make sure the first reading into the IIR isn't wildly off.
Hopefully.
btfss PIR1,CMIF ;The Peripheral Interrupt Register and comparator
interrupt flag are in Bank0.
goto $-1
; If here we know that the comparator has flipped. Start TMR1.
bcf PIR1,CMIF ;Clear the comparator interrupt flag.
bsf T1CON,TMR1ON ;Start the timer.
clrf TMR0
bcf INTCON,T0IF
first_note
btfss INTCON,T0IF
goto first_note_TMR0_handling_done
bcf INTCON,T0IF
clrz
decfsz step_timer_counter
goto first_note_TMR0_handling_done
goto first_note_done
; If we've gotten here then TMR0 has rolled STEP_TIME_CONSTANT times. We're
done with the first note.
; Is there no decfsnz command?
first_note_TMR0_handling_done
;Not time to go to the next note. Now what's up with the comparator?
btfss PIR1,CMIF ;The Peripheral Interrupt Register and comparator
interrupt flag are in Bank0.
goto first_note
; If here we know the comparator has flipped again. Stop TMR1, get the
value, and restart the timer.
bcf T1CON,TMR1ON ;Stop the timer.
bcf PIR1,CMIF ;Clear the Comparator interrupt flag.
movf TMR1L,W
movwf current_timer_readingL
movf TMR1H,W
movwf current_timer_readingH ;Move the timer value into the fiddle-ready
registers.
clrf TMR1L
clrf TMR1H
bsf T1CON,TMR1ON ;Start that shit again.
;Now that we've got the info, make it into the average.
call doIIR
goto first_note
;Once we've gotten the IIR updated, go back to the start of the loop.
first_note_done
movf IIRL,W ;Load the compare registers.
movwf CCPR1L
movf IIRH,W
movwf CCPR1H
;Clear timers, clear their interrupts. Clear CCP interrupt. Reload
the step counter with the constant.
; ? Start the timers again?
bcf PIR1,CCP1IF
bcf T1CON,TMR1ON
clrf TMR1L
clrf TMR1H
bcf INTCON,T0IF
movlw STEP_TIME_CONSTANT
movwf step_timer_counter
bcf PIR1,CMIF
clrf TMR0
bsf T1CON,TMR1ON
;--------
n_note
;All the tough shit happens here.