diff --git a/ADF7021.cpp b/ADF7021.cpp index f804fc0..abeedd3 100644 --- a/ADF7021.cpp +++ b/ADF7021.cpp @@ -34,8 +34,6 @@ volatile uint32_t AD7021_control_word; uint32_t ADF7021_RX_REG0; uint32_t ADF7021_TX_REG0; -volatile bool sle_request = false; - static void Send_AD7021_control_shift() { int AD7021_counter; @@ -51,34 +49,24 @@ static void Send_AD7021_control_shift() io.dlybit(); io.SCLK_pin(LOW); } + // to keep SDATA signal at defined level when idle (not required) + io.SDATA_pin(LOW); } -static void Send_AD7021_control_nosle() +static void Send_AD7021_control_slePulse() { - Send_AD7021_control_shift(); - sle_request = true; -} - -void Send_AD7021_control() -{ - int AD7021_counter; - - for(AD7021_counter = 31; AD7021_counter >= 0; AD7021_counter--) { - if(bitRead(AD7021_control_word, AD7021_counter) == HIGH) - io.SDATA_pin(HIGH); - else - io.SDATA_pin(LOW); - - io.dlybit(); - io.SCLK_pin(HIGH); - io.dlybit(); - io.SCLK_pin(LOW); - } - io.SLE_pin(HIGH); io.dlybit(); io.SLE_pin(LOW); - io.SDATA_pin(LOW); +} + +void Send_AD7021_control(bool doSle) +{ + Send_AD7021_control_shift(); + + if (doSle) { + Send_AD7021_control_slePulse(); + } } #if defined(SEND_RSSI_DATA) @@ -415,31 +403,36 @@ void CIO::ifConf(MMDVM_STATE modemState, bool reset) //====================================================================================================================== void CIO::setTX() { - // Send register 0 for TX operation + // PTT pin on (doing it earlier helps to measure timing impact) + PTT_pin(HIGH); + + // Send register 0 for TX operation, but do not activate yet. + // This is done in the interrupt at the correct time AD7021_control_word = ADF7021_TX_REG0; - Send_AD7021_control_nosle(); + Send_AD7021_control(false); + #if defined(BIDIR_DATA_PIN) Data_dir_out(true); // Data pin output mode #endif - - // PTT pin on - PTT_pin(HIGH); + } //====================================================================================================================== -void CIO::setRX() +void CIO::setRX(bool doSle) { - // Send register 0 for RX operation + // PTT pin off (doing it earlier helps to measure timing impact) + PTT_pin(LOW); + + // Send register 0 for RX operation, but do not activate yet. + // This is done in the interrupt at the correct time AD7021_control_word = ADF7021_RX_REG0; - Send_AD7021_control(); + Send_AD7021_control(doSle); #if defined(BIDIR_DATA_PIN) Data_dir_out(false); // Data pin input mode #endif - // PTT pin off - PTT_pin(LOW); } void CIO::setLoDevYSF(bool on) diff --git a/ADF7021.h b/ADF7021.h index cb8e843..02c3708 100644 --- a/ADF7021.h +++ b/ADF7021.h @@ -267,8 +267,8 @@ www.analog.com/media/en/technical-documentation/data-sheets/ADF7021.pdf #define bitRead(value, bit) (((value) >> (bit)) & 0x01) -void Send_AD7021_control(void); +void Send_AD7021_control(bool doSle = true); #endif -#endif \ No newline at end of file +#endif diff --git a/IO.cpp b/IO.cpp index 5d184d6..c8a3529 100644 --- a/IO.cpp +++ b/IO.cpp @@ -29,9 +29,11 @@ uint32_t m_frequency_rx; uint32_t m_frequency_tx; uint8_t m_power; -extern volatile bool sle_request; +// TODO: move to IO class as members +volatile bool totx_request = false; volatile bool torx_request = false; -bool volatile even = true; +volatile bool even = true; +static uint32_t last_clk = 2; CIO::CIO(): m_started(false), @@ -101,8 +103,7 @@ void CIO::process() // Switch off the transmitter if needed if (m_txBuffer.getData() == 0U && m_tx) { - //while(CLK_pin()==0) { asm volatile ("nop"); } - //while(CLK_pin()) { asm volatile ("nop"); } + setRX(false); torx_request = true; while(torx_request) { asm volatile ("nop"); } } @@ -158,13 +159,33 @@ void CIO::interrupt() if (!m_started) return; - uint8_t clk = CLK_pin(); + uint8_t clk = CLK_pin(); + + // this is to prevent activation by spurious interrupts + // which seem to happen if you send out an control word + // needs investigation + // this workaround will fail if only rising or falling edge + // is used to trigger the interrupt !!!! + // TODO: figure out why sending the control word seems to issue interrupts + // possibly this is a design problem of the RF7021 board or too long wires + // on the breadboard build + // but normally this will not hurt too much + if (clk == last_clk) { + return; + } else { + last_clk = clk; + } + + // we set the TX bit at TXD low, sampling of ADF7021 happens at rising clock if (m_tx && clk == 0) { m_txBuffer.get(bit); even = !even; + // use this for tracking issues + // P25_pin(even); + #if defined(BIDIR_DATA_PIN) if(bit) RXD_pin_write(HIGH); @@ -177,21 +198,26 @@ void CIO::interrupt() TXD_pin(LOW); #endif // wait a brief period before raising SLE - if (sle_request == true) { -#if 1 - asm volatile("mov r8, r8 \n\t" - "mov r8, r8 \n\t" - "mov r8, r8 \n\t" - ); -#endif + if (totx_request == true) { + asm volatile("nop \n\t" + "nop \n\t" + "nop \n\t" + ); + + // SLE Pulse, should be moved out of here into class method + // according to datasheet in 4FSK we have to deliver this before 1/4 tbit == 26uS SLE_pin(HIGH); - asm volatile("mov r8, r8 \n\t" - "mov r8, r8 \n\t" - "mov r8, r8 \n\t" - ); + asm volatile("nop \n\t" + "nop \n\t" + "nop \n\t" + ); SLE_pin(LOW); SDATA_pin(LOW); - sle_request = false; + + // now do housekeeping + totx_request = false; + // first tranmittted bit is always the odd bit + even = false; } } // we sample the RX bit at rising TXD clock edge, so TXD must be 1 and we are not in tx mode @@ -203,10 +229,26 @@ void CIO::interrupt() m_rxBuffer.put(bit); } - if (torx_request == true && even == true && m_tx && clk == 0) { - setRX(); + if (torx_request == true && even == false && m_tx && clk == 0) { + // that is absolutely crucial in 4FSK, see datasheet: + // enable sle after 1/4 tBit == 26uS when sending MSB (even == false) and clock is low + delay_us(26); + + // SLE Pulse, should be moved out of here into class method + SLE_pin(HIGH); + asm volatile("nop \n\t" + "nop \n\t" + "nop \n\t" + ); + SLE_pin(LOW); + SDATA_pin(LOW); + + // now do housekeeping m_tx = false; torx_request = false; + //last tranmittted bit is always the even bit + // since the current bit is a transitional "don't care" bit, never transmitted + even = true; } @@ -274,6 +316,9 @@ void CIO::write(uint8_t* data, uint16_t length) // Switch the transmitter on if needed if (!m_tx) { setTX(); + totx_request = true; + // not sure if needed, would be better if handled in interrupt (like torx_request) + // or move into setTX() while(CLK_pin()); m_tx = true; } diff --git a/IO.h b/IO.h index 944c6a9..6c08224 100644 --- a/IO.h +++ b/IO.h @@ -90,7 +90,7 @@ public: // RF interface API void setTX(void); - void setRX(void); + void setRX(bool doSle = true); void ifConf(MMDVM_STATE modemState, bool reset); void start(void); void startInt(void); @@ -102,6 +102,7 @@ public: // Misc functions void dlybit(void); void delay_rx(void); + void delay_us(uint32_t us); private: diff --git a/IOArduino.cpp b/IOArduino.cpp index 8b93cdc..ce26184 100644 --- a/IOArduino.cpp +++ b/IOArduino.cpp @@ -280,9 +280,9 @@ void CIO::COS_pin(bool on) digitalWrite(PIN_COS_LED, on ? HIGH : LOW); } -// TODO: Investigate why. In fact there is just a single place where this is being use -// during normal operation -#pragma GCC optimize ("O0") +void CIO::delay_us(uint32_t us) { + ::delayMicroseconds(us); +} void CIO::dlybit(void) { asm volatile("nop \n\t" diff --git a/IOSTM.cpp b/IOSTM.cpp index 467d0cc..52562a8 100644 --- a/IOSTM.cpp +++ b/IOSTM.cpp @@ -579,16 +579,15 @@ void CIO::delay_rx() { #endif } +void CIO::delay_us(uint32_t us) { + ::delay_us(us); +} -// TODO: Investigate why. In fact there is just a single place where this is being use -// during normal operation -// it seems that optimizing this code breaks some timings -#pragma GCC optimize ("O0") static inline void delay_ns() { - asm volatile("mov r8, r8 \n\t" - "mov r8, r8 \n\t" - "mov r8, r8 \n\t" + asm volatile("nop \n\t" + "nop \n\t" + "nop \n\t" ); }