Compare commits

...

2 commits

Author SHA1 Message Date
Stephan I. Böttcher
5954e875b1 ssp_batch->wait 2024-11-02 23:03:18 +01:00
Stephan I. Böttcher
57d95b7a1b timer_wait: callback args, … 2024-11-02 23:02:37 +01:00
4 changed files with 79 additions and 62 deletions

83
ssp.c
View file

@ -12,11 +12,12 @@
static volatile struct ssp_job job; static volatile struct ssp_job job;
struct ssp_match ssp_match; struct ssp_match ssp_match;
static const struct ssp_batch *ssp_batch; const struct ssp_batch *ssp_batch;
static int ssp_batch_repeats; static int ssp_batch_repeats;
unsigned int ssp_bits; unsigned int ssp_bits;
volatile unsigned int ssp_lastword; volatile unsigned int ssp_lastword;
unsigned int ssp_ssel_mask = SSP_SSEL_MASK0 | SSP_SSEL_MASK1; unsigned int ssp_ssel_mask = SSP_SSEL_MASK0 | SSP_SSEL_MASK1;
static const struct timer_wait *ssp_batch_wait;
unsigned short *ssp_buffer; unsigned short *ssp_buffer;
volatile unsigned int ssp_frame_count; volatile unsigned int ssp_frame_count;
@ -82,49 +83,44 @@ static void ssp_isr(void)
} }
j->read_count = rc; j->read_count = rc;
if (!nread && !rc && !(sr&SSPSR_BSY) && !j->cmd_count && !j->idle_count) { sr |= SSPSR; // race between SSPSR_BSY, SSPSR_RNE?
// there is nothing left to do if (!j->cmd_count && !j->idle_count) {
SSPIMSC = 0; if (!rc && !(sr & (SSPSR_BSY|SSPSR_RNE))) {
VICVectAddr = 0; SSPIMSC = 0;
return; if (ssp_batch)
ssp_run_batch();
}
else
SSPIMSC = SSP_INT_RX;
goto out;
} }
else if (!(sr & (SSPSR_BSY|SSPSR_RNE)))
nread = 8;
// Send at most as many new frames as where received. // Send at most as many new frames as where received.
// This prevents Rx FIFO overflow. // This prevents Rx FIFO overflow.
// Except, when the Tx is not busy at all, then we can fill it up. // Except, when the Tx is not busy at all, then we can fill it up.
// There may be a race, when the SSPSR_BSY goes low before the SSPSR_RNE
// goes high for the last frame sent. Does it?
// Reread SSPSR and check!
if (!(sr&SSPSR_BSY)) {
sr = SSPSR;
if (!(sr & (SSPSR_BSY|SSPSR_RNE)))
nread = 8;
}
if (rc && nread > rc)
nread = rc;
unsigned int ic = j->idle_count; unsigned int ic = j->idle_count;
while (nread && (sr&SSPSR_TNF)) { while (nread && (sr&SSPSR_TNF)) {
if (j->cmd_count) { if (j->cmd_count) {
j->cmd_count--; j->cmd_count--;
SSPDR = *j->command++; SSPDR = *j->command++;
} }
else { else if (ic) {
if (!(rc || ic)) { ic--;
// nothing to send, disable TX irq
SSPIMSC = SSP_INT_RX;
break;
}
if (ic)
ic--;
SSPDR = ssp_match.idle; SSPDR = ssp_match.idle;
} }
else {
SSPIMSC = SSP_INT_RX;
goto outic;
}
nread--; nread--;
sr = SSPSR; sr = SSPSR;
} }
outic:
j->idle_count = ic; j->idle_count = ic;
out:
VICVectAddr = 0; VICVectAddr = 0;
} }
@ -225,7 +221,11 @@ int ssp_busy(void)
return c; return c;
// Hardware is busy // Hardware is busy
if (SSPSR&(SSPSR_RNE|SSPSR_BSY)) if (SSPSR&(SSPSR_RNE|SSPSR_BSY))
return 1; return -1;
if (SSPIMSC & (SSP_INT_RX | SSP_INT_TX))
return -2;
if (!ssp_run_batch())
return -3;
done: done:
ssp_reset(); ssp_reset();
return 0; return 0;
@ -259,34 +259,42 @@ struct ssp_config ssp_conf_bate[] = {
}, },
}; };
int ssp_wait_miso(const struct ssp_wait *wait) // called first by `ssp_submit_batch()`
{ // called next by `ssp_isr()` when a job is done
return 0; // called by `timer_wait.callback()` when the delay, event happend
}
int ssp_run_batch(void) int ssp_run_batch()
{ {
const struct ssp_batch *batch = ssp_batch; const struct ssp_batch *batch = ssp_batch;
if (!batch || !batch->job) if (!batch || !batch->job)
return -1; return -1;
if (batch->wait) { const struct timer_wait *wait = batch->wait;
int c = ssp_wait_miso(batch->wait); if (wait) {
if (c) if (ssp_batch_wait != wait) {
return c; // we need to wait for something
ssp_batch_wait = wait;
timer_wait_init(wait, (void*)batch);
return 0;
}
// we did the waiting … continue with the batch
ssp_batch_wait = 0;
} }
if (ssp_batch_repeats++ >= batch->count) { if (ssp_batch_repeats++ >= batch->count) {
// we did all repeats … advance to the next job
ssp_batch_repeats = 0; ssp_batch_repeats = 0;
ssp_batch++; ssp_batch++;
} }
const struct ssp_config *ssel = batch->ssel; const struct ssp_config *ssel = batch->ssel;
if (ssel) if (ssel) {
if (ssel->mode) if (ssel->mode)
ssp_init(ssel); ssp_init(ssel);
else if (ssel->ssel) else if (ssel->ssel)
ssp_config.ssel = ssel->ssel; ssp_config.ssel = ssel->ssel;
ssp_deassert_ssel();
}
const struct ssp_match *match = batch->match; const struct ssp_match *match = batch->match;
if (match) if (match)
ssp_match = *match; ssp_match = *match;
@ -302,5 +310,6 @@ int ssp_submit_batch(const struct ssp_batch *batch, int timeout)
return c; return c;
ssp_batch_repeats = 0; ssp_batch_repeats = 0;
ssp_batch = batch; ssp_batch = batch;
ssp_batch_wait = 0;
return ssp_run_batch(); return ssp_run_batch();
} }

16
ssp.h
View file

@ -3,6 +3,7 @@
#define _ssp_h_ #define _ssp_h_
#include "gpio.h" #include "gpio.h"
#include "timer.h"
void ssp_reset(void); void ssp_reset(void);
@ -75,13 +76,14 @@ extern struct ssp_match {
unsigned int size; unsigned int size;
} ssp_match; } ssp_match;
extern const
struct ssp_batch { struct ssp_batch {
int count; int count;
struct ssp_job *job; const struct ssp_job *job;
struct ssp_match *match; const struct ssp_match *match;
struct ssp_config *ssel; const struct ssp_config *ssel;
struct ssp_wait *wait; const struct timer_wait *wait;
}; } *ssp_batch;
// search for a pattern before recording frames // search for a pattern before recording frames
static inline static inline
@ -102,4 +104,8 @@ void ssp_set_read(unsigned int count, unsigned int size)
ssp_match.size = size; ssp_match.size = size;
} }
int ssp_submit_job(const struct ssp_job *jj);
int ssp_submit_batch(const struct ssp_batch *batch, int timeout);
int ssp_run_batch();
#endif #endif

32
timer.c
View file

@ -14,7 +14,7 @@ void tick_timer(volatile struct timer_tick *tick, unsigned int ir)
if (n != 0xffff) if (n != 0xffff)
tick->n = n+1; tick->n = n+1;
if (tick->callback) if (tick->callback)
tick->callback(ir, n); tick->callback(tick);
} }
__attribute__ ((interrupt ("IRQ"))) __attribute__ ((interrupt ("IRQ")))
@ -79,28 +79,28 @@ static void timer_wait_abort(void) {
waiting = 0; waiting = 0;
} }
static void wait_callback(unsigned int ir, unsigned int n) static void wait_callback(const volatile struct timer_tick *tick)
{ {
const struct timer_wait *w = waiting; const struct timer_wait *w = waiting;
if (!w) if (!w)
return; return;
if (timer_wait_pin_status(w)) if (timer_wait_pin_status(w))
goto hit; goto hit;
if (w->mclk && n >= w->mclk) if (w->mclk && tick->ir & 0x100 && tick->n >= w->mclk)
goto hit; goto hit;
if (w->pclk && ir & 1) if (w->pclk && tick->ir & 0x200 && tick->ir & 1)
goto hit; goto hit;
return; return;
hit: hit:
timer_wait_abort(); timer_wait_abort();
if (w->callback) if (w->callback)
w->callback(); w->callback(tick);
} }
int timer_wait_init(const struct timer_wait *wait) int timer_wait_init(const struct timer_wait *wait, void *data)
{ {
timer_wait_abort(); timer_wait_abort();
if (!wait) if (!wait || timer_wait_pin_status(wait))
return 0; return 0;
timer0_tick = (struct timer_tick){.callback=0}; timer0_tick = (struct timer_tick){.callback=0};
timer1_tick = (struct timer_tick){.callback=0}; timer1_tick = (struct timer_tick){.callback=0};
@ -148,11 +148,14 @@ int timer_wait_init(const struct timer_wait *wait)
} }
waiting = wait; waiting = wait;
if (wait->ccr0 || wait->mclk) if (wait->ccr0 || wait->mclk) {
timer0_tick.callback = &wait_callback; timer0_tick.data = data;
if (wait->ccr1 || wait->pclk) timer0_tick.callback = wait_callback;
timer1_tick.callback = &wait_callback; }
wait_callback(0,0); if (wait->ccr1 || wait->pclk) {
timer1_tick.data = data;
timer1_tick.callback = wait_callback;
}
enable_irq(iflg); enable_irq(iflg);
return !!waiting; return !!waiting;
} }
@ -161,8 +164,3 @@ int timer_wait_status(const struct timer_wait *wait)
{ {
return waiting && (!wait || wait==waiting); return waiting && (!wait || wait==waiting);
} }
int timer_wait_mclk_status(const struct timer_wait *w)
{
return timer0_tick.n;
}

10
timer.h
View file

@ -6,10 +6,14 @@
void timer0_init(); void timer0_init();
void timer1_init(); void timer1_init();
struct timer_tick;
typedef void (*timer_callback_t)(const volatile struct timer_tick *tick);
extern volatile struct timer_tick { extern volatile struct timer_tick {
unsigned int ir; unsigned int ir;
unsigned int n; unsigned int n;
void (*callback)(unsigned, unsigned); timer_callback_t callback;
void *data;
} timer0_tick, timer1_tick; } timer0_tick, timer1_tick;
struct timer_wait { struct timer_wait {
@ -19,10 +23,10 @@ struct timer_wait {
unsigned short ccr1; unsigned short ccr1;
unsigned int pinmask; unsigned int pinmask;
unsigned int pinvalue; unsigned int pinvalue;
void (*callback)(void); timer_callback_t callback;
}; };
int timer_wait_init(const struct timer_wait *wait); int timer_wait_init(const struct timer_wait *wait, void *data);
int timer_wait_status(const struct timer_wait *wait); int timer_wait_status(const struct timer_wait *wait);
static inline static inline