// // Name: ATVRxController.c // // // Revision History: // // M. Gray 4 Sep 2003 V1.0 Initial release. // // M. Gray 27 Mar 2004 V1.1 Updates based on ham fest display and ANSR-17 flight. // // // COPYRIGHT (c) 2003-04 Michael Gray, KD7LMO // // 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // // Hardware specific configuration. #include <18f252.h> #device ADC=10 #fuses HS,NOWDT,NOPROTECT,NOPUT,NOBROWNOUT,NOLVP // These compiler directives set the clock, I/O ports, RS-232, and I2C interfaces. #use delay(clock=3686400) #use fast_io(B) #use fast_io(C) #use rs232(baud=38400, xmit=PIN_C6, rcv=PIN_C7) #use i2c (master, scl=PIN_C0, sda=PIN_C1) // We define types that are used for all variables. These are declared // because each processor has a different sizes for int and long. typedef int int8_t; typedef unsigned int uint8_t; typedef signed long int16_t; typedef unsigned long uint16_t; typedef int32 int32_t; typedef unsigned int32 uint32_t; // PROGRAMMING NOTE: Since we don't have embedded C++ for this processor, // we try to use C in a manner that emulates classes and methods. Each method // and variable is prefaced by the name of the class. The classes // have a method that acts as a constructor and sometimes a destructor. // Even though variables are declared as global, they are only accessed // through the appropriate class method. The order of the classes and // variables is not important in the application because we only access // the class through a method. // Prototypes for all methods. uint8_t adcGetAGC(); uint8_t adcGetBusVolt(); void adcInit(); void adcUpdate(); void cat524Write (uint8_t port, uint8_t data); uint16_t fileGetFreq(); void fileSetFreq (uint16_t freq); void fileUpdateEEPROM (uint8_t index, uint8_t value); void guiInit(); void guiSetBar(uint8_t value); void guiSetBusVoltage (uint8_t voltage); void guiSetFreq (uint16_t freq); void ioInit(); void ioInterrupt(); boolean ioIsSW1Pushed(); boolean ioIsSW2Pushed(); boolean ioIsSW3Pushed(); void lcdChar (uint8_t value); void lcdCommand (uint8_t command); void lcdCursor (uint8_t x, uint8_t y); void lcdInit(); void lcdString(char *string); void lcdText (uint8_t x, uint8_t y, char *text); void lcdWrite (uint8_t data); void sysGetLCDModeText (uint8_t mode, char *text); void sysGetVersion (char *version); void sysInit(); void sysSetFreq (uint16_t freq); void timerInit(); void timerInterrupt(); boolean timerIsUpdated(); boolean tunerIsLocked(); void tunerSetFreq(uint16_t freq); /* * Class to handle the ADC. */ // Accumulators that store a filter version of the bus and AGC voltage. uint16_t adcBusVoltage, adcAGC; // ADC channels for the desired measurements. #define ADC_MAINBUS 0 #define ADC_AGC 2 /** * Get the AGC value in the range of 0 to 15 where 0 is -80dBm * * @return agc */ uint8_t adcGetAGC() { uint8_t agc; // Scale 1 - 4 volts on the AGC to equal 0 - 15. agc = (uint8_t) (adcAGC / 82); if (agc < 5) return 0; if (agc > 15) return 15; return agc - 4; } /** * Get the main bus voltage in 0.1 volt resolution. * * @return voltage in 0.1 volt steps */ uint8_t adcGetBusVolt() { // Transfer function. 0.4 is the reverse polarity diode drop // x * 494 * 3 * 1 // ---- -- // 1024 80 return (uint8_t) ((uint32_t) (adcBusVoltage) * 741l / 40960l) + 4; } /** * Constructor. */ void adcInit() { uint8_t i; // Setup the ADC. setup_adc_ports( ALL_ANALOG ); setup_adc( ADC_CLOCK_DIV_32 ); // Zero the ADC filters. adcBusVoltage = 0; adcAGC = 0; // Charge the ADC filters. for (i = 0; i < 32; ++i) adcUpdate(); } /** * Read and filter the ADC channels for bus voltage and internal temperature. */ void adcUpdate() { // Filter the analog values using a single pole low pass filter. set_adc_channel(ADC_AGC); delay_us(20); adcAGC = read_adc() + adcAGC - (adcAGC >> 1); set_adc_channel(ADC_MAINBUS); delay_us(20); adcBusVoltage = read_adc() + adcBusVoltage - (adcBusVoltage >> 3); } /* * Class to handle the EEPROM file system. */ enum FILE_SYSTEM_MAP { FILE_MSB_MAGIC = 0x00, FILE_LSB_MAGIC, FILE_FREQ_MSB, FILE_FREQ_LSB, FILE_BACK_LIGHT, FILE_COLOR, FILE_BRIGHT, FILE_CONT, FILE_TINT, FILE_LCD_MODE }; #define FILE_MSB_MAGIC_DEFAULT 0x43 #define FILE_LSB_MAGIC_DEFAULT 0xcf /** * Get the back light setting from the file system. * * @return back light PWM */ uint8_t fileGetBackLightPWM() { return read_eeprom (FILE_BACK_LIGHT); } /** * Get the color setting from the file system. * * @return color setting */ uint8_t fileGetColor() { return read_eeprom (FILE_COLOR); } /** * Get the color setting from the file system. * * @return color setting */ uint8_t fileGetBright() { return read_eeprom (FILE_BRIGHT); } /** * Get the color setting from the file system. * * @return color setting */ uint8_t fileGetContrast() { return read_eeprom (FILE_CONT); } /** * Get the color setting from the file system. * * @return color setting */ uint8_t fileGetTint() { return read_eeprom (FILE_TINT); } /** * Get the LCD screen mode. * * @return LCD screen mode */ uint8_t fileGetLCDMode() { return read_eeprom (FILE_LCD_MODE); } /** * Get the frequency in MHz from the EEPROM file system. * * @return freq in MHz */ uint16_t fileGetFreq() { return ((uint16_t) read_eeprom (FILE_FREQ_MSB) << 8) | (uint16_t) read_eeprom (FILE_FREQ_LSB); } /** * Initialize the file system. * * * @return true if file system valid; otherwise false */ boolean fileInit() { if (read_eeprom(FILE_MSB_MAGIC) == FILE_MSB_MAGIC_DEFAULT && read_eeprom(FILE_LSB_MAGIC) == FILE_LSB_MAGIC_DEFAULT) return true; fileUpdateEEPROM (FILE_MSB_MAGIC, FILE_MSB_MAGIC_DEFAULT); fileUpdateEEPROM (FILE_LSB_MAGIC, FILE_LSB_MAGIC_DEFAULT); return false; } /** * Store the tuner frequency in MHz in the EEPROM file system. * * @param freq in MHz */ void fileSetFreq (uint16_t freq) { fileUpdateEEPROM (FILE_FREQ_MSB, freq >> 8); fileUpdateEEPROM (FILE_FREQ_LSB, freq & 0xff); } /** * Store the back light PWM <b>value</b> in the file system. */ void fileSetBackLightPWM (uint8_t value) { fileUpdateEEPROM (FILE_BACK_LIGHT, value); } /** * Store the color <b>value</b> in the file system. */ void fileSetColor (uint8_t value) { fileUpdateEEPROM (FILE_COLOR, value); } /** * Store the color <b>value</b> in the file system. */ void fileSetBright (uint8_t value) { fileUpdateEEPROM (FILE_BRIGHT, value); } /** * Store the color <b>value</b> in the file system. */ void fileSetContrast (uint8_t value) { fileUpdateEEPROM (FILE_CONT, value); } /** * Store the color <b>value</b> in the file system. */ void fileSetTint (uint8_t value) { fileUpdateEEPROM (FILE_TINT, value); } /** * Store the color <b>value</b> in the file system. */ void fileSetLCDMode (uint8_t value) { fileUpdateEEPROM (FILE_LCD_MODE, value); } void fileUpdateEEPROM (uint8_t index, uint8_t value) { if (read_eeprom (index) == value) return; write_eeprom (index, value); } /* * Class to handle the user interface. */ /** * Display the applicatino title and version. */ void guiVersion() { char buffer[20]; // Display the application name and version information on the LCD. sysGetVersion (buffer); lcdText (2, 1, buffer); } /** * Display the labels. */ void guiLabel() { char buffer[20]; strcpy (buffer, "Freq xxxxMHz"); lcdText (1, 1, buffer); strcpy (buffer, "Sig"); lcdText (1, 2, buffer); } /** * Set the AGC bar graph. * * @param agc level in the range 0 to 15. */ void guiSetAGC (uint8_t agc) { uint8_t i; char buffer[17]; // Draw solid blocks for each MSB in the age value. for (i = 0; i < agc && i < 16; ++i) buffer[i] = '\377'; // Fill in the rest with blanks. while (i < 16) buffer[i++] =' '; // NULL terminate the string. buffer[16] = 0; // Now display it. lcdText (5, 2, buffer); } /** * Set an indicator bar on the bottom line of the 2 x 20 LCD display * that represents <b>value</b>. * * @param value to display in the range 0 to 255 */ void guiSetBar(uint8_t value) { uint8_t i; lcdCursor (1, 2); for (i = 0; i < 20; ++i) lcdChar (' '); lcdCursor (1 + (uint8_t) ((uint16_t) value * 10l / 128l), 2); lcdChar ('\377'); } /** * Display the bus voltage. * * @param voltage in units of 0.1 volts */ void guiSetBusVoltage (uint8_t voltage) { char buffer[10]; sprintf (buffer, "%02d.%d", voltage / 10, voltage % 10); lcdText (1, 2, buffer); } /** * Display the frequency. * * @param frequency in MHz */ void guiSetFreq (uint16_t freq) { char buffer[10]; sprintf (buffer, "%ld", freq); lcdText (6, 1, buffer); } /* * Class to handle local I/O. */ boolean ioLastState1, ioLastState2, ioLastState3, ioTrigger1, ioTrigger2, ioTrigger3; uint8_t ioPort0, ioPort1; // Port 0 bit map. #define IO_SCAN_DOWN 0x01 #define IO_SCAN_LEFT 0x02 #define IO_MODE_1 0x04 #define IO_MODE_2 0x08 #define IO_MODE_3 0x10 #define IO_MODE_MASK 0x1c #define IO_MODE_SHIFT 2 #define IO_COMP_VIDEO 0x20 // Port 1 bit map. #define IO_CAT524_PROG 0x01 #define IO_CAT524_DI 0x02 #define IO_CAT524_CS 0x04 #define IO_CAT524_CLK 0x08 #define IO_LED 0x10 void ioUpdatePorts() { i2c_start(); i2c_write(0x40); i2c_write(0x00); i2c_write(ioPort0); i2c_write(ioPort1); i2c_stop(); i2c_start(); i2c_write(0x40); i2c_write(0x02); i2c_write(ioPort0); i2c_write(ioPort1); i2c_stop(); } void ioReadPort() { uint8_t value; // Tell the MCP23016 we want to access the GP0 and GP1 registers. i2c_start(); i2c_write(0x40); i2c_write(0x00); i2c_stop(); // Read the contents of the register. i2c_start(); i2c_write(0x41); value = i2c_read(); value = i2c_read(); i2c_stop(); // Check for changes in the input state and set a flag for high to low transitions. // Since this routine is only called every 50mS, we will automatically debounce the switch. if (ioLastState1 != ((value & 0x20) == 0x020 ? TRUE : FALSE)) { if (ioLastState1) ioTrigger1 = TRUE; ioLastState1 = ~ioLastState1; } // END if if (ioLastState2 != ((value & 0x40) == 0x040 ? TRUE : FALSE)) { if (ioLastState2) ioTrigger2 = TRUE; ioLastState2 = ~ioLastState2; } // END if if (ioLastState3 != ((value & 0x80) == 0x080 ? TRUE : FALSE)) { if (ioLastState3) ioTrigger3 = TRUE; ioLastState3 = ~ioLastState3; } // END if } /** * Constructor. */ void ioInit() { // Initial output port settings. ioPort0 = 0x00; ioPort1 = 0x00; ioLastState1 = FALSE; ioLastState2 = FALSE; ioLastState3 = FALSE; ioTrigger1 = FALSE; ioTrigger2 = FALSE; ioTrigger3 = FALSE; // Specify the port I/O direction. i2c_start(); i2c_write(0x40); i2c_write(0x06); i2c_write(0x00); i2c_write(0xe0); i2c_stop(); ioUpdatePorts(); } void ioSetCAT524Prog (boolean state) { if (state) ioPort1 |= IO_CAT524_PROG; else ioPort1 &= ~IO_CAT524_PROG; ioUpdatePorts(); } void ioSetCAT524Data (boolean state) { if (state) ioPort1 |= IO_CAT524_DI; else ioPort1 &= ~IO_CAT524_DI; ioUpdatePorts(); } void ioSetCAT524CS (boolean state) { if (state) ioPort1 |= IO_CAT524_CS; else ioPort1 &= ~IO_CAT524_CS; ioUpdatePorts(); } void ioSetCAT524Clk (boolean state) { if (state) ioPort1 |= IO_CAT524_CLK; else ioPort1 &= ~IO_CAT524_CLK; ioUpdatePorts(); } void ioScanDown (boolean state) { if (state) ioPort0 |= IO_SCAN_DOWN; else ioPort0 &= ~IO_SCAN_DOWN; ioUpdatePorts(); } void ioScanLeft (boolean state) { if (state) ioPort0 |= IO_SCAN_LEFT; else ioPort0 &= ~IO_SCAN_LEFT; ioUpdatePorts(); } void ioCompVideo (boolean state) { if (state) ioPort0 |= IO_COMP_VIDEO; else ioPort0 &= ~IO_COMP_VIDEO; ioUpdatePorts(); } void ioSetMode (uint8_t mode) { ioPort0 = (ioPort0 & ~IO_MODE_MASK) | (mode << IO_MODE_SHIFT); ioUpdatePorts(); } void ioSetLED (boolean state) { if (state) ioPort1 &= ~IO_LED; else ioPort1 |= IO_LED; ioUpdatePorts(); } /** * Determine if switch 1 was pushed. This is a one shot method that * debounces the switch contacts. * * @return true if pushed; otherwise false */ boolean ioIsSW1Pushed() { if (ioTrigger1) { ioTrigger1 = FALSE; return TRUE; } return FALSE; } /** * Determine if switch 2 was pushed. This is a one shot method that * debounces the switch contacts. * * @return true if pushed; otherwise false */ boolean ioIsSW2Pushed() { if (ioTrigger2) { ioTrigger2 = FALSE; return TRUE; } return FALSE; } /** * Determine if switch 3 was pushed. This is a one shot method that * debounces the switch contacts. * * @return true if pushed; otherwise false */ boolean ioIsSW3Pushed() { if (ioTrigger3) { ioTrigger3 = FALSE; return TRUE; } return FALSE; } #define CAT524_COLOR 0x00 #define CAT524_BRIGHT 0x02 #define CAT524_CONT 0x01 #define CAT524_TINT 0x03 /** * Set the analog <b>port</b> to the value <b>data</b> in the range 0 to 255. * * @param port index CAT524_xxx * @param data analog value */ void cat524Write (uint8_t port, uint8_t data) { uint8_t i; ioSetCAT524Data (FALSE); ioSetCAT524CS (TRUE); // Write the start bit. ioSetCAT524Data (TRUE); ioSetCAT524Clk (TRUE); ioSetCAT524Clk (FALSE); // Set the programming bit. ioSetCAT524Prog (TRUE); // Write A0 of the address. ioSetCAT524Data ((port & 0x01) ? TRUE : FALSE); ioSetCAT524Clk (TRUE); ioSetCAT524Clk (FALSE); // Write A1 of the address. ioSetCAT524Data ((port & 0x02) ? TRUE : FALSE); ioSetCAT524Clk (TRUE); ioSetCAT524Clk (FALSE); // Write the 8-data bits LSB first. for (i = 0; i < 8; ++i) { ioSetCAT524Data ((data & 0x01) ? TRUE : FALSE); data = data >> 1; ioSetCAT524Clk (TRUE); ioSetCAT524Clk (FALSE); } ioSetCAT524Data (FALSE); // Save the data to the CAT524 EEPROM. for (i = 0 ; i < 4; ++i) { delay_ms(1); ioSetCAT524Clk (TRUE); ioSetCAT524Clk (FALSE); } // Clean up. ioSetCAT524Prog (FALSE); ioSetCAT524CS (FALSE); } /* * Class to handle the HD44780 LCD controller. */ const uint8_t LCD_OFFSET[] = { 0x00, 0x40, 0x14, 0x54 }; #define IO_LCD_BIT0 PIN_B4 #define IO_LCD_BIT1 PIN_B5 #define IO_LCD_BIT2 PIN_B6 #define IO_LCD_BIT3 PIN_B7 #define IO_LCD_RW PIN_B3 #define IO_LCD_E PIN_B2 #define IO_LCD_RS PIN_B1 /** * Display the <b>character</b> on the LCD. * * @param value character to display */ void lcdChar (uint8_t value) { output_high (IO_LCD_RS); lcdWrite (value); } /** * Clear the LCD display. */ void lcdClear() { lcdCommand (0x01); } /** * Send a command to the LCD system. */ void lcdCommand (uint8_t command) { // Some commands take 1.64mS to complete, so we'll just wait on all of them. delay_ms (2); output_low (IO_LCD_RS); lcdWrite (command); } /** * Move the LCD cursor to the coordinates (x, y) where (1, 1) is * in the upper left-hand corner. * * @param x coordinate * @param y coordinate */ void lcdCursor(uint8_t x, uint8_t y) { // Only allow the range (1, 1) to (20, 2) if (x == 0 || x > 20 || y == 0 || y > 2) return; output_low (IO_LCD_RS); lcdCommand (0x7f + x + LCD_OFFSET[y - 1]); } /** * Initialize the LCD controller and display initial text. */ void lcdInit() { // Reset the interface. lcdCommand (0x33); lcdCommand (0x33); lcdCommand (0x32); // Set 4-bit interface mode and display type. lcdCommand (0x28); // Enable the display with the cursor off. lcdCommand (0x0c); // Clear the display and home the cursor. lcdCommand (0x01); // Move the cursor forward with each character. lcdCommand (0x06); } /** * Display <b>string</b> on the LCD display. */ void lcdString(char *string) { output_high (IO_LCD_RS); while (*string != 0) lcdWrite (*string++); } void lcdText (uint8_t x, uint8_t y, char *text) { lcdCursor (x, y); lcdString (text); } /** * Write a byte to the 4-bit interface. * * @param data value to write to LCD controller */ void lcdWrite (uint8_t data) { output_bit (IO_LCD_BIT3, ((data & 0x80) ? 1 : 0)); output_bit (IO_LCD_BIT2, ((data & 0x40) ? 1 : 0)); output_bit (IO_LCD_BIT1, ((data & 0x20) ? 1 : 0)); output_bit (IO_LCD_BIT0, ((data & 0x10) ? 1 : 0)); output_high (IO_LCD_E); delay_us(1); output_low (IO_LCD_E); output_bit (IO_LCD_BIT3, ((data & 0x08) ? 1 : 0)); output_bit (IO_LCD_BIT2, ((data & 0x04) ? 1 : 0)); output_bit (IO_LCD_BIT1, ((data & 0x02) ? 1 : 0)); output_bit (IO_LCD_BIT0, ((data & 0x01) ? 1 : 0)); output_high (IO_LCD_E); delay_us(1); output_low (IO_LCD_E); } /* * Class to handle the system operations. */ const uint16_t SYS_VERSION = 0x0101; #define FREQ_LOWER_RANGE 2300 #define FREQ_UPPER_RANGE 2500 // The time in 50mS increments before we save a change in the tuner frequency. #define SYS_SAVE_FREQ_TIME 300 void sysInit() { // Set default outputs before we configure the I/O state. output_b (0x00); output_c (0x03); // Configure the I/O ports direction. set_tris_b (0x00); set_tris_c (0x80); } /** * Get the software title and version string. * * @param version buffer to write version into */ void sysGetVersion (char *version) { sprintf (version, "KD7LMO FM-ATV v%d.%d", (uint8_t) (SYS_VERSION >> 8), (uint8_t) (SYS_VERSION & 0xff)); } enum SYS_OPER_MODE { MODE_FREQ, MODE_BACK_LIGHT, MODE_BRIGHT, MODE_CONTRAST, MODE_COLOR, MODE_TINT, MODE_LCD_MODE, MODE_SYS_INFO }; void sysGetLCDModeText (uint8_t mode, char *text) { switch (mode) { case 1: strcpy (text, "Normal - Right"); break; case 2: strcpy (text, "Normal - Left "); break; case 3: strcpy (text, "Zoom 2 "); break; case 4: strcpy (text, "Zoom 1 "); break; case 5: strcpy (text, "Stretch 4:3 "); break; case 6: strcpy (text, "Normal 4:3 "); break; case 7: strcpy (text, "Wide 16:9 "); break; default: strcpy (text, "Unknown Mode "); } // END switch } void sysRun() { boolean runFlag, ledState, valueChangeFlag; uint8_t value, lastBusVoltage, lastAGC, versionState, newSetting, ledStateCounter; uint16_t freq, lastFreqChange; char buffer[20]; SYS_OPER_MODE operMode; // Get the last frequency we used. freq = fileGetFreq(); // Set the tuner and LCD. tunerSetFreq(freq); // Configure the state variables. runFlag = TRUE; lastBusVoltage = 0xff; lastAGC = 0; lastFreqChange = 0; ledStateCounter = 0; versionState = 0; ledState = FALSE; operMode = MODE_FREQ; valueChangeFlag = false; // Display the application version. guiVersion(); // Display bars on the LCD screen during startup. while (versionState <= 40) { if (timerIsUpdated()) { ++versionState; if (versionState <= 20) { lcdCursor (versionState, 2); lcdChar (0x7e); } else { lcdCursor (versionState - 20, 2); lcdChar (' '); } // END if-else if (versionState == 40) { lcdClear(); guiLabel(); guiSetFreq (freq); } // END if } // END if } // END while // while (runFlag) { // Processing that occurs every 50mS. if (timerIsUpdated()) { // Read the push buttons. ioReadPort(); // Save the last frequency to EEPROM if it has changed and the user hasn't moved it recently. if (lastFreqChange <= SYS_SAVE_FREQ_TIME) if (++lastFreqChange == SYS_SAVE_FREQ_TIME) if (freq != fileGetFreq()) fileSetFreq (freq); // Read the A/D value. adcUpdate(); // Only update the displayed AGC bar graph if it changed. switch (operMode) { case MODE_FREQ: // Only update the screen if the value changed since the last update. value = adcGetAGC(); if (value != lastAGC) { lastAGC = value; guiSetAGC (value); } // END if break; case MODE_SYS_INFO: value = adcGetBusVolt(); if (value != lastBusVoltage) { lastBusVoltage = value; guiSetBusVoltage (value); } // END if break; } // END switch // Heartbeat LED. if (++ledStateCounter == 10) { ledStateCounter = 0; ledState = ~ledState; ioSetLED (ledState); } // END if } // END if // Switch modes based on the select button. if (ioIsSW1Pushed()) { // Clear the screen. lcdClear(); switch (operMode) { case MODE_FREQ: operMode = MODE_BACK_LIGHT; strcpy (buffer, "Back Light Level"); newSetting = fileGetBackLightPWM(); break; case MODE_BACK_LIGHT: fileSetBackLightPWM (newSetting); operMode = MODE_BRIGHT; strcpy (buffer, "Brightness"); newSetting = fileGetBright(); break; case MODE_BRIGHT: fileSetBright (newSetting); operMode = MODE_CONTRAST; strcpy (buffer, "Contrast"); newSetting = fileGetContrast(); break; case MODE_CONTRAST: fileSetContrast (newSetting); operMode = MODE_COLOR; strcpy (buffer, "Chroma (Color)"); newSetting = fileGetColor(); break; case MODE_COLOR: fileSetColor (newSetting); operMode = MODE_TINT; strcpy (buffer, "Phase (Tint)"); newSetting = fileGetTint(); break; case MODE_TINT: fileSetTint (newSetting); operMode = MODE_LCD_MODE; strcpy (buffer, "Display Mode"); newSetting = fileGetLCDMode(); break; case MODE_LCD_MODE: fileSetLCDMode (newSetting); operMode = MODE_SYS_INFO; sysGetVersion (buffer); break; case MODE_SYS_INFO: operMode = MODE_FREQ; strcpy (buffer, "Freq MHz"); break; } // END switch // Display the mode lable on the screen. lcdText (1, 1, buffer); // Display the current setting. switch (operMode) { case MODE_FREQ: guiSetFreq (freq); lastAGC = 0; strcpy (buffer, "Sig"); lcdText (1, 2, buffer); break; case MODE_LCD_MODE: sysGetLCDModeText (newSetting, buffer); lcdText (1, 2, buffer); break; case MODE_SYS_INFO: strcpy (buffer, "VDC"); lcdText (6, 2, buffer); guiSetBusVoltage(adcGetBusVolt()); break; default: guiSetBar (newSetting); break; } // END switch } // END if // Process the switch pushes. if (ioIsSW2Pushed()) { valueChangeFlag = true; switch (operMode) { case MODE_FREQ: if (freq < FREQ_UPPER_RANGE) { lastFreqChange = 0; ++freq; } // END if break; case MODE_LCD_MODE: if (++newSetting == 8) newSetting = 1; sysGetLCDModeText (newSetting, buffer); lcdText (1, 2, buffer); break; case MODE_SYS_INFO: break; default: if (newSetting < 248) newSetting += 8; guiSetBar (newSetting); break; } // END switch } // END switch if (ioIsSW3Pushed()) { valueChangeFlag = true; switch (operMode) { case MODE_FREQ: if (freq > FREQ_LOWER_RANGE) { lastFreqChange = 0; --freq; } // END if break; case MODE_LCD_MODE: if (--newSetting == 0) newSetting = 7; sysGetLCDModeText (newSetting, buffer); lcdText (1, 2, buffer); break; case MODE_SYS_INFO: break; default: if (newSetting > 0) newSetting -= 8; guiSetBar (newSetting); break; } // END switch } // END if if (valueChangeFlag) { valueChangeFlag = false; switch (operMode) { case MODE_FREQ: sysSetFreq (freq); break; case MODE_BACK_LIGHT: set_pwm1_duty (newSetting); break; case MODE_BRIGHT: cat524Write (CAT524_BRIGHT, newSetting); break; case MODE_CONTRAST: cat524Write (CAT524_CONT, newSetting); break; case MODE_COLOR: cat524Write (CAT524_COLOR, newSetting); break; case MODE_TINT: cat524Write (CAT524_TINT, newSetting); break; case MODE_LCD_MODE: ioSetMode (newSetting); break; } // END switch } // END if } // END while } /** * Set the receiver frequency and display it. * * @param freq in MHz */ void sysSetFreq (uint16_t freq) { guiSetFreq(freq); tunerSetFreq (freq); } /* * Class to handle the timer functions. */ uint8_t timerInterruptCount; uint16_t timerCompare; boolean timerUpdateFlag, timerPWM; // The number of CCP_2 timer clicks in a 5mS time slice. // (ClockRate / 4) / (T1_DIV_BY_x) * 576) => (14745600 / 4) / (8 * 2304) = 5mS #define TIMER_RATE 576 void timerInit() { // Setup the counters that are used in the timerInterrupt function. timerInterruptCount = 0; timerUpdateFlag = FALSE; timerPWM = FALSE; // Configure CCP2 to interrupt at 5mS rate. timerCompare = TIMER_RATE; CCP_2 = timerCompare; set_timer1(0); setup_ccp2( CCP_COMPARE_INT ); setup_timer_1( T1_INTERNAL | T1_DIV_BY_8 ); // Setup CCP1 to generate PWM pulses at 275Hz. setup_ccp1(CCP_PWM); set_timer2(0); setup_timer_2(T2_DIV_BY_16, 209, 1); set_pwm1_duty(fileGetBackLightPWM()); // Setup our interrupts. enable_interrupts(GLOBAL); enable_interrupts(INT_CCP2); } // This ISR is called when the timer register matches the compare register. // The interrupt rate is programmed to 5mS. #INT_CCP2 void timerInterrupt() { // Setup for the next interrupt. timerCompare += TIMER_RATE; CCP_2 = timerCompare; // Set a processing flag every 50mS. if (++timerInterruptCount == 10) { timerInterruptCount = 0; timerUpdateFlag = TRUE; } // END if } /** * Returns a flag that is set true every 50mS. The method automatically resets to false after * it returns true. * * @return true if 50mS has passed; otherwise false */ boolean timerIsUpdated() { if (timerUpdateFlag) { timerUpdateFlag = FALSE; return true; } // END if return false; } /* * Class to handle the 2.4GHz tuner PLL. The tuner utilizes the Mitel SA5055 2.6GHz * synthesizer. */ /** * Determine if the tuner PLL is locked * * @return true if locked; otherwise false */ boolean tunerIsLocked() { uint8_t returnCode; // Get the PLL controller status byte. i2c_start(); i2c_write(0xc3); returnCode = i2c_read(); i2c_stop(); // Bit 6 is the PLL locked flag. if ((returnCode & 0x40) == 0x40) return TRUE; else return FALSE; } /** * Set the receiver frequency. The IF is 479.5MHz so we set the frequency lower than the * desired receive frequency. The frequency is based on a 4MHz reference divided by 512. * * @param freq in MHz */ void tunerSetFreq(uint16_t freq) { // Tell the I2C device to connect i2c_start(); // Address the SA5055 PLL. i2c_write(0xc2); // Calculate the receive frequency minus the IF frequency of 479.5 MHz (3836 = 497.5 * 8) freq = (8 * freq) - 3836; // Write the divider value. i2c_write(freq >> 8); i2c_write(freq & 0xff); i2c_write(0xce); i2c_write(0x00); i2c_stop(); } /* * Class to handle the video functions. */ /** * Setup the video controller. */ void videoInit() { cat524Write (CAT524_COLOR, fileGetColor()); cat524Write (CAT524_BRIGHT, fileGetBright()); cat524Write (CAT524_CONT, fileGetContrast()); cat524Write (CAT524_TINT, fileGetTint()); ioScanDown (TRUE); ioCompVideo (TRUE); ioSetMode (fileGetLCDMode()); } // This is where we go after reset. void main() { // Initialize the base system. sysInit(); // Wait for the hardware to come up after reset. delay_ms (100); // If the file system is not valid, then set default values. if (!fileInit()) { fileSetFreq (2418); fileSetBackLightPWM (0x80); fileSetColor (0x80); fileSetBright (0x80); fileSetContrast (0x80); fileSetTint (0x80); fileSetLCDMode (0x06); } // END if // Initialize the subsystems. adcInit(); ioInit(); lcdInit(); timerInit(); videoInit(); // Now run the system. sysRun(); }