commit 5a4fd14581e9da5418a7d9e42c32ff00cafa222e Author: Steve Markgraf Date: Mon Mar 12 00:30:54 2012 +0100 initial commit Signed-off-by: Steve Markgraf diff --git a/src/Makefile b/src/Makefile new file mode 100644 index 0000000..0f08378 --- /dev/null +++ b/src/Makefile @@ -0,0 +1,10 @@ +LDFLAGS=`pkg-config --libs libusb-1.0` +CFLAGS=-Wall -O2 `pkg-config --cflags libusb-1.0` + +all: rtl-sdr + +rtl-sdr: main.o tuner_e4000.o tuner_fc0013.c + $(CC) -o $@ $^ $(LDFLAGS) + +clean: + @rm -f rtl.sdr *.o diff --git a/src/i2c.h b/src/i2c.h new file mode 100644 index 0000000..31c21bb --- /dev/null +++ b/src/i2c.h @@ -0,0 +1,7 @@ +#ifndef __I2C_H +#define __I2C_H + +int rtl_i2c_write(uint8_t i2c_addr, uint8_t *buffer, int len); +int rtl_i2c_read(uint8_t i2c_addr, uint8_t *buffer, int len); + +#endif diff --git a/src/main.c b/src/main.c new file mode 100644 index 0000000..833d81f --- /dev/null +++ b/src/main.c @@ -0,0 +1,415 @@ +/* + * rtl-sdr, a poor man's SDR using a Realtek RTL2832 based DVB-stick + * Copyright (C) 2012 by Steve Markgraf + * + * 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, see . + */ + +#include +#include +#include +#include +#include +#include + +#include + +#include "tuner_e4000.h" +#include "tuner_fc0013.h" + +#define READLEN (16 * 16384) +#define CTRL_IN (LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_ENDPOINT_IN) +#define CTRL_OUT (LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_ENDPOINT_OUT) + +/* ezcap USB 2.0 DVB-T/DAB/FM stick */ +#define EZCAP_VID 0x0bda +#define EZCAP_PID 0x2838 + +/* Terratec NOXON DAB/DAB+ USB-Stick */ +#define NOXON_VID 0x0ccd +#define NOXON_PID 0x00b3 + +static struct libusb_device_handle *devh = NULL; +static int do_exit = 0; + +enum TUNER_TYPE { + TUNER_E4000, + TUNER_FC0013 +} tuner_type; + +static int find_device(void) +{ + devh = libusb_open_device_with_vid_pid(NULL, EZCAP_VID, EZCAP_PID); + if (devh > 0) { + tuner_type = TUNER_E4000; + printf("Found ezcap stick with E4000 tuner\n"); + return 0; + } + + devh = libusb_open_device_with_vid_pid(NULL, NOXON_VID, NOXON_PID); + if (devh > 0) { + tuner_type = TUNER_FC0013; + printf("Found Terratec NOXON stick with FC0013 tuner\n"); + return 0; + } + + return -EIO; +} + +enum usb_reg { + USB_SYSCTL = 0x2000, + USB_CTRL = 0x2010, + USB_STAT = 0x2014, + USB_EPA_CFG = 0x2144, + USB_EPA_CTL = 0x2148, + USB_EPA_MAXPKT = 0x2158, + USB_EPA_MAXPKT_2 = 0x215a, + USB_EPA_FIFO_CFG = 0x2160, +}; + +enum sys_reg { + DEMOD_CTL = 0x3000, + GPO = 0x3001, + GPI = 0x3002, + GPOE = 0x3003, + GPD = 0x3004, + SYSINTE = 0x3005, + SYSINTS = 0x3006, + GP_CFG0 = 0x3007, + GP_CFG1 = 0x3008, + SYSINTE_1 = 0x3009, + SYSINTS_1 = 0x300a, + DEMOD_CTL_1 = 0x300b, + IR_SUSPEND = 0x300c, +}; + +enum blocks { + DEMODB = 0, + USBB = 1, + SYSB = 2, + TUNB = 3, + ROMB = 4, + IRB = 5, + IICB = 6, +}; + +int rtl_read_array(uint8_t block, uint16_t addr, uint8_t *array, uint8_t len) +{ + int r; + uint16_t index = (block << 8); + + r = libusb_control_transfer(devh, CTRL_IN, 0, addr, index, array, len, 0); + + return r; +} + +int rtl_write_array(uint8_t block, uint16_t addr, uint8_t *array, uint8_t len) +{ + int r; + uint16_t index = (block << 8) | 0x10; + + r = libusb_control_transfer(devh, CTRL_OUT, 0, addr, index, array, len, 0); + + return r; +} + +int rtl_i2c_write(uint8_t i2c_addr, uint8_t *buffer, int len) +{ + uint16_t addr = i2c_addr; + return rtl_write_array(IICB, addr, buffer, len); +} + +int rtl_i2c_read(uint8_t i2c_addr, uint8_t *buffer, int len) +{ + uint16_t addr = i2c_addr; + return rtl_read_array(IICB, addr, buffer, len); +} + +uint16_t rtl_read_reg(uint8_t block, uint16_t addr, uint8_t len) +{ + int r; + unsigned char data[2]; + uint16_t index = (block << 8); + uint16_t reg; + + r = libusb_control_transfer(devh, CTRL_IN, 0, addr, index, data, len, 0); + + if (r < 0) + printf("%s failed\n", __FUNCTION__); + + reg = (data[1] << 8) | data[0]; + + return reg; +} + +void rtl_write_reg(uint8_t block, uint16_t addr, uint16_t val, uint8_t len) +{ + int r; + unsigned char data[2]; + + uint16_t index = (block << 8) | 0x10; + + if (len == 1) + data[0] = val & 0xff; + else + data[0] = val >> 8; + + data[1] = val & 0xff; + + r = libusb_control_transfer(devh, CTRL_OUT, 0, addr, index, data, len, 0); + + if (r < 0) + printf("%s failed\n", __FUNCTION__); +} + +uint16_t demod_read_reg(uint8_t page, uint8_t addr, uint8_t len) +{ + int r; + unsigned char data[2]; + + uint16_t index = page; + uint16_t reg; + addr = (addr << 8) | 0x20; + + r = libusb_control_transfer(devh, CTRL_IN, 0, addr, index, data, len, 0); + + if (r < 0) + printf("%s failed\n", __FUNCTION__); + + reg = (data[1] << 8) | data[0]; + + return reg; +} + +void demod_write_reg(uint8_t page, uint16_t addr, uint16_t val, uint8_t len) +{ + int r; + unsigned char data[2]; + uint16_t index = 0x10 | page; + addr = (addr << 8) | 0x20; + + if (len == 1) + data[0] = val & 0xff; + else + data[0] = val >> 8; + + data[1] = val & 0xff; + + r = libusb_control_transfer(devh, CTRL_OUT, 0, addr, index, data, len, 0); + + if (r < 0) + printf("%s failed\n", __FUNCTION__); + + demod_read_reg(0x0a, 0x01, 1); +} + +void set_resampler(uint32_t rsamp_ratio) +{ + uint16_t tmp; + rsamp_ratio <<= 2; + + tmp = (rsamp_ratio >> 16) & 0xffff; + demod_write_reg(1, 0x9f, tmp, 2); + tmp = rsamp_ratio & 0xffff; + demod_write_reg(1, 0xa1, tmp, 2); +} + +void set_i2c_repeater(int on) +{ + demod_write_reg(1, 0x01, on ? 0x18 : 0x10, 1); +} + +void rtl_init(void) +{ + unsigned int i; + + /* default FIR coefficients used for DAB/FM by the Windows driver, + * the DVB driver uses different ones */ + uint8_t fir_coeff[] = { + 0xca, 0xdc, 0xd7, 0xd8, 0xe0, 0xf2, 0x0e, 0x35, 0x06, 0x50, + 0x9c, 0x0d, 0x71, 0x11, 0x14, 0x71, 0x74, 0x19, 0x41, 0x00, + }; + + /* initialize USB */ + rtl_write_reg(USBB, USB_SYSCTL, 0x09, 1); + rtl_write_reg(USBB, USB_EPA_MAXPKT, 0x0002, 2); + rtl_write_reg(USBB, USB_EPA_CTL, 0x1002, 2); + + /* poweron demod */ + rtl_write_reg(SYSB, DEMOD_CTL_1, 0x22, 1); + rtl_write_reg(SYSB, DEMOD_CTL, 0xe8, 1); + + /* reset demod (bit 3, soft_rst) */ + demod_write_reg(1, 0x01, 0x14, 1); + demod_write_reg(1, 0x01, 0x10, 1); + + /* disable spectrum inversion and adjacent channel rejection */ + demod_write_reg(1, 0x15, 0x00, 1); + demod_write_reg(1, 0x16, 0x0000, 2); + + /* set IF-frequency to 0 Hz */ + demod_write_reg(1, 0x19, 0x0000, 2); + + /* set FIR coefficients */ + for (i = 0; i < sizeof (fir_coeff); i++) + demod_write_reg(1, 0x1c + i, fir_coeff[i], 1); + + /* TODO setting resampler test value, max value is 0xC99999, + * value for DAB/FM is 0xE10000*/ + set_resampler(1 << 24); + + demod_write_reg(0, 0x19, 0x25, 1); + + /* init FSM state-holding register */ + demod_write_reg(1, 0x93, 0xf0, 1); + + /* disable AGC (en_dagc, bit 0) */ + demod_write_reg(1, 0x11, 0x00, 1); + + /* disable PID filter (enable_PID = 0) */ + demod_write_reg(0, 0x61, 0x60, 1); + + /* opt_adc_iq = 0, default ADC_I/ADC_Q datapath */ + demod_write_reg(0, 0x06, 0x80, 1); + + /* Enable Zero-IF mode (en_bbin bit), DC cancellation (en_dc_est), + * IQ estimation/compensation (en_iq_comp, en_iq_est) */ + demod_write_reg(1, 0xb1, 0x1b, 1); +} + +void tuner_init(int frequency) +{ + set_i2c_repeater(1); + + switch (tuner_type) { + case TUNER_E4000: + e4000_Initialize(1); + e4000_SetBandwidthHz(1, 80000); + e4000_SetRfFreqHz(1, frequency); + break; + case TUNER_FC0013: + FC0013_Open(); + FC0013_SetFrequency(frequency/1000, 8); + break; + default: + printf("No valid tuner available!"); + break; + } + + printf("Tuned to %i Hz\n", frequency); + set_i2c_repeater(0); +} + +void usage(void) +{ + printf("rtl-sdr, an I/Q recorder for RTL2832 based USB-sticks\n\n" + "Usage:\t-f frequency to tune to [Hz]\n" + "\toutput filename\n"); + exit(1); +} + +static void sighandler(int signum) +{ + do_exit = 1; +} + +int main(int argc, char **argv) +{ + struct sigaction sigact; + int r, opt; + char *filename; + unsigned int frequency = 0; + uint8_t buffer[READLEN]; + int n_read; + FILE *file; + + while ((opt = getopt(argc, argv, "f:")) != -1) { + switch (opt) { + case 'f': + frequency = atoi(optarg); + break; + default: + usage(); + break; + } + } + + if (argc <= optind) { + usage(); + } else { + filename = argv[optind]; + } + + r = libusb_init(NULL); + if (r < 0) { + fprintf(stderr, "Failed to initialize libusb\n"); + exit(1); + } + + r = find_device(); + if (r < 0) { + fprintf(stderr, "Could not find/open device\n"); + goto out; + } + + r = libusb_claim_interface(devh, 0); + if (r < 0) { + fprintf(stderr, "usb_claim_interface error %d\n", r); + goto out; + } + + sigact.sa_handler = sighandler; + sigemptyset(&sigact.sa_mask); + sigact.sa_flags = 0; + sigaction(SIGINT, &sigact, NULL); + sigaction(SIGTERM, &sigact, NULL); + sigaction(SIGQUIT, &sigact, NULL); + + /* Initialize the RTL2832 */ + rtl_init(); + + /* Initialize tuner & set frequency */ + tuner_init(frequency); + + file = fopen(filename, "wb"); + + if (!file) { + printf("Failed to open %s\n", filename); + goto out; + } + + /* reset endpoint before we start reading */ + rtl_write_reg(USBB, USB_EPA_CTL, 0x1002, 2); + rtl_write_reg(USBB, USB_EPA_CTL, 0x0000, 2); + + printf("Reading samples...\n"); + while (!do_exit) { + libusb_bulk_transfer(devh, 0x81, buffer, READLEN, &n_read, 3000); + fwrite(buffer, n_read, 1, file); + + if (n_read < READLEN) { + printf("Short bulk read, samples lost, exiting!\n"); + break; + } + } + + fclose(file); + libusb_release_interface(devh, 0); + +out: + libusb_close(devh); + libusb_exit(NULL); + return r >= 0 ? r : -r; +} + diff --git a/src/tuner_e4000.c b/src/tuner_e4000.c new file mode 100644 index 0000000..62888e6 --- /dev/null +++ b/src/tuner_e4000.c @@ -0,0 +1,2073 @@ +/* + * Elonics E4000 tuner driver, taken from the kernel driver that can be found + * on http://linux.terratec.de/tv_en.html + * + * This driver is a mess, and should be replaced by the osmo-sdr E4000 driver + * + */ + +#include + +#include "i2c.h" +#include "tuner_e4000.h" + +#define FUNCTION_ERROR 1 +#define FUNCTION_SUCCESS 0 +#define NO_USE 0 +#define LEN_2_BYTE 2 +#define I2C_BUFFER_LEN 128 +#define YES 1 +#define NO 0 + +#define CRYSTAL_FREQ 28800000 +#define E4K_I2C_ADDR 0xc8 + +/* glue functions to rtl-sdr code */ +int +I2CReadByte( + int pTuner, + unsigned char NoUse, + unsigned char RegAddr, + unsigned char *pReadingByte + ) +{ + uint8_t data = RegAddr; + + if (rtl_i2c_write(E4K_I2C_ADDR, &data, 1) < 0) + return E4000_I2C_FAIL; + + if (rtl_i2c_read(E4K_I2C_ADDR, &data, 1) < 0) + return E4000_I2C_FAIL; + + *pReadingByte = data; + + return E4000_I2C_SUCCESS; +} + +int +I2CWriteByte( + int pTuner, + unsigned char NoUse, + unsigned char RegAddr, + unsigned char WritingByte + ) +{ + uint8_t data[2]; + + data[0] = RegAddr; + data[1] = WritingByte; + + if (rtl_i2c_write(E4K_I2C_ADDR, data, 2) < 0) + return E4000_I2C_FAIL; + + return E4000_I2C_SUCCESS; +} + +int +I2CWriteArray( + int pTuner, + unsigned char NoUse, + unsigned char RegStartAddr, + unsigned char ByteNum, + unsigned char *pWritingBytes + ) +{ + unsigned int i; + uint8_t WritingBuffer[I2C_BUFFER_LEN]; + + WritingBuffer[0] = RegStartAddr; + + for(i = 0; i < ByteNum; i++) + WritingBuffer[1 + i] = pWritingBytes[i]; + + if (rtl_i2c_write(E4K_I2C_ADDR, WritingBuffer, ByteNum + 1) < 0) + return E4000_I2C_FAIL; + + return E4000_I2C_SUCCESS; +} + +/** + +@see TUNER_FP_INITIALIZE + +*/ +int +e4000_Initialize( + int pTuner + ) +{ + + // Initialize tuner. + // Note: Call E4000 source code functions. + if(tunerreset(pTuner) != E4000_1_SUCCESS) + goto error_status_execute_function; + + if(Tunerclock(pTuner) != E4000_1_SUCCESS) + goto error_status_execute_function; + + if(Qpeak(pTuner) != E4000_1_SUCCESS) + goto error_status_execute_function; + + if(DCoffloop(pTuner) != E4000_1_SUCCESS) + goto error_status_execute_function; + + if(GainControlinit(pTuner) != E4000_1_SUCCESS) + goto error_status_execute_function; + + + return FUNCTION_SUCCESS; + + +error_status_execute_function: + return FUNCTION_ERROR; +} + +/** + +@see TUNER_FP_SET_RF_FREQ_HZ + +*/ +int +e4000_SetRfFreqHz( + int pTuner, + unsigned long RfFreqHz + ) +{ +// E4000_EXTRA_MODULE *pExtra; + + int RfFreqKhz; + int CrystalFreqKhz; + + int CrystalFreqHz = CRYSTAL_FREQ; + + // Set tuner RF frequency in KHz. + // Note: 1. RfFreqKhz = round(RfFreqHz / 1000) + // CrystalFreqKhz = round(CrystalFreqHz / 1000) + // 2. Call E4000 source code functions. + RfFreqKhz = (int)((RfFreqHz + 500) / 1000); + CrystalFreqKhz = (int)((CrystalFreqHz + 500) / 1000); + + if(Gainmanual(pTuner) != E4000_1_SUCCESS) + goto error_status_execute_function; + + if(E4000_gain_freq(pTuner, RfFreqKhz) != E4000_1_SUCCESS) + goto error_status_execute_function; + + if(PLL(pTuner, CrystalFreqKhz, RfFreqKhz) != E4000_1_SUCCESS) + goto error_status_execute_function; + + if(LNAfilter(pTuner, RfFreqKhz) != E4000_1_SUCCESS) + goto error_status_execute_function; + + if(freqband(pTuner, RfFreqKhz) != E4000_1_SUCCESS) + goto error_status_execute_function; + + if(DCoffLUT(pTuner) != E4000_1_SUCCESS) + goto error_status_execute_function; + + if(GainControlauto(pTuner) != E4000_1_SUCCESS) + goto error_status_execute_function; + + return FUNCTION_SUCCESS; + + +error_status_execute_function: + return FUNCTION_ERROR; +} + +/** + +@brief Set E4000 tuner bandwidth. + +*/ +int +e4000_SetBandwidthHz( + int pTuner, + unsigned long BandwidthHz + ) +{ +// E4000_EXTRA_MODULE *pExtra; + + int BandwidthKhz; + int CrystalFreqKhz; + + int CrystalFreqHz = CRYSTAL_FREQ; + + + // Get tuner extra module. +// pExtra = &(pTuner->Extra.E4000); + + + // Set tuner bandwidth Hz. + // Note: 1. BandwidthKhz = round(BandwidthHz / 1000) + // CrystalFreqKhz = round(CrystalFreqHz / 1000) + // 2. Call E4000 source code functions. + BandwidthKhz = (int)((BandwidthHz + 500) / 1000); + CrystalFreqKhz = (int)((CrystalFreqHz + 500) / 1000); + + if(IFfilter(pTuner, BandwidthKhz, CrystalFreqKhz) != E4000_1_SUCCESS) + goto error_status_execute_function; + + + return FUNCTION_SUCCESS; + +error_status_execute_function: + return FUNCTION_ERROR; +} + + +// The following context is source code provided by Elonics. + +// Elonics source code - E4000_API_rev2_04_realtek.cpp + + +//****************************************************************************/ +// +// Filename E4000_initialisation.c +// Revision 2.04 +// +// Description: +// Initialisation script for the Elonics E4000 revC tuner +// +// Copyright (c) Elonics Ltd +// +// Any software supplied free of charge for use with elonics +// evaluation kits is supplied without warranty and for +// evaluation purposes only. Incorporation of any of this +// code into products for open sale is permitted but only at +// the user's own risk. Elonics accepts no liability for the +// integrity of this software whatsoever. +// +// +//****************************************************************************/ +//#include +//#include +// +// User defined variable definitions +// +/* +int Ref_clk = 26000; // Reference clock frequency(kHz). +int Freq = 590000; // RF Frequency (kHz) +int bandwidth = 8000; //RF channel bandwith (kHz) +*/ +// +// API defined variable definitions +//int VCO_freq; +//unsigned char writearray[5]; +//unsigned char read1[1]; +//int status; +// +// +// function definitions +// +/* +int tunerreset (); +int Tunerclock(); +int filtercal(); +int Qpeak(); +int PLL(int Ref_clk, int Freq); +int LNAfilter(int Freq); +int IFfilter(int bandwidth, int Ref_clk); +int freqband(int Freq); +int DCoffLUT(); +int DCoffloop(); +int commonmode(); +int GainControlinit(); +*/ +// +//**************************************************************************** +// --- Public functions ------------------------------------------------------ +/****************************************************************************\ +* Function: tunerreset +* +* Detailed Description: +* The function resets the E4000 tuner. (Register 0x00). +* +\****************************************************************************/ + +int tunerreset(int pTuner) +{ + unsigned char writearray[5]; + int status; + + writearray[0] = 64; + // For dummy I2C command, don't check executing status. + status=I2CWriteByte (pTuner, 200,2,writearray[0]); + status=I2CWriteByte (pTuner, 200,2,writearray[0]); + //printf("\nRegister 0=%d", writearray[0]); + if(status != E4000_I2C_SUCCESS) + { + return E4000_1_FAIL; + } + + writearray[0] = 0; + status=I2CWriteByte (pTuner, 200,9,writearray[0]); + if(status != E4000_I2C_SUCCESS) + { + return E4000_1_FAIL; + } + + writearray[0] = 0; + status=I2CWriteByte (pTuner, 200,5,writearray[0]); + if(status != E4000_I2C_SUCCESS) + { + return E4000_1_FAIL; + } + + writearray[0] = 7; + status=I2CWriteByte (pTuner, 200,0,writearray[0]); + //printf("\nRegister 0=%d", writearray[0]); + if(status != E4000_I2C_SUCCESS) + { + return E4000_1_FAIL; + } + + return E4000_1_SUCCESS; +} +/****************************************************************************\ +* Function: Tunerclock +* +* Detailed Description: +* The function configures the E4000 clock. (Register 0x06, 0x7a). +* Function disables the clock - values can be modified to enable if required. +\****************************************************************************/ + +int Tunerclock(int pTuner) +{ + unsigned char writearray[5]; + int status; + + writearray[0] = 0; + status=I2CWriteByte(pTuner, 200,6,writearray[0]); + //printf("\nRegister 6=%d", writearray[0]); + if(status != E4000_I2C_SUCCESS) + { + return E4000_1_FAIL; + } + + writearray[0] = 150; + status=I2CWriteByte(pTuner, 200,122,writearray[0]); + //printf("\nRegister 7a=%d", writearray[0]); + //**Modify commands above with value required if output clock is required, + if(status != E4000_I2C_SUCCESS) + { + return E4000_1_FAIL; + } + + return E4000_1_SUCCESS; +} +/****************************************************************************\ +* Function: filtercal +* +* Detailed Description: +* Instructs RC filter calibration. (Register 0x7b). +* +\****************************************************************************/ +/* +int filtercal(int pTuner) +{ + //writearray[0] = 1; + //I2CWriteByte (pTuner, 200,123,writearray[0]); + //printf("\nRegister 7b=%d", writearray[0]); + //return; + return E4000_1_SUCCESS; +} +*/ +/****************************************************************************\ +* Function: Qpeak() +* +* Detailed Description: +* The function configures the E4000 gains. +* Also sigma delta controller. (Register 0x82). +* +\****************************************************************************/ + +int Qpeak(int pTuner) +{ + unsigned char writearray[5]; + int status; + + writearray[0] = 1; + writearray[1] = 254; + status=I2CWriteArray(pTuner, 200,126,2,writearray); + //printf("\nRegister 7e=%d", writearray[0]); + //printf("\nRegister 7f=%d", writearray[1]); + if(status != E4000_I2C_SUCCESS) + { + return E4000_1_FAIL; + } + + status=I2CWriteByte (pTuner, 200,130,0); + //printf("\nRegister 82=0"); + if(status != E4000_I2C_SUCCESS) + { + return E4000_1_FAIL; + } + + status=I2CWriteByte (pTuner, 200,36,5); + //printf("\nRegister 24=5"); + if(status != E4000_I2C_SUCCESS) + { + return E4000_1_FAIL; + } + + writearray[0] = 32; + writearray[1] = 1; + status=I2CWriteArray(pTuner, 200,135,2,writearray); + if(status != E4000_I2C_SUCCESS) + { + return E4000_1_FAIL; + } + + //printf("\nRegister 87=%d", writearray[0]); + //printf("\nRegister 88=%d", writearray[1]); + return E4000_1_SUCCESS; +} +/****************************************************************************\ +* Function: E4000_gain_freq() +* +* Detailed Description: +* The function configures the E4000 gains vs. freq +* 0xa3 to 0xa7. Also 0x24. +* +\****************************************************************************/ +int E4000_gain_freq(int pTuner, int Freq) +{ + unsigned char writearray[5]; + int status; + + if (Freq<=350000) + { + writearray[0] = 0x10; + writearray[1] = 0x42; + writearray[2] = 0x09; + writearray[3] = 0x21; + writearray[4] = 0x94; + } + else if(Freq>=1000000) + { + writearray[0] = 0x10; + writearray[1] = 0x42; + writearray[2] = 0x09; + writearray[3] = 0x21; + writearray[4] = 0x94; + } + else + { + writearray[0] = 0x10; + writearray[1] = 0x42; + writearray[2] = 0x09; + writearray[3] = 0x21; + writearray[4] = 0x94; + } + status=I2CWriteArray(pTuner, 200,163,5,writearray); + if(status != E4000_I2C_SUCCESS) + { + return E4000_1_FAIL; + } + + if (Freq<=350000) + { + writearray[0] = 94; + writearray[1] = 6; + status=I2CWriteArray(pTuner, 200,159,2,writearray); + if(status != E4000_I2C_SUCCESS) + { + return E4000_1_FAIL; + } + + writearray[0] = 0; + status=I2CWriteArray(pTuner, 200,136,1,writearray); + if(status != E4000_I2C_SUCCESS) + { + return E4000_1_FAIL; + } + } + else + { + writearray[0] = 127; + writearray[1] = 7; + status=I2CWriteArray(pTuner, 200,159,2,writearray); + if(status != E4000_I2C_SUCCESS) + { + return E4000_1_FAIL; + } + + writearray[0] = 1; + status=I2CWriteArray(pTuner, 200,136,1,writearray); + if(status != E4000_I2C_SUCCESS) + { + return E4000_1_FAIL; + } + } + + //printf("\nRegister 9f=%d", writearray[0]); + //printf("\nRegister a0=%d", writearray[1]); + return E4000_1_SUCCESS; +} +/****************************************************************************\ +* Function: DCoffloop +* +* Detailed Description: +* Populates DC offset LUT. (Registers 0x2d, 0x70, 0x71). +* Turns on DC offset LUT and time varying DC offset. +\****************************************************************************/ +int DCoffloop(int pTuner) +{ + unsigned char writearray[5]; + int status; + + //writearray[0]=0; + //I2CWriteByte(pTuner, 200,115,writearray[0]); + //printf("\nRegister 73=%d", writearray[0]); + writearray[0] = 31; + status=I2CWriteByte(pTuner, 200,45,writearray[0]); + //printf("\nRegister 2d=%d", writearray[0]); + if(status != E4000_I2C_SUCCESS) + { + return E4000_1_FAIL; + } + + writearray[0] = 1; + writearray[1] = 1; + status=I2CWriteArray(pTuner, 200,112,2,writearray); + //printf("\nRegister 70=%d", writearray[0]); + //printf("\nRegister 71=%d", writearray[0]); + if(status != E4000_I2C_SUCCESS) + { + return E4000_1_FAIL; + } + + return E4000_1_SUCCESS; +} +/****************************************************************************\ +* Function: commonmode +* +* Detailed Description: +* Configures common mode voltage. (Registers 0x2f). +* +\****************************************************************************/ +/* +int commonmode(int pTuner) +{ + //writearray[0] = 0; + //I2CWriteByte(Device_address,47,writearray[0]); + //printf("\nRegister 0x2fh = %d", writearray[0]); + // Sets 550mV. Modify if alternative is desired. + return E4000_1_SUCCESS; +} +*/ +/****************************************************************************\ +* Function: GainControlinit +* +* Detailed Description: +* Configures gain control mode. (Registers 0x1d, 0x1e, 0x1f, 0x20, 0x21, +* 0x1a, 0x74h, 0x75h). +* User may wish to modify values depending on usage scenario. +* Routine configures LNA: autonomous gain control +* IF PWM gain control. +* PWM thresholds = default +* Mixer: switches when LNA gain =7.5dB +* Sensitivity / Linearity mode: manual switch +* +\****************************************************************************/ +int GainControlinit(int pTuner) +{ + unsigned char writearray[5]; + unsigned char read1[1]; + int status; + + unsigned char sum=255; + + writearray[0] = 23; + status=I2CWriteByte(pTuner, 200,26,writearray[0]); + if(status != E4000_I2C_SUCCESS) + { + return E4000_1_FAIL; + } + //printf("\nRegister 1a=%d", writearray[0]); + + status=I2CReadByte(pTuner, 201,27,read1); + if(status != E4000_I2C_SUCCESS) + { + return E4000_1_FAIL; + } + + writearray[0] = 16; + writearray[1] = 4; + writearray[2] = 26; + writearray[3] = 15; + writearray[4] = 167; + status=I2CWriteArray(pTuner, 200,29,5,writearray); + //printf("\nRegister 1d=%d", writearray[0]); + if(status != E4000_I2C_SUCCESS) + { + return E4000_1_FAIL; + } + + writearray[0] = 81; + status=I2CWriteByte(pTuner, 200,134,writearray[0]); + if(status != E4000_I2C_SUCCESS) + { + return E4000_1_FAIL; + } + //printf("\nRegister 86=%d", writearray[0]); + + //For Realtek - gain control logic + status=I2CReadByte(pTuner, 201,27,read1); + if(status != E4000_I2C_SUCCESS) + { + return E4000_1_FAIL; + } + + if(read1[0]<=sum) + { + sum=read1[0]; + } + + status=I2CWriteByte(pTuner, 200,31,writearray[2]); + if(status != E4000_I2C_SUCCESS) + { + return E4000_1_FAIL; + } + status=I2CReadByte(pTuner, 201,27,read1); + if(status != E4000_I2C_SUCCESS) + { + return E4000_1_FAIL; + } + + if(read1[0] <= sum) + { + sum=read1[0]; + } + + status=I2CWriteByte(pTuner, 200,31,writearray[2]); + if(status != E4000_I2C_SUCCESS) + { + return E4000_1_FAIL; + } + + status=I2CReadByte(pTuner, 201,27,read1); + if(status != E4000_I2C_SUCCESS) + { + return E4000_1_FAIL; + } + + if(read1[0] <= sum) + { + sum=read1[0]; + } + + status=I2CWriteByte(pTuner, 200,31,writearray[2]); + if(status != E4000_I2C_SUCCESS) + { + return E4000_1_FAIL; + } + + status=I2CReadByte(pTuner, 201,27,read1); + if(status != E4000_I2C_SUCCESS) + { + return E4000_1_FAIL; + } + + if(read1[0] <= sum) + { + sum=read1[0]; + } + + status=I2CWriteByte(pTuner, 200,31,writearray[2]); + if(status != E4000_I2C_SUCCESS) + { + return E4000_1_FAIL; + } + + status=I2CReadByte(pTuner, 201,27,read1); + if(status != E4000_I2C_SUCCESS) + { + return E4000_1_FAIL; + } + + if (read1[0]<=sum) + { + sum=read1[0]; + } + + writearray[0]=sum; + status=I2CWriteByte(pTuner, 200,27,writearray[0]); + if(status != E4000_I2C_SUCCESS) + { + return E4000_1_FAIL; + } + //printf("\nRegister 1b=%d", writearray[0]); + //printf("\nRegister 1e=%d", writearray[1]); + //printf("\nRegister 1f=%d", writearray[2]); + //printf("\nRegister 20=%d", writearray[3]); + //printf("\nRegister 21=%d", writearray[4]); + //writearray[0] = 3; + //writearray[1] = 252; + //writearray[2] = 3; + //writearray[3] = 252; + //I2CWriteArray(pTuner, 200,116,4,writearray); + //printf("\nRegister 74=%d", writearray[0]); + //printf("\nRegister 75=%d", writearray[1]); + //printf("\nRegister 76=%d", writearray[2]); + //printf("\nRegister 77=%d", writearray[3]); + + return E4000_1_SUCCESS; +} + +/****************************************************************************\ +* Main program +* +* +* +\****************************************************************************/ +/* +int main() +{ + tunerreset (); + Tunerclock(); + //filtercal(); + Qpeak(); + //PLL(Ref_clk, Freq); + //LNAfilter(Freq); + //IFfilter(bandwidth, Ref_clk); + //freqband(Freq); + //DCoffLUT(); + DCoffloop(); + //commonmode(); + GainControlinit(); +// system("PAUSE"); + return(0); +} +*/ + + +// Elonics source code - frequency_change_rev2.04_realtek.c + + +//****************************************************************************/ +// +// Filename E4000_freqchangerev2.04.c +// Revision 2.04 +// +// Description: +// Frequency change script for the Elonics E4000 revB tuner +// +// Copyright (c) Elonics Ltd +// +// Any software supplied free of charge for use with elonics +// evaluation kits is supplied without warranty and for +// evaluation purposes only. Incorporation of any of this +// code into products for open sale is permitted but only at +// the user's own risk. Elonics accepts no liability for the +// integrity of this software whatsoever. +// +// +//****************************************************************************/ +//#include +//#include +// +// User defined variable definitions +// +/* +int Ref_clk = 20000; // Reference clock frequency(kHz). +int Freq = 590000; // RF Frequency (kHz) +int bandwidth = 8; //RF channel bandwith (MHz) +*/ +// +// API defined variable definitions +//int VCO_freq; +//unsigned char writearray[5]; +//unsigned char read1[1]; +//int E4000_1_SUCCESS; +//int E4000_1_FAIL; +//int E4000_I2C_SUCCESS; +//int status; +// +// +// function definitions +// +/* +int Gainmanual(); +int PLL(int Ref_clk, int Freq); +int LNAfilter(int Freq); +int IFfilter(int bandwidth, int Ref_clk); +int freqband(int Freq); +int DCoffLUT(); +int GainControlauto(); +*/ +// +//**************************************************************************** +// --- Public functions ------------------------------------------------------ +/****************************************************************************\ +//****************************************************************************\ +* Function: Gainmanual +* +* Detailed Description: +* Sets Gain control to serial interface control. +* +\****************************************************************************/ +int Gainmanual(int pTuner) +{ + unsigned char writearray[5]; + int status; + + writearray[0]=0; + status=I2CWriteByte(pTuner, 200,26,writearray[0]); + //printf("\nRegister 1a=%d", writearray[0]); + if(status != E4000_I2C_SUCCESS) + { + return E4000_1_FAIL; + } + + writearray[0] = 0; + status=I2CWriteByte (pTuner, 200,9,writearray[0]); + if(status != E4000_I2C_SUCCESS) + { + return E4000_1_FAIL; + } + + writearray[0] = 0; + status=I2CWriteByte (pTuner, 200,5,writearray[0]); + if(status != E4000_I2C_SUCCESS) + { + return E4000_1_FAIL; + } + + return E4000_1_SUCCESS; +} + +/****************************************************************************\ +* Function: PLL +* +* Detailed Description: +* Configures E4000 PLL divider & sigma delta. 0x0d,0x09, 0x0a, 0x0b). +* +\****************************************************************************/ +int PLL(int pTuner, int Ref_clk, int Freq) +{ + int VCO_freq; + unsigned char writearray[5]; + int status; + + unsigned char divider; + int intVCOfreq; + int SigDel; + int SigDel2; + int SigDel3; +// int harmonic_freq; +// int offset; + + if (Freq<=72400) + { + writearray[4] = 15; + VCO_freq=Freq*48; + } + else if (Freq<=81200) + { + writearray[4] = 14; + VCO_freq=Freq*40; + } + else if (Freq<=108300) + { + writearray[4]=13; + VCO_freq=Freq*32; + } + else if (Freq<=162500) + { + writearray[4]=12; + VCO_freq=Freq*24; + } + else if (Freq<=216600) + { + writearray[4]=11; + VCO_freq=Freq*16; + } + else if (Freq<=325000) + { + writearray[4]=10; + VCO_freq=Freq*12; + } + else if (Freq<=350000) + { + writearray[4]=9; + VCO_freq=Freq*8; + } + else if (Freq<=432000) + { + writearray[4]=3; + VCO_freq=Freq*8; + } + else if (Freq<=667000) + { + writearray[4]=2; + VCO_freq=Freq*6; + } + else if (Freq<=1200000) + { + writearray[4]=1; + VCO_freq=Freq*4; + } + else + { + writearray[4]=0; + VCO_freq=Freq*2; + } + + //printf("\nVCOfreq=%d", VCO_freq); +// divider = VCO_freq * 1000 / Ref_clk; + divider = VCO_freq / Ref_clk; + //printf("\ndivider=%d", divider); + writearray[0]= divider; +// intVCOfreq = divider * Ref_clk /1000; + intVCOfreq = divider * Ref_clk; + //printf("\ninteger VCO freq=%d", intVCOfreq); +// SigDel=65536 * 1000 * (VCO_freq - intVCOfreq) / Ref_clk; + SigDel=65536 * (VCO_freq - intVCOfreq) / Ref_clk; + //printf("\nSigma delta=%d", SigDel); + if (SigDel<=1024) + { + SigDel = 1024; + } + else if (SigDel>=64512) + { + SigDel=64512; + } + SigDel2 = SigDel / 256; + //printf("\nSigdel2=%d", SigDel2); + writearray[2] = (unsigned char)SigDel2; + SigDel3 = SigDel - (256 * SigDel2); + //printf("\nSig del3=%d", SigDel3); + writearray[1]= (unsigned char)SigDel3; + writearray[3]=(unsigned char)0; + status=I2CWriteArray(pTuner, 200,9,5,writearray); + //printf("\nRegister 9=%d", writearray[0]); + //printf("\nRegister a=%d", writearray[1]); + //printf("\nRegister b=%d", writearray[2]); + //printf("\nRegister d=%d", writearray[4]); + if(status != E4000_I2C_SUCCESS) + { + return E4000_1_FAIL; + } + + if (Freq<=82900) + { + writearray[0]=0; + writearray[2]=1; + } + else if (Freq<=89900) + { + writearray[0]=3; + writearray[2]=9; + } + else if (Freq<=111700) + { + writearray[0]=0; + writearray[2]=1; + } + else if (Freq<=118700) + { + writearray[0]=3; + writearray[2]=1; + } + else if (Freq<=140500) + { + writearray[0]=0; + writearray[2]=3; + } + else if (Freq<=147500) + { + writearray[0]=3; + writearray[2]=11; + } + else if (Freq<=169300) + { + writearray[0]=0; + writearray[2]=3; + } + else if (Freq<=176300) + { + writearray[0]=3; + writearray[2]=11; + } + else if (Freq<=198100) + { + writearray[0]=0; + writearray[2]=3; + } + else if (Freq<=205100) + { + writearray[0]=3; + writearray[2]=19; + } + else if (Freq<=226900) + { + writearray[0]=0; + writearray[2]=3; + } + else if (Freq<=233900) + { + writearray[0]=3; + writearray[2]=3; + } + else if (Freq<=350000) + { + writearray[0]=0; + writearray[2]=3; + } + else if (Freq<=485600) + { + writearray[0]=0; + writearray[2]=5; + } + else if (Freq<=493600) + { + writearray[0]=3; + writearray[2]=5; + } + else if (Freq<=514400) + { + writearray[0]=0; + writearray[2]=5; + } + else if (Freq<=522400) + { + writearray[0]=3; + writearray[2]=5; + } + else if (Freq<=543200) + { + writearray[0]=0; + writearray[2]=5; + } + else if (Freq<=551200) + { + writearray[0]=3; + writearray[2]=13; + } + else if (Freq<=572000) + { + writearray[0]=0; + writearray[2]=5; + } + else if (Freq<=580000) + { + writearray[0]=3; + writearray[2]=13; + } + else if (Freq<=600800) + { + writearray[0]=0; + writearray[2]=5; + } + else if (Freq<=608800) + { + writearray[0]=3; + writearray[2]=13; + } + else if (Freq<=629600) + { + writearray[0]=0; + writearray[2]=5; + } + else if (Freq<=637600) + { + writearray[0]=3; + writearray[2]=13; + } + else if (Freq<=658400) + { + writearray[0]=0; + writearray[2]=5; + } + else if (Freq<=666400) + { + writearray[0]=3; + writearray[2]=13; + } + else if (Freq<=687200) + { + writearray[0]=0; + writearray[2]=5; + } + else if (Freq<=695200) + { + writearray[0]=3; + writearray[2]=13; + } + else if (Freq<=716000) + { + writearray[0]=0; + writearray[2]=5; + } + else if (Freq<=724000) + { + writearray[0]=3; + writearray[2]=13; + } + else if (Freq<=744800) + { + writearray[0]=0; + writearray[2]=5; + } + else if (Freq<=752800) + { + writearray[0]=3; + writearray[2]=21; + } + else if (Freq<=773600) + { + writearray[0]=0; + writearray[2]=5; + } + else if (Freq<=781600) + { + writearray[0]=3; + writearray[2]=21; + } + else if (Freq<=802400) + { + writearray[0]=0; + writearray[2]=5; + } + else if (Freq<=810400) + { + writearray[0]=3; + writearray[2]=21; + } + else if (Freq<=831200) + { + writearray[0]=0; + writearray[2]=5; + } + else if (Freq<=839200) + { + writearray[0]=3; + writearray[2]=21; + } + else if (Freq<=860000) + { + writearray[0]=0; + writearray[2]=5; + } + else if (Freq<=868000) + { + writearray[0]=3; + writearray[2]=21; + } + else + { + writearray[0]=0; + writearray[2]=7; + } + + status=I2CWriteByte (pTuner, 200,7,writearray[2]); + if(status != E4000_I2C_SUCCESS) + { + return E4000_1_FAIL; + } + + status=I2CWriteByte (pTuner, 200,5,writearray[0]); + if(status != E4000_I2C_SUCCESS) + { + return E4000_1_FAIL; + } + + return E4000_1_SUCCESS; +} + +/****************************************************************************\ +* Function: LNAfilter +* +* Detailed Description: +* The function configures the E4000 LNA filter. (Register 0x10). +* +\****************************************************************************/ + +int LNAfilter(int pTuner, int Freq) +{ + unsigned char writearray[5]; + int status; + + if(Freq<=370000) + { + writearray[0]=0; + } + else if(Freq<=392500) + { + writearray[0]=1; + } + else if(Freq<=415000) + { + writearray[0] =2; + } + else if(Freq<=437500) + { + writearray[0]=3; + } + else if(Freq<=462500) + { + writearray[0]=4; + } + else if(Freq<=490000) + { + writearray[0]=5; + } + else if(Freq<=522500) + { + writearray[0]=6; + } + else if(Freq<=557500) + { + writearray[0]=7; + } + else if(Freq<=595000) + { + writearray[0]=8; + } + else if(Freq<=642500) + { + writearray[0]=9; + } + else if(Freq<=695000) + { + writearray[0]=10; + } + else if(Freq<=740000) + { + writearray[0]=11; + } + else if(Freq<=800000) + { + writearray[0]=12; + } + else if(Freq<=865000) + { + writearray[0] =13; + } + else if(Freq<=930000) + { + writearray[0]=14; + } + else if(Freq<=1000000) + { + writearray[0]=15; + } + else if(Freq<=1310000) + { + writearray[0]=0; + } + else if(Freq<=1340000) + { + writearray[0]=1; + } + else if(Freq<=1385000) + { + writearray[0]=2; + } + else if(Freq<=1427500) + { + writearray[0]=3; + } + else if(Freq<=1452500) + { + writearray[0]=4; + } + else if(Freq<=1475000) + { + writearray[0]=5; + } + else if(Freq<=1510000) + { + writearray[0]=6; + } + else if(Freq<=1545000) + { + writearray[0]=7; + } + else if(Freq<=1575000) + { + writearray[0] =8; + } + else if(Freq<=1615000) + { + writearray[0]=9; + } + else if(Freq<=1650000) + { + writearray[0] =10; + } + else if(Freq<=1670000) + { + writearray[0]=11; + } + else if(Freq<=1690000) + { + writearray[0]=12; + } + else if(Freq<=1710000) + { + writearray[0]=13; + } + else if(Freq<=1735000) + { + writearray[0]=14; + } + else + { + writearray[0]=15; + } + status=I2CWriteByte (pTuner, 200,16,writearray[0]); + //printf("\nRegister 10=%d", writearray[0]); + if(status != E4000_I2C_SUCCESS) + { + return E4000_1_FAIL; + } + + return E4000_1_SUCCESS; +} +/****************************************************************************\ +* Function: IFfilter +* +* Detailed Description: +* The function configures the E4000 IF filter. (Register 0x11,0x12). +* +\****************************************************************************/ +int IFfilter(int pTuner, int bandwidth, int Ref_clk) +{ + unsigned char writearray[5]; + int status; + + int IF_BW; + + IF_BW = bandwidth / 2; + if(IF_BW<=2150) + { + writearray[0]=253; + writearray[1]=31; + } + else if(IF_BW<=2200) + { + writearray[0]=253; + writearray[1]=30; + } + else if(IF_BW<=2240) + { + writearray[0]=252; + writearray[1]=29; + } + else if(IF_BW<=2280) + { + writearray[0]=252; + writearray[1]=28; + } + else if(IF_BW<=2300) + { + writearray[0]=252; + writearray[1]=27; + } + else if(IF_BW<=2400) + { + writearray[0]=252; + writearray[1]=26; + } + else if(IF_BW<=2450) + { + writearray[0]=252; + writearray[1]=25; + } + else if(IF_BW<=2500) + { + writearray[0]=252; + writearray[1]=24; + } + else if(IF_BW<=2550) + { + writearray[0]=252; + writearray[1]=23; + } + else if(IF_BW<=2600) + { + writearray[0]=252; + writearray[1]=22; + } + else if(IF_BW<=2700) + { + writearray[0]=252; + writearray[1]=21; + } + else if(IF_BW<=2750) + { + writearray[0]=252; + writearray[1]=20; + } + else if(IF_BW<=2800) + { + writearray[0]=252; + writearray[1]=19; + } + else if(IF_BW<=2900) + { + writearray[0]=251; + writearray[1]=18; + } + else if(IF_BW<=2950) + { + writearray[0]=251; + writearray[1]=17; + } + else if(IF_BW<=3000) + { + writearray[0]=251; + writearray[1]=16; + } + else if(IF_BW<=3100) + { + writearray[0]=251; + writearray[1]=15; + } + else if(IF_BW<=3200) + { + writearray[0]=250; + writearray[1]=14; + } + else if(IF_BW<=3300) + { + writearray[0]=250; + writearray[1]=13; + } + else if(IF_BW<=3400) + { + writearray[0]=249; + writearray[1]=12; + } + else if(IF_BW<=3600) + { + writearray[0]=249; + writearray[1]=11; + } + else if(IF_BW<=3700) + { + writearray[0]=249; + writearray[1]=10; + } + else if(IF_BW<=3800) + { + writearray[0]=248; + writearray[1]=9; + } + else if(IF_BW<=3900) + { + writearray[0]=248; + writearray[1]=8; + } + else if(IF_BW<=4100) + { + writearray[0]=248; + writearray[1]=7; + } + else if(IF_BW<=4300) + { + writearray[0]=247; + writearray[1]=6; + } + else if(IF_BW<=4400) + { + writearray[0]=247; + writearray[1]=5; + } + else if(IF_BW<=4600) + { + writearray[0]=247; + writearray[1]=4; + } + else if(IF_BW<=4800) + { + writearray[0]=246; + writearray[1]=3; + } + else if(IF_BW<=5000) + { + writearray[0]=246; + writearray[1]=2; + } + else if(IF_BW<=5300) + { + writearray[0]=245; + writearray[1]=1; + } + else if(IF_BW<=5500) + { + writearray[0]=245; + writearray[1]=0; + } + else + { + writearray[0]=0; + writearray[1]=32; + } + status=I2CWriteArray(pTuner, 200,17,2,writearray); + //printf("\nRegister 11=%d", writearray[0]); + //printf("\nRegister 12=%d", writearray[1]); + if(status != E4000_I2C_SUCCESS) + { + return E4000_1_FAIL; + } + + return E4000_1_SUCCESS; +} +/****************************************************************************\ +* Function: freqband +* +* Detailed Description: +* Configures the E4000 frequency band. (Registers 0x07, 0x78). +* +\****************************************************************************/ +int freqband(int pTuner, int Freq) +{ + unsigned char writearray[5]; + int status; + + if (Freq<=140000) + { + writearray[0] = 3; + status=I2CWriteByte(pTuner, 200,120,writearray[0]); + if(status != E4000_I2C_SUCCESS) + { + return E4000_1_FAIL; + } + } + else if (Freq<=350000) + { + writearray[0] = 3; + status=I2CWriteByte(pTuner, 200,120,writearray[0]); + if(status != E4000_I2C_SUCCESS) + { + return E4000_1_FAIL; + } + } + else if (Freq<=1000000) + { + writearray[0] = 3; + status=I2CWriteByte(pTuner, 200,120,writearray[0]); + if(status != E4000_I2C_SUCCESS) + { + return E4000_1_FAIL; + } + } + else + { + writearray[0] = 7; + status=I2CWriteByte(pTuner, 200,7,writearray[0]); + if(status != E4000_I2C_SUCCESS) + { + return E4000_1_FAIL; + } + + writearray[0] = 0; + status=I2CWriteByte(pTuner, 200,120,writearray[0]); + if(status != E4000_I2C_SUCCESS) + { + return E4000_1_FAIL; + } + } + + return E4000_1_SUCCESS; +} +/****************************************************************************\ +* Function: DCoffLUT +* +* Detailed Description: +* Populates DC offset LUT. (Registers 0x50 - 0x53, 0x60 - 0x63). +* +\****************************************************************************/ +int DCoffLUT(int pTuner) +{ + unsigned char writearray[5]; + int status; + + unsigned char read1[1]; + unsigned char IOFF; + unsigned char QOFF; + unsigned char RANGE1; +// unsigned char RANGE2; + unsigned char QRANGE; + unsigned char IRANGE; + writearray[0] = 0; + writearray[1] = 126; + writearray[2] = 36; + status=I2CWriteArray(pTuner, 200,21,3,writearray); + if(status != E4000_I2C_SUCCESS) + { + return E4000_1_FAIL; + } + + // Sets mixer & IF stage 1 gain = 00 and IF stg 2+ to max gain. + writearray[0] = 1; + status=I2CWriteByte(pTuner, 200,41,writearray[0]); + // Instructs a DC offset calibration. + status=I2CReadByte(pTuner, 201,42,read1); + if(status != E4000_I2C_SUCCESS) + { + return E4000_1_FAIL; + } + + IOFF=read1[0]; + status=I2CReadByte(pTuner, 201,43,read1); + if(status != E4000_I2C_SUCCESS) + { + return E4000_1_FAIL; + } + + QOFF=read1[0]; + status=I2CReadByte(pTuner, 201,44,read1); + if(status != E4000_I2C_SUCCESS) + { + return E4000_1_FAIL; + } + + RANGE1=read1[0]; + //reads DC offset values back + if(RANGE1>=32) + { + RANGE1 = RANGE1 -32; + } + if(RANGE1>=16) + { + RANGE1 = RANGE1 - 16; + } + IRANGE=RANGE1; + QRANGE = (read1[0] - RANGE1) / 16; + + writearray[0] = (IRANGE * 64) + IOFF; + status=I2CWriteByte(pTuner, 200,96,writearray[0]); + if(status != E4000_I2C_SUCCESS) + { + return E4000_1_FAIL; + } + + writearray[0] = (QRANGE * 64) + QOFF; + status=I2CWriteByte(pTuner, 200,80,writearray[0]); + if(status != E4000_I2C_SUCCESS) + { + return E4000_1_FAIL; + } + + // Populate DC offset LUT + writearray[0] = 0; + writearray[1] = 127; + status=I2CWriteArray(pTuner, 200,21,2,writearray); + if(status != E4000_I2C_SUCCESS) + { + return E4000_1_FAIL; + } + + // Sets mixer & IF stage 1 gain = 01 leaving IF stg 2+ at max gain. + writearray[0]= 1; + status=I2CWriteByte(pTuner, 200,41,writearray[0]); + if(status != E4000_I2C_SUCCESS) + { + return E4000_1_FAIL; + } + + // Instructs a DC offset calibration. + status=I2CReadByte(pTuner, 201,42,read1); + if(status != E4000_I2C_SUCCESS) + { + return E4000_1_FAIL; + } + + IOFF=read1[0]; + status=I2CReadByte(pTuner, 201,43,read1); + if(status != E4000_I2C_SUCCESS) + { + return E4000_1_FAIL; + } + + QOFF=read1[0]; + status=I2CReadByte(pTuner, 201,44,read1); + if(status != E4000_I2C_SUCCESS) + { + return E4000_1_FAIL; + } + + RANGE1=read1[0]; + // Read DC offset values + if(RANGE1>=32) + { + RANGE1 = RANGE1 -32; + } + if(RANGE1>=16) + { + RANGE1 = RANGE1 - 16; + } + IRANGE = RANGE1; + QRANGE = (read1[0] - RANGE1) / 16; + + writearray[0] = (IRANGE * 64) + IOFF; + status=I2CWriteByte(pTuner, 200,97,writearray[0]); + if(status != E4000_I2C_SUCCESS) + { + return E4000_1_FAIL; + } + + writearray[0] = (QRANGE * 64) + QOFF; + status=I2CWriteByte(pTuner, 200,81,writearray[0]); + if(status != E4000_I2C_SUCCESS) + { + return E4000_1_FAIL; + } + + // Populate DC offset LUT + writearray[0] = 1; + status=I2CWriteByte(pTuner, 200,21,writearray[0]); + if(status != E4000_I2C_SUCCESS) + { + return E4000_1_FAIL; + } + + // Sets mixer & IF stage 1 gain = 11 leaving IF stg 2+ at max gain. + writearray[0] = 1; + status=I2CWriteByte(pTuner, 200,41,writearray[0]); + if(status != E4000_I2C_SUCCESS) + { + return E4000_1_FAIL; + } + + // Instructs a DC offset calibration. + status=I2CReadByte(pTuner, 201,42,read1); + if(status != E4000_I2C_SUCCESS) + { + return E4000_1_FAIL; + } + + IOFF=read1[0]; + status=I2CReadByte(pTuner, 201,43,read1); + if(status != E4000_I2C_SUCCESS) + { + return E4000_1_FAIL; + } + + QOFF=read1[0]; + status=I2CReadByte(pTuner, 201,44,read1); + if(status != E4000_I2C_SUCCESS) + { + return E4000_1_FAIL; + } + + RANGE1 = read1[0]; + // Read DC offset values + if(RANGE1>=32) + { + RANGE1 = RANGE1 -32; + } + if(RANGE1>=16) + { + RANGE1 = RANGE1 - 16; + } + IRANGE = RANGE1; + QRANGE = (read1[0] - RANGE1) / 16; + writearray[0] = (IRANGE * 64) + IOFF; + status=I2CWriteByte(pTuner, 200,99,writearray[0]); + if(status != E4000_I2C_SUCCESS) + { + return E4000_1_FAIL; + } + + writearray[0] = (QRANGE * 64) + QOFF; + status=I2CWriteByte(pTuner, 200,83,writearray[0]); + if(status != E4000_I2C_SUCCESS) + { + return E4000_1_FAIL; + } + + // Populate DC offset LUT + writearray[0] = 126; + status=I2CWriteByte(pTuner, 200,22,writearray[0]); + if(status != E4000_I2C_SUCCESS) + { + return E4000_1_FAIL; + } + + // Sets mixer & IF stage 1 gain = 11 leaving IF stg 2+ at max gain. + writearray[0] = 1; + status=I2CWriteByte(pTuner, 200,41,writearray[0]); + if(status != E4000_I2C_SUCCESS) + { + return E4000_1_FAIL; + } + + // Instructs a DC offset calibration. + status=I2CReadByte(pTuner, 201,42,read1); + if(status != E4000_I2C_SUCCESS) + { + return E4000_1_FAIL; + } + IOFF=read1[0]; + + status=I2CReadByte(pTuner, 201,43,read1); + if(status != E4000_I2C_SUCCESS) + { + return E4000_1_FAIL; + } + QOFF=read1[0]; + + status=I2CReadByte(pTuner, 201,44,read1); + if(status != E4000_I2C_SUCCESS) + { + return E4000_1_FAIL; + } + RANGE1=read1[0]; + + // Read DC offset values + if(RANGE1>=32) + { + RANGE1 = RANGE1 -32; + } + if(RANGE1>=16) + { + RANGE1 = RANGE1 - 16; + } + IRANGE = RANGE1; + QRANGE = (read1[0] - RANGE1) / 16; + + writearray[0]=(IRANGE * 64) + IOFF; + status=I2CWriteByte(pTuner, 200,98,writearray[0]); + if(status != E4000_I2C_SUCCESS) + { + return E4000_1_FAIL; + } + + writearray[0] = (QRANGE * 64) + QOFF; + status=I2CWriteByte(pTuner, 200,82,writearray[0]); + // Populate DC offset LUT + if(status != E4000_I2C_SUCCESS) + { + return E4000_1_FAIL; + } + + return E4000_1_SUCCESS; +} +/****************************************************************************\ +* Function: GainControlinit +* +* Detailed Description: +* Configures gain control mode. (Registers 0x1a) +* +\****************************************************************************/ +int GainControlauto(int pTuner) +{ + unsigned char writearray[5]; + int status; + + writearray[0] = 23; + status=I2CWriteByte(pTuner, 200,26,writearray[0]); + if(status != E4000_I2C_SUCCESS) + { + return E4000_1_FAIL; + } + + return E4000_1_SUCCESS; +} +/****************************************************************************\ +* Main program +* +* +* +\****************************************************************************/ +/* +int main() +{ + Gainmanual(); + PLL(Ref_clk, Freq); + LNAfilter(Freq); + IFfilter(bandwidth, Ref_clk); + freqband(Freq); + DCoffLUT(); + GainControlauto(); + return(0); +} +*/ + +// Elonics source code - RT2832_SW_optimisation_rev2.c + + + +/****************************************************************************\ +* Function: E4000_sensitivity +* +* Detailed Description: +* The function configures the E4000 for sensitivity mode. +* +\****************************************************************************/ + +int E4000_sensitivity(int pTuner, int Freq, int bandwidth) +{ + unsigned char writearray[2]; + int status; + int IF_BW; + + writearray[1]=0x00; + + if(Freq<=700000) + { + writearray[0] = 0x07; + } + else + { + writearray[0] = 0x05; + } + status = I2CWriteArray(pTuner,200,36,1,writearray); + if(status != E4000_I2C_SUCCESS) + { + return E4000_1_FAIL; + } + + IF_BW = bandwidth / 2; + if(IF_BW<=2500) + { + writearray[0]=0xfc; + writearray[1]=0x17; + } + else if(IF_BW<=3000) + { + writearray[0]=0xfb; + writearray[1]=0x0f; + } + else if(IF_BW<=3500) + { + writearray[0]=0xf9; + writearray[1]=0x0b; + } + else if(IF_BW<=4000) + { + writearray[0]=0xf8; + writearray[1]=0x07; + } + status = I2CWriteArray(pTuner,200,17,2,writearray); + if(status != E4000_I2C_SUCCESS) + { + return E4000_1_FAIL; + } + + return E4000_1_SUCCESS; +} +/****************************************************************************\ +* Function: E4000_linearity +* +* Detailed Description: +* The function configures the E4000 for linearity mode. +* +\****************************************************************************/ +int E4000_linearity(int pTuner, int Freq, int bandwidth) +{ + + unsigned char writearray[2]; + int status; + int IF_BW; + + writearray[1]=0x00; + + if(Freq<=700000) + { + writearray[0] = 0x03; + } + else + { + writearray[0] = 0x01; + } + status = I2CWriteArray(pTuner,200,36,1,writearray); + if(status != E4000_I2C_SUCCESS) + { + return E4000_1_FAIL; + } + + IF_BW = bandwidth / 2; + if(IF_BW<=2500) + { + writearray[0]=0xfe; + writearray[1]=0x19; + } + else if(IF_BW<=3000) + { + writearray[0]=0xfd; + writearray[1]=0x11; + } + else if(IF_BW<=3500) + { + writearray[0]=0xfb; + writearray[1]=0x0d; + } + else if(IF_BW<=4000) + { + writearray[0]=0xfa; + writearray[1]=0x0a; + } + status = I2CWriteArray(pTuner,200,17,2,writearray); + if(status != E4000_I2C_SUCCESS) + { + return E4000_1_FAIL; + } + + return E4000_1_SUCCESS; +} +/****************************************************************************\ +* Function: E4000_nominal +* +* Detailed Description: +* The function configures the E4000 for nominal +* +\****************************************************************************/ +int E4000_nominal(int pTuner, int Freq, int bandwidth) +{ + unsigned char writearray[2]; + int status; + int IF_BW; + + writearray[1]=0x00; + + if(Freq<=700000) + { + writearray[0] = 0x03; + } + else + { + writearray[0] = 0x01; + } + status = I2CWriteArray(pTuner,200,36,1,writearray); + if(status != E4000_I2C_SUCCESS) + { + return E4000_1_FAIL; + } + + IF_BW = bandwidth / 2; + if(IF_BW<=2500) + { + writearray[0]=0xfc; + writearray[1]=0x17; + } + else if(IF_BW<=3000) + { + writearray[0]=0xfb; + writearray[1]=0x0f; + } + else if(IF_BW<=3500) + { + writearray[0]=0xf9; + writearray[1]=0x0b; + } + else if(IF_BW<=4000) + { + writearray[0]=0xf8; + writearray[1]=0x07; + } + status = I2CWriteArray(pTuner,200,17,2,writearray); + if(status != E4000_I2C_SUCCESS) + { + return E4000_1_FAIL; + } + + return E4000_1_SUCCESS; +} + diff --git a/src/tuner_e4000.h b/src/tuner_e4000.h new file mode 100644 index 0000000..f74de17 --- /dev/null +++ b/src/tuner_e4000.h @@ -0,0 +1,236 @@ +#ifndef __TUNER_E4000_H +#define __TUNER_E4000_H + +/** + +@file + +@brief E4000 tuner module declaration + +One can manipulate E4000 tuner through E4000 module. +E4000 module is derived from tuner module. + + + +@par Example: +@code + +// The example is the same as the tuner example in tuner_base.h except the listed lines. + + + +#include "tuner_e4000.h" + + +... + + + +int main(void) +{ + TUNER_MODULE *pTuner; + E4000_EXTRA_MODULE *pTunerExtra; + + TUNER_MODULE TunerModuleMemory; + BASE_INTERFACE_MODULE BaseInterfaceModuleMemory; +// I2C_BRIDGE_MODULE I2cBridgeModuleMemory; + + unsigned long BandwidthMode; + + + ... + + + + // Build E4000 tuner module. + BuildE4000Module( + &pTuner, + &TunerModuleMemory, + &BaseInterfaceModuleMemory, + &I2cBridgeModuleMemory, + 0xac, // I2C device address is 0xac in 8-bit format. + CRYSTAL_FREQ_16384000HZ, // Crystal frequency is 16.384 MHz. + E4000_AGC_INTERNAL // The E4000 AGC mode is internal AGC mode. + ); + + + + + + // Get E4000 tuner extra module. + pTunerExtra = (T2266_EXTRA_MODULE *)(pTuner->pExtra); + + + + + + // ==== Initialize tuner and set its parameters ===== + + ... + + // Set E4000 bandwidth. + pTunerExtra->SetBandwidthMode(pTuner, E4000_BANDWIDTH_6MHZ); + + + + + + // ==== Get tuner information ===== + + ... + + // Get E4000 bandwidth. + pTunerExtra->GetBandwidthMode(pTuner, &BandwidthMode); + + + + // See the example for other tuner functions in tuner_base.h + + + return 0; +} + + +@endcode + +*/ + + + + + +//#include "tuner_base.h" + + + + + +// The following context is implemented for E4000 source code. + + +// Definition (implemeted for E4000) +#define E4000_1_SUCCESS 1 +#define E4000_1_FAIL 0 +#define E4000_I2C_SUCCESS 1 +#define E4000_I2C_FAIL 0 + + + +// Function (implemeted for E4000) +int +I2CReadByte( + int pTuner, + unsigned char NoUse, + unsigned char RegAddr, + unsigned char *pReadingByte + ); + +int +I2CWriteByte( + int pTuner, + unsigned char NoUse, + unsigned char RegAddr, + unsigned char WritingByte + ); + +int +I2CWriteArray( + int pTuner, + unsigned char NoUse, + unsigned char RegStartAddr, + unsigned char ByteNum, + unsigned char *pWritingBytes + ); + + + +// Functions (from E4000 source code) +int tunerreset (int pTuner); +int Tunerclock(int pTuner); +int Qpeak(int pTuner); +int DCoffloop(int pTuner); +int GainControlinit(int pTuner); + +int Gainmanual(int pTuner); +int E4000_gain_freq(int pTuner, int frequency); +int PLL(int pTuner, int Ref_clk, int Freq); +int LNAfilter(int pTuner, int Freq); +int IFfilter(int pTuner, int bandwidth, int Ref_clk); +int freqband(int pTuner, int Freq); +int DCoffLUT(int pTuner); +int GainControlauto(int pTuner); + +int E4000_sensitivity(int pTuner, int Freq, int bandwidth); +int E4000_linearity(int pTuner, int Freq, int bandwidth); +int E4000_high_linearity(int pTuner); +int E4000_nominal(int pTuner, int Freq, int bandwidth); + + +// The following context is E4000 tuner API source code + +// Definitions + +// Bandwidth in Hz +enum E4000_BANDWIDTH_HZ +{ + E4000_BANDWIDTH_6000000HZ = 6000000, + E4000_BANDWIDTH_7000000HZ = 7000000, + E4000_BANDWIDTH_8000000HZ = 8000000, +}; + + +// Manipulaing functions +void +e4000_GetTunerType( + int pTuner, + int *pTunerType + ); + +void +e4000_GetDeviceAddr( + int pTuner, + unsigned char *pDeviceAddr + ); + +int +e4000_Initialize( + int pTuner + ); + +int +e4000_SetRfFreqHz( + int pTuner, + unsigned long RfFreqHz + ); + +int +e4000_GetRfFreqHz( + int pTuner, + unsigned long *pRfFreqHz + ); + + + + + +// Extra manipulaing functions +int +e4000_GetRegByte( + int pTuner, + unsigned char RegAddr, + unsigned char *pReadingByte + ); + +int +e4000_SetBandwidthHz( + int pTuner, + unsigned long BandwidthHz + ); + +int +e4000_GetBandwidthHz( + int pTuner, + unsigned long *pBandwidthHz + ); + +#endif diff --git a/src/tuner_fc0013.c b/src/tuner_fc0013.c new file mode 100644 index 0000000..73b1ed9 --- /dev/null +++ b/src/tuner_fc0013.c @@ -0,0 +1,433 @@ +/* + * Fitipower FC0013 tuner driver, taken from the kernel driver that can be found + * on http://linux.terratec.de/tv_en.html + * + * This driver is a mess, and should be cleaned up/rewritten. + * + */ + +#include +#include "tuner_fc0013.h" + +#define CRYSTAL_FREQ 28800000 +#define FC0013_I2C_ADDR 0xc6 + +/* glue functions to rtl-sdr code */ +int FC0013_Write(int pTuner, unsigned char RegAddr, unsigned char Byte) +{ + uint8_t data[2]; + + data[0] = RegAddr; + data[1] = Byte; + + if (rtl_i2c_write(FC0013_I2C_ADDR, data, 2) < 0) + return FC0013_I2C_ERROR; + + return FC0013_I2C_SUCCESS; +} + +int FC0013_Read(int pTuner, unsigned char RegAddr, unsigned char *pByte) +{ + uint8_t data = RegAddr; + + if (rtl_i2c_write(FC0013_I2C_ADDR, &data, 1) < 0) + return FC0013_I2C_ERROR; + + if (rtl_i2c_read(FC0013_I2C_ADDR, &data, 1) < 0) + return FC0013_I2C_ERROR; + + *pByte = data; + + return FC0013_I2C_SUCCESS; +} + +int FC0013_SetVhfTrack(int pTuner, unsigned long FrequencyKHz) +{ + unsigned char read_byte; + + if (FrequencyKHz <= 177500) // VHF Track: 7 + { + if(FC0013_Read(pTuner, 0x1D, &read_byte) != FC0013_I2C_SUCCESS) goto error_status; + if(FC0013_Write(pTuner, 0x1D, (read_byte & 0xE3) | 0x1C) != FC0013_I2C_SUCCESS) goto error_status; + + } + else if (FrequencyKHz <= 184500) // VHF Track: 6 + { + if(FC0013_Read(pTuner, 0x1D, &read_byte) != FC0013_I2C_SUCCESS) goto error_status; + if(FC0013_Write(pTuner, 0x1D, (read_byte & 0xE3) | 0x18) != FC0013_I2C_SUCCESS) goto error_status; + + } + else if (FrequencyKHz <= 191500) // VHF Track: 5 + { + if(FC0013_Read(pTuner, 0x1D, &read_byte) != FC0013_I2C_SUCCESS) goto error_status; + if(FC0013_Write(pTuner, 0x1D, (read_byte & 0xE3) | 0x14) != FC0013_I2C_SUCCESS) goto error_status; + + } + else if (FrequencyKHz <= 198500) // VHF Track: 4 + { + if(FC0013_Read(pTuner, 0x1D, &read_byte) != FC0013_I2C_SUCCESS) goto error_status; + if(FC0013_Write(pTuner, 0x1D, (read_byte & 0xE3) | 0x10) != FC0013_I2C_SUCCESS) goto error_status; + + } + else if (FrequencyKHz <= 205500) // VHF Track: 3 + { + if(FC0013_Read(pTuner, 0x1D, &read_byte) != FC0013_I2C_SUCCESS) goto error_status; + if(FC0013_Write(pTuner, 0x1D, (read_byte & 0xE3) | 0x0C) != FC0013_I2C_SUCCESS) goto error_status; + + } + else if (FrequencyKHz <= 212500) // VHF Track: 2 + { + if(FC0013_Read(pTuner, 0x1D, &read_byte) != FC0013_I2C_SUCCESS) goto error_status; + if(FC0013_Write(pTuner, 0x1D, (read_byte & 0xE3) | 0x08) != FC0013_I2C_SUCCESS) goto error_status; + + } + else if (FrequencyKHz <= 219500) // VHF Track: 2 + { + if(FC0013_Read(pTuner, 0x1D, &read_byte) != FC0013_I2C_SUCCESS) goto error_status; + if(FC0013_Write(pTuner, 0x1D, (read_byte & 0xE3) | 0x08) != FC0013_I2C_SUCCESS) goto error_status; + + } + else if (FrequencyKHz <= 226500) // VHF Track: 1 + { + if(FC0013_Read(pTuner, 0x1D, &read_byte) != FC0013_I2C_SUCCESS) goto error_status; + if(FC0013_Write(pTuner, 0x1D, (read_byte & 0xE3) | 0x04) != FC0013_I2C_SUCCESS) goto error_status; + } + else // VHF Track: 1 + { + if(FC0013_Read(pTuner, 0x1D, &read_byte) != FC0013_I2C_SUCCESS) goto error_status; + if(FC0013_Write(pTuner, 0x1D, (read_byte & 0xE3) | 0x04) != FC0013_I2C_SUCCESS) goto error_status; + + } + + //------------------------------------------------ arios modify 2010-12-24 + // " | 0x10" ==> " | 0x30" (make sure reg[0x07] bit5 = 1) + + // Enable VHF filter. + if(FC0013_Read(pTuner, 0x07, &read_byte) != FC0013_I2C_SUCCESS) goto error_status; + if(FC0013_Write(pTuner, 0x07, read_byte | 0x10) != FC0013_I2C_SUCCESS) goto error_status; + + // Disable UHF & GPS. + if(FC0013_Read(pTuner, 0x14, &read_byte) != FC0013_I2C_SUCCESS) goto error_status; + if(FC0013_Write(pTuner, 0x14, read_byte & 0x1F) != FC0013_I2C_SUCCESS) goto error_status; + + + return FC0013_FUNCTION_SUCCESS; + +error_status: + return FC0013_FUNCTION_ERROR; +} + + +// FC0013 Open Function, includes enable/reset pin control and registers initialization. +//void FC0013_Open() +int FC0013_Open() +{ + int pTuner = 1; + // Enable FC0013 Power + // (...) + // FC0013 Enable = High + // (...) + // FC0013 Reset = High -> Low + // (...) + + //================================ update base on new FC0013 register bank + if(FC0013_Write(pTuner, 0x01, 0x09) != FC0013_I2C_SUCCESS) goto error_status; + if(FC0013_Write(pTuner, 0x02, 0x16) != FC0013_I2C_SUCCESS) goto error_status; + if(FC0013_Write(pTuner, 0x03, 0x00) != FC0013_I2C_SUCCESS) goto error_status; + if(FC0013_Write(pTuner, 0x04, 0x00) != FC0013_I2C_SUCCESS) goto error_status; + if(FC0013_Write(pTuner, 0x05, 0x17) != FC0013_I2C_SUCCESS) goto error_status; + if(FC0013_Write(pTuner, 0x06, 0x02) != FC0013_I2C_SUCCESS) goto error_status; +// if(FC0013_Write(pTuner, 0x07, 0x27) != FC0013_I2C_SUCCESS) goto error_status; // 28.8MHz, GainShift: 15 + if(FC0013_Write(pTuner, 0x07, 0x2A) != FC0013_I2C_SUCCESS) goto error_status; // 28.8MHz, modified by Realtek + if(FC0013_Write(pTuner, 0x08, 0xFF) != FC0013_I2C_SUCCESS) goto error_status; + if(FC0013_Write(pTuner, 0x09, 0x6F) != FC0013_I2C_SUCCESS) goto error_status; // Enable Loop Through + if(FC0013_Write(pTuner, 0x0A, 0xB8) != FC0013_I2C_SUCCESS) goto error_status; + if(FC0013_Write(pTuner, 0x0B, 0x82) != FC0013_I2C_SUCCESS) goto error_status; + + if(FC0013_Write(pTuner, 0x0C, 0xFE) != FC0013_I2C_SUCCESS) goto error_status; // Modified for up-dowm AGC by Realtek(for master, and for 2836BU dongle). +// if(FC0013_Write(pTuner, 0x0C, 0xFC) != FC0013_I2C_SUCCESS) goto error_status; // Modified for up-dowm AGC by Realtek(for slave, and for 2832 mini dongle). + +// if(FC0013_Write(pTuner, 0x0D, 0x09) != FC0013_I2C_SUCCESS) goto error_status; + if(FC0013_Write(pTuner, 0x0D, 0x01) != FC0013_I2C_SUCCESS) goto error_status; // Modified for AGC non-forcing by Realtek. + + if(FC0013_Write(pTuner, 0x0E, 0x00) != FC0013_I2C_SUCCESS) goto error_status; + if(FC0013_Write(pTuner, 0x0F, 0x00) != FC0013_I2C_SUCCESS) goto error_status; + if(FC0013_Write(pTuner, 0x10, 0x00) != FC0013_I2C_SUCCESS) goto error_status; + if(FC0013_Write(pTuner, 0x11, 0x00) != FC0013_I2C_SUCCESS) goto error_status; + if(FC0013_Write(pTuner, 0x12, 0x00) != FC0013_I2C_SUCCESS) goto error_status; + if(FC0013_Write(pTuner, 0x13, 0x00) != FC0013_I2C_SUCCESS) goto error_status; + + if(FC0013_Write(pTuner, 0x14, 0x50) != FC0013_I2C_SUCCESS) goto error_status; // DVB-T, High Gain +// if(FC0013_Write(pTuner, 0x14, 0x48) != FC0013_I2C_SUCCESS) goto error_status; // DVB-T, Middle Gain +// if(FC0013_Write(pTuner, 0x14, 0x40) != FC0013_I2C_SUCCESS) goto error_status; // DVB-T, Low Gain + + if(FC0013_Write(pTuner, 0x15, 0x01) != FC0013_I2C_SUCCESS) goto error_status; + + + return FC0013_FUNCTION_SUCCESS; + +error_status: + return FC0013_FUNCTION_ERROR; +} + + +int FC0013_SetFrequency(unsigned long Frequency, unsigned short Bandwidth) +{ +// bool VCO1 = false; +// unsigned int doubleVCO; +// unsigned short xin, xdiv; +// unsigned char reg[21], am, pm, multi; + int VCO1 = FC0013_FALSE; + unsigned long doubleVCO; + unsigned short xin, xdiv; + unsigned char reg[21], am, pm, multi; + + unsigned char read_byte; + + unsigned long CrystalFreqKhz; + + int pTuner =1; + + int CrystalFreqHz = CRYSTAL_FREQ; + + // Get tuner crystal frequency in KHz. + // Note: CrystalFreqKhz = round(CrystalFreqHz / 1000) + CrystalFreqKhz = (CrystalFreqHz + 500) / 1000; + + // modified 2011-02-09: for D-Book test + // set VHF_Track = 7 + if(FC0013_Read(pTuner, 0x1D, &read_byte) != FC0013_I2C_SUCCESS) goto error_status; + + // VHF Track: 7 + if(FC0013_Write(pTuner, 0x1D, (read_byte & 0xE3) | 0x1C) != FC0013_I2C_SUCCESS) goto error_status; + + + if( Frequency < 300000 ) + { + // Set VHF Track. + if(FC0013_SetVhfTrack(pTuner, Frequency) != FC0013_I2C_SUCCESS) goto error_status; + + // Enable VHF filter. + if(FC0013_Read(pTuner, 0x07, &read_byte) != FC0013_I2C_SUCCESS) goto error_status; + if(FC0013_Write(pTuner, 0x07, read_byte | 0x10) != FC0013_I2C_SUCCESS) goto error_status; + + // Disable UHF & disable GPS. + if(FC0013_Read(pTuner, 0x14, &read_byte) != FC0013_I2C_SUCCESS) goto error_status; + if(FC0013_Write(pTuner, 0x14, read_byte & 0x1F) != FC0013_I2C_SUCCESS) goto error_status; + } + else if ( (Frequency >= 300000) && (Frequency <= 862000) ) + { + // Disable VHF filter. + if(FC0013_Read(pTuner, 0x07, &read_byte) != FC0013_I2C_SUCCESS) goto error_status; + if(FC0013_Write(pTuner, 0x07, read_byte & 0xEF) != FC0013_I2C_SUCCESS) goto error_status; + + // enable UHF & disable GPS. + if(FC0013_Read(pTuner, 0x14, &read_byte) != FC0013_I2C_SUCCESS) goto error_status; + if(FC0013_Write(pTuner, 0x14, (read_byte & 0x1F) | 0x40) != FC0013_I2C_SUCCESS) goto error_status; + } + else if (Frequency > 862000) + { + // Disable VHF filter + if(FC0013_Read(pTuner, 0x07, &read_byte) != FC0013_I2C_SUCCESS) goto error_status; + if(FC0013_Write(pTuner, 0x07, read_byte & 0xEF) != FC0013_I2C_SUCCESS) goto error_status; + + // Disable UHF & enable GPS + if(FC0013_Read(pTuner, 0x14, &read_byte) != FC0013_I2C_SUCCESS) goto error_status; + if(FC0013_Write(pTuner, 0x14, (read_byte & 0x1F) | 0x20) != FC0013_I2C_SUCCESS) goto error_status; + } + + if (Frequency * 96 < 3560000) + { + multi = 96; + reg[5] = 0x82; + reg[6] = 0x00; + } + else if (Frequency * 64 < 3560000) + { + multi = 64; + reg[5] = 0x02; + reg[6] = 0x02; + } + else if (Frequency * 48 < 3560000) + { + multi = 48; + reg[5] = 0x42; + reg[6] = 0x00; + } + else if (Frequency * 32 < 3560000) + { + multi = 32; + reg[5] = 0x82; + reg[6] = 0x02; + } + else if (Frequency * 24 < 3560000) + { + multi = 24; + reg[5] = 0x22; + reg[6] = 0x00; + } + else if (Frequency * 16 < 3560000) + { + multi = 16; + reg[5] = 0x42; + reg[6] = 0x02; + } + else if (Frequency * 12 < 3560000) + { + multi = 12; + reg[5] = 0x12; + reg[6] = 0x00; + } + else if (Frequency * 8 < 3560000) + { + multi = 8; + reg[5] = 0x22; + reg[6] = 0x02; + } + else if (Frequency * 6 < 3560000) + { + multi = 6; + reg[5] = 0x0A; + reg[6] = 0x00; + } + else if (Frequency * 4 < 3800000) + { + multi = 4; + reg[5] = 0x12; + reg[6] = 0x02; + } + else + { + Frequency = Frequency / 2; + multi = 4; + reg[5] = 0x0A; + reg[6] = 0x02; + } + + doubleVCO = Frequency * multi; + + reg[6] = reg[6] | 0x08; +// VCO1 = true; + VCO1 = FC0013_TRUE; + + // Calculate VCO parameters: ap & pm & xin. +// xdiv = (unsigned short)(doubleVCO / (Crystal_Frequency/2)); + xdiv = (unsigned short)(doubleVCO / (CrystalFreqKhz/2)); +// if( (doubleVCO - xdiv * (Crystal_Frequency/2)) >= (Crystal_Frequency/4) ) + if( (doubleVCO - xdiv * (CrystalFreqKhz/2)) >= (CrystalFreqKhz/4) ) + { + xdiv = xdiv + 1; + } + + pm = (unsigned char)( xdiv / 8 ); + am = (unsigned char)( xdiv - (8 * pm)); + + if (am < 2) + { + reg[1] = am + 8; + reg[2] = pm - 1; + } + else + { + reg[1] = am; + reg[2] = pm; + } + +// xin = (unsigned short)(doubleVCO - ((unsigned short)(doubleVCO / (Crystal_Frequency/2))) * (Crystal_Frequency/2)); + xin = (unsigned short)(doubleVCO - ((unsigned short)(doubleVCO / (CrystalFreqKhz/2))) * (CrystalFreqKhz/2)); +// xin = ((xin << 15)/(Crystal_Frequency/2)); + xin = (unsigned short)((xin << 15)/(CrystalFreqKhz/2)); + +// if( xin >= (unsigned short) pow( (double)2, (double)14) ) +// { +// xin = xin + (unsigned short) pow( (double)2, (double)15); +// } + if( xin >= (unsigned short) 16384 ) + xin = xin + (unsigned short) 32768; + + reg[3] = (unsigned char)(xin >> 8); + reg[4] = (unsigned char)(xin & 0x00FF); + + + //===================================== Only for testing +// printf("Frequency: %d, Fa: %d, Fp: %d, Xin:%d \n", Frequency, am, pm, xin); + + + // Set Low-Pass Filter Bandwidth. + switch(Bandwidth) + { + case 6: + reg[6] = 0x80 | reg[6]; + break; + case 7: + reg[6] = ~0x80 & reg[6]; + reg[6] = 0x40 | reg[6]; + break; + case 8: + default: + reg[6] = ~0xC0 & reg[6]; + break; + } + + reg[5] = reg[5] | 0x07; + + if(FC0013_Write(pTuner, 0x01, reg[1]) != FC0013_I2C_SUCCESS) goto error_status; + if(FC0013_Write(pTuner, 0x02, reg[2]) != FC0013_I2C_SUCCESS) goto error_status; + if(FC0013_Write(pTuner, 0x03, reg[3]) != FC0013_I2C_SUCCESS) goto error_status; + if(FC0013_Write(pTuner, 0x04, reg[4]) != FC0013_I2C_SUCCESS) goto error_status; + if(FC0013_Write(pTuner, 0x05, reg[5]) != FC0013_I2C_SUCCESS) goto error_status; + if(FC0013_Write(pTuner, 0x06, reg[6]) != FC0013_I2C_SUCCESS) goto error_status; + + if (multi == 64) + { +// FC0013_Write(0x11, FC0013_Read(0x11) | 0x04); + if(FC0013_Read(pTuner, 0x11, &read_byte) != FC0013_I2C_SUCCESS) goto error_status; + if(FC0013_Write(pTuner, 0x11, read_byte | 0x04) != FC0013_I2C_SUCCESS) goto error_status; + } + else + { +// FC0013_Write(0x11, FC0013_Read(0x11) & 0xFB); + if(FC0013_Read(pTuner, 0x11, &read_byte) != FC0013_I2C_SUCCESS) goto error_status; + if(FC0013_Write(pTuner, 0x11, read_byte & 0xFB) != FC0013_I2C_SUCCESS) goto error_status; + } + + if(FC0013_Write(pTuner, 0x0E, 0x80) != FC0013_I2C_SUCCESS) goto error_status; + if(FC0013_Write(pTuner, 0x0E, 0x00) != FC0013_I2C_SUCCESS) goto error_status; + + if(FC0013_Write(pTuner, 0x0E, 0x00) != FC0013_I2C_SUCCESS) goto error_status; +// reg[14] = 0x3F & FC0013_Read(0x0E); + if(FC0013_Read(pTuner, 0x0E, &read_byte) != FC0013_I2C_SUCCESS) goto error_status; + reg[14] = 0x3F & read_byte; + + if (VCO1) + { + if (reg[14] > 0x3C) + { + reg[6] = ~0x08 & reg[6]; + + if(FC0013_Write(pTuner, 0x06, reg[6]) != FC0013_I2C_SUCCESS) goto error_status; + + if(FC0013_Write(pTuner, 0x0E, 0x80) != FC0013_I2C_SUCCESS) goto error_status; + if(FC0013_Write(pTuner, 0x0E, 0x00) != FC0013_I2C_SUCCESS) goto error_status; + } + } + else + { + if (reg[14] < 0x02) + { + reg[6] = 0x08 | reg[6]; + + if(FC0013_Write(pTuner, 0x06, reg[6]) != FC0013_I2C_SUCCESS) goto error_status; + + if(FC0013_Write(pTuner, 0x0E, 0x80) != FC0013_I2C_SUCCESS) goto error_status; + if(FC0013_Write(pTuner, 0x0E, 0x00) != FC0013_I2C_SUCCESS) goto error_status; + } + } + + + return 1; + +error_status: + return 0; +} + diff --git a/src/tuner_fc0013.h b/src/tuner_fc0013.h new file mode 100644 index 0000000..b04d7d1 --- /dev/null +++ b/src/tuner_fc0013.h @@ -0,0 +1,155 @@ +#ifndef __TUNER_FC0013_H +#define __TUNER_FC0013_H + +/** + +@file + +@brief FC0013 tuner module declaration + +One can manipulate FC0013 tuner through FC0013 module. +FC0013 module is derived from tuner module. + + +// The following context is implemented for FC0013 source code. + +**/ + +// Definitions +enum FC0013_TRUE_FALSE_STATUS +{ + FC0013_FALSE, + FC0013_TRUE, +}; + + +enum FC0013_I2C_STATUS +{ + FC0013_I2C_SUCCESS, + FC0013_I2C_ERROR, +}; + + +enum FC0013_FUNCTION_STATUS +{ + FC0013_FUNCTION_SUCCESS, + FC0013_FUNCTION_ERROR, +}; + + + +// Functions +int FC0013_Read(int pTuner, unsigned char RegAddr, unsigned char *pByte); +int FC0013_Write(int pTuner, unsigned char RegAddr, unsigned char Byte); + +int +fc0013_SetRegMaskBits( + int pTuner, + unsigned char RegAddr, + unsigned char Msb, + unsigned char Lsb, + const unsigned char WritingValue + ); + +int +fc0013_GetRegMaskBits( + int pTuner, + unsigned char RegAddr, + unsigned char Msb, + unsigned char Lsb, + unsigned char *pReadingValue + ); + +int FC0013_Open(); +int FC0013_SetFrequency(unsigned long Frequency, unsigned short Bandwidth); + +// Set VHF Track depends on input frequency +int FC0013_SetVhfTrack(int pTuner, unsigned long Frequency); + + +// The following context is FC0013 tuner API source code + + +// Definitions + +// Bandwidth mode +enum FC0013_BANDWIDTH_MODE +{ + FC0013_BANDWIDTH_6000000HZ = 6, + FC0013_BANDWIDTH_7000000HZ = 7, + FC0013_BANDWIDTH_8000000HZ = 8, +}; + + +// Default for initialing +#define FC0013_RF_FREQ_HZ_DEFAULT 50000000 +#define FC0013_BANDWIDTH_MODE_DEFAULT FC0013_BANDWIDTH_8000000HZ + + +// Tuner LNA +enum FC0013_LNA_GAIN_VALUE +{ + FC0013_LNA_GAIN_LOW = 0x00, // -6.3dB + FC0013_LNA_GAIN_MIDDLE = 0x08, // 7.1dB + FC0013_LNA_GAIN_HIGH_17 = 0x11, // 19.1dB + FC0013_LNA_GAIN_HIGH_19 = 0x10, // 19.7dB +}; + +// Manipulaing functions +void +fc0013_GetTunerType( + int pTuner, + int *pTunerType + ); + +void +fc0013_GetDeviceAddr( + int pTuner, + unsigned char *pDeviceAddr + ); + +int +fc0013_Initialize( + int pTuner + ); + +int +fc0013_SetRfFreqHz( + int pTuner, + unsigned long RfFreqHz + ); + +int +fc0013_GetRfFreqHz( + int pTuner, + unsigned long *pRfFreqHz + ); + +// Extra manipulaing functions +int +fc0013_SetBandwidthMode( + int pTuner, + int BandwidthMode + ); + +int +fc0013_GetBandwidthMode( + int pTuner, + int *pBandwidthMode + ); + +int +fc0013_RcCalReset( + int pTuner + ); + +int +fc0013_RcCalAdd( + int pTuner, + int RcValue + ); + + + + +#endif