static void data_pump() { ctrl_clr_set(CTRL_INTERRUPT, 0); spi_set(CmdSetRXNsamps, NRX_SAMPS-1); evDP(EC_EVENT, EV_DPUMP, -1, "dpump_init", evprintf("INIT: SPI CTRL_INTERRUPT %d", GPIO_READ_BIT(GPIO0_15))); while (1) { evDP(EC_EVENT, EV_DPUMP, -1, "data_pump", evprintf("SLEEPING: SPI CTRL_INTERRUPT %d", GPIO_READ_BIT(GPIO0_15))); TaskSleep(0); ctrl_clr_set(CTRL_INTERRUPT, 0); // ack interrupt, and updates spi status evDP(EC_EVENT, EV_DPUMP, -1, "data_pump", evprintf("WAKEUP: SPI CTRL_INTERRUPT %d", GPIO_READ_BIT(GPIO0_15))); interrupt_task_last_run = timer_us64(); evDP(EC_EVENT, EV_DPUMP, -1, "data_pump", evprintf("interrupt last run @%.6f ", (float) interrupt_task_last_run / 1000000)); snd_service(); for (int ch=0; ch < RX_CHANS; ch++) { rx_chan_t *rx = &rx_chan[ch]; if (!rx->enabled) continue; conn_t *c = rx->conn; assert(c); if (c->task) { TaskWakeup(c->task, FALSE, 0); } #ifdef SND_SEQ_CHECK if (audio_dropped != last_audio_dropped) { send_msg(c, SM_NO_DEBUG, "MSG audio_dropped=%d", audio_dropped); } #endif } #ifdef SND_SEQ_CHECK if (audio_dropped != last_audio_dropped) last_audio_dropped = audio_dropped; #endif } }
void spi_dev(SPI_SEL sel, SPI_MOSI *mosi, int tx_xfers, SPI_MISO *miso, int rx_xfers) { int rx=0, tx=0; u4_t stat; SPI_T *txb = mosi->msg; SPI_T *rxb = miso->msg; assert(init); if (sel == SPI_BOOT) { GPIO_CLR_BIT(SPI0_CS1); } evSpiDev(EC_EVENT, EV_SPILOOP, -1, "spi_dev", evprintf("%s(%d) T%dx R%dx", (sel != SPI_HOST)? "BOOT" : cmds[mosi->data.cmd], mosi->data.cmd, tx_xfers, rx_xfers)); if (use_spidev) { int spi_bytes = SPI_X2B(MAX(tx_xfers, rx_xfers)); struct spi_ioc_transfer spi_tr; memset(&spi_tr, 0, sizeof spi_tr); spi_tr.tx_buf = (unsigned long) txb; spi_tr.rx_buf = (unsigned long) rxb; spi_tr.len = spi_bytes; spi_tr.delay_usecs = 0; spi_tr.speed_hz = speed; spi_tr.bits_per_word = SPI_BPW; // zero also means 8-bits? spi_tr.cs_change = 0; int actual_rxbytes; if ((actual_rxbytes = ioctl(spi_fd, SPI_IOC_MESSAGE(1), &spi_tr)) < 0) sys_panic("SPI_IOC_MESSAGE"); check(actual_rxbytes == spi_bytes); if (actual_rxbytes != spi_bytes) printf("actual_rxbytes %d spi_bytes %d\n", actual_rxbytes, spi_bytes); } else { SPI0_CONF = FORCE | SPI_CONF(spi_clkg, spi_speed); // add FORCE SPI0_CTRL = EN; static char pbuf[65536]; char *p = pbuf; int evp_spi; #if defined(EV_MEAS_SPI_DEV) || defined(SPI_PUMP_CHECK) evp_spi = (sel == SPI_HOST); #else evp_spi = 0; #endif int evp = evp_spi; if (evp) p += sprintf(p, "T %p %p %d R %p %p %d ", mosi, txb, tx_xfers, miso, rxb, rx_xfers); while (tx < tx_xfers) { stat = SPI0_STAT; if (!(stat & TX_FULL)) { if (evp) p += sprintf(p, "TA%d:%x ", tx, txb[tx]); SPI0_TX = txb[tx++]; // move data only if FIFOs are able to accept } if (!(stat & RX_EMPTY)) { rxb[rx++] = SPI0_RX; if (evp) p += sprintf(p, "RA%d:%x ", rx-1, rxb[rx-1]); } } // at this point all tx data in FIFO but rx data may or may not have been moved out of FIFO // if necessary send dummy tx words to force larger number of rx words to be pulled through while (tx < rx_xfers) { stat = SPI0_STAT; if (!(stat & TX_FULL)) { if (evp) p += sprintf(p, "TB%d:Z ", tx); SPI0_TX = 0; tx++; } if (!(stat & RX_EMPTY)) { rxb[rx++] = SPI0_RX; if (evp) p += sprintf(p, "RB%d:%x ", rx-1, rxb[rx-1]); } if (tx == 8 && evp) { p += sprintf(p, "... "); evp = 0; } if (tx == (rx_xfers-3)) evp = evp_spi; } evp = evp_spi; // handles the case of the FIFOs being slightly out-of-sync given that // tx/rx words moved must eventually be equal #ifdef SPI_32XXX int spin=0, rfull=0; while (rx < rx_xfers) { stat = SPI0_STAT; if (stat & RX_FULL) rfull++; spin++; if (!(stat & RX_EMPTY)) { rxb[rx++] = SPI0_RX; if (evp) p += sprintf(p, "RC%d:%x ", rx-1, rxb[rx-1]); spin=0; } if ((rx == (rx_xfers-1)) && ((stat & (EOT|RXS)) == (EOT|RXS))) { rxb[rx++] = SPI0_RX; // last doesn't show in fifo flags if (evp) p += sprintf(p, "RL%d:%x ", rx-1, rxb[rx-1]); } if ((spin > 1024) && ((stat & (EOT|RXS)) == (EOT|RXS))) { printf("%s STUCK: rfull %d rx %d rx_xfers %d stat %02x\n", TaskName(), rfull, rx, rx_xfers, stat); while (rx < rx_xfers) { rxb[rx++] = SPI0_RX; } break; } } #else while (rx < rx_xfers) { stat = SPI0_STAT; if (!(stat & RX_EMPTY)) { rxb[rx++] = SPI0_RX; if (evp) p += sprintf(p, "RC%d:%x ", rx-1, rxb[rx-1]); } if ((rx == (rx_xfers-1)) && ((stat & (EOT|RXS)) == (EOT|RXS))) { rxb[rx++] = SPI0_RX; // last doesn't show in fifo flags if (evp) p += sprintf(p, "RL%d:%x ", rx-1, rxb[rx-1]); } } #endif if (evp) evSpiDev(EC_EVENT, EV_SPILOOP, -1, "spi_dev", evprintf("%s", pbuf)); while ((SPI0_STAT & TX_EMPTY) == 0) // FIXME: needed for 6 MHz case, why? ; while ((SPI0_STAT & EOT) == 0) // FIXME: really needed? ; SPI0_CTRL = 0; SPI0_CONF = SPI_CONF(spi_clkg, spi_speed); // remove FORCE } if (sel == SPI_BOOT) { GPIO_SET_BIT(SPI0_CS1); } }
static void snd_service() { int j; SPI_MISO *miso = &dp_miso; rx_data_t *rxd = (rx_data_t *) &miso->word[0]; #ifdef SND_SEQ_CHECK rxd->magic = 0; #endif // use noduplex here because we don't want to yield evDPC(EC_TRIG3, EV_DPUMP, -1, "snd_svc", "CmdGetRX.."); spi_get_noduplex(CmdGetRX, miso, sizeof(rx_data_t)); evDPC(EC_EVENT, EV_DPUMP, -1, "snd_svc", "..CmdGetRX"); evDP(EC_TRIG2, EV_DPUMP, -1, "snd_service", evprintf("SERVICED SEQ %d %%%%%%%%%%%%%%%%%%%%", rxd->seq)); //evDP(EC_TRIG2, EV_DPUMP, 15000, "SND", "SERVICED ----------------------------------------"); #ifdef SND_SEQ_CHECK if (rxd->magic != 0x0ff0) { evDPC(EC_EVENT, EV_DPUMP, -1, "DATAPUMP", evprintf("BAD MAGIC 0x%04x", rxd->magic)); if (ev_dump) evDP(EC_DUMP, EV_DPUMP, ev_dump, "DATAPUMP", evprintf("DUMP in %.3f sec", ev_dump/1000.0)); } if (!initial_seq) { seq = rxd->seq; initial_seq = true; } u2_t new_seq = rxd->seq; if (seq != new_seq) { //printf("$dp %d:%d(%d)\n", seq, new_seq, new_seq-seq); evDPC(EC_EVENT, EV_DPUMP, -1, "SEQ DROP", evprintf("$dp %d:%d(%d)", seq, new_seq, new_seq-seq)); audio_dropped++; //TaskLastRun(); bool dump = false; //bool dump = true; //bool dump = (new_seq-seq < 0); //bool dump = (audio_dropped == 6); if (dump && ev_dump) evNT(EC_DUMP, EV_NEXTTASK, ev_dump, "NextTask", evprintf("DUMP IN %.3f SEC", ev_dump/1000.0)); seq = new_seq; } seq++; #endif TYPECPX *i_samps[RX_CHANS]; for (j=0; j < RX_CHANS; j++) { rx_dpump_t *rx = &rx_dpump[j]; i_samps[j] = rx->in_samps[rx->wr_pos]; } rx_iq_t *iqp = (rx_iq_t*) &rxd->iq_t; for (j=0; j<NRX_SAMPS; j++) { for (int ch=0; ch < RX_CHANS; ch++) { if (rx_chan[ch].enabled) { s4_t i, q; i = S24_8_16(iqp->i3, iqp->i); q = S24_8_16(iqp->q3, iqp->q); // NB: i&q reversed to get correct sideband polarity; fixme: why? // [probably because mixer NCO polarity is wrong, i.e. cos/sin should really be cos/-sin] i_samps[ch]->re = q * rescale; i_samps[ch]->im = i * rescale; i_samps[ch]++; } iqp++; } } for (int ch=0; ch < RX_CHANS; ch++) { if (rx_chan[ch].enabled) { rx_dpump_t *rx = &rx_dpump[ch]; rx->wr_pos = (rx->wr_pos+1) & (N_DPBUF-1); } } }