-
- // at the end of each line.
- fprintf (PC_HOST, "\n\r");
-
- // Advance to the next block of memory.
- address += DIAG_BYTES_PER_LINE;
- } while (dataFoundFlag && !userStopFlag);
-
- // Feedback to let the user know why the transfer stopped.
- if (userStopFlag)
- fprintf (PC_HOST, "User aborted download!\n\r");
-}
-
-void diag1PPS()
-{
- uint16_t timeStamp, lastTimeStamp;
-
- lastTimeStamp = 0x0000;
-
- gpsPowerOn();
-
- for (;;)
- {
- timeStamp = CCP_2;
-
- if (timeStamp != lastTimeStamp)
- {
- delay_ms (10);
-
- timeStamp = CCP_2;
-
- fprintf (PC_HOST, "%lu %lu\n\r", timeStamp, (timeStamp - lastTimeStamp));
-
- lastTimeStamp = timeStamp;
- }
- }
-}
-
-/**
- * Process diagnostic commands through the debug RS-232 port.
- */
-void diagPort()
-{
- bool_t diagDoneFlag, ledFlag, paFlag, showSettingsFlag;
- uint8_t command, amplitude;
- uint32_t freqHz;
-
- // If the input is low, we aren't connected to the RS-232 device so continue to boot.
- if (!input(PIN_B6))
- return;
-
- fprintf (PC_HOST, "Engineering Mode\n\r");
- fprintf (PC_HOST, "Application Built %s %s\n\r", __DATE__, __TIME__);
-
- // Current state of the status LED.
- ledFlag = false;
- output_bit (IO_LED, ledFlag);
-
- // This flag indicates we are ready to leave the diagnostics mode.
- diagDoneFlag = false;
-
- // Current state of the PA.
- paFlag = false;
-
- // Flag that indicate we should show the current carrier frequency.
- showSettingsFlag = false;
-
- // Set the initial carrier frequency and amplitude.
- freqHz = 445950000;
- amplitude = 0;
-
- // Wait for the exit command.
- while (!diagDoneFlag)
- {
- // Wait for the user command.
- command = fgetc(PC_HOST);
-
- // Decode and process the key stroke.
- switch (command)
- {
- case 'e':
- diagEraseFlash();
- logInit();
- break;
-
- case 'l':
- case 'L':
- ledFlag = (ledFlag ? false : true);
- output_bit (IO_LED, ledFlag);
- break;
-
- case 'h':
- case 'H':
- case '?':
- diagMenu();
- break;
-
- case 'r':
- diagReadFlash();
- break;
-
- case 't':
- tncHighRate (true);
- fprintf (PC_HOST, "Set high rate TNC.\n\r");
- break;
-
- case 'f':
- freqHz -= 1000;
- ddsSetFreq (freqHz);
-
- // Display the new frequency.
- showSettingsFlag = true;
- break;
-
- case 'F':
- freqHz += 1000;
- ddsSetFreq (freqHz);
-
- // Display the new frequency.
- showSettingsFlag = true;
- break;
-
- case 'c':
- freqHz -= 25000;
- ddsSetFreq (freqHz);
-
- // Display the new frequency.
- showSettingsFlag = true;
- break;
-
- case 'C':
- freqHz += 25000;
- ddsSetFreq (freqHz);
-
- // Display the new frequency.
- showSettingsFlag = true;
- break;
-
- case 'p':
- case 'P':
- ddsSetFreq (freqHz);
-
- paFlag = (paFlag ? false : true);
- output_bit (IO_PTT, paFlag);
- output_bit (IO_OSK, paFlag);
-
- if (paFlag)
- {
- ddsSetMode (DDS_MODE_AFSK);
- ddsSetAmplitude (amplitude);
- } else
- ddsSetMode (DDS_MODE_POWERDOWN);
-
- break;
-
- case 'a':
- if (amplitude != 200)
- {
- amplitude += 5;
- ddsSetAmplitude (amplitude);
-
- // Display the new amplitude.
- showSettingsFlag = true;
- }
- break;
-
- case 'A':
- if (amplitude != 0)
- {
- amplitude -= 5;
- ddsSetAmplitude (amplitude);
-
- // Display the new amplitude.
- showSettingsFlag = true;
- }
- break;
-
- case 'g':
- diag1PPS();
- break;
-
- case 'x':
- diagDoneFlag = true;
- break;
-
- default:
- fprintf (PC_HOST, "Invalid command. (H)elp for menu.\n\r");
- break;
- } // END switch
-
- // Display the results of any user requests or commands.
- if (showSettingsFlag)
- {
- showSettingsFlag = false;
-
- fprintf (PC_HOST, "%03ld.%03ld MHz ", freqHz / 1000000, (freqHz / 1000) % 1000);
- fprintf (PC_HOST, "%d.%01ddBc\n\r", amplitude / 10, amplitude % 10);
-
- } // END if
-
- } // END while
-
- // Let the user know we are done with this mode.
- fprintf (PC_HOST, "Exit diagnostic mode.\n\r");
-
- return;
-}
-
-/** @} */
-
-
-/**
- * @defgroup DDS AD9954 DDS (Direct Digital Synthesizer)
- *
- * Functions to control the Analog Devices AD9954 DDS.
- *
- * @{
- */
-
-/// AD9954 CFR1 - Control functions including RAM, profiles, OSK, sync, sweep, SPI, and power control settings.
-#define DDS_AD9954_CFR1 0x00
-
-/// AD9954 CFR2 - Control functions including sync, PLL multiplier, VCO range, and charge pump current.
-#define DDS_AD9954_CFR2 0x01
-
-/// AD9954 ASF - Auto ramp rate speed control and output scale factor (0x0000 to 0x3fff).
-#define DDS_AD9954_ASF 0x02
-
-/// AD9954 ARR - Amplitude ramp rate for OSK function.
-#define DDS_AD9954_ARR 0x03
-
-/// AD9954 FTW0 - Frequency tuning word 0.
-#define DDS_AD9954_FTW0 0x04
-
-/// AD9954 FTW1 - Frequency tuning word 1
-#define DDS_AD9954_FTW1 0x06
-
-/// AD9954 NLSCW - Negative Linear Sweep Control Word used for spectral shaping in FSK mode
-#define DDS_AD9954_NLSCW 0x07
-
-/// AD9954 PLSCW - Positive Linear Sweep Control Word used for spectral shaping in FSK mode
-#define DDS_AD9954_PLSCW 0x08
-
-/// AD9954 RSCW0 - RAM Segment Control Word 0
-#define DDS_AD9954_RWCW0 0x07
-
-/// AD9954 RSCW0 - RAM Segment Control Word 1
-#define DDS_AD9954_RWCW1 0x08
-
-/// AD9954 RAM segment
-#define DDS_RAM 0x0b
-
-/// Current operational mode.
-DDS_MODE ddsMode;
-
-/// Number of digits in DDS frequency to FTW conversion.
-#define DDS_FREQ_TO_FTW_DIGITS 9
-
-/// Array of multiplication factors used to convert frequency to the FTW.
-const uint32_t DDS_MULT[DDS_FREQ_TO_FTW_DIGITS] = { 11, 7, 7, 3, 4, 8, 4, 9, 1 };
-
-/// Array of divisors used to convert frequency to the FTW.
-const uint32_t DDS_DIVISOR[DDS_FREQ_TO_FTW_DIGITS - 1] = { 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000 };
-
-/// Lookup table to convert dB amplitude scale in 0.5 steps to a linear DDS scale factor.
-const uint16_t DDS_AMP_TO_SCALE[] =
-{
- 16383, 15467, 14601, 13785, 13013, 12286, 11598, 10949, 10337, 9759, 9213, 8697,
- 8211, 7752, 7318, 6909, 6522, 6157, 5813, 5488, 5181, 4891, 4617, 4359, 4115, 3885, 3668, 3463,
- 3269, 3086, 2913, 2750, 2597, 2451, 2314, 2185, 2062, 1947, 1838, 1735, 1638
-};
-
-
-/// Frequency Word List - 4.0KHz FM frequency deviation at 81.15MHz (445.950MHz)
-const uint32_t freqTable[256] =
-{
- 955418300, 955419456, 955420611, 955421765, 955422916, 955424065, 955425210, 955426351,
- 955427488, 955428618, 955429743, 955430861, 955431971, 955433073, 955434166, 955435249,
- 955436322, 955437385, 955438435, 955439474, 955440500, 955441513, 955442511, 955443495,
- 955444464, 955445417, 955446354, 955447274, 955448176, 955449061, 955449926, 955450773,
- 955451601, 955452408, 955453194, 955453960, 955454704, 955455426, 955456126, 955456803,
- 955457457, 955458088, 955458694, 955459276, 955459833, 955460366, 955460873, 955461354,
- 955461809, 955462238, 955462641, 955463017, 955463366, 955463688, 955463983, 955464250,
- 955464489, 955464701, 955464884, 955465040, 955465167, 955465266, 955465337, 955465380,
- 955465394, 955465380, 955465337, 955465266, 955465167, 955465040, 955464884, 955464701,
- 955464489, 955464250, 955463983, 955463688, 955463366, 955463017, 955462641, 955462238,
- 955461809, 955461354, 955460873, 955460366, 955459833, 955459276, 955458694, 955458088,
- 955457457, 955456803, 955456126, 955455426, 955454704, 955453960, 955453194, 955452408,
- 955451601, 955450773, 955449926, 955449061, 955448176, 955447274, 955446354, 955445417,
- 955444464, 955443495, 955442511, 955441513, 955440500, 955439474, 955438435, 955437385,
- 955436322, 955435249, 955434166, 955433073, 955431971, 955430861, 955429743, 955428618,
- 955427488, 955426351, 955425210, 955424065, 955422916, 955421765, 955420611, 955419456,
- 955418300, 955417144, 955415989, 955414836, 955413684, 955412535, 955411390, 955410249,
- 955409113, 955407982, 955406857, 955405740, 955404629, 955403528, 955402435, 955401351,
- 955400278, 955399216, 955398165, 955397126, 955396100, 955395088, 955394089, 955393105,
- 955392136, 955391183, 955390246, 955389326, 955388424, 955387540, 955386674, 955385827,
- 955385000, 955384192, 955383406, 955382640, 955381896, 955381174, 955380474, 955379797,
- 955379143, 955378513, 955377906, 955377324, 955376767, 955376235, 955375728, 955375246,
- 955374791, 955374362, 955373959, 955373583, 955373234, 955372912, 955372618, 955372350,
- 955372111, 955371900, 955371716, 955371560, 955371433, 955371334, 955371263, 955371220,
- 955371206, 955371220, 955371263, 955371334, 955371433, 955371560, 955371716, 955371900,
- 955372111, 955372350, 955372618, 955372912, 955373234, 955373583, 955373959, 955374362,
- 955374791, 955375246, 955375728, 955376235, 955376767, 955377324, 955377906, 955378513,
- 955379143, 955379797, 955380474, 955381174, 955381896, 955382640, 955383406, 955384192,
- 955385000, 955385827, 955386674, 955387540, 955388424, 955389326, 955390246, 955391183,
- 955392136, 955393105, 955394089, 955395088, 955396100, 955397126, 955398165, 955399216,
- 955400278, 955401351, 955402435, 955403528, 955404629, 955405740, 955406857, 955407982,
- 955409113, 955410249, 955411390, 955412535, 955413684, 955414836, 955415989, 955417144
-};
-
-/**
- * Initialize the DDS regsiters and RAM.
- */
-void ddsInit()
-{
- // Setup the SPI port for the DDS interface.
- setup_spi( SPI_MASTER | SPI_L_TO_H | SPI_CLK_DIV_4 | SPI_XMIT_L_TO_H );
-
- // Set the initial DDS mode. The ddsSetMode function uses this value to make the desired DDS selections.
- ddsMode = DDS_MODE_NOT_INITIALIZED;
-
- // Set the DDS operational mode.
- ddsSetMode (DDS_MODE_POWERDOWN);
-
- // Set the output to full scale.
- ddsSetOutputScale (0x3fff);
-
- // CFR2 (Control Function Register No. 2)
- output_low (IO_CS);
- spi_write (DDS_AD9954_CFR2);
-
- spi_write (0x00); // Unused register bits
- spi_write (0x00);
- spi_write (0x9c); // 19x reference clock multipler, high VCO range, nominal charge pump current
- output_high (IO_CS);
-
- // ARR (Amplitude Ramp Rate) to 15mS for OSK
- output_low (IO_CS);
- spi_write (DDS_AD9954_ARR);
-
- spi_write (83);
- output_high (IO_CS);
-
- // Strobe the part so we apply the updates.
- output_high (IO_UPDATE);
- output_low (IO_UPDATE);
-}
-
-/**
- * Set DDS amplitude value in the range 0 to 16383 where 16383 is full scale. This value is a
- * linear multiplier and needs to be scale for RF output power in log scale.
- *
- * @param scale in the range 0 to 16383
- */
-void ddsSetOutputScale (uint16_t scale)
-{
- // Set ASF (Amplitude Scale Factor)
- output_low (IO_CS);
- spi_write (DDS_AD9954_ASF);
-
- spi_write ((scale >> 8) & 0xff);
- spi_write (scale & 0xff);
-
- output_high (IO_CS);
-
- // Strobe the DDS to set the amplitude.
- output_high (IO_UPDATE);
- output_low (IO_UPDATE);
-}
-
-/**
- * Set the DDS amplitude in units of dBc of full scale where 1 is 0.1 dB. For example, a value of 30 is 3dBc
- * or a value of 85 is 8.5dBc.
- *
- * @param amplitude in 0.1 dBc of full scale
- */
-void ddsSetAmplitude (uint8_t amplitude)
-{
- // Range limit based on the lookup table size.
- if (amplitude > 200)
- return;
-
- // Set the linear DDS ASF (Amplitude Scale Factor) based on the dB lookup table.
- ddsSetOutputScale (DDS_AMP_TO_SCALE[amplitude / 5]);
-
- // Toggle the DDS output low and then high to force it to ramp to the new output level setting.
- output_low (IO_OSK);
- delay_ms(25);
-
- output_high (IO_OSK);
- delay_ms(25);
-}
-
-/**
- * Set DDS frequency tuning word. The output frequency is equal to RefClock * (ftw / 2 ^ 32).
- *
- * @param ftw Frequency Tuning Word
- */
-void ddsSetFTW (uint32_t ftw)
-{
- // Set FTW0 (Frequency Tuning Word 0)
- output_low (IO_CS);
- spi_write (DDS_AD9954_FTW0);
-
- spi_write ((ftw >> 24) & 0xff);
- spi_write ((ftw >> 16) & 0xff);
- spi_write ((ftw >> 8) & 0xff);
- spi_write (ftw & 0xff);
-
- output_high (IO_CS);
-
- // Strobe the DDS to set the frequency.
- output_high (IO_UPDATE);
- output_low (IO_UPDATE);
-}
-
-/**
- * Convert frequency in hertz to 32-bit DDS FTW (Frequency Tune Word).
- *
- * @param freq frequency in Hertz
- *
- */
-void ddsSetFreq(uint32_t freq)
-{
- uint8_t i;
- uint32_t ftw;
-
- // To avoid rounding errors with floating point math, we do a long multiply on the data.
- ftw = freq * DDS_MULT[0];
-
- for (i = 0; i < DDS_FREQ_TO_FTW_DIGITS - 1; ++i)
- ftw += (freq * DDS_MULT[i+1]) / DDS_DIVISOR[i];
-
- ddsSetFTW (ftw);
-}
-
-/**
- * Set DDS frequency tuning word for the FSK 0 and 1 values. The output frequency is equal
- * to RefClock * (ftw / 2 ^ 32).
- *
- * @param ftw0 frequency tuning word for the FSK 0 value
- * @param ftw1 frequency tuning word for the FSK 1 value
- */
-void ddsSetFSKFreq (uint32_t ftw0, uint32_t ftw1)
-{
- // Set FTW0 (Frequency Tuning Word 0)
- output_low (IO_CS);
- spi_write (DDS_AD9954_FTW0);
-
- spi_write ((ftw0 >> 24) & 0xff);
- spi_write ((ftw0 >> 16) & 0xff);
- spi_write ((ftw0 >> 8) & 0xff);
- spi_write (ftw0 & 0xff);
-
- output_high (IO_CS);
-
- // Set FTW0 (Frequency Tuning Word 1)
- output_low (IO_CS);
- spi_write (DDS_AD9954_FTW1);
-
- spi_write ((ftw1 >> 24) & 0xff);
- spi_write ((ftw1 >> 16) & 0xff);
- spi_write ((ftw1 >> 8) & 0xff);
- spi_write (ftw1 & 0xff);
-
- output_high (IO_CS);
-
- // Strobe the DDS to set the frequency.
- output_high (IO_UPDATE);
- output_low (IO_UPDATE);
-}
-
-/**
- * Set the DDS to run in A-FSK, FSK, or PSK31 mode
- *
- * @param mode DDS_MODE_APRS, DDS_MODE_PSK31, or DDS_MODE_HF_APRS constant
- */
-void ddsSetMode (DDS_MODE mode)
-{
- // Save the current mode.
- ddsMode = mode;
-
- switch (mode)
- {
- case DDS_MODE_POWERDOWN:
- // CFR1 (Control Function Register No. 1)
- output_low (IO_CS);
- spi_write (DDS_AD9954_CFR1);
-
- spi_write (0x00);
- spi_write (0x00);
- spi_write (0x00);
- spi_write (0xf0); // Power down all subsystems.
- output_high (IO_CS);
- break;
-
- case DDS_MODE_AFSK:
- // CFR1 (Control Function Register No. 1)
- output_low (IO_CS);
- spi_write (DDS_AD9954_CFR1);
-
- spi_write (0x03); // OSK Enable and Auto OSK keying
- spi_write (0x00);
- spi_write (0x00);
- spi_write (0x40); // Power down comparator circuit
- output_high (IO_CS);
- break;
-
- case DDS_MODE_FSK:
- // CFR1 (Control Function Register No. 1)
- output_low (IO_CS);
- spi_write (DDS_AD9954_CFR1);
-
- spi_write (0x03); // Clear RAM Enable, OSK Enable, Auto OSK keying
- spi_write (0x00);
- spi_write (0x00);
- spi_write (0x40); // Power down comparator circuit
- output_high (IO_CS);
-
- // NOTE: The sweep rate requires 1/4 of a bit time (26uS) to transition.
- // 6KHz delta = 70641 counts = (6KHz / 364.8MHz) * 2 ^ 32
- // SYNC_CLK = 91.2MHz 1/91.2MHz * 70641 * 1/29 = 26.7uS
-
- // NLSCW (Negative Linear Sweep Control Word)
- output_low (IO_CS);
- spi_write (DDS_AD9954_NLSCW);
-
- spi_write (1); // Falling sweep ramp rate word
- spi_write (0x00); // Delta frequency tuning word
- spi_write (0x00);
- spi_write (0x00);
- spi_write (250);
- output_high (IO_CS);
-
- // PLSCW (Positive Linear Sweep Control Word)
- output_low (IO_CS);
- spi_write (DDS_AD9954_PLSCW);
-
- spi_write (1); // Rising sweep ramp rate word
- spi_write (0x00); // Delta frequency tuning word
- spi_write (0x00);
- spi_write (0x00);
- spi_write (250);
- output_high (IO_CS);
- break;
- } // END switch
-
- // Strobe the DDS to change the mode.
- output_high (IO_UPDATE);
- output_low (IO_UPDATE);
-}
-
-/** @} */
-
-/**
- * @defgroup flash Flash Manager
- *
- * Functions to control the ST MP25P80 serial flash device.
- *
- * @{
- */
-
-/// Flash Chip Select - Port B3
-#define FLASH_CS PIN_B3
-
-/// Flash Clock - Port B5
-#define FLASH_CLK PIN_B5
-
-/// Flash Data Input - Port B4
-#define FLASH_D PIN_B4
-
-/// Flash Data Output - Port B2
-#define FLASH_Q PIN_B2
-
-/**
- * Determine if a flash write or erase operation is currently in progress.
- *
- * @return true if write/erase in progress
- */
-bool_t flashIsWriteInProgress()
-{
- uint8_t status;
-
- output_low (FLASH_CS);
-
- // Read Status Register (RDSR) flash command.
- flashSendByte (0x05);
-
- status = flashGetByte();
-
- output_high (FLASH_CS);
-
- return (((status & 0x01) == 0x01) ? true : false);
-}
-
-/**
- * Read a block of memory from the flash device.
- *
- * @param address of desired location in the range 0x00000 to 0xFFFFF (1MB)
- * @param block pointer to locate of data block
- * @param length number of bytes to read
- */
-void flashReadBlock(uint32_t address, uint8_t *block, uint16_t length)
-{
- uint16_t i;
-
- output_low (FLASH_CS);
-
- // Read Data Byte(s) (READ) flash command.
- flashSendByte (0x03);
- flashSendAddress (address);
-
- for (i = 0; i < length; ++i)
- *block++ = flashGetByte();
-
- output_high (FLASH_CS);
-}
-
-/**
- * Write a block of memory to the flash device.
- *
- * @param address of desired location in the range 0x00000 to 0xFFFFF (1MB)
- * @param block pointer data block to write
- * @param length number of bytes to write
- */
-void flashWriteBlock(uint32_t address, uint8_t *block, uint8_t length)
-{
- uint8_t i;
-
- output_low (FLASH_CS);
- // Write Enable (WREN) flash command.
- flashSendByte (0x06);
- output_high (FLASH_CS);
-
- output_low (FLASH_CS);
- // Page Program (PP) flash command.
- flashSendByte (0x02);
- flashSendAddress (address);
-
- for (i = 0; i < length; ++i)
- {
- // Send each byte in the data block.
- flashSendByte (*block++);
-
- // Track the address in the flash device.
- ++address;
-
- // If we cross a page boundary (a page is 256 bytes) we need to stop and send the address again.
- if ((address & 0xff) == 0x00)
- {
- output_high (FLASH_CS);
-
- // Write this block of data.
- while (flashIsWriteInProgress());
-
- output_low (FLASH_CS);
- // Write Enable (WREN) flash command.
- flashSendByte (0x06);
- output_high (FLASH_CS);
-
- output_low (FLASH_CS);
- // Page Program (PP) flash command.
- flashSendByte (0x02);
- flashSendAddress (address);
- } // END if
- } // END for
-
- output_high (FLASH_CS);
-
- // Wait for the final write operation to complete.
- while (flashIsWriteInProgress());
-}
-
-/**
- * Erase the entire flash device (all locations set to 0xff).
- */
-void flashErase()
-{
- output_low (FLASH_CS);
- // Write Enable (WREN) flash command.
- flashSendByte (0x06);
- output_high (FLASH_CS);
-
- output_low (FLASH_CS);
- // Bulk Erase (BE) flash command.
- flashSendByte (0xc7);
- output_high (FLASH_CS);
-
- while (flashIsWriteInProgress());
-}
-
-/**
- * Read a single byte from the flash device through the serial interface. This function
- * only controls the clock line. The chip select must be configured before calling
- * this function.
- *
- * @return byte read from device
- */
-uint8_t flashGetByte()
-{
- uint8_t i, value;
-
- value = 0;
-
- // Bit bang the 8-bits.
- for (i = 0; i < 8; ++i)
- {
- // Data is ready on the rising edge of the clock.
- output_high (FLASH_CLK);
-
- // MSB is first, so shift left.
- value = value << 1;
-
- if (input (FLASH_Q))
- value = value | 0x01;
-
- output_low (FLASH_CLK);