All tested compilers & make build now have proper timing for tx switching (gcc 4.9.3, O0, Os, O3, gcc 6.3. O0, O3)

This commit is contained in:
danilo 2017-04-02 03:09:30 +02:00
parent 02ee23b684
commit 70457f269e
6 changed files with 104 additions and 66 deletions

View file

@ -34,8 +34,6 @@ volatile uint32_t AD7021_control_word;
uint32_t ADF7021_RX_REG0; uint32_t ADF7021_RX_REG0;
uint32_t ADF7021_TX_REG0; uint32_t ADF7021_TX_REG0;
volatile bool sle_request = false;
static void Send_AD7021_control_shift() static void Send_AD7021_control_shift()
{ {
int AD7021_counter; int AD7021_counter;
@ -51,34 +49,24 @@ static void Send_AD7021_control_shift()
io.dlybit(); io.dlybit();
io.SCLK_pin(LOW); 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.SLE_pin(HIGH);
io.dlybit(); io.dlybit();
io.SLE_pin(LOW); 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) #if defined(SEND_RSSI_DATA)
@ -415,31 +403,36 @@ void CIO::ifConf(MMDVM_STATE modemState, bool reset)
//====================================================================================================================== //======================================================================================================================
void CIO::setTX() 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; AD7021_control_word = ADF7021_TX_REG0;
Send_AD7021_control_nosle(); Send_AD7021_control(false);
#if defined(BIDIR_DATA_PIN) #if defined(BIDIR_DATA_PIN)
Data_dir_out(true); // Data pin output mode Data_dir_out(true); // Data pin output mode
#endif #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; AD7021_control_word = ADF7021_RX_REG0;
Send_AD7021_control(); Send_AD7021_control(doSle);
#if defined(BIDIR_DATA_PIN) #if defined(BIDIR_DATA_PIN)
Data_dir_out(false); // Data pin input mode Data_dir_out(false); // Data pin input mode
#endif #endif
// PTT pin off
PTT_pin(LOW);
} }
void CIO::setLoDevYSF(bool on) void CIO::setLoDevYSF(bool on)

View file

@ -267,8 +267,8 @@ www.analog.com/media/en/technical-documentation/data-sheets/ADF7021.pdf
#define bitRead(value, bit) (((value) >> (bit)) & 0x01) #define bitRead(value, bit) (((value) >> (bit)) & 0x01)
void Send_AD7021_control(void); void Send_AD7021_control(bool doSle = true);
#endif #endif
#endif #endif

83
IO.cpp
View file

@ -29,9 +29,11 @@ uint32_t m_frequency_rx;
uint32_t m_frequency_tx; uint32_t m_frequency_tx;
uint8_t m_power; 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; volatile bool torx_request = false;
bool volatile even = true; volatile bool even = true;
static uint32_t last_clk = 2;
CIO::CIO(): CIO::CIO():
m_started(false), m_started(false),
@ -101,8 +103,7 @@ void CIO::process()
// Switch off the transmitter if needed // Switch off the transmitter if needed
if (m_txBuffer.getData() == 0U && m_tx) { if (m_txBuffer.getData() == 0U && m_tx) {
//while(CLK_pin()==0) { asm volatile ("nop"); } setRX(false);
//while(CLK_pin()) { asm volatile ("nop"); }
torx_request = true; torx_request = true;
while(torx_request) { asm volatile ("nop"); } while(torx_request) { asm volatile ("nop"); }
} }
@ -158,13 +159,33 @@ void CIO::interrupt()
if (!m_started) if (!m_started)
return; 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 // we set the TX bit at TXD low, sampling of ADF7021 happens at rising clock
if (m_tx && clk == 0) { if (m_tx && clk == 0) {
m_txBuffer.get(bit); m_txBuffer.get(bit);
even = !even; even = !even;
// use this for tracking issues
// P25_pin(even);
#if defined(BIDIR_DATA_PIN) #if defined(BIDIR_DATA_PIN)
if(bit) if(bit)
RXD_pin_write(HIGH); RXD_pin_write(HIGH);
@ -177,21 +198,26 @@ void CIO::interrupt()
TXD_pin(LOW); TXD_pin(LOW);
#endif #endif
// wait a brief period before raising SLE // wait a brief period before raising SLE
if (sle_request == true) { if (totx_request == true) {
#if 1 asm volatile("nop \n\t"
asm volatile("mov r8, r8 \n\t" "nop \n\t"
"mov r8, r8 \n\t" "nop \n\t"
"mov r8, r8 \n\t" );
);
#endif // 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); SLE_pin(HIGH);
asm volatile("mov r8, r8 \n\t" asm volatile("nop \n\t"
"mov r8, r8 \n\t" "nop \n\t"
"mov r8, r8 \n\t" "nop \n\t"
); );
SLE_pin(LOW); SLE_pin(LOW);
SDATA_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 // 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); m_rxBuffer.put(bit);
} }
if (torx_request == true && even == true && m_tx && clk == 0) { if (torx_request == true && even == false && m_tx && clk == 0) {
setRX(); // 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; m_tx = false;
torx_request = 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 // Switch the transmitter on if needed
if (!m_tx) { if (!m_tx) {
setTX(); 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()); while(CLK_pin());
m_tx = true; m_tx = true;
} }

3
IO.h
View file

@ -90,7 +90,7 @@ public:
// RF interface API // RF interface API
void setTX(void); void setTX(void);
void setRX(void); void setRX(bool doSle = true);
void ifConf(MMDVM_STATE modemState, bool reset); void ifConf(MMDVM_STATE modemState, bool reset);
void start(void); void start(void);
void startInt(void); void startInt(void);
@ -102,6 +102,7 @@ public:
// Misc functions // Misc functions
void dlybit(void); void dlybit(void);
void delay_rx(void); void delay_rx(void);
void delay_us(uint32_t us);
private: private:

View file

@ -280,9 +280,9 @@ void CIO::COS_pin(bool on)
digitalWrite(PIN_COS_LED, on ? HIGH : LOW); digitalWrite(PIN_COS_LED, on ? HIGH : LOW);
} }
// TODO: Investigate why. In fact there is just a single place where this is being use void CIO::delay_us(uint32_t us) {
// during normal operation ::delayMicroseconds(us);
#pragma GCC optimize ("O0") }
void CIO::dlybit(void) void CIO::dlybit(void)
{ {
asm volatile("nop \n\t" asm volatile("nop \n\t"

View file

@ -579,16 +579,15 @@ void CIO::delay_rx() {
#endif #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() { static inline void delay_ns() {
asm volatile("mov r8, r8 \n\t" asm volatile("nop \n\t"
"mov r8, r8 \n\t" "nop \n\t"
"mov r8, r8 \n\t" "nop \n\t"
); );
} }