Compare commits

...

3 commits

Author SHA1 Message Date
Stephan I. Böttcher
fb7c5498fa leia: update comments 2025-10-22 22:25:31 +02:00
Stephan I. Böttcher
b26a64514c leia: conf → v.conf, v.stat 2025-10-22 22:19:33 +02:00
Stephan I. Böttcher
267ad36409 leia: conf size 2025-10-22 21:21:49 +02:00

View file

@ -60,8 +60,8 @@ const char revision[] = Id;
#define VERSION 1
struct conf {
unsigned int magic; // 0
unsigned char version; // 2
uint16_t magic; // 0
uint8_t version; // 2
uint8_t flags; // 3
uint16_t period; // 4
uint16_t slen; // 6
@ -72,20 +72,26 @@ struct conf {
uint8_t reset; // 12
uint8_t dir; // 13
uint16_t n_steps; // 14
uint16_t dac; // 16
uint16_t dac_ramp; // 18
uint16_t dac_step; // 20
uint8_t adc_idx; // 22
uint8_t adc_incr; // 23
uint8_t adc_period; // 24
uint8_t pad[7]; // 25
uint8_t adc_ch[16]; // 32
} conf; // 64
enum {
FLAG_WDT = 1,
};
struct stat {
uint16_t adc[16]; // 48
uint16_t dac; // 80
uint8_t adc_idx; // 82
uint8_t pad[45]; //128
};
struct vars {
struct conf conf;
struct stat stat;
} v;
#define STEP_RESOLUTION 23148L // ns
#define STEP_NS(ns) (((ns)+STEP_RESOLUTION/2)/STEP_RESOLUTION)
#define TICK_RESOLUTION 92593L // ns
@ -132,12 +138,12 @@ void stepper_init()
// 16-bit Timer 1 PWM by OCR1A, prescaled by 256
TCCR1A = 1<<WGM10 | 1<<WGM11 ;
TCCR1B = 1<<WGM12 | 1<<WGM13 | 4<<CS10;
OCR1AH = conf.period >> 8;
OCR1AL = conf.period;
OCR1BH = conf.slen >> 8;
OCR1BL = conf.slen;
RESET_PORT = conf.enable & ~conf.reset;
DIR_PORT = conf.dir;
OCR1AH = v.conf.period >> 8;
OCR1AL = v.conf.period;
OCR1BH = v.conf.slen >> 8;
OCR1BL = v.conf.slen;
RESET_PORT = v.conf.enable & ~v.conf.reset;
DIR_PORT = v.conf.dir;
STEP_PORT = 0;
DDRB = MISO | RESET | ENABLE | SLEEP | LEDON;
DDRD = STEP1 | STEP2;
@ -147,8 +153,8 @@ void stepper_init()
static inline
void stepper_start(uint8_t reset)
{
RESET_PORT = conf.enable & ~reset;
DIR_PORT = conf.dir;
RESET_PORT = v.conf.enable & ~reset;
DIR_PORT = v.conf.dir;
TCNT1H = 0;
TCNT1L = 0;
TIMSK1 = (1<<OCIE1B);
@ -169,13 +175,13 @@ char stepper_status()
#if 1
ISR(TIMER1_COMPA_vect)
{
if (!conf.n_steps || (LIMIT_PORT & conf.lmask) != conf.lval) {
if (!v.conf.n_steps || (LIMIT_PORT & v.conf.lmask) != v.conf.lval) {
STEP_PORT = 0;
TIMSK1 = 0;
return;
}
conf.n_steps--;
STEP_PORT = conf.step;
v.conf.n_steps--;
STEP_PORT = v.conf.step;
}
#else
ISR(TIMER1_COMPA_vect, ISR_NAKED)
@ -215,10 +221,10 @@ ISR(TIMER1_COMPA_vect, ISR_NAKED)
"out __SREG__, r24" "\n\t"
"pop r24" "\n\t"
"reti" "\n"
:[N] "+m" (conf.n_steps)
:[M] "m" (conf.lmask),
[V] "m" (conf.lval),
[S] "m" (conf.step),
:[N] "+m" (v.conf.n_steps)
:[M] "m" (v.conf.lmask),
[V] "m" (v.conf.lval),
[S] "m" (v.conf.step),
[MSK] "n" (_SFR_MEM_ADDR(TIMSK1)),
[P] "n" (_SFR_IO_ADDR(STEP_PORT)),
[L] "n" (_SFR_IO_ADDR(LIMIT_PORT))
@ -230,7 +236,7 @@ ISR(TIMER1_COMPA_vect, ISR_NAKED)
ISR(TIMER1_COMPB_vect)
{
STEP_PORT = 0;
RESET_PORT = conf.enable;
RESET_PORT = v.conf.enable;
TIMSK1 = TIFR1 = 1<<OCIE1B | 1<<OCIE1A;
}
#else
@ -252,7 +258,7 @@ ISR(TIMER1_COMPB_vect, ISR_NAKED)
[IFR] "n" (_SFR_IO_ADDR(TIFR1)),
[RES] "n" (_SFR_IO_ADDR(RESET_PORT)),
[STP] "n" (_SFR_IO_ADDR(STEP_PORT)),
[ENA] "m" (conf.enable),
[ENA] "m" (v.conf.enable),
[IE] "n" (1<<OCIE1B | 1<<OCIE1A)
);
}
@ -261,19 +267,19 @@ ISR(TIMER1_COMPB_vect, ISR_NAKED)
#if 1
ISR(TIMER0_COMPA_vect)
{
uint16_t d = conf.dac;
if (d == conf.dac_ramp) {
uint16_t d = v.stat.dac;
if (d == v.conf.dac_ramp) {
TIMSK0 = 0;
return;
}
uint16_t s = conf.dac_step;
if (d > conf.dac_ramp)
uint16_t s = v.conf.dac_step;
if (d > v.conf.dac_ramp)
d -= s;
else
d += s;
DACL = d;
DACH = d>>8;
conf.dac = d;
v.stat.dac = d;
}
#else
// Avoid some push, pop, cp, and jumps
@ -330,9 +336,9 @@ ISR(TIMER0_COMPA_vect, ISR_NAKED)
"out __SREG__, r24" "\n\t"
"pop r24" "\n\t"
"reti" "\n"
:[D] "+m" (conf.dac)
:[R] "m" (conf.dac_ramp),
[S] "m" (conf.dac_step),
:[D] "+m" (v.stat.dac)
:[R] "m" (v.conf.dac_ramp),
[S] "m" (v.conf.dac_step),
[MSK] "n" (_SFR_MEM_ADDR(TIMSK0)),
[DH] "n" (_SFR_MEM_ADDR(DACH)),
[DL] "n" (_SFR_MEM_ADDR(DACL))
@ -347,13 +353,13 @@ void dac_set(uint16_t d)
DACL = d;
DACH = d>>8;
DACON = 1<<DALA | 1<<DAEN | 1<<DAOE;
conf.dac = conf.dac_ramp = d;
v.stat.dac = v.conf.dac_ramp = d;
}
static
void dac_ramp(uint16_t d)
{
uint16_t s = conf.dac_step;
uint16_t s = v.conf.dac_step;
if (!s) {
dac_set(d);
return;
@ -362,9 +368,9 @@ void dac_ramp(uint16_t d)
d &= s;
TIMSK0 = 0;
DACON = 1<<DALA | 1<<DAEN | 1<<DAOE;
conf.dac = DAC & s;
conf.dac_ramp = d;
if (d != conf.dac)
v.stat.dac = DAC & s;
v.conf.dac_ramp = d;
if (d != v.stat.dac)
TIMSK0 = 1<<OCIE0A;
}
@ -383,9 +389,9 @@ static
void adc_start(uint8_t i)
{
i &= 15;
conf.adc_idx = i<<4;
OCR0A = OCR0B = conf.adc_period;
uint8_t ch = conf.adc_ch[i];
v.stat.adc_idx = i<<4;
OCR0A = OCR0B = v.conf.adc_period;
uint8_t ch = v.conf.adc_ch[i];
if (!(ch & 1<<REFS0))
return;
ADMUX = ch;
@ -399,8 +405,6 @@ void adc_stop()
ADCSRA = 1<<ADEN | 1<<ADIF | 6<<ADPS0;
}
uint16_t adc[16];
#if 1
ISR(ADC_vect)
{
@ -410,17 +414,17 @@ ISR(ADC_vect)
a |= ADCH<<8;
}
else {
a = adc[conf.adc_idx >> 4];
a = v.stat.adc[v.stat.adc_idx >> 4];
a -= a>>6;
a += ADCL;
a += ADCH<<8;
}
adc[conf.adc_idx >> 4] = a;
conf.adc_idx += conf.adc_incr;
uint8_t ch = conf.adc_ch[conf.adc_idx >> 4];
v.stat.adc[v.stat.adc_idx >> 4] = a;
v.stat.adc_idx += v.conf.adc_incr;
uint8_t ch = v.conf.adc_ch[v.stat.adc_idx >> 4];
if (!(ch & 1<<REFS0)) {
conf.adc_idx = 0;
ch = conf.adc_ch[0];
v.stat.adc_idx = 0;
ch = v.conf.adc_ch[0];
}
if (!(ch & 1<<REFS0))
adc_stop();
@ -522,10 +526,10 @@ ISR(ADC_vect, ISR_NAKED)
"out __SREG__, r24" "\n\t"
"pop r24" "\n\t"
"reti" "\n"
:[I] "+m" (conf.adc_idx),
[D] "+m" (adc)
:[C] "m" (conf.adc_ch),
[II] "m" (conf.adc_incr),
:[I] "+m" (v.stat.adc_idx),
[D] "+m" (v.stat.adc)
:[C] "m" (v.conf.adc_ch),
[II] "m" (v.conf.adc_incr),
[AL] "n" (_SFR_MEM_ADDR(ADCL)),
[AH] "n" (_SFR_MEM_ADDR(ADCH)),
[X] "n" (_SFR_MEM_ADDR(ADMUX)),
@ -543,8 +547,8 @@ static void conf_init()
{
cli();
adc_init();
adc_start(conf.adc_idx>>4);
dac_set(conf.dac_ramp);
adc_start(v.stat.adc_idx>>4);
dac_set(v.conf.dac_ramp);
stepper_init();
}
@ -563,7 +567,7 @@ ISR(EE_READY_vect)
eewr_n = --n;
EEAR = eewr_a + n;
EECR |= 1<<EERE;
uint8_t d = ((uint8_t*)&conf)[n];
uint8_t d = ((uint8_t*)&v.conf)[n];
if (EEDR == d)
continue;
EEDR = d;
@ -598,8 +602,8 @@ ISR(EE_READY_vect, ISR_NAKED)
"adc r30, r31" "\n\t"
"out %[AH], r30" "\n\t"
"sbi %[C], %[RE]" "\n\t"
"ldi r30, lo8(conf)" "\n\t"
"ldi r31, hi8(conf)" "\n\t"
"ldi r30, lo8(%[V])" "\n\t"
"ldi r31, hi8($[V])" "\n\t"
"add r30, r24" "\n\t"
"brcc 3f" "\n\t"
"subi r31, -1" "\n"
@ -624,7 +628,8 @@ ISR(EE_READY_vect, ISR_NAKED)
"pop r24" "\n\t"
"reti" "\n"
:
:[C] "n" (_SFR_IO_ADDR(EECR)),
:[V] "m" (v.conf),
[C] "n" (_SFR_IO_ADDR(EECR)),
[AL] "n" (_SFR_IO_ADDR(EEARL)),
[AH] "n" (_SFR_IO_ADDR(EEARH)),
[D] "n" (_SFR_IO_ADDR(EEDR)),
@ -640,12 +645,10 @@ ISR(EE_READY_vect, ISR_NAKED)
static inline
uint8_t eeprom_save(uint16_t a)
{
// eeprom_update_block(&conf, (void*)a, sizeof(conf));
if (EECR & 1<<EERIE)
return 1;
eewr_a = a;
eewr_n = sizeof(conf);
eewr_n = sizeof(struct conf);
GPIOR2 = 0;
EECR = 1<<EERIE;
return 0;
@ -654,14 +657,13 @@ uint8_t eeprom_save(uint16_t a)
static inline
uint8_t eeprom_load(uint16_t a)
{
// eeprom_read_block(&conf, (void*)a, sizeof(conf));
cli();
if (EECR & 1<<EEWE) {
sei();
return 1;
}
uint8_t n = sizeof(conf);
uint8_t *c = (uint8_t*)&conf;
uint8_t n = sizeof(struct conf);
uint8_t *c = (uint8_t*)&v.conf;
while (n--) {
EEAR = a++;
EECR |= 1<<EERE;
@ -789,7 +791,7 @@ void reg88(uint8_t *v1, uint8_t *v2, unsigned char *r, const unsigned char *c)
// 'Z': eeprom what, a
// what=='e' or 'E": read eeprom from address a*4 to conf
// what=='F': ignore magic/version mismatch
// what=='E' or 'F': reinitialize with conf.
// what=='E' or 'F': reinitialize with v.conf.
// 'y': peek a
// 'Y': poke a, v
@ -798,7 +800,9 @@ void reg88(uint8_t *v1, uint8_t *v2, unsigned char *r, const unsigned char *c)
// interrupts are disabled, so that the SPI reciever can respond to
// all bytes in time. All commands execute fast, the master µC shall
// not time out while waiting for the reponse. The stepping timer is
// restarted after command execution, when any steps are commanded.
// restarted after command execution, when any steps are pending.
// The CPU sleeps while waiting for a command from the SPI, until SSEL
// goes low.
//
// Interrupts
// PCINT2: disable global interrupts
@ -817,13 +821,13 @@ int main()
DDRB = MISO;
eeprom_load(0);
adc_init();
if (conf.magic == MAGIC && conf.version == VERSION)
if (v.conf.magic == MAGIC && v.conf.version == VERSION)
conf_init();
while (1) {
unsigned char cmd[3];
unsigned char resp[3];
if (!stepper_status() && conf.step && conf.n_steps)
if (!stepper_status() && v.conf.step && v.conf.n_steps)
stepper_start(0);
if (spi_slave_Rx(cmd, 3)) {
spi_slave_Tx((const unsigned char*)"\xff\xff\xff" "EEY", 6);
@ -832,7 +836,7 @@ int main()
stepper_stop();
char up = upcase(cmd[0]);
if (up)
conf.step = 0;
v.conf.step = 0;
resp[0] = cmd[0];
uint8_t i;
switch (cmd[0] | 0x20) {
@ -841,49 +845,49 @@ int main()
resp[1] = 'E';
resp[2] = cmd[0];
break;
case 'm': reg88(&conf.lmask, &conf.lval, resp, cmd); break;
case 'q': reg16(&conf.period, resp, cmd);
if (0) case 'l': reg16(&conf.slen, resp, cmd);
case 'm': reg88(&v.conf.lmask, &v.conf.lval, resp, cmd); break;
case 'q': reg16(&v.conf.period, resp, cmd);
if (0) case 'l': reg16(&v.conf.slen, resp, cmd);
if (up)
stepper_init();
break;
case 'o': reg8f(&conf.enable, resp, cmd);
case 'o': reg8f(&v.conf.enable, resp, cmd);
if (up)
RESET_PORT = conf.enable;
RESET_PORT = v.conf.enable;
break;
case '0': conf.step = 0;
if (0) case '1': conf.step = STEP1;
if (0) case '2': conf.step = STEP2;
conf.dir = cmd[1] & 0xf;
case '0': v.conf.step = 0;
if (0) case '1': v.conf.step = STEP1;
if (0) case '2': v.conf.step = STEP2;
v.conf.dir = cmd[1] & 0xf;
if (cmd[2])
conf.n_steps = cmd[2] << ((cmd[1]>>4) & 7);
v.conf.n_steps = cmd[2] << ((cmd[1]>>4) & 7);
// fall through, return n_steps
case 's': reg16(&conf.n_steps, resp, cmd); break;
case 'r': reg8(&conf.reset, resp, cmd);
case 's': reg16(&v.conf.n_steps, resp, cmd); break;
case 'r': reg8(&v.conf.reset, resp, cmd);
resp[2] = cmd[2];
if (cmd[2]) {
conf.step = 0;
v.conf.step = 0;
if (cmd[2] & 0x80)
stepper_init();
if (cmd[2] & 1)
stepper_start(conf.reset);
stepper_start(v.conf.reset);
}
break;
case 'd': reg16(&conf.dac, resp, cmd);
dac_ramp(conf.dac);
case 'd': reg16(&v.stat.dac, resp, cmd);
dac_ramp(v.stat.dac);
break;
case 'p': reg16(&conf.dac_step, resp, cmd); break;
case 'p': reg16(&v.conf.dac_step, resp, cmd); break;
case 'a':
resp[2] = cmd[2];
i = cmd[2] & 15;
switch ((cmd[2]>>4) & 7) {
case 0: int2frame(adc[i], resp+1);
if (up) adc[i] = 0;
case 0: int2frame(v.stat.adc[i], resp+1);
if (up) v.stat.adc[i] = 0;
break;
case 1: reg8(conf.adc_ch+i, resp, cmd); break;
case 2: reg8(&conf.adc_idx, resp, cmd); break;
case 3: reg8(&conf.adc_incr, resp, cmd); break;
case 4: reg8(&conf.adc_period, resp, cmd); break;
case 1: reg8(v.conf.adc_ch+i, resp, cmd); break;
case 2: reg8(&v.stat.adc_idx, resp, cmd); break;
case 3: reg8(&v.conf.adc_incr, resp, cmd); break;
case 4: reg8(&v.conf.adc_period, resp, cmd); break;
case 5: reg8(&ADMUX, resp, cmd); break;
case 6: reg8(&ADCSRA, resp, cmd); break;
case 7: reg8(&ADCH, resp, cmd); break;
@ -905,7 +909,7 @@ int main()
break;
case 'z': // Load/Save conf
resp[1] = cmd[1];
resp[2] = sizeof(conf);
resp[2] = sizeof(struct conf);
if (!up) {
if (cmd[1]!='W' || eeprom_save(cmd[2]*4)) {
resp[0] = 'E';
@ -922,9 +926,9 @@ int main()
break;
}
}
if (conf.magic != MAGIC || conf.version != VERSION) {
if (v.conf.magic != MAGIC || v.conf.version != VERSION) {
resp[0] = 'E';
resp[2] = conf.version;
resp[2] = v.conf.version;
if (cmd[1] != 'F')
break;
}
@ -933,14 +937,14 @@ int main()
break;
case 'x': // conf Byte
resp[2] = cmd[1];
if (cmd[1] >= sizeof(conf)) {
if (cmd[1] >= sizeof(struct vars)) {
resp[0] = 'E';
resp[1] = sizeof(conf);
resp[1] = sizeof(struct vars);
break;
}
resp[1] = ((unsigned char *)(&conf))[cmd[1]];
resp[1] = ((unsigned char *)(&v))[cmd[1]];
if (up)
((unsigned char *)(&conf))[cmd[1]] = cmd[2];
((unsigned char *)(&v))[cmd[1]] = cmd[2];
break;
case 'y': // peek, poke
resp[2] = cmd[1];