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;
struct ssp_match ssp_match;
static const struct ssp_batch *ssp_batch;
const struct ssp_batch *ssp_batch;
static int ssp_batch_repeats;
unsigned int ssp_bits;
volatile unsigned int ssp_lastword;
unsigned int ssp_ssel_mask = SSP_SSEL_MASK0 | SSP_SSEL_MASK1;
static const struct timer_wait *ssp_batch_wait;
unsigned short *ssp_buffer;
volatile unsigned int ssp_frame_count;
@ -82,49 +83,44 @@ static void ssp_isr(void)
}
j->read_count = rc;
if (!nread && !rc && !(sr&SSPSR_BSY) && !j->cmd_count && !j->idle_count) {
// there is nothing left to do
SSPIMSC = 0;
VICVectAddr = 0;
return;
sr |= SSPSR; // race between SSPSR_BSY, SSPSR_RNE?
if (!j->cmd_count && !j->idle_count) {
if (!rc && !(sr & (SSPSR_BSY|SSPSR_RNE))) {
SSPIMSC = 0;
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.
// This prevents Rx FIFO overflow.
// 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;
while (nread && (sr&SSPSR_TNF)) {
if (j->cmd_count) {
j->cmd_count--;
SSPDR = *j->command++;
}
else {
if (!(rc || ic)) {
// nothing to send, disable TX irq
SSPIMSC = SSP_INT_RX;
break;
}
if (ic)
ic--;
else if (ic) {
ic--;
SSPDR = ssp_match.idle;
}
else {
SSPIMSC = SSP_INT_RX;
goto outic;
}
nread--;
sr = SSPSR;
}
outic:
j->idle_count = ic;
out:
VICVectAddr = 0;
}
@ -225,7 +221,11 @@ int ssp_busy(void)
return c;
// Hardware is busy
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:
ssp_reset();
return 0;
@ -259,34 +259,42 @@ struct ssp_config ssp_conf_bate[] = {
},
};
int ssp_wait_miso(const struct ssp_wait *wait)
{
return 0;
}
// called first by `ssp_submit_batch()`
// called next by `ssp_isr()` when a job is done
// 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;
if (!batch || !batch->job)
return -1;
if (batch->wait) {
int c = ssp_wait_miso(batch->wait);
if (c)
return c;
const struct timer_wait *wait = batch->wait;
if (wait) {
if (ssp_batch_wait != wait) {
// 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) {
// we did all repeats … advance to the next job
ssp_batch_repeats = 0;
ssp_batch++;
}
const struct ssp_config *ssel = batch->ssel;
if (ssel)
if (ssel) {
if (ssel->mode)
ssp_init(ssel);
else if (ssel->ssel)
ssp_config.ssel = ssel->ssel;
ssp_deassert_ssel();
}
const struct ssp_match *match = batch->match;
if (match)
ssp_match = *match;
@ -302,5 +310,6 @@ int ssp_submit_batch(const struct ssp_batch *batch, int timeout)
return c;
ssp_batch_repeats = 0;
ssp_batch = batch;
ssp_batch_wait = 0;
return ssp_run_batch();
}

16
ssp.h
View file

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

32
timer.c
View file

@ -14,7 +14,7 @@ void tick_timer(volatile struct timer_tick *tick, unsigned int ir)
if (n != 0xffff)
tick->n = n+1;
if (tick->callback)
tick->callback(ir, n);
tick->callback(tick);
}
__attribute__ ((interrupt ("IRQ")))
@ -79,28 +79,28 @@ static void timer_wait_abort(void) {
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;
if (!w)
return;
if (timer_wait_pin_status(w))
goto hit;
if (w->mclk && n >= w->mclk)
if (w->mclk && tick->ir & 0x100 && tick->n >= w->mclk)
goto hit;
if (w->pclk && ir & 1)
if (w->pclk && tick->ir & 0x200 && tick->ir & 1)
goto hit;
return;
hit:
timer_wait_abort();
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();
if (!wait)
if (!wait || timer_wait_pin_status(wait))
return 0;
timer0_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;
if (wait->ccr0 || wait->mclk)
timer0_tick.callback = &wait_callback;
if (wait->ccr1 || wait->pclk)
timer1_tick.callback = &wait_callback;
wait_callback(0,0);
if (wait->ccr0 || wait->mclk) {
timer0_tick.data = data;
timer0_tick.callback = wait_callback;
}
if (wait->ccr1 || wait->pclk) {
timer1_tick.data = data;
timer1_tick.callback = wait_callback;
}
enable_irq(iflg);
return !!waiting;
}
@ -161,8 +164,3 @@ int timer_wait_status(const struct timer_wait *wait)
{
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 timer1_init();
struct timer_tick;
typedef void (*timer_callback_t)(const volatile struct timer_tick *tick);
extern volatile struct timer_tick {
unsigned int ir;
unsigned int n;
void (*callback)(unsigned, unsigned);
timer_callback_t callback;
void *data;
} timer0_tick, timer1_tick;
struct timer_wait {
@ -19,10 +23,10 @@ struct timer_wait {
unsigned short ccr1;
unsigned int pinmask;
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);
static inline