Compare commits

..

4 commits

Author SHA1 Message Date
Stephan I. Böttcher
6ad8702936 ads8688: batch driven
- add batch driven operations
  - `read_cb`: read manually selected channels up to 256 time
  - `read_auto_cb`: read auto channels
  - `gains_cb`: read or set channel ranges

- `adc/frame`: send single spi frames
- `adc/gains`: read or set channel ranges
- `adc/read`: start readout
- `adc/print`: act on read results/status
2024-11-08 15:43:06 +01:00
Stephan I. Böttcher
131d90dd9d ssp: fixes and changes for ads8688
- remove `ssp_lastword`, unused
- `ssp_set_buffer(0, size)` limit scratch buffer use to `size`
- `ssp_callback` reset when called.
- `ssp_submit_job` call `ssp_set_buffer()`, set `ssp_callback`
- `s/ssp_submit_batch/ssp_start_batch/`
- new: `ssp_submit_batch()` to atomically set `ssp_callback`
- `ssel_delay()`: `__asm__ volatile`
- `ssp_b_scratch`, `ssp_b_buffer`: `call ssp_set_buffer()`
- `ssp_b_whilebuf`: abort `ssp_b_repeat` when buffer runs out.
- `ssp_b_stop`, `ssp_b_return`: postpone while `ssp_b_repeat`
- `ssp_b_jump`: fix jump offset, apply offset to `->batch` too
- `ssp_b_job`: only submit when nonempty
- `ssp_start_batch()`: do not set `ssp_callback`
2024-11-08 15:25:37 +01:00
stephan
d6be6f5afe parser: avoid non-const string
git-svn-id: svn+ssh://asterix.ieap.uni-kiel.de/home/subversion/stephan/solo/eda/arm@9133 bc5caf13-1734-44f8-af43-603852e9ee25
2024-11-08 15:17:01 +01:00
stephan
dfbbb088d2 isr: add "memory" to CPSR asm
git-svn-id: svn+ssh://asterix.ieap.uni-kiel.de/home/subversion/stephan/solo/eda/arm@9134 bc5caf13-1734-44f8-af43-603852e9ee25
2024-11-08 15:16:46 +01:00
8 changed files with 466 additions and 144 deletions

462
ads8688.c
View file

@ -5,34 +5,340 @@
#include "message.h"
#include <string.h>
#define N 4
static unsigned int timeout = 1000;
static int nread = 2;
static struct ads8688_data {
unsigned short last;
unsigned char feature;
unsigned char alarm;
unsigned char range[8];
unsigned short data[N];
unsigned short first[N];
unsigned int n;
unsigned int sum[N];
int square[N];
} data;
const struct keywords ads8688_variable_names[] = {
VARIABLE("adc_timeout", &timeout),
VARIABLE("adc_nread", &nread),
VARIABLE("adc_last", &data.last),
VARIABLE("adc_range", &data.range),
VARIABLE("adc_data", &data.data),
VARIABLE("adc_avr", &data.n),
VARIABLE("adc_sum", &data.sum),
VARIABLE("adc_square", &data.square),
KW_END
struct ads8688_control;
typedef int (*adc_callback_t)(struct ads8688_control *);
static struct ads8688_control {
unsigned int status;
unsigned short frame;
unsigned short frame2;
unsigned short channels;
unsigned short nbuf;
unsigned short nchannels;
unsigned short tchannels;
unsigned int gains;
unsigned int first[10];
unsigned int sum[10];
int square[10];
unsigned int navg[10];
struct ssp_job job;
struct ssp_match match;
adc_callback_t callback;
} ads8688_control;
void ads8688_readings(struct ads8688_control *c, unsigned int cc, int i, int ii)
{
unsigned short first = ssp_buffer[0];
unsigned int sum = first;
int square = 0;
int n = 1;
unsigned short sdo = 0;
if (!i && ii > 1)
sdo = ssp_buffer[1];
while (i < c->nbuf) {
int d = ssp_buffer[i];
sum += d;
d -= first;
square += d*d;
n++;
i += ii;
}
if (cc > 9)
cc = 9;
c->sum[cc] = sum;
c->square[cc] = square;
c->navg[cc] = n;
c->first[cc] = sdo<<16 | first;
cc = 1<<cc;
c->nchannels |= cc;
c->tchannels |= cc;
c->status |= 0x10000 | cc<<8;
}
static inline int tcnh_cb(struct ads8688_control *c)
{
c->status |= 0xE0000000;
return 1;
}
static inline int alldone_cb(struct ads8688_control *c)
{
c->status |= 0xD0000000;
return 1;
}
static int read_cb(struct ads8688_control *c)
{
c->status = c->status & 0xff | 0x300;
if ((c->frame & 0xf0ff) != 0xc000)
return tcnh_cb(c);
unsigned int cc = c->frame >> 8 & 0xf;
if (cc <= 8) {
ads8688_readings(c, cc, 0, c->match.read_count);
cc++;
}
if (cc == 15)
cc = 0;
while (cc <= 8 && !(c->channels & 1<<cc))
cc++;
if (cc > 8)
return alldone_cb(c);
c->frame = 0xc000 | cc;
ssp_set_buffer(0, c->nbuf);
return ssp_submit_batch(&c->frame, 1, 2, 0, 0);
}
static int read_auto_cb(struct ads8688_control *c)
{
c->status = c->status & 0xff | 0x400;
if (c->frame == 0xa000) {
int ii = 0;
int i = 0;
unsigned int cc = c->channels;
while (cc) {
cc >>= 1;
ii++;
}
for (cc=0; cc<8; cc++)
if (c->channels & 1<<cc)
ads8688_readings(c, cc, i++, ii);
return alldone_cb(c);
}
if (c->frame == 0)
c->frame = 0x0300 | c->channels & 0xff;
else if ((c->frame & 0xff) == 0x03)
c->frame = 0xa000;
else
return tcnh_cb(c);
ssp_set_buffer(0, c->nbuf);
return ssp_submit_batch(&c->frame, 1, 2, 0, 0);
}
inline static
unsigned int save_gain(unsigned short frame, unsigned short data, unsigned int *gains)
{
unsigned int cc = (frame >> 9) - 5 & 15;
if (cc > 8 || frame & 0x100)
return cc;
unsigned int g = data >> 8 & 15;
*gains &= ~(0xf << 4*cc);
*gains |= g << 4*cc;
return cc;
}
static int gains_cb(struct ads8688_control *c)
{
c->status = c->status & ~0xf00 | 0x500;
unsigned short f = c->frame;
if (f & 0x1e00)
return tcnh_cb(c);
unsigned int cc = save_gain(f, *ssp_buffer, &c->gains);
if (cc == 11)
cc = 0;
else if (cc >= 8)
return alldone_cb(c);
else
c->status |= 0x10000 | cc<<8;
c->frame = cc + 5 << 9;
if (f & 0x100)
c->frame |= 0x100 | c->gains >> 4*cc;
return 0;
}
static int ads8688_cb(const struct ssp_batch *b)
{
struct ads8688_control *c = b->data;
c->status = c->status + 1 & 0xff | 0x200;
return c->callback(c);
}
static const struct ssp_batch ads8688_batch[] = {
[0] = {
.flags = ssp_b_config,
{ .ssel = &ssp_conf_adc },
},
[1] = {
.flags = ssp_b_call,
{ .callback = ads8688_cb },
{ .data = &ads8688_control },
},
[2] {
.flags = ssp_b_job
| SSP_B_REPEAT(256) | ssp_b_whilebuf
| ssp_b_deassert | ssp_b_assert | SSP_B_DELAY(10),
{ .job = &ads8688_control.job},
{ .match = &ads8688_control.match},
},
[3] {
.flags = ssp_b_goto | SSP_B_JUMP(-2) | ssp_b_stop,
},
};
static int ads8688_start(int nskip, int nread)
{
struct ads8688_control *c = &ads8688_control;
c->status = 0x100;
c->job.command = &c->frame;
c->job.count = 1 + nskip + nread;
c->job.idle_frame = 0;
c->match.frame_count = nskip;
c->match.read_count = nread;
return ssp_start_batch(ads8688_batch, 0);
}
int adc_gains_cmd(struct command *cmd, const struct command_par *par)
{
static const struct keywords kw[] = { FLAG_VAL("read", 0), {}};
const struct keywords *k;
error_msg_t e = parse_flag(cmd, kw, &k, 2);
if (e)
return parser_error_message(cmd, e);
struct ads8688_control *c = &ads8688_control;
c->frame = 0; // read
unsigned int oldgains = c->gains;
if (!k) {
parse_expression(cmd, &c->gains);
c->frame = 0x0100; // write
}
unsigned int newgains = c->gains; // volatile
c->nbuf = 8;
c->job.cmd_count = 1;
c->callback = gains_cb;
int r = ads8688_start(1, 1);
int code = par->code;
if (r)
code++;
parser_format_message(cmd, "%03d gains[%04x/%d] 0x%08x → 0x%08x\n",
code, c->frame, r, oldgains, newgains);
return code;
}
int adc_read_cmd(struct command *cmd, const struct command_par *par)
{
static const struct keywords kw[] = { FLAG_VAL("auto", 0), {}};
const struct keywords *k;
error_msg_t e = parse_flag(cmd, kw, &k, 2);
if (e)
return parser_error_message(cmd, e);
struct ads8688_control *c = &ads8688_control;
parse_expression(cmd, (unsigned int *)&c->channels); // { nbuf, aidx, ch}
int aidx = c->channels >> 12;
if (!k) {
c->frame = 0xcf00;
c->callback = read_cb;
}
else {
c->frame = 0x0000;
c->callback = read_auto_cb;
}
c->job.cmd_count = 0; // idle_frame = continue command
int r = ads8688_start(aidx+1, 1);
int code = par->code;
if (r)
code++;
parser_format_message(cmd, "%03d adc read (%d) 0x%04x 0x%08x\n",
code, r, c->channels, c->status);
return code;
}
int adc_print_cmd(struct command *cmd, const struct command_par *par)
{
struct ads8688_control *c = &ads8688_control;
int code = par->code;
static const struct keywords kw[] = {
FLAG_VAL("status", 0x01000000),
FLAG_VAL("wait", 0x02000000),
FLAG_VAL("send", 0x00010000),
FLAG_VAL("msg", 0x00020000),
FLAG_VAL("force", 0x00100000),
FLAG_VAL("all", 0x000001ff),
FLAG_VAL("aux", 0x00000100),
FLAG_VAL("abort", 0x04000000),
{}
};
unsigned int chs = 0;
error_msg_t e = parse_flags(cmd, kw, &chs);
if (e)
return parser_error_message(cmd, e);
unsigned int what = chs;
if (what & 0x07000000) {
int r = 0;
if (what & 0x02000000) {
parse_expression_square(cmd, &timeout, 1);
r = ssp_wait(timeout);
}
else
r = ssp_busy();
if (r && what & 0x04000000) {
int rr = ssp_abort_batch(ads8688_batch);
if (rr==-1)
c->status |= 0xF0000000;
else
c->status |= 0xA0000000 | rr<<20;
}
if (what & 0x01000000 || c) {
if (r)
code++;
parser_format_message(cmd, "%03d busy: 0x%x status: 0x%08x\n",
code, r, c->status);
return code;
}
}
parse_expression(cmd, &chs);
unsigned int ach = c->tchannels;
if (!(what & 0x00010000) || !ach)
ach = c->nchannels;
if (!(chs &= 0x1ff))
chs = ach & ~(ach-1);
else if (ach & chs && !(what & 0x00100000))
chs = ach;
chs &= 0x1ff;
if (!chs) {
code ++;
parser_format_message(cmd, "%03d no adc data\n", code);
return code;
}
if (what & 0x00010000)
c->tchannels &=~ chs;
unsigned int aidx = c->channels >> 8 & 0xf0;
int ch = 0;
unsigned int ccc = chs;
int n = 0;
while (ccc) {
while (!(ccc & 1)) {
ccc >>= 1;
ch++;
}
static const char fmt[] = "%03d ADS %x %d 0x%04x %u %u\n";
if (what & 0x00010000)
printf(0, fmt+5, aidx+ch, c->navg[ch], c->first[ch], c->sum[ch], c->square[ch]);
if (what & 0x00020000)
message(MSG_PRIO_INFO, fmt+5, aidx+ch, c->navg[ch], c->first[ch], c->sum[ch], c->square[ch]);
if (!n++) {
parser_format_message(cmd, fmt, code, aidx+ch, c->navg[ch], c->first[ch], c->sum[ch], c->square[ch]);
c->nchannels &= ~(1<<ch);
}
}
return code;
}
#define N 4
static struct ads8688_data {
unsigned short data[N];
unsigned short frame;
unsigned short nread;
} data;
int ads8688(unsigned short *frame, int n, int flags, int timeout)
{
if (flags & adc_f_init)
@ -49,7 +355,7 @@ int ads8688(unsigned short *frame, int n, int flags, int timeout)
return r;
}
int adc_cmd(struct command *cmd, const struct command_par *par)
int adc_frame_cmd(struct command *cmd, const struct command_par *par)
{
static const struct keywords kw[] = {
FLAG_VAL("continue", 0x0000),
@ -81,7 +387,7 @@ int adc_cmd(struct command *cmd, const struct command_par *par)
FLAG_VAL("highlsb", 0x2e00),
FLAG_VAL("lowmsb", 0x3000),
FLAG_VAL("lowlsb", 0x3200),
FLAG_VAL("send", 0x10000),
FLAG_VAL("unipolar", 0x0b04),
KW_END };
const struct keywords *k;
@ -91,14 +397,10 @@ int adc_cmd(struct command *cmd, const struct command_par *par)
unsigned int flags = adc_f_init;
unsigned int code = par->code;
unsigned short frame = 0;
unsigned int send = 0;
if (k) {
if (k)
frame = k->val;
send = k->val & 0xffff0000;
if (send)
e = parse_flag(cmd, kw, &k, 2);
}
// adc/send/«cmd» [«n»] [«timeout»] «value» zero or one value
// adc/«cmd» [«n»] «value» zero or one value
if (!e)
e = parse_expression_square(cmd, &ch, 1);
@ -110,86 +412,60 @@ int adc_cmd(struct command *cmd, const struct command_par *par)
e = parse_expression(cmd, &val);
int r = 0;
int n = 1;
if (frame & 0x8000) {
if (frame == 0xc000)
frame |= ch << 10;
if (e)
val = nread;
r = ads8688(&frame, val, flags, timeout);
data.last = frame;
goto done;
}
if (!frame) {
if (nread > N)
nread = N;
memset(&data.n, 0, sizeof(int)*(2*N+1));
if (e || val >= 0x1000)
val = 0x1000;
while (data.n < val) {
r = ads8688(&frame, nread, flags, timeout);
flags = 0;
if (r)
break;
if (!data.n)
memcpy(data.first, data.data, sizeof(data.first));
for (int i=0; i < nread; i++) {
data.sum[i] += data.data[i];
int diff = data.data[i] - data.first[i];
data.square[i] += diff*diff;
}
data.n++;
}
if (!data.n)
goto done;
if (send)
for (int i=0; i < nread; i++)
printf(0, "A %d %d %d 0x%04x %u %d\n",
ch, i, data.n, data.first[i], data.sum[i], data.square[i]);
parser_format_message(cmd, "%03d adc[%u] → [%d] %d %04x %04x %04x %04x\n",
code, ch, r, data.n,
data.sum[0], data.sum[1],
data.sum[2], data.sum[3] );
return code;
if (!e)
data.nread = val;
n = data.nread;
goto send;
}
if (frame == 0x0a00)
frame += ch << 9;
if (frame >= 0x2a00 && frame <= 0x3200)
frame += (5*ch) << 9;
frame += 5*ch << 9;
if (frame >= 0x2200 && frame <= 0x2400)
frame += (ch & 4) << 7;
if (!e)
frame |= 0x100 | val & 0xff;
r = ads8688(&frame, 1, flags, timeout);
if (r)
goto done;
if ((frame & 0xff00) == 0x0700)
data.feature = val;
if (frame >= 0x0b00 && frame < 0x1a00 && frame & 0x100)
data.range[((frame>>9)-5)&7] = val;
if (frame == 0x2000)
data.alarm = data.data[0] >> 8;
done:
send:
data.frame = frame;
r = ads8688(&data.frame, n, flags, timeout);
if (r)
code++;
if (send)
printf(0, "AF 0x%04x %u %d 0x%04x 0x%04x 0x%04x 0x%04x\n",
frame, val, r,
data.data[0], data.data[1],
data.data[2], data.data[3] );
parser_format_message(cmd, "%03d adc 0x%04x → [%d] %04x %04x %04x %04x\n",
code, frame, r,
data.data[0], data.data[1],
data.data[2], data.data[3] );
return code;
}
const struct keywords ads8688_variable_names[] = {
VARIABLE("adc_timeout", &timeout),
VARIABLE("adc_navg", ads8688_control.navg),
VARIABLE("adc_nread", &data.nread),
VARIABLE("adc_data", &data.data),
VARIABLE("adc_dframe", &data.frame),
VARIABLE("adc_frame", &ads8688_control.frame),
VARIABLE("adc_channels", &ads8688_control.channels),
VARIABLE("adc_nbuffer", &ads8688_control.nbuf),
VARIABLE("adc_gains", &ads8688_control.gains),
VARIABLE("adc_first", ads8688_control.first),
VARIABLE("adc_sum", ads8688_control.sum),
VARIABLE("adc_square", ads8688_control.square),
VARIABLE("adc_status", &ads8688_control.status),
KW_END
};
const struct keywords adc_commands[] = {
CMD_KW("frame", adc_frame_cmd, 370, 0),
CMD_KW("gains", adc_gains_cmd, 372, 0),
CMD_KW("read", adc_read_cmd, 374, 0),
CMD_KW("print", adc_print_cmd, 376, 0),
CMD_END
};

View file

@ -11,5 +11,6 @@ enum adc_flags {
};
extern const struct keywords ads8688_variable_names[];
extern const struct keywords adc_commands[];
#endif

4
isr.h
View file

@ -8,13 +8,13 @@ void init_vic(void);
static inline unsigned int cpsr(void)
{
unsigned int r;
__asm__ __volatile__ ("MRS %0, CPSR" : "=r" (r));
__asm__ __volatile__ ("MRS %0, CPSR" : "=r" (r) :: "memory");
return r;
}
static inline void cpsr_c(unsigned int r)
{
__asm__ __volatile__ ("MSR CPSR_c, %0" :: "r" (r));
__asm__ __volatile__ ("MSR CPSR_c, %0" :: "r" (r) : "memory");
}
static inline unsigned int disable_irq(unsigned int flag)

View file

@ -520,7 +520,7 @@ static const struct keywords main_command_table[] = {
CMD_KW("pressure", pressure_cmd, 366, 0),
CMD_KW("bate", bate_cmd, 368, 0),
CMD_KW("dac", dac_cmd, 364, 0),
CMD_KW("adc", adc_cmd, 362, 0),
CMD_KW("adc", parse_sub_command, 909, adc_commands),
CMD_KW("ssp", parse_sub_command, 909, ssp_commands),
{"flash", {.par=&flash_command}},
{"dma", {.par=&usb_command}},

View file

@ -81,10 +81,7 @@ error_msg_t expect_char(struct command *cmd, char what)
{
if (parse_char(cmd, what))
return 0;
static char mes[] = ". expected\n";
static ERRORMESSAGE(error, 709, mes);
mes[0] = what;
return &error;
return error_printf(709, "%c expected\n", what);
}
const struct keywords *parse_keyword(struct command *cmd, const struct keywords *table)

View file

@ -199,7 +199,7 @@ int pressure_cmd(struct command *cmd, const struct command_par *par)
if (what & 0x0020) {
ssp_conf_bate = ssp_confs_bate[!!idx];
bate_status = 2;
int c = ssp_submit_batch(bate_batch, 0);
int c = ssp_start_batch(bate_batch, 0);
if (!c) {
parser_format_message(cmd, "%03d bate[%d] triggered\n",
code, idx);

117
ssp.c
View file

@ -15,7 +15,6 @@ static volatile struct ssp_job job;
struct ssp_match ssp_match;
unsigned int ssp_bits;
int (*ssp_callback)();
volatile unsigned int ssp_lastword;
unsigned int ssp_ssel_mask = SSP_SSEL_MASK0 | SSP_SSEL_MASK1;
unsigned short *ssp_buffer;
@ -24,13 +23,14 @@ volatile int ssp_frames_read;
unsigned short ssp_scratch[256];
void ssp_set_buffer(short *buf, int size)
void ssp_set_buffer(short *buf, unsigned int size)
{
unsigned int iflg = disable_irq(INT_DISABLE);
volatile struct ssp_job *j=&job;
if (!(size && buf)) {
if (!buf) {
buf = ssp_scratch;
size = sizeof(ssp_scratch)/2;
if (!size || size > sizeof(ssp_scratch)/2)
size = sizeof(ssp_scratch)/2;
}
ssp_buffer = (unsigned short *)buf;
j->buf_ptr = (unsigned short *)buf;
@ -65,7 +65,6 @@ static void ssp_isr(void)
unsigned int dr = SSPDR;
sr=SSPSR;
nread++;
ssp_lastword = ssp_lastword << ssp_bits | dr;
if (ssp_frames_read++ >= ssp_match.frame_count
&& !rc
&& (dr & ssp_match.mask) == ssp_match.value) {
@ -94,11 +93,12 @@ static void ssp_isr(void)
goto outic;
else {
SSPIMSC = 0;
if (ssp_callback)
ssp_callback();
int (*cb)() = ssp_callback;
ssp_callback = 0;
if (cb)
cb();
goto out;
}
}
else if (!(sr & (SSPSR_BSY|SSPSR_RNE)))
nread = 8;
@ -154,18 +154,41 @@ int ssp_submit(const unsigned short *cmd, short cmd_size, unsigned short ic, uns
return 0;
}
int ssp_submit_batch(const unsigned short *cmd, short cmd_size,
unsigned short ic, unsigned short rc, unsigned short fc)
{
volatile struct ssp_job *j=&job;
unsigned int iflg = disable_irq(INT_DISABLE);
j->command = cmd;
j->cmd_count = cmd_size;
j->count = ic;
if (!fc) {
j->read_count = rc;
ssp_match.frame_count = 0;
ssp_match.read_count = 0;
}
else {
j->read_count = 0;
ssp_match.frame_count = fc;
ssp_match.read_count = rc;
}
ssp_frames_sent = 0;
ssp_frames_read = 0;
ssp_callback = ssp_run_batch;
enable_irq(iflg);
ssp_poll();
return 0;
}
int ssp_submit_job(const struct ssp_job *jj)
{
unsigned int iflg = disable_irq(INT_DISABLE);
size_t n = sizeof(job);
if (!jj->buf_ptr) {
n -= 8;
if (jj->buf_count)
ssp_set_buffer(0, 0);
}
memcpy((void*)&job, jj, n);
memcpy((void*)&job, jj, sizeof(job)-8);
if (jj->buf_ptr || jj->buf_count)
ssp_set_buffer(0, jj->buf_count);
ssp_frames_sent = 0;
ssp_frames_read = 0;
ssp_callback = ssp_run_batch;
enable_irq(iflg);
ssp_poll();
return 0;
@ -280,8 +303,9 @@ const struct ssp_batch *ssp_batch;
static inline
void ssel_delay(int delay)
{
delay &= ssp_b_delay;
delay >>= ssp_b_dshift;
while (delay-->0) __asm__("");
while (delay-->0) __asm__ volatile ("");
}
// called first by `ssp_submit_batch()`
@ -308,35 +332,40 @@ int ssp_run_batch()
if (c == ssp_b_config)
ssp_init(batch->ssel);
if (f & ssp_b_scratch)
ssp_set_buffer(0, 0);
if (c == ssp_b_buffer)
ssp_set_buffer(batch->buffer, f & 0xffff);
if (f & ssp_b_deassert) {
ssp_deassert_ssel();
if (c == ssp_b_job)
ssel_delay(f & ssp_b_delay);
ssel_delay(f);
}
if (f & ssp_b_assert || c == ssp_b_config) {
ssp_assert_ssel();
if (c == ssp_b_job)
ssel_delay(f & ssp_b_delay);
}
static unsigned int repeats;
if (c != ssp_b_job && c != ssp_b_gosub
|| repeats++ >= f & ssp_b_repeat) {
// we did all repeats … advance to the next job
repeats = 0;
ssp_batch++;
ssel_delay(f);
}
static const struct ssp_batch *gosub_return;
static int gosub_repeats;
static unsigned int repeats, gosub_repeats;
if (c != ssp_b_job && c != ssp_b_gosub
|| repeats++ >= f & ssp_b_repeat
|| ssp_b_whilebuf & !job.buf_count) {
// we did all repeats … advance to the next job
repeats = 0;
ssp_batch++;
if (f & ssp_b_stop)
ssp_batch = 0;
if (f & ssp_b_stop)
ssp_batch = 0;
if (f & ssp_b_return) {
ssp_batch = gosub_return;
repeats = gosub_repeats;
gosub_return = 0;
if (f & ssp_b_return) {
ssp_batch = gosub_return;
repeats = gosub_repeats;
gosub_return = 0;
}
}
if (c == ssp_b_call) {
@ -350,11 +379,16 @@ int ssp_run_batch()
gosub_return = ssp_batch;
gosub_repeats = repeats;
}
short jmp = f; // sign extend (f & 0xffff)
if (batch->batch)
ssp_batch = batch->batch;
else
if (batch->batch) {
short jmp = (f & ssp_b_jump) >> ssp_b_jshift;
if (f & ssp_b_jsign)
jmp -= 1 + (ssp_b_jump >> ssp_b_jshift);
if (batch->batch)
ssp_batch = batch->batch;
else
ssp_batch = batch;
ssp_batch += jmp;
}
}
if (c == ssp_b_job) {
@ -362,7 +396,8 @@ int ssp_run_batch()
ssp_match = *batch->match;
else
memset(&ssp_match, 0, sizeof(ssp_match));
return ssp_submit_job(batch->job);
if (batch->job && batch->job->count)
return ssp_submit_job(batch->job);
}
if (c == ssp_b_wait) {
@ -400,19 +435,17 @@ doit:
return n;
}
int ssp_submit_batch(const struct ssp_batch *batch, int timeout)
int ssp_start_batch(const struct ssp_batch *batch, int timeout)
{
unsigned int c = ssp_wait(timeout);
if (c)
return c;
ssp_batch = batch;
ssp_callback = ssp_run_batch;
return ssp_run_batch();
}
const struct keywords ssp_variable_names[] = {
VARIABLE("ssp_buffer", ssp_scratch),
VARIABLE("ssp_response", (void *)&ssp_lastword),
VARIABLE("ssp_match", &ssp_match),
VARIABLE("ssp_ssel_mask", &ssp_ssel_mask),
VARIABLE("ssp_frames_sent", (void *)&ssp_frames_sent),

25
ssp.h
View file

@ -8,14 +8,14 @@
void ssp_reset(void);
void ssp_set_buffer(short *buf, int size);
void ssp_set_buffer(short *buf, unsigned int size);
void ssp_poll(void);
int ssp_submit(const unsigned short *cmd, short cmd_size, unsigned short ic, unsigned short rc);
unsigned int ssp_busy(void);
int ssp_wait(int timeout);
extern unsigned int ssp_bits;
extern volatile unsigned int ssp_lastword;
unsigned short *ssp_buffer;
extern unsigned int ssp_ssel_mask;
extern unsigned int ssp_ssel;
extern unsigned int ssp_read_size;
@ -25,7 +25,8 @@ extern unsigned int ssp_match_value;
extern unsigned int ssp_match_count;
extern volatile int ssp_frames_sent;
extern volatile int ssp_frames_read;
extern unsigned short ssp_scratch[256];
#define NSCRATCH 256
extern unsigned short ssp_scratch[NSCRATCH];
extern int (*ssp_callback)();
extern struct ssp_config {
@ -96,9 +97,11 @@ struct ssp_batch {
const struct timer_wait *wait;
ssp_batch_callback_t callback;
const struct ssp_batch *batch;
unsigned short *buffer;
};
union {
const struct ssp_match *match;
unsigned int value;
void *data;
};
} *ssp_batch;
@ -106,14 +109,20 @@ struct ssp_batch {
enum ssp_batch_flags {
ssp_b_count = 0x00ffffff,
ssp_b_repeat = 0x00000fff,
ssp_b_delay = 0x00fff000,
ssp_b_delay = 0x007ff000,
ssp_b_dshift = 12,
ssp_b_jump = 0x000ff000,
ssp_b_jsign = 0x00080000,
ssp_b_jshift = 12,
ssp_b_scratch = 0x00800000,
ssp_b_whilebuf = 0x00400000,
ssp_b_job = 0x01000000,
ssp_b_config = 0x02000000,
ssp_b_wait = 0x03000000,
ssp_b_call = 0x04000000,
ssp_b_goto = 0x05000000,
ssp_b_gosub = 0x06000000,
ssp_b_buffer = 0x07000000,
ssp_b_what = 0x0f000000,
ssp_b_assert = 0x10000000,
ssp_b_deassert = 0x20000000,
@ -121,6 +130,10 @@ enum ssp_batch_flags {
ssp_b_return = 0x80000000,
};
#define SSP_B_DELAY(m) (((m)<<ssp_b_dshift)&ssp_b_delay)
#define SSP_B_REPEAT(c) (((c)-1)&ssp_b_repeat)
#define SSP_B_JUMP(r) (((r)<<ssp_b_jshift)&ssp_b_jump)
// skip `count` frames before recording `size` frames.
static inline
void ssp_set_read(unsigned short count, unsigned short size)
@ -130,7 +143,9 @@ void ssp_set_read(unsigned short count, unsigned short size)
}
int ssp_submit_job(const struct ssp_job *jj);
int ssp_submit_batch(const struct ssp_batch *batch, int timeout);
int ssp_submit_batch(const unsigned short *cmd, short cmd_size,
unsigned short ic, unsigned short rc, unsigned short fc);
int ssp_start_batch(const struct ssp_batch *batch, int timeout);
int ssp_run_batch();
int ssp_abort_batch(const struct ssp_batch *batch);