diff --git a/si4432.cpp b/si4432.cpp index 20daf17..b2c3004 100644 --- a/si4432.cpp +++ b/si4432.cpp @@ -97,82 +97,6 @@ bool Si4432::Init ( uint8_t cap ) if ( !Reset () ) // Reset the module return false; // If that failed - SubInit (); // Things common to both modules - - -/* - * - * We turn on receive mode ("RXON"), the PLL ("PLLON") and ready mode - * ("XTON"). The Si4432 module does not have the 32.768 kHz crystal for - * the microcontroller, so we do not turn on the "X32KSEL" bit. - * - * The initial frequency is set to 433.92 MHz which is a typical IF - * Finally the GPIO-2 pin is set to ground. - * - * 03/24 - Logic verified against A440 register edscription document - */ - - WriteByte ( REG_OFC1, ( RXON | PLLON | XTON )); // Receiver, PLL and "Ready Mode" all on - Tune ( cap ); // Set the crystal capacitance to fine tune frequency - - SetFrequency ( 443920000 ); // 443.92MHz - delayMicroseconds ( 300 ); // Time to allow the SI4432 state machine to do its stuff - Serial.printf ( "End of Init - _cs = %i\n", _cs ); - return true; -} - - -//bool Si4432::TX_Init ( uint8_t cap, uint8_t power ) -//{ -// _type = TX_4432; // We're a transmitter -// -// if ( !Reset () ) // Reset the module -// return false; // If that failed -// _pwr = power; // Set the transmitter power level -// SubInit (); // Things common to both modules -// -// -///* -// * Settings specific to the transmitter module. -// * -// * This is almost identical to how we set up the receiver except we turn -// * on the "TXON" bit (0x08) instead of the "RXON" bit. We also set the -// * transmitter power based on the mixer module being used. ("CalcPower" -// * function sets the value). -// * -// * GPIO-2 is handled differently; here, we set GPIO-2 to output the -// * microcontroller clock at maximum drive level (0xC0). We also set the -// * microcontroller clock speed to 10MHz. -// * -// * 03/24 - Logic verified against A440 -// */ -// -// Tune ( cap ); // Set the crystal capacitance -// WriteByte ( REG_TXPWR, _pwr ); // Power based on mixer in use -// -// WriteByte ( REG_GPIO2, 0xC0 ); // Maximum drive and microcontroller clock output -// WriteByte ( REG_MCOC, 0x02 ); // Set 10MHz clock output -// -// SetFrequency ( 443920000 ); // 433.92MHz (setting.IF_Freq???) -// -// delayMicroseconds ( 300 ); // Doesn't work without this! -// -// WriteByte ( REG_OFC1, ( TXON | PLLON | XTON )); // Transmitter, PLL and "Ready Mode" all on -// -//// Serial.println ( "End of TX_Init" ); -// -// return true; -//} - - -/* - * "SubInit" is used by the "Init" function to set up - * all the registers. - */ - -void Si4432::SubInit () -{ - /* @@ -257,10 +181,31 @@ void Si4432::SubInit () WriteByte ( REG_GPIO1, 0x15 ); // GPIO-1 RX State (output) WriteByte ( REG_GPIO2, 0x1F ); // Set GPIO-2 output to ground until needed - + + +/* + * + * We turn on receive mode ("RXON"), the PLL ("PLLON") and ready mode + * ("XTON"). The Si4432 module does not have the 32.768 kHz crystal for + * the microcontroller, so we do not turn on the "X32KSEL" bit. + * + * The initial frequency is set to 433.92 MHz which is a typical IF + * Finally the GPIO-2 pin is set to ground. + * + * 03/24 - Logic verified against A440 register edscription document + */ + + WriteByte ( REG_OFC1, ( RXON | PLLON | XTON )); // Receiver, PLL and "Ready Mode" all on + Tune ( cap ); // Set the crystal capacitance to fine tune frequency + + SetFrequency ( 443920000 ); // 443.92MHz + delayMicroseconds ( 300 ); // Time to allow the SI4432 state machine to do its stuff + Serial.printf ( "End of Init - _cs = %i\n", _cs ); + return true; } + /* * "Reset" - Initializes the Si4432. * @@ -369,7 +314,7 @@ uint8_t Si4432::ReadByte ( uint8_t reg ) void Si4432::SetFrequency ( uint32_t freq ) { -int hbsel; // High/low band select bit +int hbsel; // high band select, but shifted to the correct location in the byte int sbsel; // Sideband select bit uint16_t carrier; // Carrier frequency uint32_t reqFreq = freq; // Copy of requested frequency @@ -440,56 +385,31 @@ uint8_t registerBuf[4]; // Used to send frequency data in burst mode /* * M0WID mod - Update the frequency in "burst" mode as opposed to separate - * writes for each register, but only update what is needed + * writes for each register */ uint8_t ncf1 = ( carrier >> 8 ) & 0xFF; -// if (fbs != _fbs) // write all three registers -// { - registerBuf[0] = REG_FBS|0x80; // First register in write mode (bit 7 set) - registerBuf[1] = fbs; // FBS register value - registerBuf[2] = ncf1 ; // NCF1 value - registerBuf[3] = carrier & 0xFF; // NCF0 value - - //_spi->beginTransaction ( SPISettings ( BUS_SPEED, BUS_ORDER, BUS_MODE )); - // spiSimpleTransaction(_spi->bus()); - digitalWrite ( _cs, LOW ); // Select the correct device - _spi->transfer ( registerBuf, 4 ); // Send the data - digitalWrite ( _cs, HIGH ); // Deselect the device - //_spi->endTransaction(); - _ncf1 = ncf1; - _fbs = fbs; -// } -// else if (ncf1 != _ncf1) // Only write both bytes of the carrier data -// { -// registerBuf[0] = REG_NCF1|0x80; // First register in write mode (bit 7 set) -// registerBuf[1] = ncf1 ; // NCF1 value -// registerBuf[2] = carrier & 0xFF; // NCF0 value -// digitalWrite ( _cs, LOW ); // Select the correct device -// _spi->transfer ( registerBuf, 3 ); // Send the data -// digitalWrite ( _cs, HIGH ); // Deselect the device -// _ncf1 = ncf1; -// } -// else // Only write the least significant byte of the carrier register -// { -// registerBuf[0] = REG_NCF0|0x80; // First register in write mode (bit 7 set) -// registerBuf[1] = carrier & 0xFF; // NCF0 value -// digitalWrite ( _cs, LOW ); // Select the correct device -// _spi->transfer ( registerBuf, 2 ); // Send the data -// digitalWrite ( _cs, HIGH ); // Deselect the device -// -// } + registerBuf[0] = REG_FBS|0x80; // First register in write mode (bit 7 set) + registerBuf[1] = fbs; // FBS register value + registerBuf[2] = ncf1 ; // NCF1 value + registerBuf[3] = carrier & 0xFF; // NCF0 value + + //_spi->beginTransaction ( SPISettings ( BUS_SPEED, BUS_ORDER, BUS_MODE )); +// spiSimpleTransaction(_spi->bus()); + digitalWrite ( _cs, LOW ); // Select the correct device + _spi->transfer ( registerBuf, 4 ); // Send the data + digitalWrite ( _cs, HIGH ); // Deselect the device + //_spi->endTransaction(); + _ncf1 = ncf1; + _fbs = fbs; uint32_t fb = ( fbs & F_BAND ) ; - hbsel = hbsel>>5; // should be 1 or 0 + _hbsel = hbsel>>5; // should be 1 or 0 // _freq will contain the actual frequency, not necessarily what was requested - _freq = (double)(10000000 * (hbsel + 1 )) * ( (double)fb + (double)24 + (double)carrier / (double)64000) ; + _freq = (double)(10000000 * (_hbsel + 1 )) * ( (double)fb + (double)24 + (double)carrier / (double)64000) ; // Serial.printf("set Freq :%i, actual:%i, fb:%i, fc:%i, hbsel:%i\n", reqFreq, _freq, fb, carrier, hbsel); -// _spi->endTransaction(); // Release the bus -// delayMicroseconds ( WRITE_DELAY ); // Delay needed when writing frequency - // Serial.print ( ", N = " ); // Serial.print ( N ); @@ -518,10 +438,55 @@ uint8_t registerBuf[4]; // Used to send frequency data in burst mode * handled by the calling program. */ -// delayMicroseconds ( _dt ); // M0WID - Delay depends on RBW +// delayMicroseconds ( _dt ); } + +/* + * "SetOffset" adjusts the frequency from the nominal value set in SetFrequency. + * It is intended for use by the SI4432 AFC algorithm to enable more accurate + * frequency matching of different radios, but we can turn off the AFC and use it + * to adjust the frequency without having the Si4432 go through its TX-RX-TX state machine + * and enable reduced edlay times from setting a frequency to getting valid readings + * The offset can vary +- 80kHz in low bands (f<480MHz) and +-160kHz in high bands (480-960MHz) + * negative numbers are twos complement of the positive offset + */ +void Si4432::SetOffset ( int32_t offset ) +{ + uint8_t registerBuf[3]; // Used to send data in burst mode + + uint32_t posOffset; + if (offset < 0) + posOffset = -offset; + else + posOffset = offset; + + uint16_t fo = (double)offset/(156.25 * (double)(_hbsel + 1)); + + if (offset < 0) + // do twos complement - invert the bits (0-8) (use XOR) and add one + fo = (fo ^ 0x3F) + 1; + + Serial.printf(" offset %i fo=%3x \n", offset, fo); + + // write to the Si4432 + registerBuf[0] = REG_FOFF1|0x80; // First register in write mode (bit 7 set) + registerBuf[1] = fo & 0xFF; // first 8 bits + registerBuf[2] = (fo >> 8 ) & 0x03; // last 2 bits + + //_spi->beginTransaction ( SPISettings ( BUS_SPEED, BUS_ORDER, BUS_MODE )); + // spiSimpleTransaction(_spi->bus()); + digitalWrite ( _cs, LOW ); // Select the correct device + _spi->transfer ( registerBuf, 3 ); // Send the data + digitalWrite ( _cs, HIGH ); // Deselect the device + //_spi->endTransaction(); + +} + + + + /* * "SetRBW" Sets the "Resolution Bandwidth" based on a required value passed in * and returns the actual value chosen as well as the required delay to allow the diff --git a/si4432.h b/si4432.h index ade99ba..93f75d4 100644 --- a/si4432.h +++ b/si4432.h @@ -142,6 +142,9 @@ #define REG_TXPWR 0x6D // Transmitter Power +#define REG_FOFF1 0x73 // Frequency Offset registers +#define REG_FOFF2 0x74 + #define REG_FBS 0x75 // Frequency Band Select #define SBSEL 0x40 #define HBSEL 0x20 @@ -175,6 +178,8 @@ void SetFrequency ( uint32_t Freq ); // Set module's frequency uint32_t GetFrequency (); // Get the module's frequency uint32_t ReadFrequency (); // Read frequency from SI4432 +void SetOffset ( int32_t offset ); // Set a frequency offset from the nominal frequency + void SetPowerReference ( int freq ); // Set the GPIO output for the LO void SetDrive ( uint8_t level ); // Sets the drive level void TxMode ( uint8_t level ); // Put module in TX mode @@ -221,6 +226,7 @@ uint8_t _pwr; // Current power output (TX only?) uint8_t _type; // Transmitter or receiver uint8_t _capacitance; // Crystal load capacitance SPIClass* _spi; // Pointer to the SPI object +int _hbsel; // High band (1) or low band (0) uint8_t _fbs; // Current value of frequency band select register uint8_t _ncf1; // Current value for most significant byte of carrier uint32_t _freq; // Current actual frequency