Compare commits
2 commits
6c8119424b
...
5954e875b1
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5954e875b1 | ||
|
|
57d95b7a1b |
4 changed files with 79 additions and 62 deletions
83
ssp.c
83
ssp.c
|
|
@ -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
16
ssp.h
|
|
@ -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
32
timer.c
|
|
@ -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
10
timer.h
|
|
@ -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
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue