Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improved Radio Buffering and Initialization #19

Open
wants to merge 5 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
219 changes: 100 additions & 119 deletions Firmware/radio/radio.c
Original file line number Diff line number Diff line change
Expand Up @@ -35,14 +35,15 @@
#include "golay.h"
#include "crc.h"

__xdata uint8_t radio_buffer[MAX_PACKET_LENGTH];
__xdata uint8_t radio_buffer[2][MAX_PACKET_LENGTH];
__pdata uint8_t receive_packet_length;
__pdata uint8_t partial_packet_length;
__pdata uint8_t last_rssi;
__pdata uint8_t netid[2];

static volatile __bit packet_received;
static volatile __bit preamble_detected;
static volatile __bit ping_pong;

__pdata struct radio_settings settings;

Expand All @@ -52,8 +53,8 @@ __pdata struct radio_settings settings;
static void register_write(uint8_t reg, uint8_t value) __reentrant;
static uint8_t register_read(uint8_t reg);
static bool software_reset(void);
static void set_frequency_registers(uint32_t frequency);
static uint32_t scale_uint32(uint32_t value, uint32_t scale);
static void set_frequency_registers(__pdata uint32_t frequency);
static uint32_t scale_uint32(__pdata uint32_t value, __pdata uint32_t scale);
static void clear_status_registers(void);

// save and restore radio interrupt. We use this rather than
Expand Down Expand Up @@ -101,15 +102,15 @@ radio_receive_packet(uint8_t *length, __xdata uint8_t * __pdata buf)
if (!feature_golay) {
// simple unencoded packets
*length = receive_packet_length;
memcpy(buf, radio_buffer, receive_packet_length);
memcpy(buf, radio_buffer[ping_pong], receive_packet_length);
radio_receiver_on();
return true;
}

// decode it in the callers buffer. This relies on the
// in-place decode properties of the golay code. Decoding in
// this way allows us to overlap decoding with the next receive
memcpy(buf, radio_buffer, receive_packet_length);
memcpy(buf, radio_buffer[ping_pong], receive_packet_length);

// enable the receiver for the next packet. This also
// enables the EX0 interrupt
Expand Down Expand Up @@ -299,20 +300,21 @@ radio_transmit_simple(__data uint8_t length, __xdata uint8_t * __pdata buf, __pd
{
__pdata uint16_t tstart;
bool transmit_started;
bool just_refilled_tx;
__data uint8_t n;

if (length > sizeof(radio_buffer)) {
if (length > sizeof(radio_buffer[0])) {
panic("oversized packet");
}

radio_clear_transmit_fifo();

register_write(EZRADIOPRO_TRANSMIT_PACKET_LENGTH, length);

// put packet in the FIFO
// put packet bytes in the FIFO, leaving room for the CRC
n = length;
if (n > TX_FIFO_THRESHOLD_LOW) {
n = TX_FIFO_THRESHOLD_LOW;
if (n > TX_FIFO_THRESHOLD_HIGH) {
n = TX_FIFO_THRESHOLD_HIGH;
}
radio_write_transmit_fifo(n, buf);
length -= n;
Expand All @@ -324,94 +326,74 @@ radio_transmit_simple(__data uint8_t length, __xdata uint8_t * __pdata buf, __pd

preamble_detected = 0;
transmit_started = false;
just_refilled_tx = true;

// start TX
register_write(EZRADIOPRO_OPERATING_AND_FUNCTION_CONTROL_1, EZRADIOPRO_TXON | EZRADIOPRO_XTON);

// wait for transmit complete or timeout
tstart = timer2_tick();
while ((uint16_t)(timer2_tick() - tstart) < timeout_ticks) {
__data uint8_t status;

// see if we can put some more bytes into the FIFO
status = register_read(EZRADIOPRO_INTERRUPT_STATUS_1);
if (transmit_started && length != 0 && (status & EZRADIOPRO_ITXFFAEM)) {
// the FIFO is below the low threshold. We
// should be able to put in
// 64-TX_FIFO_THRESHOLD_LOW more bytes, but
// it seems that this gives us an occasional
// fifo overflow error, so put in just 4 bytes
// at a time
n = 4;
if (n > length) {
n = length;
}
radio_write_transmit_fifo(n, buf);
length -= n;
buf += n;
continue;
}
if (transmit_started && length != 0 && (status & EZRADIOPRO_ITXFFAFULL) == 0) {
// the FIFO is below the high threshold. See
// comment above on how many bytes we add to
// the FIFO
n = 4;
if (n > length) {
n = length;
}
radio_write_transmit_fifo(n, buf);
length -= n;
buf += n;
continue;
}

if (status & EZRADIOPRO_IFFERR) {
// we ran out of bytes in the FIFO
radio_clear_transmit_fifo();
debug("FFERR %u\n", (unsigned)length);
if (errors.tx_errors != 0xFFFF) {
errors.tx_errors++;
}
return false;
}

register uint8_t interrupt_status;

if (!transmit_started && register_read(EZRADIOPRO_DEVICE_STATUS) & 0x02) {
transmit_started = true;

// the interrupt status bits only become valid once
// the transmitter is in full tx state
status = register_read(EZRADIOPRO_DEVICE_STATUS);
if (status & 0x02) {
// the chip power status is in TX mode
transmit_started = true;
continue;
}
if (transmit_started && (status & 0x02) == 0) {
// transmitter has finished. See if we got the
// whole packet out
} else if (transmit_started) {
if (length != 0) {
debug("TX short %u\n", (unsigned)length);
if (errors.tx_errors != 0xFFFF) {
errors.tx_errors++;
// see if we can put some more bytes into the FIFO.
// Use hysteresis when sampling the almost empty bit
// since it updates only on internal TX domain clock
// cycles (see EZRadioPro detailed register
// descriptions, AN440).
interrupt_status = register_read(EZRADIOPRO_INTERRUPT_STATUS_1);
if ((interrupt_status & EZRADIOPRO_ITXFFAEM) == 0) {
just_refilled_tx = false;
} else if (!just_refilled_tx) {
n = TX_FIFO_THRESHOLD_HIGH - (TX_FIFO_THRESHOLD_LOW + 1);
if (n > length) {
n = length;
}
radio_write_transmit_fifo(n, buf);
just_refilled_tx = true;
length -= n;
buf += n;
}

if (interrupt_status & EZRADIOPRO_IFFERR) {
// we ran out of bytes in the FIFO
radio_clear_transmit_fifo();
debug("FFERR %u\n", (unsigned)length);
goto txfail;
}
return false;
} else if ((register_read(EZRADIOPRO_DEVICE_STATUS) & 0x02) == 0) {
// transmitter has finished. See if we got the
// whole packet out
if (length != 0) {
debug("TX short %u\n", (unsigned)length);
goto txfail;
}
return true;
}
return true;
}

}

// transmit timeout ... clear the FIFO
debug("TX timeout %u ts=%u tn=%u len=%u\n",
timeout_ticks,
tstart,
timer2_tick(),
(unsigned)length);
timeout_ticks,
tstart,
timer2_tick(),
(unsigned)length);
txfail:
if (errors.tx_errors != 0xFFFF) {
errors.tx_errors++;
}

return false;
}


// start transmitting a packet from the transmit FIFO
//
// @param length number of data bytes to send
Expand All @@ -427,7 +409,7 @@ radio_transmit_golay(uint8_t length, __xdata uint8_t * __pdata buf, __pdata uint
__xdata uint8_t gin[3];
__data uint8_t elen, rlen;

if (length > (sizeof(radio_buffer)/2)-6) {
if (length > (sizeof(radio_buffer[0])/2)-6) {
debug("golay packet size %u\n", (unsigned)length);
panic("oversized golay packet");
}
Expand All @@ -444,7 +426,7 @@ radio_transmit_golay(uint8_t length, __xdata uint8_t * __pdata buf, __pdata uint
gin[2] = length;

// golay encode the header
golay_encode(3, gin, radio_buffer);
golay_encode(3, gin, radio_buffer[ping_pong]);

// next add a CRC, we round to 3 bytes for simplicity, adding
// another copy of the length in the spare byte
Expand All @@ -454,12 +436,12 @@ radio_transmit_golay(uint8_t length, __xdata uint8_t * __pdata buf, __pdata uint
gin[2] = length;

// golay encode the CRC
golay_encode(3, gin, &radio_buffer[6]);
golay_encode(3, gin, &radio_buffer[ping_pong][6]);

// encode the rest of the payload
golay_encode(rlen, buf, &radio_buffer[12]);
golay_encode(rlen, buf, &radio_buffer[ping_pong][12]);

return radio_transmit_simple(elen, radio_buffer, timeout_ticks);
return radio_transmit_simple(elen, radio_buffer[ping_pong], timeout_ticks);
}

// start transmitting a packet from the transmit FIFO
Expand Down Expand Up @@ -502,17 +484,12 @@ radio_receiver_on(void)

packet_received = 0;
receive_packet_length = 0;
preamble_detected = 0;
partial_packet_length = 0;

// enable receive interrupts
register_write(EZRADIOPRO_INTERRUPT_ENABLE_1, RADIO_RX_INTERRUPTS);
register_write(EZRADIOPRO_INTERRUPT_ENABLE_2, EZRADIOPRO_ENPREAVAL);

clear_status_registers();
radio_clear_transmit_fifo();
radio_clear_receive_fifo();

// put the radio in receive mode
register_write(EZRADIOPRO_OPERATING_AND_FUNCTION_CONTROL_1, EZRADIOPRO_RXON | EZRADIOPRO_XTON);

Expand All @@ -532,40 +509,44 @@ radio_initialise(void)

delay_msec(50);

// make sure there is a radio on the SPI bus
status = register_read(EZRADIOPRO_DEVICE_VERSION);
if (status == 0xFF || status < 5) {
// no valid radio there?
return false;
}

status = register_read(EZRADIOPRO_INTERRUPT_STATUS_2);

if ((status & EZRADIOPRO_IPOR) == 0) {
// it hasn't powered up cleanly, reset it
return software_reset();
}

if (status & EZRADIOPRO_ICHIPRDY) {
// already ready
return true;
if(!software_reset()) {
return false;
}
}

// enable chip ready interrupt
register_write(EZRADIOPRO_INTERRUPT_ENABLE_1, 0);
register_write(EZRADIOPRO_INTERRUPT_ENABLE_2, EZRADIOPRO_ENCHIPRDY);

// wait for the chip ready bit for 10ms
delay_set(50);
while (!delay_expired()) {
status = register_read(EZRADIOPRO_INTERRUPT_STATUS_1);
status = register_read(EZRADIOPRO_INTERRUPT_STATUS_2);
if (status & EZRADIOPRO_ICHIPRDY) {
return true;
if ((status & EZRADIOPRO_ICHIPRDY) == 0) {
// enable chip ready interrupt
register_write(EZRADIOPRO_INTERRUPT_ENABLE_1, 0);
register_write(EZRADIOPRO_INTERRUPT_ENABLE_2, EZRADIOPRO_ENCHIPRDY);
register_write(EZRADIOPRO_OPERATING_AND_FUNCTION_CONTROL_1, EZRADIOPRO_XTON);

// wait for the chip ready bit for 10ms
delay_set(50);
while (!delay_expired()) {
status = register_read(EZRADIOPRO_INTERRUPT_STATUS_1);
status = register_read(EZRADIOPRO_INTERRUPT_STATUS_2);
if (status & EZRADIOPRO_ICHIPRDY) {
break;
}
}
}

if ((status & EZRADIOPRO_ICHIPRDY) == 0) {
return false;
}

// make sure the radio version is valid
status = register_read(EZRADIOPRO_DEVICE_VERSION);
if (status == 0xFF || status < 5) {
// no valid radio there?
return false;
}

return false;
return true;
}


Expand Down Expand Up @@ -1167,7 +1148,7 @@ INTERRUPT(Receiver_ISR, INTERRUPT_INT0)
debug("rx pplen=%u\n", (unsigned)partial_packet_length);
goto rxfail;
}
read_receive_fifo(RX_FIFO_THRESHOLD_HIGH, &radio_buffer[partial_packet_length]);
read_receive_fifo(RX_FIFO_THRESHOLD_HIGH, &radio_buffer[ping_pong ^ 0x1][partial_packet_length]);
partial_packet_length += RX_FIFO_THRESHOLD_HIGH;
last_rssi = register_read(EZRADIOPRO_RECEIVED_SIGNAL_STRENGTH_INDICATOR);
}
Expand All @@ -1191,26 +1172,26 @@ INTERRUPT(Receiver_ISR, INTERRUPT_INT0)
goto rxfail;
}
if (partial_packet_length < len) {
read_receive_fifo(len-partial_packet_length, &radio_buffer[partial_packet_length]);
read_receive_fifo(len-partial_packet_length, &radio_buffer[ping_pong ^ 0x1][partial_packet_length]);
}
receive_packet_length = len;

// we have a full packet
packet_received = true;

// disable interrupts until the tdm code has grabbed the packet
register_write(EZRADIOPRO_INTERRUPT_ENABLE_1, 0);
register_write(EZRADIOPRO_INTERRUPT_ENABLE_2, 0);

// go into tune mode
register_write(EZRADIOPRO_OPERATING_AND_FUNCTION_CONTROL_1, EZRADIOPRO_PLLON);
partial_packet_length = 0;
preamble_detected = false;

// allow the main program to access the finalized buffer
ping_pong ^= 0x1;
}
return;

rxfail:
if (errors.rx_errors != 0xFFFF) {
errors.rx_errors++;
}
clear_status_registers();
radio_clear_receive_fifo();
radio_receiver_on();
}

2 changes: 1 addition & 1 deletion Firmware/radio/serial.c
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@
// would be about 16x larger than the largest air packet if we have
// 8 TDM time slots
//
__xdata uint8_t rx_buf[1900] = {0};
__xdata uint8_t rx_buf[1600] = {0};
__xdata uint8_t tx_buf[650] = {0};

// FIFO insert/remove pointers
Expand Down