To allow multiple users to share one carrier frequency, many handheld transceivers employ Continuous Tone Coded Squelch System (CTCSS) encoders and decoders. CTCSS systems add a tone at the low end of what the human ear can hear to a transmitted signal. On the receiving end, a CTCSS decoder allows you to choose which signals are heard in your radio's speaker after the tone is removed. Many signals may appear on the same frequency, but you'll only hear the one that is encoded with a pre-selected tone. All other signals are suppressed or squelched. With this approach, multiple short-range radios can coexist on the same carrier frequency in the same area without users having to listen to everyone else's conversations.
Motorola developed the original tone-control system, called "Private Line" or PL for short. To this day, the tone frequencies established by Private Line remain the CTCSS standards (Table 1).
CTCSS also works with longer range radios, making it possible for different groups to use the same frequencies without bothering each other. This application is seen most often in repeater networks. Additionally, CTCSS systems can act as electronic gate keepers, enabling system operators to restrict access to remote repeaters.
This article demonstrates how to implement a CTCSS carrier generator using a 256-B sine-wave lookup table (LUT). The basic routine for generating the sine wave is not application specific. It can be used to generate other waveforms and frequencies as well. The example project is based on Cypress MicroSystems' PSoC mixed-signal array, which includes an 8-b microcontroller. The CTCSS application does not use all of the PSoC's configurable mixed-signal array. In addition, it can be combined with other functions to implement a more complex design.
Before delving into the implementation, however, it's important to understand the different aspects of CTCSS. An example is its carrier frequencies. CTCSS uses 38 different frequencies between 67.0 and 250.3 Hz as the selection tones. Table 1 shows the frequency associated with each of those tones. Some radios use additional "non-standard" frequencies for CTCSS functionality. Here, the application focuses on the standard CTCSS frequencies.
Frequency generation also must be considered. In this project, the CTCSS frequencies are generated by transferring data from a 256-entry, 8-b LUT into a DAC6 User Module (a 6-b DAC) at a fixed rate. A User Module is a pre-configured and characterized set of PSoC resources and application-programming-interface (API) functions. It creates a virtual peripheral, which a designer can use to customize the PSoC's configuration. The DAC is updated at a constant rate in an Interrupt Service Routine (ISR), which is controlled by a Timer8 User Module (an 8-b timer). To adjust the frequency of the CTCSS tone, just vary the step size through the LUT.
The 256-B LUT contains data that represents one cycle of a sine wave. This data is stored in sign and magnitude format. Sign and magnitude is the native format of the DAC data register. It allows the write to the DAC to be done more efficiently than with other formats.
In this example project, the Timer8 is set to approximately 10 kHz. The frequency of the CTCSS waveform is determined by the step size of an index through the LUT. For example, with a 10-kHz update rate and a step size of 1, the resulting sine wave would have a frequency of about 39 Hz (10,000/256). If a step size of 2 were used, the resulting sine wave would have about 78 Hz—twice the frequency.
The 256-B LUT is stored in ROM. It is accessed using the MCU's INDEX instruction. That instruction uses a base address, which is hardcoded as the instruction's operand. It also utilizes an index that is the value in the Accumulator at the start of the command. When the INDEX instruction is executed, the table entry that's pointed to by the sum of the base address and the index is loaded into the Accumulator.
The LUT's 8-b index comes from the upper byte of a 16-b index (iCTCSSFreqIndex). That upper byte can be thought of as the integer portion of the index. Think of the lower byte as the index's fractional portion.
To step through the LUT, a 16-b index increment (iCTCSSFreqInc) is added to the 16-b accumulated index. That index increment also has integer and fractional portions. As a result, non-integer increments can be used to step through the LUT. This approach creates a more accurate frequency compared to what can be achieved with an integer increment.
In the previous example, where a step size of 2 resulted in an output frequency of 78 Hz from a 10-kHz update rate, the index increment would be 0x0200. To get an output frequency of 67 Hz (CTCSS tone 1), a step size of 1.72 is needed. The index increment in this case would be 0x01b5 (1 + 184/256).
Frequency selection also is a vital aspect of CTCSS. In this project, a function is provided that sets the index increment value for the desired frequency. This function, SetCTCSSFreq(), is passed a 1-B argument that is the CTCSS tone number. That tone number is manipulated (subtract 1 and multiply by 2) to convert it into an index for a 38-entry, 16-b LUT. The LUT contains index increment values.
Phase coherence may sometimes become an issue for waveform generation. In this application, when the output frequency is changed, the accumulated index variable is not cleared. This approach has a beneficial side effect. The sine wave then exhibits no discontinuity when the frequency changes. Although this isn't critical for CTCSS generation, it may be required in other waveform applications.
Figure 1 shows the placement of the three user modules that are used in this project. CTCSS_DAC, a DAC6, outputs the analog signal that is the sine wave. CTCSS_DAC is configured to use a SignAndMagnitude data format. The output to the analog column bus is enabled. Buf0 is enabled to output the analog signal to Port0\[3\].
DAC_Timer, which is a Timer8 that's configured to divide the 48M clock by 61, is used to generate the column clock for the DAC6. This results in a DAC update rate of 197 kHz. In this application, a high DAC update rate is desired. The DAC update frequency will appear in the spectrum of the output. If the DAC update rate is higher, it will be more effectively removed with a simple RC low-pass filter.
Sine_Timer, a Timer8 configured to divide the output of DAC_Timer by 78, generates an output frequency of 10.088 kHz. To enable the analog signal to be output, Port0\[3\] (pin 3 on a 28-pin package) is set to AnalogOutBuf0 with a drive mode of High Z.
The frequency accuracy requirement for CTCSS is usually better than the +/-2.5% accuracy of the Internal Main Oscillator in the PSoC microcontroller. An external crystal oscillator is therefore required. The Port1\[0\] and Port1\[1\] pins are set to High Z. A 32.678-kHz crystal is connected to the part as specified in the CY8C25xxx/CY8C26xxx Device Family datasheet.
It's possible that other tasks will need to be taken care of by the PSoC microprocessor. The amount of CPU overhead that's used by the ISR while generating the CTCSS output then becomes important. Three factors define the ISR overhead: the DAC6 analog column clock speed, the CPU clock speed, and the Sine_Timer clock rate.
The Sine_Timer ISR involves a write stall when updating the CTCSS_DAC. A write stall pauses the CPU until the start of the rising edge of the Phi1 clock in the analog column. Glitches are thereby prevented from occurring on the DAC output. (See the Analog Synchronization section of the CY8C25xxx/CY8C26xxx Device Family Data Sheet for more details on write stall.) The worst-case stall period for the DAC_Timer period used in this project is 5.1 msec. Apart from the write stall, the ISR takes an additional 93 CPU clock cycles to execute.
With a DAC update rate of 10.088 kHz, the worst-case ISR overhead is 15%. Table 2 shows the ISR overhead for different CPU clock rates. It assumes an analog column clock of 197 kHz and a DAC update rate of 10.088 kHz. If the designer chooses to use different timings for this application, the resulting ISR overhead will differ from what is shown in the table. In addition, this design only uses three of the 24 available configurable analog and digital blocks in the PSoC. These extra blocks can be used to implement other functions. Or, a smaller part in the PSoC family could be used.
When designing a waveform generator, some tradeoffs must be made. ISR overhead versus DAC update rate is one tradeoff that must be weighed. More steps in one wavelength will result in a lower harmonic distortion of the waveform. Fewer steps in one wavelength will reduce the ISR overhead, leaving more of the CPU available for other tasks.
Waveform distortion versus output-filter complexity is another part of the same tradeoff. If the DAC update rate is much higher than the frequency of the output waveform, the major contributor to distortion will be at the DAC update frequency. In this case, a simple RC low-pass filter on the output may acceptably reduce the waveform distortion. Often, such a filter is called a reconstruction filter.
If the DAC update rate is too close to the output waveform's frequency, the harmonics of the output frequency will be the major contributor to distortion. Here, something more than a simple RC low-pass filter will be needed to clean up the waveform. A low-pass-filter User Module (LPF2) may be needed.
In some designs, the source for the DAC's analog column clock must be shared with another function. This issue would occur when resources are limited. If such sharing is taking place, a slower clock may need to be used. This clock can impact the ISR overhead by increasing the maximum stall time. The higher stall time, in turn, will raise the waveform distortion by moving the DAC clock frequency closer to the output frequency. Ideally, a frequency close to the DAC6 maximum update rate (see the DAC6 User Module datasheet) would be used.
This project picked a 6-b DAC over an 8-b DAC. Although the 8-b DAC would result in more precise voltage steps, it would use more analog PSoC blocks. An 8-b DAC would also require two register writes to update the DAC, which would lead to a slower update rate and fewer steps per waveform. Compared to the DAC resolution, it was found that the number of steps per waveform had a much greater impact on the output waveform's voltage precision.
To test performance, the timers were configured as described. Using an external crystal, data was collected to determine the frequency accuracy and waveform distortion of the output. The output frequencies were measured for all 48 CTCSS tones using a Fluke 87 digital multimeter (Table 3). The resulting range of the frequency error is between +0.10% and −0.13%.
The waveform distortions for selected CTCSS tones (1, 7, 13, 19, 26, 32, and 38) were calculated based on measurements taken with a Hewlett-Packard 3585A spectrum analyzer. The measurements were taken directly from the output of the PSoC microcontroller with no reconstruction filter (FIG. 2). As would be expected, the maximum distortion of 3.8% occurred at the highest output frequency. Additional testing was run using a slower DAC update rate (Sine_Timer) of 6.5 kHz. The maximum distortion increased to 6.3%.
With a Tektronix TDS 3034 digital storage oscilloscope, the waveforms were captured for Tone 1 (FIG. 3). They also were captured for Tone 38 (FIG. 4). Notice that the individual DAC increments are more apparent at the higher frequency. They're more visible because there are fewer steps per cycle at the higher frequencies. As a result, there is greater waveform distortion.
With a history of almost 30 years, CTCSS systems have proven their worth. In today's crowded radio-frequency bands, the ability to have your own 'private line' is increasingly valuable. The carrier generation system described in this article can be easily built and integrated into CTCSS encoder/decoder systems. C and ASM code for the tone generator are available upon request from Cypress MicroSystems.