Skip to content

Commit

Permalink
Avoid bridge state corruption when the SoC polls too fast
Browse files Browse the repository at this point in the history
Increase the delay in spid and make the bridge code more resilient
against the EVSYS ISR preempting the DMA ISR when the bridge gets a new
transaction before finishing processing the last one.

There could be a better solution with more invasive changes to tell the
SoC when it is allowed to poll. This fix doesn't guarantee correctness,
and costs performance, but substantially improves stability when using
all three bridge pipes simultaneously.
  • Loading branch information
kevinmehall committed Aug 26, 2016
1 parent 120ad3c commit 45250d8
Show file tree
Hide file tree
Showing 2 changed files with 27 additions and 11 deletions.
35 changes: 26 additions & 9 deletions firmware/bridge.c
Original file line number Diff line number Diff line change
Expand Up @@ -120,13 +120,15 @@ void bridge_handle_sync() {
for (u8 chan=0; chan<BRIDGE_NUM_CHAN; chan++) {
u8 size = ctrl_rx.size[chan];
if (ctrl_tx.status & (1<<chan) && size > 0) {
out_chan_ready &= ~ (1<<chan);
dma_fill_sercom_tx(&dma_chain_data_tx[desc], SERCOM_BRIDGE, NULL, size);
dma_fill_sercom_rx(&dma_chain_data_rx[desc], SERCOM_BRIDGE, out_chan_ptr[chan], size);
desc++;
}

size = ctrl_tx.size[chan];
if (ctrl_rx.status & (1<<chan) && size > 0) {
in_chan_size[chan] = 0;
dma_fill_sercom_tx(&dma_chain_data_tx[desc], SERCOM_BRIDGE, in_chan_ptr[chan], size);
dma_fill_sercom_rx(&dma_chain_data_rx[desc], SERCOM_BRIDGE, NULL, size);
desc++;
Expand Down Expand Up @@ -161,26 +163,33 @@ void bridge_handle_sync() {
void bridge_dma_rx_completion() {
if (bridge_state == BRIDGE_STATE_DATA) {

// Copy the global state to this stack frame in case SYNC changes and the ISR overwrites these
uint8_t rx_status = ctrl_rx.status;
uint8_t tx_status = ctrl_tx.status;
uint8_t rx_size[BRIDGE_NUM_CHAN];
memcpy(rx_size, ctrl_rx.size, sizeof(rx_size));
uint8_t tx_size[BRIDGE_NUM_CHAN];
memcpy(tx_size, ctrl_tx.size, sizeof(tx_size));
__asm__ __volatile__ ("" : : : "memory");

#define CHECK_OPEN(x) \
if ((ctrl_rx.status & (0x10<<x)) && !(was_open & (0x10<<x))) { \
bridge_open_##x(ctrl_rx.size[x]); \
if ((rx_status & (0x10<<x)) && !(was_open & (0x10<<x))) { \
bridge_open_##x(rx_size[x]); \
}

#define CHECK_COMPLETION_OUT(x) \
if (ctrl_tx.status & (1<<x) && ctrl_rx.size[x] > 0) { \
out_chan_ready &= ~ (1<<x); \
bridge_completion_out_##x(ctrl_rx.size[x]); \
if (tx_status & (1<<x) && rx_size[x] > 0) { \
bridge_completion_out_##x(rx_size[x]); \
}

#define CHECK_COMPLETION_IN(x) \
if (ctrl_rx.status & (1<<x) && ctrl_tx.size[x] > 0) { \
in_chan_size[x] = 0; \
if (rx_status & (1<<x) && tx_size[x] > 0) { \
bridge_completion_in_##x(); \
}

#define CHECK_CLOSE(x) \
if (!(ctrl_rx.status & (0x10<<x)) && (was_open & (0x10<<x))) { \
bridge_close_##x(ctrl_rx.size[x]); \
if (!(rx_status & (0x10<<x)) && (was_open & (0x10<<x))) { \
bridge_close_##x(rx_size[x]); \
}

CHECK_OPEN(0)
Expand Down Expand Up @@ -211,24 +220,32 @@ void bridge_dma_rx_completion() {
}

void bridge_start_in(u8 channel, u8* data, u8 length) {
__disable_irq();
in_chan_ptr[channel] = data;
in_chan_size[channel] = length;
__enable_irq();
pin_high(PIN_BRIDGE_IRQ);
}

void bridge_start_out(u8 channel, u8* data) {
__disable_irq();
out_chan_ptr[channel] = data;
out_chan_ready |= (1<<channel);
__enable_irq();
pin_high(PIN_BRIDGE_IRQ);
}

void bridge_enable_chan(u8 channel) {
__disable_irq();
out_chan_ready |= (0x10<<channel);
__enable_irq();
pin_high(PIN_BRIDGE_IRQ);
}

void bridge_disable_chan(u8 channel) {
__disable_irq();
out_chan_ready &= ~(0x11<<channel); // Also clears the "ready to accept data" bit
in_chan_size[channel] = 0; // Clears any data that was waiting to be sent
__enable_irq();
pin_high(PIN_BRIDGE_IRQ);
}
3 changes: 1 addition & 2 deletions soc/spid.c
Original file line number Diff line number Diff line change
Expand Up @@ -108,8 +108,7 @@ struct pollfd fds[N_POLLFDS];
int usbd_sock_fd;
struct sockaddr_un usbd_sock_addr;
void delay() {
volatile int i = 1000;
while(i--);
usleep(10);
}

/*
Expand Down

0 comments on commit 45250d8

Please sign in to comment.