/* * This 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 3, or (at your option) * any later version. * * The software 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 GNU Radio; see the file COPYING. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, * Boston, MA 02110-1301, USA. */ #include "ch.h" #include "hal.h" #include "nanovna.h" #include #include "si4432.h" #include "spi.h" #pragma GCC push_options #pragma GCC optimize ("Os") //#define __USE_FRR_FOR_RSSI__ // Define for use hardware SPI mode #define USE_HARDWARE_SPI_MODE // 10MHz clock #define SI4432_10MHZ 10000000U // !!!! FROM ili9341.c for disable it !!!! //#define LCD_CS_HIGH palSetPad(GPIOB, GPIOB_LCD_CS) // Not use delays for CS #if 1 #define SI_CS_DELAY #define PE_CS_DELAY #define ADF_CS_DELAY #else #define SI_CS_DELAY {__asm("NOP");__asm("NOP");__asm("NOP");__asm("NOP");} #define PE_CS_DELAY {__asm("NOP");__asm("NOP");__asm("NOP");__asm("NOP");} #define ADF_CS_DELAY {__asm("NOP");__asm("NOP");__asm("NOP");__asm("NOP");} #endif #define SI_CS_LOW {palClearLine(LINE_RX_SEL);SI_CS_DELAY;} #define SI_CS_HIGH {SI_CS_DELAY;palSetLine(LINE_RX_SEL);} #define SI_SDN_LOW palClearLine(LINE_RX_SDN); #define SI_SDN_HIGH palSetLine(LINE_RX_SDN); // Hardware or software SPI use #ifdef USE_HARDWARE_SPI_MODE #define SI4432_SPI SPI1 // Check device SPI clock speed #if STM32_PCLK2 > 48000000 // 48 or 72M MCU // On 72M MCU STM32_PCLK2 = 72M, SPI = 72M/4 = 18M //#define SI4432_SPI_SPEED SPI_BR_DIV4 #define SI4432_SPI_SPEED SPI_BR_DIV8 #else // On 48M MCU STM32_PCLK2 = 48M, SPI = 48M/2 = 24M //#define SI4432_SPI_SPEED SPI_BR_DIV2 #define SI4432_SPI_SPEED SPI_BR_DIV4 #endif //#define ADF_SPI_SPEED SPI_BR_DIV64 //#define ADF_SPI_SPEED SPI_BR_DIV32 #define ADF_SPI_SPEED SPI_BR_DIV2 #define PE4302_HW_SHIFT true #define PE_SPI_SPEED SPI_BR_DIV8 #define PE_SW_DELAY 2 static uint32_t old_spi_settings; #else static uint32_t new_port_moder; #endif static uint32_t old_port_moder; #define SPI1_CLK_HIGH palSetPad(GPIOB, GPIOB_SPI_SCLK) #define SPI1_CLK_LOW palClearPad(GPIOB, GPIOB_SPI_SCLK) #define SPI1_SDI_HIGH palSetPad(GPIOB, GPIOB_SPI_MOSI) #define SPI1_SDI_LOW palClearPad(GPIOB, GPIOB_SPI_MOSI) #define SPI1_RESET palClearPort(GPIOB, (1<>GPIOB_SPI_MISO)&1) #define SPI1_portSDO (palReadPort(GPIOB)&(1<CR1; SPI_BR_SET(SI4432_SPI, SI4432_SPI_SPEED); #else // Init legs mode for software bitbang old_port_moder = GPIOB->MODER; new_port_moder = old_port_moder & ~(PIN_MODE_ANALOG(GPIOB_SPI_SCLK)|PIN_MODE_ANALOG(GPIOB_SPI_MISO)|PIN_MODE_ANALOG(GPIOB_SPI_MOSI)); new_port_moder|= PIN_MODE_OUTPUT(GPIOB_SPI_SCLK)|PIN_MODE_INPUT(GPIOB_SPI_MISO)|PIN_MODE_OUTPUT(GPIOB_SPI_MOSI); GPIOB->MODER = new_port_moder; // Pull down SPI SPI1_SDI_LOW; SPI1_CLK_LOW; #endif } void stop_SI4432_SPI_mode(void){ #ifdef USE_HARDWARE_SPI_MODE SI4432_SPI->CR1 = old_spi_settings; #else // Restore hardware SPI GPIOB->MODER = old_port_moder; #endif } void start_PE4312_SPI_mode(void){ // Init legs mode for software bitbang old_spi_settings = SI4432_SPI->CR1; old_port_moder = GPIOB->MODER; uint32_t new_port_moder = old_port_moder & ~(PIN_MODE_ANALOG(GPIOB_SPI_SCLK)|PIN_MODE_ANALOG(GPIOB_SPI_MISO)|PIN_MODE_ANALOG(GPIOB_SPI_MOSI)); new_port_moder|= PIN_MODE_OUTPUT(GPIOB_SPI_SCLK)|PIN_MODE_INPUT(GPIOB_SPI_MISO)|PIN_MODE_OUTPUT(GPIOB_SPI_MOSI); GPIOB->MODER = new_port_moder; // Pull down SPI SPI1_SDI_LOW; SPI1_CLK_LOW; } void stop_PE4312_SPI_mode(void){ // Restore hardware SPI GPIOB->MODER = old_port_moder; SI4432_SPI->CR1 = old_spi_settings; } #if 0 static void software_shiftOut(uint8_t val) { SI4432_log(SI4432_Sel); SI4432_log(val); uint8_t i = 0; do { if (val & 0x80) SPI1_SDI_HIGH; my_microsecond_delay(PE_SW_DELAY); SPI1_CLK_HIGH; my_microsecond_delay(PE_SW_DELAY); SPI1_RESET; val<<=1; }while((++i) & 0x07); } #endif static void shiftOut(uint8_t val) { #ifdef USE_HARDWARE_SPI_MODE while (SPI_TX_IS_NOT_EMPTY(SI4432_SPI)); SPI_WRITE_8BIT(SI4432_SPI, val); while (SPI_IS_BUSY(SI4432_SPI)) // drop rx and wait tx (void)SPI_READ_8BIT(SI4432_SPI); #else SI4432_log(SI4432_Sel); SI4432_log(val); uint8_t i = 0; do { SPI1_SDI_HIGH; SPI1_CLK_HIGH; SPI1_RESET; val<<=1; }while((++i) & 0x07); #endif } static uint8_t shiftIn(void) { #ifdef USE_HARDWARE_SPI_MODE // while (SPI_TX_IS_NOT_EMPTY(SI4432_SPI)); SPI_WRITE_8BIT(SI4432_SPI, 0xFF); while (SPI_RX_IS_EMPTY(SI4432_SPI)) ; // drop rx and wait tx return SPI_READ_8BIT(SI4432_SPI); #else uint32_t value = 0; uint8_t i = 0; do { value<<=1; SPI1_CLK_HIGH; value|=SPI1_portSDO; SPI1_CLK_LOW; }while((++i) & 0x07); return value>>GPIOB_SPI_MISO; #endif } uint32_t SI4432_step_delay = 1500; uint32_t SI4432_offset_delay = 1500; #define MINIMUM_WAIT_FOR_RSSI 280 //------------PE4302 ----------------------------------------------- #ifdef __PE4302__ void PE4302_init(void) { CS_PE_LOW; } static unsigned char old_attenuation = 255; bool PE4302_Write_Byte(unsigned char DATA ) { // if (old_attenuation == DATA) /// Must always have same execution time // return false; old_attenuation = DATA; #ifdef __ARW621__ DATA = DATA << 1; #endif #if PE4302_HW_SHIFT set_SPI_mode(SPI_MODE_SI); if (SI4432_SPI_SPEED != PE_SPI_SPEED) SPI_BR_SET(SI4432_SPI, PE_SPI_SPEED); SPI_WRITE_8BIT(SI4432_SPI, DATA); while (SPI_IS_BUSY(SI4432_SPI)); #else // Run PE4312 in SW mode to avoid disturbances set_SPI_mode(SPI_MODE_PE); software_shiftOut(DATA); #endif CS_PE_HIGH; my_microsecond_delay(PE_SW_DELAY); CS_PE_LOW; my_microsecond_delay(PE_SW_DELAY); #if PE4302_HW_SHIFT if (SI4432_SPI_SPEED != PE_SPI_SPEED) SPI_BR_SET(SI4432_SPI, SI4432_SPI_SPEED); #endif return true; } #endif //------------------------------- ADF4351 ------------------------------------- //#define SI5351_INITIAL_FREQ 3206896551 //#define SI5351_INITIAL_FREQ 15000000000ULL #define NO_SHIFT_MUL 30 #define NO_SHIFT_DIV 30 #ifdef __SI5351__ #include "si5351.h" static int shifted = 0; //static int old_shifted = -1; #define SHIFT_MUL 31 #define SHIFT_DIV 29 //#define SI5351_INITIAL_FREQ 3000000000ULL void ADF4350_shift_ref(int f) { if (f == shifted) return; shifted = f; if (si5351_available && shifted) si5351_set_int_mul_div(0, SHIFT_MUL, SHIFT_DIV, 0); else si5351_set_int_mul_div(0, NO_SHIFT_MUL, NO_SHIFT_DIV, 0); ADF4351_recalculate_PFDRFout(); } #else int si5351_available = false; #endif #define __NEW_ADF4351__ #ifdef __NEW_ADF4351__ bool ADF4351_frequency_changed = false; uint16_t R = 1; int old_R = 0; uint16_t N = 1; uint16_t frac = 0; uint16_t modulus = 200; uint16_t out_div = 0; uint16_t mux = 0; uint16_t csr = 1; // cycle slip reduction, if enabled cp must be lowest value uint16_t bscm = 1; // Band select clock mode // uint32_t reg_0 = 0; uint32_t reg_1 = 0; uint32_t reg_2 = 0; uint32_t reg_3 = 0; uint32_t reg_4 = 0; uint32_t reg_5 = 0; uint16_t id = 0; uint8_t rfPower = 0b00; static freq_t prev_actual_freq = 0; bool pdwn = false; uint16_t powerDown = 0; static const uint8_t auxPower = 0b11; // band select divider. 1 to 255. volatile uint16_t bsDivider = 100; // For set internal logic clock (24M / 192 = 125k) max 125k // charge pump current, 0 to 15. static uint8_t cpCurrent = 0; // Must be zero when using either CSR or Fast Lock // CLKDIV divider (for fastlock and phase resync). 0 to 4095. volatile uint16_t fastlockDivider = 6; // Not used when in CSR mode static const uint16_t phase = 1; enum { CLKDIVMODE_OFF = 0b00, CLKDIVMODE_FASTLOCK = 0b01, CLKDIVMODE_RESYNC = 0b10 } clkDivMode = CLKDIVMODE_FASTLOCK; static const enum { LD_LOW = 0b00, LD_LOCK_DETECT = 0b01, LD_HIGH = 0b11 } ld_pin = LD_LOCK_DETECT; // Used for led output bool refDouble = false; static const bool refDiv2 = false; static const bool rfEnable = true; static bool auxEnable = false; static const bool feedbackFromDivided = true; static const bool LDF = false; // for fractional mode static const bool LDP = true; // 6 ns static const bool LDS = true; static enum { LD_LOW_NOISE = 0b00, LD_LOW_SPUR1 = 0b10, LD_LOW_SPUR2 = 0b11 } noiseMode = LD_LOW_SPUR1; /* static const enum { p_4_div_5 = 0, // min integer 23, max freq = 3.0GHz p_8_div_9 = 1 // min integer 75, max freq = 4.4GHz } prescaler = p_8_div_9; */ static const enum { CPt_NORMAL = 0b00, // Work, use default CPt_LONG_RESET = 0b01, // Work CPt_FORCE_SOURCE = 0b10, CPt_FORCE_SINK = 0b11, } CP_Test = CPt_NORMAL; const enum { CPm_DISABLE = 0b00, // Default CPm_10pct = 0b01, CPm_20pct = 0b10, CPm_30pct = 0b11, // ! Show best linearity result } CP_Mode = CPm_DISABLE; #define CS_ADF0_HIGH {palSetLine(LINE_LO_SEL);ADF_CS_DELAY;} #define CS_ADF0_LOW {palClearLine(LINE_LO_SEL);ADF_CS_DELAY;} bool ADF4351_dirty = false; void ADF4351_WriteRegister32(int channel, const uint32_t value) { (void) channel; // Select chip CS_ADF0_LOW; // Send 32 bit register #if 1 SPI_WRITE_8BIT(SI4432_SPI, (value >> 24)); SPI_WRITE_8BIT(SI4432_SPI, (value >> 16)); SPI_WRITE_8BIT(SI4432_SPI, (value >> 8)); SPI_WRITE_8BIT(SI4432_SPI, (value >> 0)); ADF4351_dirty = true; // while (SPI_IS_BUSY(SI4432_SPI)); // drop rx and wait tx #else shiftOut((value >> 24) & 0xFF); shiftOut((value >> 16) & 0xFF); shiftOut((value >> 8) & 0xFF); shiftOut((value >> 0) & 0xFF); #endif // unselect // CS_ADF0_HIGH; } void ADF4351_Latch(void) { if (ADF4351_dirty == false) return; while (SPI_IS_BUSY(SI4432_SPI)); // drop rx and wait tx CS_ADF0_HIGH; } void sendConfig(void) { if (SI4432_SPI_SPEED != ADF_SPI_SPEED) SPI_BR_SET(SI4432_SPI, ADF_SPI_SPEED); if (max2871) { // pdwn = false; //Power down is no longer active. uint32_t reg; const bool fractional = false; const uint32_t phase = 1; // Recommended // const bool LDS = (SI5351_INITIAL_FREQ > 3200000000ULL ? true: false); // reg 5 // LD pin register 5 reg = (ld_pin<<22) | 0b101; if (reg!=reg_5) {ADF4351_WriteRegister32(id, reg); reg_5 = reg;} // reg 4 // bs devider fb rf divider bs divider VCO down mtld aux sel aux en aux pwr rf en rf pwr register 4 reg = (bsDivider>>7) << 24 | (feedbackFromDivided<<23) | (out_div<<20) | ((bsDivider&0x7f)<<12) | (powerDown<<11) | (0<<10) | (0<<9) | (auxEnable<<8) | (auxPower<<6) | (rfEnable<<5) | (rfPower<<3) | 0b100; if (reg!=reg_4) {ADF4351_Latch(); ADF4351_WriteRegister32(id, reg); reg_4 = reg;} // reg 3 // bscm | csr mutedel clkdiv mode clkdiv register 3 reg = (bscm<<23) | (csr<<18) | (0<<17) | (clkDivMode<<15) | (fastlockDivider<<3) | 0b011; if (reg!=reg_3) {ADF4351_Latch(); ADF4351_WriteRegister32(id, reg); reg_3 = reg;} // reg 2 cp three reset // LD speed noise mode muxout ref dbr ref div2 R DB CP current LDF LDP PD pol powerdown state counter register 2 reg = (LDS<<31) | (LD_LOW_SPUR1<<29) | (mux<<26) | (refDouble<<25) | (refDiv2 << 24) | (R<<14) | (0<<13) | (cpCurrent<<9) | (LDF<<8) | (LDP<<7) | (1<<6) | (pdwn<<5) | (0<<4) | (0<<3) | 0b010; if (reg!=reg_2) {ADF4351_Latch(); ADF4351_WriteRegister32(id, reg); reg_2 = reg;} // reg 1 // CP mode CP test phase frac modulus reg = (CP_Mode<<29) | (CP_Test<<27) | (phase<<15) | (modulus<<3) | 0b001; if (reg!=reg_1) {ADF4351_Latch(); ADF4351_WriteRegister32(id, reg); reg_1 = reg;} // reg 0 (need always send for apply some reg 1 - 5 settings reg = (fractional<<31) | (N<<15) | (frac<<3) | 0b000; /*if (reg!=reg_0)*/ {ADF4351_Latch(); ADF4351_WriteRegister32(id, reg);/* reg_0 = reg;*/} ADF4351_Latch(); } else { // pdwn = false; //Power down is no longer active. uint32_t reg; #ifdef BOARD_DOUBLE_REF_MODE uint32_t prescaler = (N > 75) ? 1 : 0; #else uint32_t prescaler = 1; #endif // reg 5 // LD pin register 5 reg = (ld_pin<<22) | (0b11<<19)| 0b101; if (reg!=reg_5) {ADF4351_WriteRegister32(id, reg); reg_5 = reg;} // reg 4 // fb rf divider bs divider VCO down mtld aux sel aux en aux pwr rf en rf pwr register 4 reg = (feedbackFromDivided<<23) | (out_div<<20) | (bsDivider<<12) | (0<<11) | (0<<10) | (0<<9) | (auxEnable<<8) | (auxPower<<6) | (rfEnable<<5) | (rfPower<<3) | 0b100; if (reg!=reg_4) { ADF4351_Latch(); ADF4351_WriteRegister32(id, reg); reg_4 = reg;} // reg 3 // csr clkdiv mode clkdiv register 3 reg = (csr<<18) | (clkDivMode<<15) | (fastlockDivider<<3) | 0b011; if (reg!=reg_3) {ADF4351_Latch(); ADF4351_WriteRegister32(id, reg); reg_3 = reg;} // reg 2 cp three reset // noise mode muxout ref dbr ref div2 R DB CP current LDF LDP PD pol powerdown state counter register 2 reg = (LD_LOW_NOISE<<29) | (mux<<26) | (refDouble<<25) | (refDiv2 << 24) | (R<<14) | (0<<13) | (cpCurrent<<9) | (LDF<<8) | (LDP<<7) | (1<<6) | (pdwn<<5) | (0<<4) | (0<<3) | 0b010; if (reg!=reg_2) {ADF4351_Latch(); ADF4351_WriteRegister32(id, reg); reg_2 = reg;} // reg 1 // prescaler phase frac modulus reg = (prescaler<<27) | (phase<<15) | (modulus<<3) | 0b001; if (reg!=reg_1) {ADF4351_Latch(); ADF4351_WriteRegister32(id, reg); reg_1 = reg;} // reg 0 (need always send for apply some reg 1 - 5 settings reg = (N<<15) | (frac<<3) | 0b000; /*if (reg!=reg_0)*/ {ADF4351_Latch(); ADF4351_WriteRegister32(id, reg);/* reg_0 = reg;*/} ADF4351_Latch(); } if (SI4432_SPI_SPEED != ADF_SPI_SPEED) SPI_BR_SET(SI4432_SPI, SI4432_SPI_SPEED); } void sendPowerdown(bool p) { if(pdwn == p) return; pdwn = p; uint32_t reg = (noiseMode<<29) | (0b001<<26) | (refDouble<<25) | (refDiv2 << 24) | (R<<14) | (cpCurrent<<9) | (0<<8) | (0<<7) | (1<<6) | (pdwn<<5) | 0b010; if (reg!=reg_2) {ADF4351_WriteRegister32(id, reg); reg_2 = reg;ADF4351_Latch(); } } static uint32_t adf4350_get_O(uint64_t freqHz) { if(max2871) { if(freqHz > 3000000000) return 0; // 1 else if(freqHz > 1500000000) return 1; // 2 else if(freqHz > 750000000) return 2; // 4 else if(freqHz > 375000000) return 3; // 8 else if(freqHz > 187500000) return 4; // 16 else if(freqHz > 137500000) return 5; // 32 else if(freqHz > 68750000) return 6; // 64 else/*if(freqHz > 34375000)*/return 7; //128 }else{ if(freqHz > 2200000000) return 0; // 1 else if(freqHz > 1100000000) return 1; // 2 else if(freqHz > 550000000) return 2; // 4 else if(freqHz > 275000000) return 3; // 8 else/*if(freqHz > 137500000)*/return 4; // 16 } } freq_t xtal; uint64_t ADF4351_set_frequency(int channel, uint64_t freqHz) { (void) channel; // RFout = xtalFreqHz × (N + FRAC/MOD) = xtalFreqHz × (N * MOD + FRAC) / MOD // step = xtalFreqHz / MOD; !!!! should get integer result, also this result should divided by 16 // for 24M step = 24M / 4000 = 6k and 6k/16 = 375 // Nx = RFout / step // N * 4000 + frac = Nx // N = Nx / 4000 // frac = Nx % 4000 #if 1 out_div = adf4350_get_O(freqHz); #ifdef __SI5351__ // if (shifted != old_shifted || xtal == 0) { // old_shifted = shifted; if (shifted) xtal = (config.setting_frequency_30mhz * SHIFT_MUL) / SHIFT_DIV; else { #endif xtal = config.setting_frequency_30mhz; // * NO_SHIFT_MUL)/ NO_SHIFT_DIV; #ifdef __SI5351__ } } #endif if (refDouble) { xtal<<=1; } if (R > 1) xtal /= R; #if 1 uint32_t modulus_x2 = modulus<<1; uint32_t INTA_F = (((freqHz << out_div) * (uint64_t)(modulus_x2*FREQ_MULTIPLIER))/ xtal) + 1; N = INTA_F / modulus_x2; frac = (INTA_F - N * modulus_x2)>>1; if (frac >= modulus) { frac -= modulus; N++; } freq_t actual_freq = (((uint64_t)xtal *(uint64_t)(N * modulus +frac)) >> out_div) / (modulus*FREQ_MULTIPLIER); #else uint32_t _N = ((freqHz<>1; if (FRAC >= MOD) { FRAC -= MOD; INTA++; } freq_t actual_freq = ((uint64_t)xtal *(N * modulus +frac))/ (1<1) setting.increased_R = true; else setting.increased_R = false; clear_frequency_cache(); // When R changes the possible frequencies will change } void ADF4351_mux(int m) { mux = m; sendConfig(); } void ADF4351_csr(int c) { csr = (c & 0x1); sendConfig(); } void ADF4351_fastlock(int c) { clkDivMode = (c & 0x3); sendConfig(); } void ADF4351_CP(int p) { if (cpCurrent == p) return; cpCurrent = p; sendConfig(); } uint16_t ADF4351_get_CP(void) { return cpCurrent; } void ADF4351_drive(int p) { if (rfPower == p) return; rfPower = p; sendConfig(); my_microsecond_delay(1000); } #if 0 void ADF4351_aux_drive(int p) { if ( auxPower == p) return; auxPower = p; sendConfig(); } #endif void ADF4351_enable_aux_out(int s) { if ( auxEnable == s) return; auxEnable = s; sendConfig(); } void ADF4351_enable(int s) { if ( powerDown == !s) return; powerDown = !s; sendConfig(); osalThreadSleepMilliseconds(10); } void ADF4351_enable_out(int s) { if ( pdwn == !s) return; powerDown = !s; pdwn = !s; sendConfig(); osalThreadSleepMilliseconds(10); } void ADF4351_recalculate_PFDRFout(void) { int local_r = old_R; old_R = -1; ADF4351_R_counter(local_r); sendConfig(); } void ADF4351_Setup(void) { CS_ADF0_HIGH; #ifdef __SI5351__ si5351_available = si5351_init(); if (si5351_available) { si5351_set_frequency(0, (config.setting_frequency_30mhz * NO_SHIFT_MUL)/ NO_SHIFT_DIV /100, 0); si5351_set_int_mul_div(0, NO_SHIFT_MUL, NO_SHIFT_DIV, 0); } si5351_available = false; // Don't use shifting #endif cpCurrent = 0; if (max2871) { // refDouble = true; } else { ADF4351_csr(1); //Cycle slip enabled ADF4351_fastlock(1); // Fastlock enabled cpCurrent = 0; } // R = 1; ADF4351_set_frequency(0,3000000000); ADF4351_mux(0); // Tristate } #else #define bitRead(value, bit) (((value) >> (bit)) & 0x01) #define bitSet(value, bit) ((value) |= (1UL << (bit))) #define bitClear(value, bit) ((value) &= ~(1UL << (bit))) #define bitWrite(value, bit, bitvalue) ((bitvalue) ? bitSet(value, bit) : bitClear(value, bit)) #define maskedWrite(reg, bit, mask, value) (reg) &= ~(((uint32_t)mask) << (bit)); (reg) |= ((((uint32_t) (value)) & ((uint32_t)mask)) << (bit)); #define CS_ADF0_HIGH {palSetLine(LINE_LO_SEL);ADF_CS_DELAY;} #define CS_ADF1_HIGH {ADF_CS_DELAY;palSetLine(LINE_LO_SEL);} #define CS_ADF0_LOW {palClearLine(LINE_LO_SEL);ADF_CS_DELAY;} #define CS_ADF1_LOW {ADF_CS_DELAY;palClearLine(LINE_LO_SEL);} #define CS_ADF_LOW(ch) {palClearLine(ch);ADF_CS_DELAY;} #define CS_ADF_HIGH(ch) {ADF_CS_DELAY;palSetLine(ch);} uint32_t registers[6] = {0xC88000, 0x8008011, 0x1800C642, 0x48963,0xA5003C , 0x580005} ; //10 MHz ref uint32_t old_registers[6]; int debug = 0; ioline_t ADF4351_LE[2] = { LINE_LO_SEL, LINE_LO_SEL}; //int ADF4351_Mux = 7; bool ADF4351_frequency_changed = false; //#define DEBUG(X) // Serial.print( X ) //#define DEBUGLN(X) Serial.println( X ) //#define DEBUGFLN(X,Y) Serial.println( X,Y ) //#define DEBUGF(X,Y) Serial.print( X,Y ) #define DEBUG(X) #define DEBUGLN(X) #define XTAL 300000000 uint64_t PFDRFout[6] = {XTAL,XTAL,XTAL,10000000,10000000,10000000}; //Reference freq in MHz int64_t ADF4350_modulo = 0, // Linked to spur table!!!!! target_freq; int old_R = 0; void ADF4351_Setup(void) { // palSetPadMode(GPIOA, 1, PAL_MODE_OUTPUT_PUSHPULL ); // palSetPadMode(GPIOA, 2, PAL_MODE_OUTPUT_PUSHPULL ); local_setting_frequency_30mhz_x100 = config.setting_frequency_30mhz; #ifdef __SI5351__ si5351_available = si5351_init(); if (si5351_available) si5351_set_frequency(0, 30000000, 0); si5351_available = false; // Don't use shifting #endif // SPI3_CLK_HIGH; // SPI3_SDI_HIGH; CS_ADF0_HIGH; // CS_ADF1_HIGH; // bitSet (registers[2], 17); // R set to 8 // bitClear (registers[2], 14); // R set to 8 // while(1) { // ADF4351_R_counter(1); ADF4351_CP(0); ADF4351_fastlock(1); // Fastlock enabled ADF4351_csr(1); //Cycle slip enabled ADF4351_set_frequency(0,200000000); ADF4351_mux(0); // Tristate // ADF4351_mux(6); // Show lock on led } void ADF4351_WriteRegister32(int channel, const uint32_t value) { // Select chip CS_ADF_LOW(ADF4351_LE[channel]); // Send 32 bit register #if 1 SPI_WRITE_8BIT(SI4432_SPI, (value >> 24)); SPI_WRITE_8BIT(SI4432_SPI, (value >> 16)); SPI_WRITE_8BIT(SI4432_SPI, (value >> 8)); SPI_WRITE_8BIT(SI4432_SPI, (value >> 0)); while (SPI_IS_BUSY(SI4432_SPI)); // drop rx and wait tx #else shiftOut((value >> 24) & 0xFF); shiftOut((value >> 16) & 0xFF); shiftOut((value >> 8) & 0xFF); shiftOut((value >> 0) & 0xFF); #endif // unselect CS_ADF_HIGH(ADF4351_LE[channel]); } void ADF4351_Set(int channel) { #if 0 for (int i = 5; i >= 0; i--) { if (registers[i] != old_registers[i]) goto update; } return; update: #endif set_SPI_mode(SPI_MODE_SI); if (SI4432_SPI_SPEED != ADF_SPI_SPEED) SPI_BR_SET(SI4432_SPI, ADF_SPI_SPEED); for (int i = 5; i >= 0; i--) { #if 0 if (i == 0 || registers[i] != old_registers[i]) #endif ADF4351_WriteRegister32(channel, registers[i]); old_registers[i] = registers[i]; } if (SI4432_SPI_SPEED != ADF_SPI_SPEED) SPI_BR_SET(SI4432_SPI, SI4432_SPI_SPEED); } static freq_t prev_actual_freq = 0; void ADF4351_force_refresh(void) { prev_actual_freq = 0; for (int i = 5; i >= 0; i--) old_registers[i] = 0; } void ADF4351_modulo(int m) { ADF4350_modulo = m; // ADF4351_set_frequency(0, (uint64_t)prev_actual_freq); } uint64_t ADF4351_set_frequency(int channel, uint64_t freq) // freq / 10Hz { uint64_t actual_freq = ADF4351_prepare_frequency(channel,freq); if (actual_freq != prev_actual_freq) { ADF4351_frequency_changed = true; ADF4351_Set(channel); prev_actual_freq = actual_freq; } return actual_freq; } void ADF4351_spur_mode(int S) { bitWrite(registers[2], 29, S & 1); bitWrite(registers[2], 30, S & 2); ADF4351_Set(0); } void ADF4351_R_counter(int R) { if (R == old_R) return; old_R = R; int dbl = false; if (R < 0) { dbl = true; R = -R; } if (R<1) return; bitWrite(registers[2], 25, dbl); // Reference doubler for (int channel=0; channel < 6; channel++) { PFDRFout[channel] = (local_setting_frequency_30mhz_x100 * (dbl?2:1)) / R; } maskedWrite(registers[2],14, 0x3FF, R); // ADF4351_Set(0); // Let next frequency set do the writing // ADF4351_force_refresh(); clear_frequency_cache(); // When R changes the possible frequencies will change } void ADF4351_recalculate_PFDRFout(void){ int local_r = old_R; old_R = -1; local_setting_frequency_30mhz_x100 = config.setting_frequency_30mhz; ADF4351_R_counter(local_r); } void ADF4351_mux(int R) { maskedWrite(registers[2],26, 0x7, R); // registers[2] &= ~(((uint32_t) 0x7) << 26); // registers[2] |= (((uint32_t)R & 0x07) << 26); ADF4351_Set(0); } void ADF4351_csr(int c) { maskedWrite(registers[3],18, 0x1, c); // registers[3] &= ~(((uint32_t) 0x1) << 18); // registers[3] |= (((uint32_t)c & 0x01) << 18); ADF4351_Set(0); } void ADF4351_fastlock(int c) { maskedWrite(registers[3],15, 0x3, c); // registers[3] &= ~(((uint32_t) 0x3) << 15); // registers[3] |= (((uint32_t)c & 0x03) << 15); ADF4351_Set(0); } void ADF4351_CP(int p) { maskedWrite(registers[2],9, 0xF, p); // registers[2] &= ~(((uint32_t)0xF) << 9); // registers[2] |= (((uint32_t) p) << 9); ADF4351_Set(0); } void ADF4351_drive(int p) { if (((registers[4] >> 3) & 0x03 ) == (p & 0x03)) return; maskedWrite(registers[4],3, 0x3, p); // p &= 0x03; // registers[4] &= ~(((uint32_t)0x3) << 3); // registers[4] |= (((uint32_t) p) << 3); ADF4351_Set(0); my_microsecond_delay(1000); } void ADF4351_aux_drive(int p) { if (((registers[4] >> 6) & 0x03 ) == (p & 0x03)) return; maskedWrite(registers[4],6, 0x3, p); // p &= 0x03; // registers[4] &= ~(((uint32_t)0x3) << 6); // registers[4] |= (((uint32_t) p) << 6); ADF4351_Set(0); } #if 0 static uint32_t gcd(uint32_t x, uint32_t y) { uint32_t z; while (y != 0) { z = x % y; x = y; y = z; } return x; } #endif uint64_t ADF4351_prepare_frequency(int channel, uint64_t freq) // freq / 10Hz { uint32_t output_divider; target_freq = freq; if (max2871) { if (freq >= 3000000000) { output_divider = 1 * FREQ_MULTIPLIER; bitWrite (registers[4], 22, 0); // 0 bitWrite (registers[4], 21, 0); bitWrite (registers[4], 20, 0); } else if (freq >= 1500000000) { output_divider = 2 * FREQ_MULTIPLIER; bitWrite (registers[4], 22, 0); // 1 bitWrite (registers[4], 21, 0); bitWrite (registers[4], 20, 1); } else if (freq >= 750000000) { output_divider = 4 * FREQ_MULTIPLIER; bitWrite (registers[4], 22, 0); // 2 bitWrite (registers[4], 21, 1); bitWrite (registers[4], 20, 0); } else if (freq >= 375000000) { output_divider = 8 * FREQ_MULTIPLIER; bitWrite (registers[4], 22, 0); // 3 bitWrite (registers[4], 21, 1); bitWrite (registers[4], 20, 1); } else if (freq >= 187500000) { output_divider = 16 * FREQ_MULTIPLIER; bitWrite (registers[4], 22, 1); // 4 bitWrite (registers[4], 21, 0); bitWrite (registers[4], 20, 0); } else if (freq >= 137500000) { output_divider = 32 * FREQ_MULTIPLIER; bitWrite (registers[4], 22, 1); // 5 bitWrite (registers[4], 21, 0); bitWrite (registers[4], 20, 1); } else if (freq >= 68750000) { output_divider = 64 * FREQ_MULTIPLIER; bitWrite (registers[4], 22, 1); // 6 bitWrite (registers[4], 21, 1); bitWrite (registers[4], 20, 0); } else { // > 34375000 output_divider = 128 * FREQ_MULTIPLIER; bitWrite (registers[4], 22, 1); // 7 bitWrite (registers[4], 21, 1); bitWrite (registers[4], 20, 1); } } else { if (freq >= 2200000000) { output_divider = 1 * FREQ_MULTIPLIER; bitWrite (registers[4], 22, 0); bitWrite (registers[4], 21, 0); bitWrite (registers[4], 20, 0); } else if (freq >= 1100000000) { output_divider = 2 * FREQ_MULTIPLIER; bitWrite (registers[4], 22, 0); bitWrite (registers[4], 21, 0); bitWrite (registers[4], 20, 1); } else if (freq >= 550000000) { output_divider = 4 * FREQ_MULTIPLIER; bitWrite (registers[4], 22, 0); bitWrite (registers[4], 21, 1); bitWrite (registers[4], 20, 0); } else if (freq >= 275000000) { output_divider = 8 * FREQ_MULTIPLIER; bitWrite (registers[4], 22, 0); bitWrite (registers[4], 21, 1); bitWrite (registers[4], 20, 1); } else { // > 137500000 output_divider = 16 * FREQ_MULTIPLIER; bitWrite (registers[4], 22, 1); bitWrite (registers[4], 21, 0); bitWrite (registers[4], 20, 0); } } uint32_t PFDR = (uint32_t)PFDRFout[channel]; uint32_t MOD = ADF4350_modulo; if (MOD == 0) MOD = 60; uint32_t MOD_X2 = MOD<<1; uint32_t INTA_F = ((freq * (uint64_t)output_divider) * (uint64_t)MOD_X2/ PFDR) + 1; uint32_t INTA = INTA_F / MOD_X2; uint32_t FRAC = (INTA_F - INTA * MOD_X2)>>1; if (FRAC >= MOD) { FRAC -= MOD; INTA++; } #if 0 // No visible performance improvement uint32_t reduce = gcd(MOD, FRAC); if (reduce>1) { FRAC /= reduce; MOD /= reduce; if (MOD == 1) MOD=2; } #endif uint64_t actual_freq = ((uint64_t)PFDR *(INTA * MOD +FRAC))/output_divider / MOD; #if 0 // Only for debugging int max_delta = PFDRFout[channel]/output_divider/MOD/100; if (actual_freq < freq - max_delta || actual_freq > freq + max_delta ){ while(1) my_microsecond_delay(10); } max_delta = freq - actual_freq; if (max_delta > 200000 || max_delta < -200000 || freq == 0) { while(1) my_microsecond_delay(10); } if (FRAC >= MOD ){ while(1) my_microsecond_delay(10); } #endif bitWrite (registers[4], 10, 1); // Mute till lock detect registers[0] = 0; registers[0] = INTA << 15; // OK registers[0] = registers[0] + (FRAC << 3); if (MOD == 1) MOD = 2; registers[1] = 0; registers[1] = MOD << 3; registers[1] |= 1 ; // restore register address "001" registers[1] |= 1 << 15; // Set PHASE to 1 bitSet (registers[1], 27); // Prescaler at 8/9 return actual_freq; } void ADF4351_enable(int s) { if (bitRead(registers[4],11) != (s & 0x01)) return; if (s) bitClear(registers[4], 11); // Inverse logic!!!!! else bitSet(registers[4], 11); ADF4351_Set(0); osalThreadSleepMilliseconds(10); } void ADF4351_enable_aux_out(int s) { if (bitRead(registers[4],8) == (s & 0x01)) return; if (s) { bitSet(registers[4], 8); maskedWrite(registers[4],6, 0x3, 3); // Max drive aux out } else bitClear(registers[4], 8); ADF4351_Set(0); osalThreadSleepMilliseconds(10); } void ADF4351_enable_out(int s) { if (bitRead(registers[4],5) == (s & 0x01)) return; if (s) { bitClear(registers[4], 11); // Disable VCO power down bitClear(registers[2], 5); // Disable power down bitSet(registers[4], 5); // Enable output } else { bitClear(registers[4], 5); // Disable output bitSet(registers[2], 5); // Enable power down bitSet(registers[4], 11); // Enable VCO power down } ADF4351_Set(0); osalThreadSleepMilliseconds(1); } #endif // ------------------------------ SI4468 ------------------------------------- bool SI4463_frequency_changed = false; bool SI4463_offset_changed = false; int SI4463_offset_value = 0; uint8_t SI4463_rbw_selected = 0; static int SI4463_band = -1; //static freq_t SI4463_prev_freq = 0; //static float SI4463_step_size = 100; // Will be recalculated once used static uint8_t SI4463_channel = 0; static uint8_t SI4463_in_tx_mode = false; //int SI4463_R = 5; static int SI4463_output_level = 0x20; static si446x_state_t SI4463_get_state(void); static int SI4463_set_state(si446x_state_t); #define SI4463_READ_CTS (palReadLine(LINE_RX_CTS)) #define SI4463_CTS_TIMEOUT 1000000 #ifdef __WAIT_CTS_WHILE_SLEEPING__ extern volatile int sleep; #if 0 #define SI4463_WAIT_CTS while (!SI4463_READ_CTS) {\ if (sleep) {\ CS_PE_HIGH;\ __WFI();\ CS_PE_LOW;\ } \ }; #else int SI4463_wait_CTS(void) { int t=0; while (!SI4463_READ_CTS) { t++; if (t >=SI4463_CTS_TIMEOUT) return -1; } return 0; } #define SI4463_WAIT_CTS SI4463_wait_CTS() //#define SI4463_WAIT_CTS {int t=0; while (!SI4463_READ_CTS) { t++; if (t >=SI4463_CTS_TIMEOUT) ili9341_drawstring("SI4486 deadlock", 0,20);} } #endif #else #define SI4463_WAIT_CTS while (!SI4463_READ_CTS) ; #endif #if 0 // not used static void SI4463_write_byte(uint8_t ADR, uint8_t DATA) { set_SPI_mode(SPI_MODE_SI); SI_CS_LOW; ADR |= 0x80 ; // RW = 1 shiftOut( ADR ); shiftOut( DATA ); SI_CS_HIGH; } static void SI4463_write_buffer(uint8_t ADR, uint8_t *DATA, int len) { set_SPI_mode(SPI_MODE_SI); SI_CS_LOW; ADR |= 0x80 ; // RW = 1 shiftOut( ADR ); while (len-- > 0) shiftOut( *(DATA++) ); SI_CS_HIGH; } #endif static uint8_t SI4463_read_byte( uint8_t ADR ) { uint8_t DATA ; set_SPI_mode(SPI_MODE_SI); SI_CS_LOW; shiftOut( ADR ); DATA = shiftIn(); SI_CS_HIGH; return DATA ; } #ifdef NOTUSED static uint8_t SI4463_get_response(void* buff, uint8_t len) { uint8_t cts = 0; // set_SPI_mode(SPI_MODE_SI); cts = SI4463_READ_CTS; if (!cts) { return false; } // __disable_irq(); SI_CS_LOW; shiftOut( SI446X_CMD_READ_CMD_BUFF ); cts = (shiftIn() == 0xFF); if (cts) { // Get response data for(uint8_t i=0;i>8), len, (uint8_t)prop }; // Copy values into data, starting at index 4 memcpy(data + 4, values, len); SI4463_do_api(data, len + 4, NULL, 0); } #endif #include "si446x_cmd.h" #include "radio_config_Si4468_undef.h" #undef RADIO_CONFIGURATION_DATA_ARRAY #include "radio_config_Si4468_default.h" // Used in RBW setting #define GLOBAL_GPIO_PIN_CFG 0x13, 0x07, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00 #define GLOBAL_CLK_CFG 0x11, 0x00, 0x01, 0x01, 0x00 // ---------------------------------------------------------------------------------------------------- v ------------ RSSI control byte #define GLOBAL_RF_MODEM_RAW_CONTROL 0x11, 0x20, 0x0A, 0x45, 0x03, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x03, 0x10, 0x40 //0x11 SI446X_CMD_SET_PROPERTY //0x20 SI446X_PROP_GROUP_MODEM //0x0A 10 Count //0x45 Start register //0x03 [0x45] MODEM_RAW_CONTROL //0x00 [0x46] RAWEYE[10:8] //0x00 [0x47] RAWEYE[7:0] //0x01 [0x48] MODEM_ANT_DIV_MODE //0x00 [0x49] MODEM_ANT_DIV_CONTROL //0xFF [0x4A] MODEM_RSSI_THRESH //0x06 [0x4B] MODEM_RSSI_JUMP_THRESH //0x18 [0x4C] MODEM_RSSI_CONTROL //0x10 [0x4D] MODEM_RSSI_CONTROL2 //0x40 [0x4E] MODEM_RSSI_COMP // -----------------------------------------------------------------------------------------------------^ -------------- #define GLOBAL_RF_MODEM_AGC_CONTROL 0x11, 0x20, 0x01, 0x35, 0xF1 // Override AGC gain increase #undef RF_MODEM_AGC_CONTROL_1 #define RF_MODEM_AGC_CONTROL_1 GLOBAL_RF_MODEM_AGC_CONTROL #undef RF_MODEM_AGC_WINDOW_SIZE_12_1 //#define RF_MODEM_AGC_WINDOW_SIZE_12_1 0x11, 0x20, 0x0C, 0x38, 0x11, 0x07, 0x07, 0x80, 0x02, 0x4C, 0xCD, 0x00, 0x27, 0x0C, 0x84, 0x23 #define RF_MODEM_AGC_WINDOW_SIZE_12_1 0x11, 0x20, 0x0C, 0x38, 0x11, 0x07, 0x07, 0x80, 0x1C, 0x4C, 0xCD, 0x00, 0x27, 0x0C, 0x84, 0x23 #undef RF_GPIO_PIN_CFG #define RF_GPIO_PIN_CFG GLOBAL_GPIO_PIN_CFG #undef RF_GLOBAL_CLK_CFG_1 #define RF_GLOBAL_CLK_CFG_1 GLOBAL_CLK_CFG // Remember to change RF_MODEM_AFC_LIMITER_1_3_1 !!!!!!!!! static const uint8_t SI4468_config[] = RADIO_CONFIGURATION_DATA_ARRAY; // Set new state static int SI4463_set_state(si446x_state_t newState) { uint8_t data[] = { SI446X_CMD_CHANGE_STATE, newState }; return SI4463_do_api(data, sizeof(data), NULL, 0); } static uint8_t gpio_state[5] = { SI446X_GPIO_MODE_DIV_CLK, SI446X_GPIO_MODE_CTS, SI446X_GPIO_MODE_DONOTHING, SI446X_GPIO_MODE_DONOTHING, SI446X_GPIO_MODE_DRIVE1 }; int SI4463_refresh_gpio(void) { uint8_t data2[] = { SI446X_CMD_GPIO_PIN_CFG, gpio_state[0], // GPIO[0] gpio_state[1], // GPIO[1] gpio_state[2], // GPIO[2] // High gpio_state[3], // GPIO[3] // TX/RX gpio_state[4], // NIRQ // Direct 0, // SDO 0 // GEN_CONFIG }; return SI4463_do_api(data2, sizeof(data2), NULL, 0); } void SI4463_set_gpio(int i, int s) { if (gpio_state[i] == s) return; gpio_state[i] = s; #if 0 // debug gpio gpio_state[2] = 3; gpio_state[3] = 2; #endif SI4463_refresh_gpio(); } #if 0 static void SI4463_clear_FIFO(void) { // 'static const' saves 20 bytes of flash here, but uses 2 bytes of RAM static const uint8_t clearFifo[] = { SI446X_CMD_FIFO_INFO, SI446X_FIFO_CLEAR_RX | SI446X_FIFO_CLEAR_TX }; SI4463_do_api((uint8_t*)clearFifo, sizeof(clearFifo), NULL, 0); } #endif void SI4463_set_output_level(int t) { SI4463_output_level = t; if (SI4463_in_tx_mode) { #if 1 { uint8_t data[] = { SI446X_CMD_SET_PROPERTY, 0x22, 0x04, 0x00, // PA_MODE 0x08, // Coarse PA mode and class E PA Fine PA mode = 0x04 (uint8_t)SI4463_output_level, // Level 0x00, // Duty 0x00 // Ramp }; SI4463_do_api(data, sizeof(data), NULL, 0); } #else SI4463_start_tx(0); // Refresh output level #endif } } void SI4463_start_tx(uint8_t CHANNEL) { // si446x_state_t s; #if 0 s = SI4463_get_state(); if (s == SI446X_STATE_RX){ SI4463_set_state(SI446X_STATE_READY); my_microsecond_delay(200); s = SI4463_get_state(); if (s != SI446X_STATE_READY){ my_microsecond_delay(1000); } } #endif #if 1 { uint8_t data[] = { SI446X_CMD_SET_PROPERTY, 0x20, 0x01, 0x00, 0x00, // CW mode }; SI4463_do_api(data, sizeof(data), NULL, 0); } #endif #if 1 { uint8_t data[] = { SI446X_CMD_SET_PROPERTY, 0x22, 0x04, 0x00, // PA_MODE 0x08, // Coarse PA mode and class E PA Fine PA mode = 0x04 (uint8_t)SI4463_output_level, // Level 0x00, // Duty 0x00 // Ramp }; SI4463_do_api(data, sizeof(data), NULL, 0); } #endif // retry: { uint8_t data[] = { SI446X_CMD_ID_START_TX, CHANNEL, 0, // Stay in TX state 0, // TX len 0, // TX len 0,// TX delay 0// Num repeat }; SI4463_do_api(data, sizeof(data), NULL, 0); } SI4463_in_tx_mode = true; my_microsecond_delay(1000); #if 0 // Check state for debugging s = SI4463_get_state(); if (s != SI446X_STATE_TX){ my_microsecond_delay(1000); goto retry; } #endif } int SI4463_start_rx(uint8_t CHANNEL) { si446x_state_t s = SI4463_get_state(); if (s == SI446X_STATE_TX){ if (SI4463_set_state(SI446X_STATE_READY)) return -1; } if (SI4463_refresh_gpio()) return -1; #if 0 { uint8_t data[] = { 0x11, 0x10, 0x01, 0x03, 0xf0 }; SI4463_do_api(data, sizeof(data), NULL, 0); // Send PREAMBLE_CONFIG_STD_2 for long timeout } { uint8_t data[] = { 0x11, 0x20, 0x01, 0x00, 0x09, // Restore OOK mode }; SI4463_do_api(data, sizeof(data), NULL, 0); } #endif uint8_t data[] = { SI446X_CMD_ID_START_RX, CHANNEL, 0, 0, 0, #ifdef __USE_FRR_FOR_RSSI__ SI446X_CMD_START_RX_ARG_NEXT_STATE1_RXTIMEOUT_STATE_ENUM_RX, #else SI446X_CMD_START_RX_ARG_NEXT_STATE1_RXTIMEOUT_STATE_ENUM_NOCHANGE, #endif SI446X_CMD_START_RX_ARG_NEXT_STATE2_RXVALID_STATE_ENUM_RX, SI446X_CMD_START_RX_ARG_NEXT_STATE3_RXINVALID_STATE_ENUM_RX }; //retry: if (SI4463_do_api(data, sizeof(data), NULL, 0)) return -1; #if 0 // Get state for debugging si446x_state_t s = SI4463_get_state(); if (s != SI446X_STATE_RX) { my_microsecond_delay(1000); goto retry; } #endif #if 0 { uint8_t data2[] = { 0x11, 0x20, 0x01, 0x58, 0x10 }; // set FAST_DELAY to 0x10, SI4463_do_api(data2, sizeof(data2), NULL, 0); } #endif SI4463_in_tx_mode = false; return 0; } void SI4463_short_start_rx(void) { uint8_t data[] = { SI446X_CMD_ID_START_RX, }; SI4463_do_api(data, sizeof(data), NULL, 0); SI4463_in_tx_mode = false; } void SI4463_clear_int_status(void) { uint8_t data[9] = { SI446X_CMD_ID_GET_INT_STATUS }; SI4463_do_api(data, 1, data, SI446X_CMD_REPLY_COUNT_GET_INT_STATUS); } void set_calibration_freq(int ref) { if (ref >= 0) { SI4463_set_gpio(0, SI446X_GPIO_MODE_DIV_CLK); // GPIO 0 is clock out uint8_t data2[5] = { // GLOBAL_CLK_CFG Clock config SI446X_CMD_SET_PROPERTY, SI446X_PROP_GROUP_GLOBAL, 0x01, 0x01, 0x40|(ref<<3)// DIVIDED_CLK_EN = 1, DIVIDED_CLK_SEL = ref, CLK_32K_SEL = 0 }; SI4463_do_api(data2, 5, NULL, 0); } else { SI4463_set_gpio(0, SI446X_GPIO_MODE_TRISTATE); // stop clock out } } si446x_info_t SI4463_info; void Si446x_getInfo(si446x_info_t* info) { uint8_t data[8] = {SI446X_CMD_PART_INFO}; SI4463_do_api(data, 1, data, 8); info->chipRev = data[0]; info->part = (data[1]<<8) | data[2]; info->partBuild = data[3]; info->id = (data[4]<<8) | data[5]; info->customer = data[6]; info->romId = data[7]; data[0] = SI446X_CMD_FUNC_INFO; SI4463_do_api(data, 1, data, 6); info->revExternal = data[0]; info->revBranch = data[1]; info->revInternal = data[2]; info->patch = (data[3]<<8) | data[4]; info->func = data[5]; } float old_temp = -100; #define TEMP_HISTERESE 0.5 float Si446x_get_temp(void) { uint8_t data[8] = { SI446X_CMD_GET_ADC_READING, 0x10, 0 }; SI4463_do_api(data, 3, data, 8); float t = (data[4] << 8) + data[5]; t = (899.0 * t /4096.0) - 293.0; if (t > old_temp - TEMP_HISTERESE && t < old_temp + TEMP_HISTERESE) { return(old_temp); } old_temp = t; return t; } #ifdef notused static uint8_t SI4463_get_device_status(void) { uint8_t data[2] = { SI446X_CMD_ID_REQUEST_DEVICE_STATE, 0 }; SI4463_do_api(data, 1, data, SI446X_CMD_REPLY_COUNT_REQUEST_DEVICE_STATE); return(data[0]); } #endif // Read a fast response register uint8_t getFRR(uint8_t reg) { set_SPI_mode(SPI_MODE_SI); // SPI_BR_SET(SI4432_SPI, SI4432_SPI_SPEED); return SI4463_read_byte(reg); } // Get current radio state static si446x_state_t SI4463_get_state(void) { #if 0 #if 0 uint8_t data[2] = { SI446X_CMD_REQUEST_DEVICE_STATE }; SI4463_do_api(data, 1, data, 2); uint8_t state = data[0] & 0x0F; #endif uint8_t state = SI4463_get_device_status(); #else //again: // SI4463_wait_for_cts(); uint8_t state = getFRR(SI446X_CMD_READ_FRR_B); #endif #if 0 // Only for debugging if (state == 255) { my_microsecond_delay(100); goto again; } #endif if(state == SI446X_STATE_TX_TUNE) state = SI446X_STATE_TX; else if(state == SI446X_STATE_RX_TUNE) state = SI446X_STATE_RX; else if(state == SI446X_STATE_READY2) state = SI446X_STATE_READY; else state = state; return (si446x_state_t)state; } void set_RSSI_comp(void) { // Set properties: RF_MODEM_RSSI_COMP_1 // Number of properties: 1 // Group ID: 0x20 // Start ID: 0x4E // Default values: 0x40, // Descriptions: // MODEM_RSSI_COMP - RSSI compensation value. // // #define RF_MODEM_RSSI_COMP_1 0x11, 0x20, 0x01, 0x4E, 0x40 uint8_t data[5] = { SI446X_CMD_SET_PROPERTY, SI446X_PROP_GROUP_MODEM, 0x01, 0x4E, // MODEM_RSSI_COMP set as 0x40 // RSSI_COMP }; SI4463_do_api(data, sizeof(data), NULL, 0); } static bool SI4463_offset_active = false; static void SI4463_set_offset(int16_t offset){ // Set properties: MODEM_FREQ_OFFSET // Number of properties: 2 // Group ID: 0x20 // Start ID: 0x0d // Default values: 0x00, 0x00 // Descriptions: // MODEM_FREQ_OFFSET1 - High byte of the offset // MODEM_FREQ_OFFSET2 - Low byte of the offset // uint8_t data[] = { SI446X_CMD_SET_PROPERTY, SI446X_PROP_GROUP_MODEM, 0x02, 0x0d, // MODEM_FREQ_OFFSET (uint8_t) ((offset>>8) & 0xff), (uint8_t) ((offset) & 0xff) }; SI4463_do_api(data, sizeof(data), NULL, 0); SI4463_offset_changed = true; SI4463_offset_active = (offset != 0); } // Set offset for frequency void si_set_offset(int16_t offset) { SI4463_offset_value = offset; SI4463_set_offset(offset); } // Set additional offset for fm modulation output void si_fm_offset(int16_t offset) { SI4463_set_offset(offset + SI4463_offset_value); } #ifdef __FAST_SWEEP__ extern deviceRSSI_t age[POINTS_COUNT]; static int buf_index = 0; static uint16_t buf_end = 0; static bool buf_read = false; static char Si446x_readRSSI(void){ uint8_t rssi; #ifdef __USE_FRR_FOR_RSSI__ #if 0 // Restart RX, not needed as modem stays in RX mode SI4463_WAIT_CTS; // Wait for CTS SPI_WRITE_8BIT(SI4432_SPI, SI446X_CMD_ID_START_RX); while (SPI_IS_BUSY(SI4432_SPI)) ; // wait tx SPI_READ_8BIT(SI4432_SPI); // Skip command byte response #endif while (SPI_RX_IS_NOT_EMPTY(SI4432_SPI)) (void)SPI_READ_8BIT(SI4432_SPI); // Remove lingering bytes do { SI_CS_LOW; SPI_WRITE_8BIT(SI4432_SPI, SI446X_CMD_READ_FRR_A); SPI_WRITE_8BIT(SI4432_SPI, 0xFF); // read FRR_A while (SPI_IS_BUSY(SI4432_SPI)); // wait SPI_READ_8BIT(SI4432_SPI); rssi = SPI_READ_8BIT(SI4432_SPI); // get last byte as FRR_A (rssi) SI_CS_HIGH; } while (rssi == 0); // Wait for latch to happen #elif 0 SI_CS_LOW; SI4463_WAIT_CTS; // Wait for CTS SPI_WRITE_8BIT(SI4432_SPI, SI446X_CMD_GET_MODEM_STATUS); while (SPI_IS_BUSY(SI4432_SPI)) ; // wait tx SI_CS_HIGH; while (SPI_RX_IS_NOT_EMPTY(SI4432_SPI)) (void)SPI_READ_8BIT(SI4432_SPI); // Remove lingering bytes SI4463_WAIT_CTS; // Wait for CTS SI_CS_LOW; SPI_WRITE_8BIT(SI4432_SPI, SI446X_CMD_READ_CMD_BUFF); // read answer while (SPI_IS_BUSY(SI4432_SPI)) ; // wait tx SPI_READ_8BIT(SI4432_SPI); // Drop SI446X_CMD_READ_CMD_BUFF read SPI_WRITE_16BIT(SI4432_SPI, 0xFFFF); // begin read 2 bytes SPI_WRITE_16BIT(SI4432_SPI, 0xFFFF); // next read 2 bytes while (SPI_IS_BUSY(SI4432_SPI)); // wait tx SPI_READ_8BIT(SI4432_SPI); // read CMD_ COMPLETE SPI_READ_8BIT(SI4432_SPI); // MODEM_PEND SPI_READ_8BIT(SI4432_SPI); // MODEM_STATUS rssi = SPI_READ_8BIT(SI4432_SPI); // CURR_RSSI // SPI_WRITE_8BIT(SI4432_SPI, 0xFF); // while (SPI_IS_BUSY(SI4432_SPI)) ; // wait tx // rssi = SPI_READ_8BIT(SI4432_SPI); // LATCH_RSSI SI_CS_HIGH; #else uint8_t data[4]; data[0] = SI446X_CMD_GET_MODEM_STATUS; SI4463_do_api(data, 1, data, 3); rssi = data[2]; if (rssi > 197) rssi -= 1; #endif return rssi; } //--------------------------- Trigger ------------------- // ************** trigger mode if need #if 0 // trigger on measure 4 point #define T_POINTS 4 #define T_LEVEL_UNDEF (1<<(16-T_POINTS)) // should drop after 4 shifts left #define T_LEVEL_BELOW 1 #define T_LEVEL_ABOVE 0 // Trigger mask, should have width T_POINTS bit #define T_DOWN_MASK (0b0011) // 2 from up 2 to bottom #define T_UP_MASK (0b1100) // 2 from bottom 2 to up #define T_LEVEL_CLEAN ~(1<= sweep_points) i = 0; switch (waiting) { case ST_ARMING: if (i == sweep_points-1) { waiting = ST_WAITING; setting.measure_sweep_time_us = sa_ST2US(chVTGetSystemTimeX() - measure); } break; case ST_WAITING: // Store data level bitfield (remember only last 2 states) // T_LEVEL_UNDEF mode bit drop after 2 shifts #if 0 if (rssi < trigger_lvl) { data_level = ((data_level<<1) | (T_LEVEL_BELOW))&(T_LEVEL_CLEAN); } else { data_level = ((data_level<<1) | (T_LEVEL_ABOVE))&(T_LEVEL_CLEAN); } #else data_level = ((data_level<<1) | (rssi < trigger_lvl ? T_LEVEL_BELOW : T_LEVEL_ABOVE))&(T_LEVEL_CLEAN); #endif if (data_level == t_mode) { // wait trigger // if (i == 128) { // wait trigger waiting = ST_FILLING; switch (trigger_mode) { case T_PRE: // Trigger at the begin of the scan buf_index = i; goto fill_rest; break; case T_POST: // Trigger at the end of the scan buf_index = i; goto done; break; case T_MID: // Trigger in the middle of the scan buf_index = i + sweep_points/2; if (buf_index >= sweep_points) buf_index -= sweep_points; break; } } break; case ST_FILLING: if (i == buf_index) goto done; } fill_rest: if (t) my_microsecond_delay(t); }while(1); done: buf_end = buf_index; buf_read = true; } void SI446x_Fill(int s, int start) { (void)s; set_SPI_mode(SPI_MODE_SI); #if 0 // Only for testing uint8_t data2[] = { 0x11, 0x20, 0x01, 0x4C, 0x03 // set RSSI control }; SI4463_do_api(data2, sizeof(data2), NULL, 0); uint8_t data[] = { 0x12, 0x20, 0x01, 0x4C // get RSSI control }; SI4463_do_api(data, sizeof(data), data, 1); #endif // SPI_BR_SET(SI4432_SPI, SI4432_SPI_FASTSPEED); uint32_t t = setting.additional_step_delay_us; static uint32_t old_t = 0; if (t < old_t +100 && t + 100 > old_t) { // avoid oscillation t = (t + old_t) >> 1; } old_t = t; systime_t measure = chVTGetSystemTimeX(); int i = start; // For SI446X_CMD_READ_FRR_A need drop Rx buffer #ifdef __USE_FRR_FOR_RSSI__ while(SPI_RX_IS_NOT_EMPTY(SI4432_SPI)) (void)SPI_READ_8BIT(SI4432_SPI); // Remove lingering bytes // Get first point data pureRSSI_t last; do{ SI_CS_LOW; SPI_WRITE_8BIT(SI4432_SPI, SI446X_CMD_READ_FRR_A); SPI_WRITE_8BIT(SI4432_SPI, 0xFF); // begin read 1 bytes while (SPI_IS_BUSY(SI4432_SPI)) ; // wait tx SPI_READ_8BIT(SI4432_SPI); // Skip command byte response last = SPI_READ_8BIT(SI4432_SPI); // Get FRR A SI_CS_HIGH; } while (last == 0); #endif __disable_irq(); do { #ifndef __USE_FRR_FOR_RSSI__ if (t) my_microsecond_delay(t); age[i] = Si446x_readRSSI(); if (++i >= sweep_points) break; #else // DEBUG!! restart SI_CS_LOW; SPI_WRITE_8BIT(SI4432_SPI, SI446X_CMD_READ_FRR_A); SPI_WRITE_8BIT(SI4432_SPI, 0xFF); // begin read 1 bytes while (SPI_IS_BUSY(SI4432_SPI)) ; // wait tx SPI_READ_8BIT(SI4432_SPI); // Skip command byte response age[i] = SPI_READ_8BIT(SI4432_SPI); // Get FRR A SI_CS_HIGH; // latched RSSI reset for next measure - use last known data, for stable measure time if (age[i] == 0) age[i] = last; last = age[i]; if (t) my_microsecond_delay(t); if (++i >= sweep_points) break; #endif } while(1); __enable_irq(); setting.measure_sweep_time_us = sa_ST2US(chVTGetSystemTimeX() - measure); buf_index = (start<=0 ? 0 : start); // Is used to skip 1st entry during level triggering buf_end = sweep_points - 1; buf_read = true; } #endif #ifdef __LISTEN__ const uint8_t dBm_to_volt [] = { 255, 225, 198, 175, 154, 136, 120, 106, 93, 82, 72, 64, 56, 50, 44, 39, 34, 30, 26, 23, 21, 18, 16, 14, 12, 11, 10, 8, 7, 7, 6, 5, 5, }; static int32_t RSSI_RAW = 0; void SI4432_Listen(int s) { (void) s; uint8_t max = 0; uint16_t count = 0; operation_requested = OP_NONE; // SI4463_WAIT_CTS; // Wait for CTS do { uint8_t v = Si446x_readRSSI(); if (config.no_audio_agc) { DAC->DHR12R1 = v << 4; // Use DAC: CH1 and put 12 bit right aligned value } else { if (max < v) // Peak max = v; if (count > 1000) { // Decay max -= 1; count = 0; } else count++; v = max - v; DAC->DHR12R1 = dBm_to_volt[v] << 4; // Use DAC: CH1 and put 12 bit right aligned value } } while(operation_requested == OP_NONE); count = 0; // dacPutChannelX(&DACD2, 0, 0); } #endif int16_t Si446x_RSSI(bool break_on_operation) { #ifdef __FAST_SWEEP__ if (buf_read) { pureRSSI_t val = DEVICE_TO_PURE_RSSI(age[buf_index++]); if (buf_index >= sweep_points) buf_index = 0; if (buf_index == buf_end) buf_read = false; return val; } #endif int i = setting.repeat; if (setting.exp_aver == 1) RSSI_RAW = 0; // SI4463_WAIT_CTS; // Wait for CTS do{ // if (MODE_INPUT(setting.mode) && RSSI_R #define SAMPLE_COUNT 1 int j = SAMPLE_COUNT; //setting.repeat; int RSSI_RAW_ARRAY[3]; do{ // if (setting.step_delay) // my_microsecond_delay(setting.step_delay); // moved to sweep RSSI_RAW_ARRAY[--j] = Si446x_readRSSI(); if (j == 0) break; // my_microsecond_delay(20); }while(1); #if SAMPLE_COUNT == 3 int t; if (RSSI_RAW_ARRAY[0] > RSSI_RAW_ARRAY[1]) { t = RSSI_RAW_ARRAY[1]; RSSI_RAW_ARRAY[1] = RSSI_RAW_ARRAY[0]; RSSI_RAW_ARRAY[0] = t; } if (RSSI_RAW_ARRAY[1] > RSSI_RAW_ARRAY[2]) { t = RSSI_RAW_ARRAY[2]; RSSI_RAW_ARRAY[2] = RSSI_RAW_ARRAY[1]; RSSI_RAW_ARRAY[1] = t; } if (RSSI_RAW_ARRAY[0] > RSSI_RAW_ARRAY[1]) { t = RSSI_RAW_ARRAY[1]; RSSI_RAW_ARRAY[1] = RSSI_RAW_ARRAY[0]; RSSI_RAW_ARRAY[0] = t; } RSSI_RAW += DEVICE_TO_PURE_RSSI(RSSI_RAW_ARRAY[1]); #else #ifdef TINYSA4 if (setting.exp_aver == 1) RSSI_RAW += DEVICE_TO_PURE_RSSI(RSSI_RAW_ARRAY[0]); else RSSI_RAW = ((setting.exp_aver-1) * RSSI_RAW + DEVICE_TO_PURE_RSSI(RSSI_RAW_ARRAY[0]))/setting.exp_aver; #else RSSI_RAW += DEVICE_TO_PURE_RSSI(RSSI_RAW_ARRAY[0]); #endif #endif if (--i <= 0) break; if (setting.repeat > 1) my_microsecond_delay(SI4432_step_delay); if (break_on_operation && operation_requested) break; }while(1); if (setting.repeat > 1 && setting.exp_aver == 1) RSSI_RAW = RSSI_RAW / setting.repeat; return RSSI_RAW; } void SI446x_set_AGC_LNA(uint8_t v) { uint8_t data[2] = { 0xd0, // AGC_OVERRIDE v }; SI4463_do_api(data, sizeof(data), NULL, 0); #if 0 if (v == 0) { data[0] = 0xd1; // Read AGC?????? NO SI4463_do_api(data, 1, data, 1); } #endif } #ifdef notused // Do an ADC conversion static uint16_t getADC(uint8_t adc_en, uint8_t adc_cfg, uint8_t part) { uint8_t data[6] = { SI446X_CMD_GET_ADC_READING, adc_en, adc_cfg }; SI4463_do_api(data, 3, data, 6); return (data[part]<<8 | data[part + 1]); } #endif // -------------- 0.2 kHz ---------------------------- #include "radio_config_Si4468_undef.h" #include "radio_config_Si4468_200Hz.h" #include "radio_config_Si4468_short.h" static const uint8_t SI4463_RBW_02kHz[] = RADIO_CONFIGURATION_DATA_ARRAY; // -------------- 1kHz ---------------------------- #include "radio_config_Si4468_undef.h" #include "radio_config_Si4468_1kHz.h" #include "radio_config_Si4468_short.h" static const uint8_t SI4463_RBW_1kHz[] = RADIO_CONFIGURATION_DATA_ARRAY; // -------------- 3 kHz ---------------------------- #include "radio_config_Si4468_undef.h" #include "radio_config_Si4468_3kHz.h" #include "radio_config_Si4468_short.h" static const uint8_t SI4463_RBW_3kHz[] = RADIO_CONFIGURATION_DATA_ARRAY; // -------------- 10 kHz ---------------------------- #include "radio_config_Si4468_undef.h" #include "radio_config_Si4468_10kHz.h" #include "radio_config_Si4468_short.h" static const uint8_t SI4463_RBW_10kHz[] = RADIO_CONFIGURATION_DATA_ARRAY; // -------------- 30 kHz ---------------------------- #include "radio_config_Si4468_undef.h" #include "radio_config_Si4468_30kHz.h" #include "radio_config_Si4468_short.h" static const uint8_t SI4463_RBW_30kHz[] = RADIO_CONFIGURATION_DATA_ARRAY; // -------------- 100kHz ---------------------------- #include "radio_config_Si4468_undef.h" #include "radio_config_Si4468_100kHz.h" #include "radio_config_Si4468_short.h" static const uint8_t SI4463_RBW_100kHz[] = RADIO_CONFIGURATION_DATA_ARRAY; // -------------- 300kHz ---------------------------- #include "radio_config_Si4468_undef.h" #include "radio_config_Si4468_300kHz.h" #include "radio_config_Si4468_short.h" static const uint8_t SI4463_RBW_300kHz[] = RADIO_CONFIGURATION_DATA_ARRAY; // -------------- 600kHz ---------------------------- #include "radio_config_Si4468_undef.h" #include "radio_config_Si4468_600kHz.h" #include "radio_config_Si4468_short.h" static const uint8_t SI4463_RBW_600kHz[] = RADIO_CONFIGURATION_DATA_ARRAY; // -------------- 850kHz ---------------------------- #include "radio_config_Si4468_undef.h" #include "radio_config_Si4468_850kHz.h" #include "radio_config_Si4468_short.h" static const uint8_t SI4463_RBW_850kHz[] = RADIO_CONFIGURATION_DATA_ARRAY; // User asks for an RBW of WISH, go through table finding the last triple // for which WISH is greater than the first entry, use those values, // Return the first entry of the following triple for the RBW actually achieved #define IF_BW(dwn3, ndec, filset) (((dwn3)<<7)|((ndec)<<4)|(filset)) typedef struct { const uint8_t *reg; // IF_BW(dwn3, ndec, filset) int16_t RSSI_correction_x_10; // Correction * 10 int16_t RBWx10; // RBW in kHz int16_t noise_correction_x10; // Noise marker correction * 10 }RBW_t; // sizeof(RBW_t) = 8 bytes static const RBW_t RBW_choices[] = { #if 0 // BW register corr freq {SI4463_RBW_02kHz, 20,3, 26}, {SI4463_RBW_1kHz, 23,10, 8}, {SI4463_RBW_3kHz, 17,30, 9}, {SI4463_RBW_10kHz, 12,100, 7}, {SI4463_RBW_30kHz, 12,300, 10}, {SI4463_RBW_100kHz, 2,1000, 17}, {SI4463_RBW_300kHz, 4,3000, 10}, {SI4463_RBW_600kHz, -10,6000, 8}, {SI4463_RBW_850kHz, -9,8500, 8}, #else #define NOISE_BASE_CORRECTION 7 // 7 {SI4463_RBW_02kHz, 10,2, NOISE_BASE_CORRECTION + 0}, // {SI4463_RBW_1kHz, 15,10, NOISE_BASE_CORRECTION + -5},// {SI4463_RBW_3kHz, 10,30, NOISE_BASE_CORRECTION + -5},// {SI4463_RBW_10kHz, 14,100,NOISE_BASE_CORRECTION + -2}, // {SI4463_RBW_30kHz, 0,300, NOISE_BASE_CORRECTION + -2},// {SI4463_RBW_100kHz, 0,1000,NOISE_BASE_CORRECTION + -1},// {SI4463_RBW_300kHz, 0,3000,NOISE_BASE_CORRECTION}, // 300k must have RSSI correction = 0 {SI4463_RBW_600kHz, 5,6000,NOISE_BASE_CORRECTION + -2},// {SI4463_RBW_850kHz, 8,8500,NOISE_BASE_CORRECTION + 2},// #endif }; const uint8_t SI4432_RBW_count = ((int)(sizeof(RBW_choices)/sizeof(RBW_t))); static pureRSSI_t SI4463_RSSI_correction = float_TO_PURE_RSSI(-120); bool SI4463_RSSI_correction_enabled = true; int16_t SI4463_noise_correction_x10; static int prev_band = -1; pureRSSI_t getSI4463_RSSI_correction(void){ return SI4463_RSSI_correction; }; void switch_SI4463_RSSI_correction(bool enabled){ SI4463_RSSI_correction_enabled = enabled; }; void SI4463_set_IF(int band) { // Set properties: MODEM_IF_FREQ // Number of properties: 3 // Group ID: 0x20 // Start ID: 0x1b // Descriptions: // MODEM_IF_FREQ - Set the IF frequency as a function of frequency band. // #define RF_MODEM_CLKGEN_BAND_1 0x11, 0x20, 0x01, 0x51, 0x0A //#define RF_MODEM_TX_RAMP_DELAY_12 0x11, 0x20, 0x03, 0x18, 0x03, 0xC0, 0x00 static const uint8_t if_freq_high[6] = { 0x03, 0x03, 0x03, 0x03, 0, 0x02}; static const uint8_t if_freq_low[6] = { 0xc0, 0x60, 0x80, 0x40, 0, 0x80}; uint8_t data3[] = { 0x11, 0x20, 0x03, 0x1b, if_freq_high[band], if_freq_low[band] }; SI4463_do_api(data3, sizeof(data3), NULL, 0); } void SI4463_set_modem_DSM(void) { // Set properties: MODEM_DSM_CTRL // Number of properties: 1 // Group ID: 0x20 // Start ID: 0x02 // Descriptions: // MODEM_DSM_CTRL - Miscellaneous control bits for the Delta-Sigma Modulator (DSM) in the PLL Synthesizer. //#define MODEM_DSM_CTRL 0x11, 0x20, 0x01, 0x02, 0x07 static const uint8_t data3[] = { 0x11, 0x20, 0x01, 0x02, 0x03}; SI4463_do_api((uint8_t *)data3, sizeof(data3), NULL, 0); } uint16_t force_rbw(int f) { if (/*SI4463_in_tx_mode || */ f >= (int)(sizeof(RBW_choices)/sizeof(RBW_t))) return(0); // RBW can be selected before switch to input mode is made SI4463_set_state(SI446X_STATE_READY); const uint8_t *config = RBW_choices[f].reg; uint16_t i=0; while(config[i] != 0) { SI4463_do_api((void *)&config[i+1], config[i], NULL, 0); i += config[i]+1; } if (prev_band != 0) SI4463_set_IF(prev_band); // restore IF frequency if not in band zero if (setting.frequency_step < 100) SI4463_set_modem_DSM(); // Set small frequency steps if needed SI4463_clear_int_status(); SI4463_short_start_rx(); // This can cause recalibration // SI4463_wait_for_cts(); set_RSSI_comp(); // prev_band = -1; SI4463_RSSI_correction = ( SI4463_RSSI_correction_enabled ? float_TO_PURE_RSSI(RBW_choices[f].RSSI_correction_x_10 - 1200)/10 : float_TO_PURE_RSSI(-120) ) ; // Set RSSI correction SI4463_noise_correction_x10 = RBW_choices[f].noise_correction_x10; SI4463_rbw_selected = f; return RBW_choices[f].RBWx10; // RBW achieved by SI4463 in kHz * 10 } uint16_t set_rbw(uint16_t WISH) { int i; for (i=0; i < (int)(sizeof(RBW_choices)/sizeof(RBW_t)) - 1; i++) if (WISH <= RBW_choices[i].RBWx10) break; return force_rbw(i); } #define Npresc 1 // 0=low / 1=High performance mode freq_t SI4463_set_freq(freq_t freq) { uint32_t output_divider; // SI4463_set_gpio(3,SI446X_GPIO_MODE_DRIVE1); // For measuring duration of set_freq int S = 4 ; // Approx 100 Hz channels SI4463_channel = 0; if (freq >= 822000000 && freq <= 1150000000) { // 822 to 1130MHz SI4463_band = 0; output_divider = 4 * FREQ_MULTIPLIER; } else if (freq >= 411000000 && freq <= 566000000) { // 411 to 568MHz SI4463_band = 2; output_divider = 8 * FREQ_MULTIPLIER ; } else if (freq >= 329000000 && freq <= 454000000) { // 329 to 454MHz SI4463_band = 1; output_divider = 10 * FREQ_MULTIPLIER; } else if (freq >= 274000000 && freq <= 378000000) { // 274 to 378 SI4463_band = 3; output_divider = 12 * FREQ_MULTIPLIER; } else if (freq >= 137000000 && freq <= 189000000){ // 137 to 189 SI4463_band = 5; output_divider = 24 * FREQ_MULTIPLIER; #if 0 // Band 4, 6 and 7 do not function } else if (freq >= 137000000 && freq <= 189000000){ // 220 to 266 SI4463_band = 4; output_divider = 12; #endif } else return 0; if (SI4463_offset_active) { si_set_offset(0); SI4463_offset_active = false; } uint32_t R = (freq * output_divider) / (Npresc ? 2*config.setting_frequency_30mhz : 4*config.setting_frequency_30mhz) - 1; // R between 0x00 and 0x7f (127) uint64_t MOD = 524288; // = 2^19 uint32_t F = ((freq * output_divider*MOD) / (Npresc ? 2*config.setting_frequency_30mhz : 4*config.setting_frequency_30mhz)) - R*MOD; freq_t actual_freq = (R*MOD + F) * (Npresc ? 2*config.setting_frequency_30mhz : 4*config.setting_frequency_30mhz)/ output_divider/MOD; #if 0 // Only for debugging int delta = freq - actual_freq; if (delta < -100 || delta > 100 ){ while(1) my_microsecond_delay(10); } if (F < MOD || F >= MOD*2){ while(1) my_microsecond_delay(10); } #endif #if 0 // Hopping is fast but frequency setting is not yet reliable !!!!! if (SI4463_band == prev_band) { int vco = 2091 + ((((freq / 4 ) * output_divider - 850000000)/1000) * 492) / 200000; if (SI4463_in_tx_mode) { uint8_t data[] = { SI446X_CMD_ID_TX_HOP, (uint8_t) R, // R data[4] (uint8_t) ((F>>16) & 255), // F2,F1,F0 data[5] .. data[7] (uint8_t) ((F>> 8) & 255), // F2,F1,F0 data[5] .. data[7] (uint8_t) ((F ) & 255), // F2,F1,F0 data[5] .. data[7] (vco>>8) & 0xff, vco & 0xff, 0x00, 0x32 }; SI4463_do_api(data, sizeof(data), NULL, 0); } else { uint8_t data[] = { SI446X_CMD_ID_RX_HOP, (uint8_t) R, // R data[4] (uint8_t) ((F>>16) & 255), // F2,F1,F0 data[5] .. data[7] (uint8_t) ((F>> 8) & 255), // F2,F1,F0 data[5] .. data[7] (uint8_t) ((F ) & 255), // F2,F1,F0 data[5] .. data[7] (vco>>8) & 0xff, vco & 0xff }; SI4463_do_api(data, sizeof(data), NULL, 0); } SI4463_frequency_changed = true; // SI4463_set_gpio(3,SI446X_GPIO_MODE_DRIVE0); // For measuring duration of set_freq return actual_freq; } #endif SI4463_set_state(SI446X_STATE_READY); /* // Set properties: RF_FREQ_CONTROL_INTE_8 // Number of properties: 8 // Group ID: 0x40 // Start ID: 0x00 // Default values: 0x3C, 0x08, 0x00, 0x00, 0x00, 0x00, 0x20, 0xFF, // Descriptions: // FREQ_CONTROL_INTE - Frac-N PLL Synthesizer integer divide number. // FREQ_CONTROL_FRAC_2 - Frac-N PLL fraction number. // FREQ_CONTROL_FRAC_1 - Frac-N PLL fraction number. // FREQ_CONTROL_FRAC_0 - Frac-N PLL fraction number. // FREQ_CONTROL_CHANNEL_STEP_SIZE_1 - EZ Frequency Programming channel step size. // FREQ_CONTROL_CHANNEL_STEP_SIZE_0 - EZ Frequency Programming channel step size. // FREQ_CONTROL_W_SIZE - Set window gating period (in number of crystal reference clock cycles) for counting VCO frequency during calibration. // FREQ_CONTROL_VCOCNT_RX_ADJ - Adjust target count for VCO calibration in RX mode. */ // #define RF_FREQ_CONTROL_INTE_8_1 0x11, 0x40, 0x08, 0x00, 0x41, 0x0D, 0xA9, 0x5A, 0x4E, 0xC5, 0x20, 0xFE uint8_t data[] = { 0x11, 0x40, 0x06, 0x00, (uint8_t) R, // R data[4] (uint8_t) ((F>>16) & 255), // F2,F1,F0 data[5] .. data[7] (uint8_t) ((F>> 8) & 255), // F2,F1,F0 data[5] .. data[7] (uint8_t) ((F ) & 255), // F2,F1,F0 data[5] .. data[7] (uint8_t) ((S>> 8) & 255), // Step size data[8] .. data[9] (uint8_t) ((S ) & 255), // Step size data[8] .. data[9] #if 1 0x20, // Window gate 0xFF, // Adj count #endif }; SI4463_do_api(data, sizeof(data), NULL, 0); if (SI4463_band != prev_band) { /* // Set properties: RF_MODEM_CLKGEN_BAND_1 // Number of properties: 1 // Group ID: 0x20 // Start ID: 0x51 // Default values: 0x08, // Descriptions: // MODEM_CLKGEN_BAND - Select PLL Synthesizer output divider ratio as a function of frequency band. */ // #define RF_MODEM_CLKGEN_BAND_1 0x11, 0x20, 0x01, 0x51, 0x0A uint8_t data2[] = { 0x11, 0x20, 0x01, 0x51, /* 0x10 + */ (uint8_t)(SI4463_band + (Npresc ? 0x08 : 0)) // 0x08 for high performance mode, 0x10 to skip recal }; SI4463_do_api(data2, sizeof(data2), NULL, 0); SI4463_set_IF(SI4463_band); prev_band = SI4463_band; } if (SI4463_in_tx_mode) SI4463_start_tx(0); else { SI4463_start_rx(0); } // SI4463_set_gpio(3,SI446X_GPIO_MODE_DRIVE0); // For measuring duration of set_freq SI4463_frequency_changed = true; return actual_freq; } void SI4463_init_rx(void) { reset: SI_SDN_LOW; my_microsecond_delay(10000); SI_SDN_HIGH; my_microsecond_delay(10000); SI_SDN_LOW; my_microsecond_delay(100000); if (SI4463_WAIT_CTS) { ili9341_drawstring("SI4468 Reset fail", 0,10); goto reset; } for(uint16_t i=0;i