-
Notifications
You must be signed in to change notification settings - Fork 10
/
Copy pathfreq_pi.c
958 lines (744 loc) · 26.6 KB
/
freq_pi.c
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
/*
This file is part of freq_pi Copyright (c) Jan Panteltje 2013-always
email: panteltje@yahoo.com
This code contains parts of code from Pifm.c
Start GPL license:
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
If you take this code and port it to that Redmond crap you STILL must release SOURCE code,
this program has secret beyond bit level encrypted bits that make it traceable and you will be bitten by the FSF if you violate these terms.
*/
/* set TABs to 4 for correct formatting of this file, or if you do not know what that is replace all TABs with 4 spaces, else you cannot READ this */
/*
Raspberry Pi 2 support added Jenny List http://www.languagespy.com 2015-07-04 and 2015-10-16
*/
/*
Program name:
freq_pi
Function:
programmable frequency generator on GPIO_4 pin 7
To compile:
gcc -Wall -O4 -o freq_pi freq_pi.c -std=gnu99 -lm
To install:
cp freq_pi /usr/local/bin/
To run:
freq_pi
*/
#define PROGRAM_VERSION "0.72"
/*
Changes:
0.1:
First release
0.2:
dunno
0.3:
Added sweep function
0.4:
Added loop and trigger output,
0.5:
Added -s command line option delay between scans.
0.6:
Put menu option in alphabetic order, fixed some things in menu.
Added -q for exit with frequency off.
0.7:
Added ppm frequency correction -y command line flag.
0.71
Minor modification to add Raspberry Pi 2 base address support
0.72
Brought in code to automatically select Pi or Pi 2
From minimal_clk.c courtesy of http://abyz.co.uk/rpi/pigpio/index.html which is Public Domain
*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <dirent.h>
#include <math.h>
#include <fcntl.h>
#include <assert.h>
#include <malloc.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <signal.h>
#include <unistd.h>
#include <getopt.h>
#include <stdint.h>
#include <time.h>
#include <getopt.h>
#include <ctype.h>
#include <errno.h>
#include <fcntl.h>
#define PAGE_SIZE (4*1024)
#define BLOCK_SIZE (4*1024)
int mem_fd;
char *gpio_mem, *gpio_map;
char *spi0_mem, *spi0_map;
int wait_for_gpio8_flag;
double ppm_correction;
double pllo_frequency;
//#define PLL0_FREQUENCY 250000000.0
#define PLL0_FREQUENCY 500000000.0
//Variables used by auto Pi model detection
static volatile uint32_t piModel = 1;
static volatile uint32_t piPeriphBase = 0x20000000;
static volatile uint32_t piBusAddr = 0x40000000;
static volatile uint32_t piGpioBase;
// I/O access
volatile unsigned *gpio;
volatile unsigned *allof7e;
// GPIO setup macros. Always use INP_GPIO(x) before using OUT_GPIO(x) or SET_GPIO_ALT(x,y)
#define INP_GPIO(g) *(gpio+((g)/10)) &= ~(7<<(((g)%10)*3))
#define OUT_GPIO(g) *(gpio+((g)/10)) |= (1<<(((g)%10)*3))
#define SET_GPIO_ALT(g,a) *(gpio+(((g)/10))) |= (((a)<=3?(a)+4:(a)==4?3:2)<<(((g)%10)*3))
#define GPIO_SET *(gpio+7) // sets bits which are 1 ignores bits which are 0
#define GPIO_CLR *(gpio+10) // clears bits which are 1 ignores bits which are 0
#define GPIO_GET *(gpio+13) // sets bits which are 1 ignores bits which are 0
#define ACCESS(base) *(volatile int*)((int)allof7e+base-0x7e000000)
#define SETBIT(base, bit) ACCESS(base) |= 1<<bit
#define CLRBIT(base, bit) ACCESS(base) &= ~(1<<bit)
#define CM_GP0CTL (0x7e101070)
#define GPFSEL0 (0x7E200000)
#define CM_GP0DIV (0x7e101074)
#define CLKBASE (0x7E101000)
#define DMABASE (0x7E007000)
#define PWMBASE (0x7e20C000) /* PWM controller */
#define GPIO_IN0 *(gpio+13) // Reads GPIO input bits 0-31
// GPIO8 pin 24 START_IN in
// GPIO17 pin 11 TRIGGER_OUT output
#define START_IN 8
#define TRIGGER_OUT 17
//Code to automatically sense the Pi version
//Thanks to http://abyz.co.uk/rpi/pigpio/examples.html#Misc_code
unsigned gpioHardwareRevision(void)
{
static unsigned rev = 0;
FILE * filp;
char buf[512];
char term;
int chars=4; /* number of chars in revision string */
if (rev) return rev;
piModel = 0;
filp = fopen ("/proc/cpuinfo", "r");
if (filp != NULL)
{
while (fgets(buf, sizeof(buf), filp) != NULL)
{
if (piModel == 0)
{
if (!strncasecmp("model name", buf, 10))
{
if (strstr (buf, "ARMv6") != NULL)
{
piModel = 1;
chars = 4;
piPeriphBase = 0x20000000;
piBusAddr = 0x40000000;
}
else if (strstr (buf, "ARMv7") != NULL)
{
piModel = 2;
chars = 6;
piPeriphBase = 0x3F000000;
piBusAddr = 0xC0000000;
}
}
}
piGpioBase = (piPeriphBase + 0x200000);
if (!strncasecmp("revision", buf, 8))
{
if (sscanf(buf+strlen(buf)-(chars+1),
"%x%c", &rev, &term) == 2)
{
if (term != '\n') rev = 0;
}
}
}
fclose(filp);
}
return rev;
}
struct GPCTL
{
char SRC : 4;
char ENAB : 1;
char KILL : 1;
char : 1;
char BUSY : 1;
char FLIP : 1;
char MASH : 2;
unsigned int : 13;
char PASSWD : 8;
};
int verbose;
// Set up a memory regions to access GPIO
void setup_io()
{
/* open /dev/mem */
if ((mem_fd = open("/dev/mem", O_RDWR|O_SYNC) ) < 0)
{
printf("can't open /dev/mem \n");
exit(-1);
}
/* mmap GPIO */
gpio_map = mmap(
NULL, //Any adddress in our space will do
BLOCK_SIZE, //Map length
PROT_READ|PROT_WRITE,// Enable reading & writting to mapped memory
MAP_SHARED, //Shared with other processes
mem_fd, //File to map
piGpioBase //Offset to GPIO peripheral
);
close(mem_fd); // No need to keep mem_fd open after mmap
if(gpio_map == MAP_FAILED)
{
printf("mmap error %d\n", (int)gpio_map);//errno also set!
exit(-1);
}
// Always use volatile pointer!
gpio = (volatile unsigned *)gpio_map;
} /* end function setup_io */
void set_gpio_directions()
{
if(wait_for_gpio8_flag)
{
// START_IN to input
INP_GPIO(START_IN);
}
// TRIGGER_OUT to output
INP_GPIO(TRIGGER_OUT);
OUT_GPIO(TRIGGER_OUT);
} /* end function set_gpio_directions */
void getRealMemPage(void** vAddr, void** pAddr)
{
void* a = valloc(4096);
((int*)a)[0] = 1; // use page to force allocation.
mlock(a, 4096); // lock into ram.
*vAddr = a; // yay - we know the virtual address
unsigned long long frameinfo;
int fp = open("/proc/self/pagemap", 'r');
lseek(fp, ((int)a)/4096*8, SEEK_SET);
read(fp, &frameinfo, sizeof(frameinfo));
*pAddr = (void*)((int)(frameinfo*4096));
}
void freeRealMemPage(void* vAddr)
{
munlock(vAddr, 4096); // unlock ram.
free(vAddr);
}
void start_rf_output(int source)
{
/* open /dev/mem */
if( (mem_fd = open("/dev/mem", O_RDWR|O_SYNC) ) < 0)
{
fprintf(stderr, "freq_pi: can't open /dev/mem, aborting.\n");
exit (1);
}
//Pi 1 line in original code
// allof7e = (unsigned *)mmap( NULL, 0x01000000, /*len */ PROT_READ|PROT_WRITE, MAP_SHARED, mem_fd, 0x20000000 /* base */ );
//Replacement line for Pi 2 version. piPeriphBase inserted instead of hard coded address.
//Should work with either Pi given the right base address definition at the top of the file.
allof7e = (unsigned *)mmap( NULL, 0x01000000, /*len */ PROT_READ|PROT_WRITE, MAP_SHARED, mem_fd, piPeriphBase /* base */ );
if( (int)allof7e == -1) exit(1);
SETBIT(GPFSEL0 , 14);
CLRBIT(GPFSEL0 , 13);
CLRBIT(GPFSEL0 , 12);
/*
Clock source
0 = GND
1 = oscillator
2 = testdebug0
3 = testdebug1
4 = PLLA per
5 = PLLC per
6 = PLLD per
7 = HDMI auxiliary
8-15 = GND
*/
struct GPCTL setupword = {source, 1, 0, 0, 0, 1,0x5a};
ACCESS(CM_GP0CTL) = *((int*)&setupword);
}
void modulate(int m)
{
ACCESS(CM_GP0DIV) = (0x5a << 24) + 0x4d72 + m;
}
struct CB
{
volatile unsigned int TI;
volatile unsigned int SOURCE_AD;
volatile unsigned int DEST_AD;
volatile unsigned int TXFR_LEN;
volatile unsigned int STRIDE;
volatile unsigned int NEXTCONBK;
volatile unsigned int RES1;
volatile unsigned int RES2;
};
struct DMAregs
{
volatile unsigned int CS;
volatile unsigned int CONBLK_AD;
volatile unsigned int TI;
volatile unsigned int SOURCE_AD;
volatile unsigned int DEST_AD;
volatile unsigned int TXFR_LEN;
volatile unsigned int STRIDE;
volatile unsigned int NEXTCONBK;
volatile unsigned int DEBUG;
};
struct PageInfo
{
void* p; // physical address
void* v; // virtual address
};
struct PageInfo constPage;
struct PageInfo instrPage;
struct PageInfo instrs[1024];
int set_frequency(uint32_t frequency)
{
if(verbose)
{
fprintf(stderr, "set_frequency(): arg frequency=%d\n", frequency);
}
uint32_t ua;
uint16_t divi; // integer part divider [23:12] 12 bits wide, max 4095
uint16_t divf; // fractional part divider [11:0] 12 bits wide, max 4095
/* set frequeny */
/* calculate divider */
double da;
da = pllo_frequency;
da += pllo_frequency * (ppm_correction / 1000000.0);
da /= (double) frequency;
divi = (int) da;
divf = 4096.0 * (da - (double)divi);
if(verbose)
{
fprintf(stderr, "ppm_correction=%f frequency=%d da=%f divi=%d divf=%d\n", ppm_correction, frequency, da, divi, divf);
}
/*
To get fractional part 4095 try:
./freq_pi -f 777605
frequency=777605 da=642.999981 divi=642 divf=4095
This gives (1 second measurements:
777,095 Hz
777,123 Hz
777,211 Hz
777,155 Hz
776,995 Hz
777,191 Hz
777,135 Hz
777,131 Hz
777,211 Hz
777,123 Hz
777,179 Hz
777,215 Hz
776,891 Hz
776,983 Hz
776,995 Hz
776,995 Hz
776,915 Hz
777,071 Hz
777,075 Hz
777,071 Hz
777,103 Hz
777,143 Hz
So we wobble around the requested 777605 Hz a LOT.
Not a good frequency to select if you like low phase noise.....
Use a very long time constant PLL as slave?
*/
if( (divi > 4095.0) || (divi < 1.0) )
{
fprintf(stderr, "freq_pi: requested frequency out of range, aborting.\n");
exit(1);
}
if(divf > 4095.0)
{
fprintf(stderr, "freq_pi: requested frequency out of range, aborting.\n");
exit(1);
}
ua = (0x5a << 24) + (divi << 12) + divf;
ACCESS(CM_GP0DIV) = ua;
if(verbose)
{
fprintf(stderr, "set_frequency: frequency set to %d\n", frequency);
}
return 1;
} /* end function set_frequency */
void print_usage()
{
fprintf(stderr,\
"\nPanteltje freq_pi-%s\n\
Usage:\nfreq_pic [-b begin_frequency] [-d step_delay] [-e end_frequency] [-f frequency] [-h] [-i frequency_increment] [-l] [-r] [-s scan_delay] [-q] [-v] [-w] [-y ppm_correction]\n\
-b int begin frequency in sweep mode.\n\
-d int delay in micro seconds between frequency steps in sweep mode, default 1.\n\
-e int end frequency in sweep mode.\n\
-f int frequency to output on GPIO_4 pin 7, on my revision 2 board from 130 kHz to 250 MHz,\n\
phase noise is caused by divf (fractional part of divider) not being zero, use -v to show divf.\n\
-h help (this help).\n\
-i int frequency increment between steps in sweep mode, default 1 MHz.\n\
-l loop mode, trigger output signals start sweep.\n\
-r wait for low level on GPIO8 pin 24 in case -f -w.\n\
-q switch output off and exit.\n\
-s int delay between scans in us, default 1.\n\
-v verbose.\n\
-w wait for GPIO8 pin 24 to go high to start a scan.\n\
-y float frequency correction in parts per million (ppm), positive or negative, for calibration, default 0.\n\
\n",\
PROGRAM_VERSION);
fprintf(stderr,\
"Note:\n\
GPIO17 pin 11 is trigger output, positive, high during sweep, for example for scope.\n\n");
fprintf(stderr,\
"GPIO8 pin 24 is only initialized when the -w command line flag is used, else it can be used for other things.\n\n");
fprintf(stderr,\
"Example for 1 MHz, with +39.4 parts per million correction :\n\
freq_pi -f 100000000 -y 39.4\n\
\n\
Example for a sweep from 1 MHz to 100 MHz step 1 MHz with 100 mS delay between steps:\n\
freq_pi -b 1000000 -e 100000000 -i 1000000 -d 100000\n\
\n\
Use -v to see where you are, but this makes it slower than the speed specified with -d.\n\
\n\
Example for a repeated scan every second from 1 MHz to 100 MHz with 1 MHz increments and 10 mS delay between increments:\n\
freq_pi freq_pi -b 1000000 -e 100000000 -i 1000000 -d 100000 -s 1000000 -l\n\
\n\
Control C exits.\n\
freq_pi -q switches off output, then exits.\n\
\n\
");
} /* end function print_usage */
int main(int argc, char **argv)
{
int a;
uint32_t frequency = 0; // -Wall
uint32_t frequency_increment;
int step_delay;
uint32_t begin_frequency;
uint32_t end_frequency;
int reverse_start_polarity_flag;
int loop_mode_flag;
int scan_delay;
int exit_with_output_off_flag;
/* defaults */
verbose = 0;
step_delay = 1;
frequency_increment = 1000000;
begin_frequency = 0;
end_frequency = 0;
wait_for_gpio8_flag = 0;
reverse_start_polarity_flag = 0;
loop_mode_flag = 0;
scan_delay = 1;
exit_with_output_off_flag = 0;
pllo_frequency = PLL0_FREQUENCY;
ppm_correction = 0.0;
/* end defaults */
/* proces any command line arguments */
while(1)
{
a = getopt(argc, argv, "b:d:e:f:hi:lqs:vwry:");
if(a == -1) break;
switch(a)
{
case 'b': // begin_frequency
begin_frequency = atoi(optarg);
break;
case 'd': // delay between frequency increments
step_delay = atoi(optarg);
break;
case 'e': // end_frequency
end_frequency = atoi(optarg);
break;
case 'f': // frequency
a = atoi(optarg);
frequency = a;
break;
case 'h': // help
print_usage();
exit(1);
break;
break;
case 'i':// fequency increment in sweep mode
frequency_increment = atoi(optarg);
break;
case 'l': // loop mode
loop_mode_flag = 1;
break;
case 'v': // verbose
verbose = 1 - verbose;
break;
case 'w': // wai tfor GPIO8 pin 24 to go high
wait_for_gpio8_flag = 1;
break;
case 'r': // wait for low level in case -w
reverse_start_polarity_flag = 1;
break;
case 'q': // switch of output
exit_with_output_off_flag = 1;
break;
case 's': // scan delay
scan_delay = atoi(optarg);
break;
case 'y': // ppm correction
ppm_correction = atof(optarg);
break;
case -1:
break;
case '?':
if (isprint(optopt) )
{
fprintf(stderr, "send_iq: unknown option `-%c'.\n", optopt);
}
else
{
fprintf(stderr, "freq_pi: unknown option character `\\x%x'.\n", optopt);
}
print_usage();
exit(1);
break;
default:
print_usage();
exit(1);
break;
}/* end switch a */
}/* end while getopt() */
gpioHardwareRevision(); /* sets piModel, needed for peripherals address */
setup_io();
set_gpio_directions(); // start pin only
/*
From ducument BCM2835-ARM-Peripherals.pdf
page 105
6.3 General Purpose GPIO Clocks
The General Purpose clocks can be output to GPIO pins.
They run from the peripherals clock sources and use clock generators with noise-shaping MASH dividers.
These allow the GPIO clocks to be used to drive audio devices.
The fractional divider operates by periodically dropping source clock pulses, therefore the output frequency will periodically switch between:
source_frequency / DIVI, and source_frequency / (DIVI + 1)
Jitter is therefore reduced by increasing the source clock frequency.
In applications where jitter is a concern, the fastest available clock source should be used.
The General Purpose clocks have MASH noise-shaping dividers which push this fractional divider jitter out of the audio band.
MASH noise-shaping is incorporated to push the fractional divider jitter out of the audio band if required.
The MASH can be programmed for 1, 2 or 3-stage filtering. MASH filter, the frequency is spread around the requested frequency and the user must ensure that the module is not exposed to frequencies higher than 25MHz.
Also, the MASH filter imposes a low limit on the range of DIVI.
MASH min DIVI min output freq average output freq max output freq
0 (int divide) 1 source / ( DIVI ) source / ( DIVI ) source / ( DIVI )
1 2 source / ( DIVI ) source / ( DIVI + DIVF / 1024 ) source / ( DIVI + 1 )
2 3 source / ( DIVI - 1 ) source / ( DIVI + DIVF / 1024 ) source / ( DIVI + 2 )
3 5 source / ( DIVI - 3 ) source / ( DIVI + DIVF / 1024 ) source / ( DIVI + 4 )
Table 6-32 Effect of MASH Filter on Frequency
The following example illustrates the spreading of output clock frequency resulting from the
use of the MASH filter. Note that the spread is greater for lower divisors.
PLL target min ave max
freq freq freq freq freq
(MHz) (MHz) MASH divisor DIVI DIVF (MHz) (MHz) (MHz) error
650 18.32 0 35.480 35 492 18.57 18.57 18.57 ok
650 18.32 1 35.480 35 492 18.06 18.32 18.57 ok
650 18.32 2 35.480 35 492 17.57 18.32 19.12 ok
650 18.32 3 35.480 35 492 16.67 18.32 20.31 ok
400 18.32 0 21.834 21 854 19.05 19.05 19.05 ok
400 18.32 1 21.834 21 854 18.18 18.32 19.05 ok
400 18.32 2 21.834 21 854 17.39 18.32 20.00 ok
400 18.32 3 21.834 21 854 16.00 18.32 22.22 ok
200 18.32 0 10.917 10 939 20.00 20.00 20.00 ok
200 18.32 1 10.917 10 939 18.18 18.32 20.00 ok
200 18.32 2 10.917 10 939 16.67 18.32 22.22 ok
200 18.32 3 10.917 10 939 14.29 18.32 28.57 error
Table 6-33 Example of Frequency Spread when using MASH Filtering
Operating Frequency
The maximum operating frequency of the General Purpose clocks is ~125MHz at 1.2V but this will be reduced if the GPIO pins are heavily loaded or have a capacitive load.
Register Definitions
Clock Manager General Purpose Clocks Control (CM_GP0CTL, GP1CTL &
GP2CTL)
Address 0x 7e10 1070 CM_GP0CTL
0x 7e10 1078 CM_GP1CTL
0x 7e10 1080 CM_GP2CTL
Bit Field Read/
Description Reset
Number Name Write
31-24 PASSWD Clock Manager password "5a" W 0
23-11 - Unused R 0
10-9 MASH MASH control R/W 0
0 = integer division
1 = 1-stage MASH (equivalent to non-MASH dividers)
2 = 2-stage MASH
3 = 3-stage MASH
To avoid lock-ups and glitches do not change this
control while BUSY=1 and do not change this control
at the same time as asserting ENAB.
8 FLIP Invert the clock generator output R/W 0
This is intended for use in test/debug only. Switching
this control will generate an edge on the clock
generator output. To avoid output glitches do not
switch this control while BUSY=1.
7 BUSY Clock generator is running R 0
Indicates the clock generator is running. To avoid
glitches and lock-ups, clock sources and setups must
not be changed while this flag is set.
6 - Unused R 0
5 KILL Kill the clock generator R/W 0
0 = no action
1 = stop and reset the clock generator
This is intended for test/debug only. Using this control
may cause a glitch on the clock generator output.
4 ENAB Enable the clock generator R/W 0
This requests the clock to start or stop without
glitches. The output clock will not stop immediately
because the cycle must be allowed to complete to
avoid glitches. The BUSY flag will go low when the
final cycle is completed.
3-0 SRC Clock source R/W 0
0 = GND
1 = oscillator
2 = testdebug0
3 = testdebug1
4 = PLLA per
5 = PLLC per
6 = PLLD per
7 = HDMI auxiliary
8-15 = GND
To avoid lock-ups and glitches do not change this
control while BUSY=1 and do not change this control
at the same time as asserting ENAB.
06 February 2012 Broadcom Europe Ltd. 406 Science Park Milton Road Cambridge CB4 0WW Page 107
2012 Broadcom Corporation. All rights reserved
Clock Manager General Purpose Clock Divisors (CM_GP0DIV, CM_GP1DIV &
CM_GP2DIV)
Address 0x 7e10 1074 CM_GP0DIV
0x 7e10 107c CM_GP1DIV
0x 7e10 1084 CM_GP2DIV
Bit Field Read/
Description Reset
Number Name Write
31-24 PASSWD Clock Manager password "5a" W 0
23-12 DIVI Integer part of divisor R/W 0
This value has a minimum limit determined by the
MASH setting. See text for details. To avoid lock-ups
and glitches do not change this control while BUSY=1.
11-0 DIVF Fractional part of divisor R/W 0
To avoid lock-ups and glitches do not change this
control while BUSY=1.
Table 6-35 General Purpose Clock Divisors
*/
//struct GPCTL setupword = {6 /* clock source */, 1 /* enable */, 0 /* not kill */, 0 , 0, 1 /* 1 stage MASH (equivalent to no MASH */, 0x5a /* password */ };
//ACCESS(CM_GP0CTL) = *((int*)&setupword);
//ACCESS(CM_GP0DIV) = (0x5a << 24) + 0x4d72 + m
/*
clock sources are 650 MHz, 400 MHz, and 200 MHz
So the lowest frequency we can make is 200,000,000 / 4095.4095 = 48,835.165323516 Hz
But I get 61,043 Hz
4095.4095 * 61043 = 249,996,082.108499999 Hz....
But for MASH 1,
MASH min DIVI min output freq average output freq max output freq
0 (int divide) 1 source / ( DIVI ) source / ( DIVI ) source / ( DIVI )
* 1 2 source / ( DIVI ) source / ( DIVI + DIVF / 1024 ) source / ( DIVI + 1 )
2 3 source / ( DIVI - 1 ) source / ( DIVI + DIVF / 1024 ) source / ( DIVI + 2 )
3 5 source / ( DIVI - 3 ) source / ( DIVI + DIVF / 1024 ) source / ( DIVI + 4 )
200,000,000 / (4095 = 48840.048840048
200,000,000 / (4095 + (4095/1024) ) = 48792.400011912
So
61043 * (4095 + .3999023437) = 249995496.238766479 Hz, looks liike we have a 250 MHz clock.
Lowest frequency then is 61,043 Hz,
highest frequency then is 250,000,000 / 1 = 250,000,000 Hz
mm looks like a 500 MHz clock to me...
*/
int clock_source;
/*
Clock source
0 = GND
1 = oscillator
2 = testdebug0
3 = testdebug1
4 = PLLA per
5 = PLLC per
6 = PLLD per
7 = HDMI auxiliary
8-15 = GND
*/
/* init hardware */
if(exit_with_output_off_flag)
{
/* RF off */
clock_source = 0; // ground
start_rf_output(clock_source);
fprintf(stderr, "freq_pi: output is off.\n");
exit(0);
}
clock_source = 6; /* this GPIO_4 pin 7 allows only the PLLD clock as source, the other clock GPIO lines are not on a pin in revision 2 board, so we have to work with PLLD, and that seems to be 500 MHz */
start_rf_output(clock_source);
if(frequency) // if normal mode
{
if(begin_frequency)
{
print_usage();
fprintf(stderr, "freq_pi: cannot use both normal and scan mode at the same time, aborting.\n");
exit(1);
}
set_frequency(frequency);
exit(0);
}
// test for scan mode
if(! begin_frequency)
{
print_usage();
fprintf(stderr, "freq_pi: no begin frequency specified, aborting.\n");
exit(1);
}
if(! end_frequency)
{
print_usage();
fprintf(stderr, "freq_pi: no end frequency specified, aborting.\n");
exit(1);
}
if(end_frequency <= begin_frequency)
{
fprintf(stderr, "freq_pi: end_frequency must be > begin_frequency, aborting.\n");
exit(1);
}
*(gpio + 10) = (1<<TRIGGER_OUT); // reset trigger out
while(1)
{
if(wait_for_gpio8_flag)
{
/* wait for GIO trigger to go high */
while(1)
{
a = GPIO_IN0 & (1<<START_IN);
if(verbose) fprintf(stderr, "wait pin=%d\n", a);
if(! reverse_start_polarity_flag)
{
if(a) break;
}
else
{
if(! a ) break;
}
usleep(1000); // 1 us reduce procesor cycles
}
} /* end if wait_for_gpio8_flag */
/* trigger output high */
*(gpio + 7) = (1<<TRIGGER_OUT); // set trigger out
frequency = begin_frequency;
while(1)
{
set_frequency(frequency);
usleep(step_delay);
frequency += frequency_increment;
if(frequency >= end_frequency) break;
}
/* trigger output low */
*(gpio + 10) = (1<<TRIGGER_OUT); // reset trigger out
if(! loop_mode_flag) break;
usleep(scan_delay);
} /* end while loop mode */
/* RF off */
clock_source = 0; // ground
start_rf_output(clock_source);
exit(0);
} /* end function main */