summaryrefslogtreecommitdiff
path: root/openpicc/application/ssc.c
diff options
context:
space:
mode:
Diffstat (limited to 'openpicc/application/ssc.c')
-rw-r--r--openpicc/application/ssc.c128
1 files changed, 108 insertions, 20 deletions
diff --git a/openpicc/application/ssc.c b/openpicc/application/ssc.c
index 7c63104..d1d4e48 100644
--- a/openpicc/application/ssc.c
+++ b/openpicc/application/ssc.c
@@ -79,6 +79,9 @@ static struct {
[METRIC_MANAGEMENT_ERRORS_2] = {METRIC_MANAGEMENT_ERRORS_2, "Internal buffer management error type 2", 0},
[METRIC_MANAGEMENT_ERRORS_3] = {METRIC_MANAGEMENT_ERRORS_3, "Internal buffer management error type 3", 0},
[METRIC_LATE_TX_FRAMES] = {METRIC_LATE_TX_FRAMES, "Late Tx frames", 0},
+ [METRIC_RX_FRAMES] = {METRIC_RX_FRAMES, "Rx frames", 0},
+ [METRIC_TX_FRAMES] = {METRIC_TX_FRAMES, "Tx frames", 0},
+ [METRIC_TX_ABORTED_FRAMES] = {METRIC_TX_ABORTED_FRAMES, "Aborted Tx frames", 0},
};
static ssc_dma_rx_buffer_t _rx_buffers[SSC_DMA_BUFFER_COUNT];
@@ -186,29 +189,60 @@ void ssc_frame_started(void)
_ssc_rx_irq(_ssc.ssc->SSC_SR, 1, pdFALSE);
}
+static void __ramfunc _ssc_tx_end(ssc_handle_t *sh, int is_an_abort)
+{
+ AT91F_PDC_DisableTx(sh->pdc);
+ AT91F_SSC_DisableTx(sh->ssc);
+ sh->ssc->SSC_IDR = SSC_TX_IRQ_MASK;
+
+ AT91F_PIO_CfgPeriph(AT91C_BASE_PIOA, AT91C_PA15_TF, 0);
+ usb_print_string_f(">",0);
+
+ AT91F_PDC_SetTx(sh->pdc, 0, 0);
+ AT91F_PDC_SetNextTx(sh->pdc, 0, 0);
+
+ if(sh->tx_buffer) {
+ sh->tx_buffer->state = FREE;
+ sh->tx_running = 0;
+ }
+
+ if(sh->rx_running) {
+ /* Receiver has been suspended by the pending transmission. Restart it. */
+ AT91F_SSC_EnableRx(sh->ssc);
+ }
+
+ if(sh->callback) {
+ if(is_an_abort)
+ sh->callback(CALLBACK_TX_FRAME_ABORTED, sh->tx_buffer);
+ else
+ sh->callback(CALLBACK_TX_FRAME_ENDED, sh->tx_buffer);
+ }
+
+ sh->tx_buffer = NULL;
+}
+
static int __ramfunc _ssc_tx_irq(u_int32_t sr, portBASE_TYPE task_woken)
{
ssc_handle_t *sh = &_ssc;
- if( sr & AT91C_SSC_TXEMPTY ) {
- /* Tx has ended */
- AT91F_PDC_DisableTx(sh->pdc);
- AT91F_SSC_DisableTx(sh->ssc);
- sh->ssc->SSC_IDR = SSC_TX_IRQ_MASK;
-
- if(sh->tx_buffer) {
- sh->tx_buffer->state = FREE;
- sh->tx_running = 0;
- }
-
- if(sh->rx_running) {
- /* Receiver has been suspended by the pending transmission. Restart it. */
- AT91F_SSC_EnableRx(sh->ssc);
- }
+ if( sr & AT91C_SSC_TXSYN ) {
+ /* Tx starting, hardwire TF pin to high */
+ AT91F_PIO_SetOutput(AT91C_BASE_PIOA, AT91C_PA15_TF);
+ AT91F_PIO_CfgOutput(AT91C_BASE_PIOA, AT91C_PA15_TF);
+ usb_print_string_f("<",0);
+ /* Also set SSC mode to continous
+ * FIXME BUG: This will somehow drop some samples or something on the SSC*/
+ sh->ssc->SSC_TCMR = (sh->ssc->SSC_TCMR & ~AT91C_SSC_START) | AT91C_SSC_START_CONTINOUS;
+
if(sh->callback)
- sh->callback(CALLBACK_TX_FRAME_ENDED, sh->tx_buffer);
- sh->tx_buffer = NULL;
+ sh->callback(CALLBACK_TX_FRAME_BEGIN, NULL);
+ }
+
+ if( sr & AT91C_SSC_TXEMPTY ) {
+ /* Tx has ended */
+ ssc_metrics[METRIC_TX_FRAMES].value++;
+ _ssc_tx_end(sh, 0);
}
return task_woken;
@@ -460,6 +494,7 @@ static inline int _init_ssc_rx(ssc_handle_t *sh)
OPENPICC_PIO_FRAME,
0);
+ /* FIXME: This is handled by tc_cdiv_sync and shouldn't be necessary */
AT91F_PIO_CfgOutput(AT91C_BASE_PIOA, OPENPICC_PIO_SSC_DATA_CONTROL);
AT91F_PIO_ClearOutput(AT91C_BASE_PIOA, OPENPICC_PIO_SSC_DATA_CONTROL);
@@ -571,12 +606,11 @@ ssc_handle_t* ssc_open(u_int8_t init_rx, u_int8_t init_tx, enum ssc_mode mode, s
if(!sh->rx_enabled) {
ssc_close(sh);
return NULL;
- } else {
- _ssc_rx_mode_set(sh, mode);
}
}
if(sh->rx_enabled || sh->tx_enabled) {
+ _ssc_rx_mode_set(sh, mode);
AT91F_AIC_ConfigureIt(AT91C_ID_SSC,
OPENPICC_IRQ_PRIO_SSC,
AT91C_AIC_SRCTYPE_INT_HIGH_LEVEL, (THandler)&ssc_irq);
@@ -646,7 +680,7 @@ int ssc_send(ssc_handle_t* sh, ssc_dma_tx_buffer_t *buffer)
AT91F_PDC_SetNextTx(sh->pdc, 0, 0);
buffer->state = PENDING;
- sh->ssc->SSC_IER = AT91C_SSC_TXEMPTY;
+ sh->ssc->SSC_IER = AT91C_SSC_TXEMPTY | AT91C_SSC_TXSYN;
/* Enable DMA */
sh->ssc->SSC_THR = 0;
AT91F_PDC_EnableTx(sh->pdc);
@@ -664,6 +698,18 @@ int ssc_send(ssc_handle_t* sh, ssc_dma_tx_buffer_t *buffer)
return 0;
}
+int ssc_send_abort(ssc_handle_t* sh)
+{
+ if(!sh) return -EINVAL;
+ if(!sh->tx_enabled) return -EINVAL;
+ if(!sh->tx_running) return -EINVAL;
+
+ ssc_metrics[METRIC_TX_ABORTED_FRAMES].value++;
+ _ssc_tx_end(sh, 1);
+
+ return 0;
+}
+
int ssc_close(ssc_handle_t* sh)
{
if(sh->rx_running)
@@ -682,6 +728,48 @@ int ssc_close(ssc_handle_t* sh)
return 0;
}
+/* Hard reset the SSC to flush all buffers and whatnot. Call with IRQs disabled */
+void ssc_hard_reset(ssc_handle_t *sh)
+{
+ if(sh == NULL) return;
+ if(!sh->rx_enabled && !sh->tx_enabled) return;
+
+ u_int32_t
+ cmr = sh->ssc->SSC_CMR,
+ rcmr = sh->ssc->SSC_RCMR,
+ rfmr = sh->ssc->SSC_RFMR,
+ tcmr = sh->ssc->SSC_TCMR,
+ tfmr = sh->ssc->SSC_TFMR,
+ rc0r = sh->ssc->SSC_RC0R,
+ rc1r = sh->ssc->SSC_RC1R,
+ sr = sh->ssc->SSC_SR,
+ imr = sh->ssc->SSC_IMR;
+
+ sh->ssc->SSC_CR = AT91C_SSC_SWRST;
+
+ sh->ssc->SSC_CMR = cmr;
+ sh->ssc->SSC_RCMR = rcmr;
+ sh->ssc->SSC_RFMR = rfmr;
+ sh->ssc->SSC_TCMR = tcmr;
+ sh->ssc->SSC_TFMR = tfmr;
+ sh->ssc->SSC_RC0R = rc0r;
+ sh->ssc->SSC_RC1R = rc1r;
+
+ sh->ssc->SSC_IDR = ~imr;
+ sh->ssc->SSC_IER = imr;
+
+ if(sr & AT91C_SSC_RXEN)
+ AT91F_SSC_EnableRx(sh->ssc);
+ else
+ AT91F_SSC_DisableRx(sh->ssc);
+
+ if(sr & AT91C_SSC_TXEN)
+ AT91F_SSC_EnableTx(sh->ssc);
+ else
+ AT91F_SSC_DisableTx(sh->ssc);
+}
+
+
int ssc_get_metric(ssc_metric metric, char **description, int *value)
{
char *_name="Undefined";
personal git repositories of Harald Welte. Your mileage may vary