Compare commits

...

2 commits

Author SHA1 Message Date
Stephan I. Böttcher
977af7648b The machine is complete, no space left for the main program 2026-01-09 21:00:02 +01:00
Stephan I. Böttcher
133f55edf6 section_status, pipe, fpga, HAVE_<OPT> 2026-01-08 00:36:23 +01:00
22 changed files with 721 additions and 324 deletions

View file

@ -7,8 +7,15 @@ default: all
all: $(PROJ).hex
SN_dose = 1
MCU_dose = attiny424
C_FILES_dose = config.c cmd.c pipe.c pwm.c uart.c base85.c bch4369.c rtc.c spi.c flash.c adc.c
MCU_dose = $(MCU_$(VAR))
MCU_nFETs = attiny424
MCU_FPGA = attiny3224
VAR=nFETs
C_FILES_nFETs =
C_FILES_FPGA = fpga.c
CFLAGS_dose = -DHAVE_$(VAR)
C_FILES_dose = config.c rtc.c adc.c pwm.c $(C_FILES_$(VAR)) uart.c cmd.c pipe.c base85.c bch4369.c spi.c flash.c
S_FILES_dose = uart_tx.S base85a.S
MCU = $(MCU_$(PROJ))
@ -24,20 +31,20 @@ CC=avr-gcc -Wall -Wno-parentheses -MMD -std=c99 $(OPT) \
-mint8
SN = $(SN_$(PROJ))
CFLAGS = $($*_CFLAGS) $(DEBUG) -I. -DSN="$(SN)"
CFLAGS = $(CFLAGS_$(PROJ)) $(DEBUG) -I. -DSN="$(SN)"
C_FILES = $(C_FILES_$(PROJ))
S_FILES = $(S_FILES_$(PROJ))
OBJS = $(patsubst %.c, %.o, $(C_FILES)) $(patsubst %.S, %.o, $(S_FILES))
%.s: %.c %.o
%.s: %.c
$(CC) $(CFLAGS) -S $<
%.o: %.c
$(CC) -g $(CFLAGS) -c $<
$(CC) $(CFLAGS) -c $<
%.o: %.S
$(CC) -g $(CFLAGS) -c $<
$(CC) $(CFLAGS) -c $<
-include *.d
@ -60,6 +67,7 @@ OBJCOPY = avr-objcopy
pMCU-attiny424 = t424
pMCU-attiny824 = t824
pMCU-attiny824 = t3224
# WDT
fuse0_dose= 0x00

View file

@ -2,18 +2,18 @@
// adc.c
//
#include "config.h"
#include "adc.h"
#include <avr/interrupt.h>
#include "pwm.h"
#include "rtc.h"
enum adc_conf_parameter {
INP = ADC_VIA_ADC_gc,
INN = ADC_VIA_ADC_gc,
REF = 10 << ADC_TIMEBASE_gp,
MODE = ADC_MODE_BURST_SCALING_gc | ADC_START_IMMEDIATE_gc,
MODE = ADC_MODE_SERIES_SCALING_gc | ADC_START_EVENT_TRIGGER_gc,
MODE_DIFF = ADC_MODE_BURST_SCALING_gc | ADC_START_IMMEDIATE_gc | ADC_DIFF_bm,
VD1 = ADC_MUXPOS_AIN7_gc,
VD2 = ADC_MUXPOS_AIN10_gc,
VDG = ADC_MUXPOS_AIN6_gc,
};
__attribute__((section(".eeprom1")))
@ -28,40 +28,45 @@ struct adc_conf adc_conf[N_ADC] = {
.ref = REF | ADC_REFSEL_1024MV_gc,
.inp = INP | ADC_MUXPOS_TEMPSENSE_gc,
},
#ifdef HAVE_nFETs
{ // VD1
.mode = MODE,
.ref = REF | ADC_REFSEL_1024MV_gc,
.inp = INP | VD1,
.inp = INP | ADC_D1,
},
{ // VD2
.mode = MODE,
.ref = REF | ADC_REFSEL_1024MV_gc,
.inp = INP | VD2,
.inp = INP | ADC_D2,
},
{ // VD1
.mode = MODE,
.ref = REF | ADC_REFSEL_2500MV_gc,
.inp = INP | VD1,
.inp = INP | ADC_D1,
},
{ // VD2
.mode = MODE,
.ref = REF | ADC_REFSEL_2500MV_gc,
.inp = INP | VD2,
.inp = INP | ADC_D2,
},
{ // VDG
.mode = MODE,
.ref = REF | ADC_REFSEL_2500MV_gc,
.inp = INP | VDG,
.inp = INP | ADC_G,
},
{ // VDG
.mode = MODE,
.ref = REF | ADC_REFSEL_VDD_gc,
.inp = INP | VDG,
.inp = INP | ADC_G,
},
#endif
};
uint16_t adc_readings[N_ADC];
uint8_t adc_current = 0xff;
section_status(adc.n) uint8_t adc_current;
section_status(adc.r) uint16_t adc_readings[N_ADC];
#ifdef HAVE_nFETs
section_status(pwm) uint16_t pwm_dutycycle;
#endif
static inline
void start_conversion(const struct adc_conf *c)
@ -72,29 +77,24 @@ void start_conversion(const struct adc_conf *c)
ADC.COMMAND = c->mode;
}
#ifdef NO_EE_CONFIG
void init_adc()
{
PORTB.PIN1CTRL |= PORT_ISC_INPUT_DISABLE_gc;
PORTA.PIN6CTRL |= PORT_ISC_INPUT_DISABLE_gc;
PORTA.PIN7CTRL |= PORT_ISC_INPUT_DISABLE_gc;
}
#endif
struct_ioconf(adc_config) = {
conf_prefix(ADC),
conf_io(ADC.CTRLA, ADC_ENABLE_bm),
conf_io(ADC.CTRLB, ADC_PRESC_DIV10_gc),
conf_io(ADC.CTRLE, 250 << ADC_SAMPDUR_gp),
conf_io(ADC.CTRLF, ADC_SAMPNUM_ACC256_gc | ADC_LEFTADJ_bm),
conf_io(ADC.INTCTRL, ADC_RESRDY_bm),
conf_prefix(EVSYS),
conf_io(EVSYS.CHANNEL0, EVSYS_CHANNEL0_TCA0_CMP1_LCMP1_gc),
conf_io(EVSYS.USERADC0START, 1),
};
void start_adc()
{
if (!adc_conf->mode)
return;
ADC.CTRLA = ADC_ENABLE_bm | ADC_RUNSTDBY_bm;
ADC.COMMAND = 0;
ADC.CTRLB = ADC_PRESC_DIV10_gc;
ADC.CTRLE = 32 << ADC_SAMPDUR_gp;
ADC.CTRLF = ADC_SAMPNUM_ACC64_gc | ADC_LEFTADJ_bm;
adc_current = 0;
ADC.INTFLAGS = 0xff;
ADC.INTCTRL = ADC_RESRDY_bm;
start_conversion(adc_conf);
}
@ -154,7 +154,6 @@ ISR(ADC0_RESRDY_vect, ISR_NAKED)
"ldi r31, 0" "\n\t"
"lsl r30" "\n\t"
"lsl r30" "\n\t"
"lsl r30 ; NADC==8!" "\n\t"
"subi r30, lo8(-(adc_conf))" "\n\t"
"sbci r31, hi8(-(adc_conf))" "\n\t"
"ldd r25, Z+1" "\n\t"
@ -178,6 +177,7 @@ ISR(ADC0_RESRDY_vect, ISR_NAKED)
"reti" "\n"
"3:" "\n\t"
"clr r24" "\n\t"
"sts %[COMMAND], r24" "\n\t"
"sts %[CTRLA], r24" "\n\t"
"ldi r24, %[NADC]" "\n\t"
"rjmp 2b" "\n"
@ -192,3 +192,30 @@ ISR(ADC0_RESRDY_vect, ISR_NAKED)
);
}
#endif
void adc_start_stream(uint8_t flag)
{
#ifdef HAVE_nFETs
if (flag & ADC_PWM)
pwm_set(config.pwm_min, 1);
#endif
start_adc();
}
uint8_t adc_poll(uint8_t flags)
{
time(); // fill `clock`
uint8_t r = adc_busy();
if (r)
return r;
if (flags) {
#ifdef HAVE_nFETs
if (flags & ADC_PWM)
pwm_step(config.pwm_max);
pwm_dutycycle = PWM.CMP0;
if (pwm_busy() || flags & ADC_CONV)
#endif
start_adc();
}
return 0;
}

View file

@ -12,12 +12,33 @@ struct adc_conf {
uint8_t inn;
};
#ifdef HAVE_nFETs
#define N_ADC 8
#define ADC_D1 7
#define ADC_D1_PINCTRL PORTA.PIN7CTRL
#define ADC_D2 10
#define ADC_D2_PINCTRL PORTB.PIN1CTRL
#define ADC_G 6
#define ADC_G_PINCTRL PORTA.PIN6CTRL
#else
#define N_ADC 2
#endif
extern uint16_t adc_readings[N_ADC];
extern uint8_t adc_current;
void start_adc();
void init_adc();
static inline uint8_t adc_busy() { return ADC.STATUS & 1; }
static inline uint8_t adc_busy() { return ADC.COMMAND; }
extern struct adc_conf adc_conf[N_ADC];
uint8_t adc_poll(uint8_t flag);
void adc_start_stream(uint8_t flag);
enum adc_flags {
ADC_CONV = 1,
ADC_PWM = 2,
ADC_SIZE = 0x70, // opencoded in pipe.c
ADC_16 = 0x10,
ADC_32 = 0x20,
ADC_64 = 0x40,
};

View file

@ -5,3 +5,20 @@ extern uint8_t bch_parity[16];
void bch4369(uint8_t d);
static inline void bch4369_init() { memset(bch_parity, 0 , 16); }
void bch4369_str(const uint8_t *b, uint8_t n);
static inline
uint8_t *bch4369_stri(uint8_t *b, uint8_t n)
{
__asm__ volatile(
"1:" "\n\t"
"ld r24, Y+" "\n\t"
"rcall bch4369" "\n\t"
"subi %[N], 1" "\n\t"
"brne 1b" "\n"
: [N] "+r" (n), [B] "+y" (b)
:: "r0",
"r20", "r21", "r24", "r25",
"r26", "r27", "r30", "r31"
);
return b;
}

101
src/cmd.c
View file

@ -10,10 +10,13 @@
#include "uart.h"
#include "pipe.h"
uint8_t cmd_buffer[16];
uint8_t flash_buffer_valid;
#ifdef HAVE_FPGA
#include "fpga.h"
#endif
uint8_t cmd_buffer[16];
uint8_t base85_str[6];
#if 0
void base85_send(const uint32_t *v)
{
@ -67,8 +70,6 @@ const uint8_t *base85_fill_buffer(const uint8_t *s) {
return s;
}
uint8_t * poke_addr;
uint8_t peek_size;
struct peak_poke {
uint8_t *addr;
uint8_t size;
@ -77,26 +78,21 @@ struct peak_poke {
};
static inline
uint8_t poke(struct peak_poke *p, uint8_t hp, uint8_t poke)
uint8_t poke(struct peak_poke *p, uint8_t poke)
{
if (hp) {
poke_addr = p->addr;
peek_size = p->size;
}
else {
p->addr = poke_addr;
p->size = peek_size;
}
uint8_t s = peek_size;
uint8_t *a = poke_addr;
if (s > 12)
s = 12;
peek_size -= s;
poke_addr += s;
uint8_t s = p->size;
uint8_t *a = p->addr;
uint8_t n = s;
if (n > 12)
n = 12;
p->size = s - n;
p->addr = a + n;
if (!n)
return 0;
if (poke) {
if (p->ccp)
NVMCTRL.CTRLA = NVMCTRL_CMD_PAGEBUFCLR_gc;
memcpy(a, p->data, s);
_memcopy(a, p->data, n);
if (p->ccp && !(0x8000 & (uint16_t)a))
__asm__(
"out %[ccp], %[key] \n\t"
@ -109,8 +105,8 @@ uint8_t poke(struct peak_poke *p, uint8_t hp, uint8_t poke)
);
}
else
memcpy(p->data, a, s);
return s && !poke;
_memcopy(p->data, a, n);
return n;
}
const uint8_t *cmd_flags;
@ -148,10 +144,12 @@ uint8_t cmd_flag(uint8_t f)
}
#endif
uint8_t cmd_pending;
void parse_command(const uint8_t *s, uint8_t n)
{
// ^[A-Z][!-@]+( [!-u]{20}])?$
// cmd flags base85
// cmd flags ␣base85
uint8_t r = 0;
uint8_t cmd = *s++;
@ -173,13 +171,16 @@ void parse_command(const uint8_t *s, uint8_t n)
s++;
uint8_t have_b = 0;
if (*s==' ') {
cmd_pending = 0;
s = base85_fill_buffer(s+1);
if (base85_error) {
r = base85_error;
goto error;
}
have_b = 1;
}
cmd_pending = cmd;
} else if (cmd_flag('~'))
have_b = cmd_pending == cmd;
if (*s != '\n')
goto error;
switch(cmd) {
@ -193,22 +194,32 @@ void parse_command(const uint8_t *s, uint8_t n)
}
break;
case 'B':
if (have_b && bflg) {
if (cmd_flag('|'))
flash_buffer_valid |= bflg;
memcpy(bptr, cmd_buffer, 16);
if (cmd_flag('@'))
pipe.valid = 0;
r = pipe.valid;
if (have_b) {
if (cmd_flag('!') || ~r & bflg) {
pipe.valid |= bflg;
memcpy(bptr, cmd_buffer, 16);
}
else
goto error;
}
if (cmd_flag('%')) {
if (cmd_flag('!'))
if (cmd_flag('@'))
memset(bch_parity, 0, 16);
bch4369_str(bptr, 16);
if (cmd_flag('!')) {
memcpy(flash_buffer+64, cmd_buffer, 16);
pipe.valid |= 0x10;
}
}
if (cmd_flag('<')) {
if (cmd_flag('|'))
flash_buffer_valid &=~ bflg;
base85_send_buffer(bptr);
if (!cmd_flag('!') && ~r & bflg)
goto error;
pipe.valid &=~ bflg;
goto send_buffer;
}
r = flash_buffer_valid;
break;
case 'F':
if (have_b)
@ -218,13 +229,29 @@ void parse_command(const uint8_t *s, uint8_t n)
break;
case 'P':
if (have_b)
r = pipe_config(cmd_buffer);
pipe_config((void*)cmd_buffer);
else
r = pipe_poll(cmd_flag('!'));
r = pipe_poll();
break;
goto send_buffer;
break;
#ifdef HAVE_FPGA
case 'C':
if (cmd_flag('@')) {
fpga_reset();
break;
}
if (!have_b)
goto error;
fpga_cmd((void*)cmd_buffer);
goto send_buffer;
#endif
case 'M':
if (poke((void*)cmd_buffer, have_b, have_b && cmd_flag('!')))
base85_send_buffer(cmd_buffer);
if (!have_b)
goto error;
r = poke((void*)cmd_buffer, cmd_flag('!'));
send_buffer:
base85_send_buffer(bptr);
break;
default:
error:

View file

@ -1,6 +1,7 @@
#include "config.h"
#include "flash.h"
#include "adc.h"
////////////////////////////////////////////////////////////////////////////////
//
@ -8,8 +9,8 @@
__attribute__((section(".userrow")))
const struct config config = {
.magic = USE_USERROW,
.version = USE_VERSION,
.magic = MAGIC,
.version = VERSION,
.cpu_clk = CLKCTRL_PDIV_2X_gc | 1, // 10MHz (max @ 3V)
.flash_page_size = FM_528 >> 8,
.burn_page = 0x88, // Buffer 1 Page Program w/o Erase
@ -19,6 +20,10 @@ const struct config config = {
[0] = 0xd1 | FM_READ>>8, // Buffer 1 Read (Low-Frequency)
[1] = 0xd3 | FM_READ>>8, // Buffer 2 Read (Low-Frequency)
},
#ifdef HAVE_nFETs
.pwm_min = 0x0000,
.pwm_max = 0xffff,
#endif
};
////////////////////////////////////////////////////////////////////////////////
@ -28,55 +33,32 @@ const struct config config = {
struct_ioconf(port_config) = {
conf_prefix(PORTA),
conf_io(PORTA.PIN6CTRL, PORT_ISC_INPUT_DISABLE_gc), // AIN
conf_io(PORTA.PIN7CTRL, PORT_ISC_INPUT_DISABLE_gc), // AIN
conf_io(PORTB.PIN1CTRL, PORT_ISC_INPUT_DISABLE_gc), // AIN
conf_io(PORTA.OUT, Bit(SSEL_PIN)),
conf_io(PORTA.DIR, Bit(SSEL_PIN) | Bit(DRAIN_PIN)
| Bit(MOSI_PIN) | Bit(SCK_PIN)),
conf_io(PORTB.OUT, 0),
conf_io(PORTB.DIR, Bit(PWM_PIN)),
};
#if 0
void apply_config(const struct io_config *c, uint8_t n)
{
uint8_t prefix = 0;
while (n--) {
const struct io_config *io = c++;
if (io->addr == 0xff)
prefix = io->val;
else {
uint8_t *p = (uint8_t*)((uint16_t)prefix << 8 | io->addr);
*p = io->val;
}
}
}
#else
__attribute__((naked))
void apply_config(const struct io_config *c, uint8_t n)
{
__asm__(
"movw r30,r24" "\n\t"
"clr r24" "\n"
"1:" "\n\t"
"mov r24, r27" "\n\t"
"subi r22,-1" "\n\t"
"brcs 9f" "\n"
"2:" "\n\t"
"ld r25, Z+" "\n\t"
"ld r24, Z+" "\n\t"
"cpi r25, 0xff" "\n\t"
"breq 1b" "\n\t"
"st X, r25" "\n\t"
"subi r22,1" "\n\t"
"brcc 2b" "\n\t"
"9:" "\n\t"
"ret" "\n\t"
);
}
conf_io(RxD_PINCTRL, PORT_PULLUPEN_bm),
#ifdef HAVE_nFETs
conf_io(ADC_D1_PINCTRL, PORT_ISC_INPUT_DISABLE_gc),
conf_io(ADC_D2_PINCTRL, PORT_ISC_INPUT_DISABLE_gc),
conf_io(ADC_G_PINCTRL, PORT_ISC_INPUT_DISABLE_gc),
#endif
#ifdef HAVE_FPGA
conf_io(nSTATUS_PINCTRL, PORT_PULLUPEN_bm),
conf_io(CRCERR_PINCTRL, PORT_PULLUPEN_bm),
#endif
conf_io(PORTA.OUT, Bit(SSEL_PIN)),
conf_io(PORTA.DIR, Bit(SSEL_PIN) | Bit(MOSI_PIN) | Bit(SCK_PIN)
#ifdef HAVE_nFETs
| Bit(DRAIN_PIN)
#endif
#ifdef HAVE_FPGA
| Bit(nCONFIG_PIN) | Bit(TxE_PIN)
#endif
),
conf_io(PORTB.OUT, Bit(TxD_PIN)),
conf_io(PORTB.DIR, Bit(TxD_PIN)
#ifdef HAVE_nFETs
| Bit(PWM_PIN)
#endif
#ifdef HAVE_FPGA
| Bit(TxE_PIN) | Bit(PEN_PIN)
#endif
),
};

View file

@ -10,17 +10,28 @@ struct config {
uint8_t magic;
uint8_t version;
uint8_t cpu_clk;
uint8_t cron;
uint8_t flash_page_size;
uint16_t burn_page;
uint16_t erase_page;
uint16_t write_buffer;
uint16_t read_array;
uint16_t read_buffer[2];
#ifdef HAVE_nFETs
uint16_t pwm_min;
uint16_t pwm_max;
#endif
};
enum magic_flags {
USE_USERROW = 0xD0,
USE_VERSION = 0x01,
#ifdef HAVE_nFETs
MAGIC = 0xD0,
VERSION = 0x01,
#endif
#ifdef HAVE_FPGA
MAGIC = 0xC5,
VERSION = 0x01,
#endif
};
extern const struct config config;
@ -38,29 +49,148 @@ struct io_config {
#define conf_prefix(_io) { 0xff, (uint16_t)&(_io) >> 8 }
#define conf_io(_io, _v) { (uint16_t)&(_io) & 0xff, (_v) }
#define conf_ioo(_io, _o, _v) { (uint16_t)&(_io) + _o & 0xff, (_v) }
#define conf_iow(_io, _v) conf_io(_io, (_v) & 0xff), conf_ioo(_io, 1, (_v) >> 8)
#define conf_iow(_io, _v) conf_io(_io, (_v) & 0xff), conf_ioo(_io, 1, (uint16_t)(_v) >> 8)
void apply_config(const struct io_config *c, uint8_t n);
extern struct io_config *ee9_start, *ee9_end;
#define IO_CONFIG ee9_start
#define IO_CONFIG_SIZE (ee9_end - ee9_start)
extern struct io_config ee9_start[], ee9_end[];
#define Bit(x) (1<<(x))
#define DRAIN_VPORT VPORTA
#define DRAIN_PORT PORTA
#define DRAIN_PIN 5
#define SSEL_VPORT VPORTA
#define SSEL_PORT PORTA
#define SSEL_PIN 4
#define PWM_VPORT VPORTB
#define PWM_PORT PORTB
#define PWM_PIN 0
#define SPI_VPORT VPORTA
#define SPI_PORT PORTA
#define MOSI_PIN 1
#define MISO_PIN 2
#define SCK_PIN 3
#define UART_VPORT VPORTB
#define UART_PORT PORTB
#define TxE_PIN 1
#define TxD_PIN 2
#define RxD_PIN 3
#define RxD_PINCTRL UART_PORT.PIN3CTRL
#ifdef HAVE_FPGA
#define SSEL_VPORT VPORTA
#define SSEL_PORT PORTA
#define SSEL_PIN 7
#define nCONFIG_VPORT VPORTA
#define nCONFIG_PORT PORTA
#define nCONFIG_PIN 6
#define nSTATUS_VPORT VPORTA
#define nSTATUS_PORT PORTA
#define nSTATUS_PIN 4
#define nSTATUS_PINCTRL nSTATUS_PORT.PIN4CTRL
#define CRCERR_VPORT VPORTA
#define CRCERR_PORT PORTA
#define CRCERR_PIN 5
#define CRCERR_PINCTRL CRCERR_PORT.PIN5CTRL
#define PEN_VPORT VPORTB
#define PEN_PORT PORTB
#define PEN_PIN 1
#else
#define SSEL_VPORT VPORTA
#define SSEL_PORT PORTA
#define SSEL_PIN 4
#endif
#ifdef HAVE_nFETs
#define DRAIN_VPORT VPORTA
#define DRAIN_PORT PORTA
#define DRAIN_PIN 5
#define PWM_VPORT VPORTB
#define PWM_PORT PORTB
#define PWM_PIN 0
#endif
#if 0
static inline
void apply_config()
{
uint8_t n = ee_end - ee_start;
struct io_config = ee_start;
uint8_t prefix = 0;
while (n--) {
const struct io_config *io = c++;
if (io->addr == 0xff)
prefix = io->val;
else {
uint8_t *p = (uint8_t*)((uint16_t)prefix << 8 | io->addr);
*p = io->val;
}
}
}
#else
static inline
void apply_config()
{
__asm__ volatile(
"ldi r30, lo8(ee9_start)" "\n\t"
"ldi r31, hi8(ee9_start)" "\n\t"
"ldi r24, lo8(ee9_size)" "\n\t"
"clr r26" "\n"
"1:" "\n\t"
"mov r27, r26" "\n\t"
"subi r24, 2" "\n\t"
"brcs 3f" "\n"
"2:" "\n\t"
"ld r26, Z+" "\n\t"
"ld r25, Z+" "\n\t"
"cpi r26, 0xff" "\n\t"
"breq 1b" "\n\t"
"st X, r25" "\n\t"
"subi r24, 2" "\n\t"
"brcc 2b" "\n"
"3:" "\n\t"
::: "r24", "r25", "r26", "r27", "r30", "r31");
}
#endif
#define section_status(_n) __attribute__((section(".bss."#_n)))
extern struct magic {
uint8_t magic;
uint8_t reset_source;
} magic;
#if 0
#define _memcopy memcpy
#define _memcopyyz memcpy
#else
// avoid the avr-libc memcpy.
// ¡ n must not be zero !
static inline
void _memcopy(uint8_t *d, uint8_t *s, uint8_t n)
{
__asm__ volatile ("\n"
"1:" "\n\t"
"ld r0, Z+" "\n\t"
"st X+, r0" "\n\t"
"dec %[N]" "\n\t"
"brne 1b" "\n"
: [D] "+x" (d),
[S] "+z" (s),
[N] "+r" (n)
:: "r0", "memory");
}
static inline
void _memcopyyz(uint8_t *d, uint8_t *s, uint8_t n)
{
__asm__ volatile ("\n"
"1:" "\n\t"
"ld r0, Z+" "\n\t"
"st Y+, r0" "\n\t"
"dec %[N]" "\n\t"
"brne 1b" "\n"
: [D] "+y" (d),
[S] "+z" (s),
[N] "+r" (n)
:: "r0", "memory");
}
#endif
#endif // _CONFIG_H

View file

@ -13,18 +13,28 @@
#include "config.h"
#include "dose.h"
#include "pipe.h"
#include "uart.h"
#include "rtc.h"
#include "spi.h"
#include "cmd.h"
#include "adc.h"
#include "pwm.h"
#include "flash.h"
////////////////////////////////////////////////////////////////////////////////
//
// main()
section_status(main) struct magic magic;
const struct pipe_config cron_job[1] =
{
[0] = {
.pipe = {
},
},
};
int main()
{
while (CLKCTRL.MCLKCTRLB != config.cpu_clk) {
@ -32,19 +42,27 @@ int main()
CLKCTRL.MCLKCTRLB = config.cpu_clk;
}
set_sleep_mode(SLEEP_MODE_IDLE);
sleep_enable();
while (config.magic != USE_USERROW)
magic.magic = config.magic;
while (magic.magic != MAGIC)
sleep_cpu();
apply_config(IO_CONFIG, IO_CONFIG_SIZE);
uint8_t reset_source = RSTCTRL.RSTFR;
RSTCTRL.RSTFR = reset_source;
apply_config();
magic.reset_source = RSTCTRL.RSTFR;
RSTCTRL.RSTFR = magic.reset_source;
send_str("\nV Turbo Dose V0.9");
send_hex_byte_eol(reset_source);
send_hex_byte_eol(magic.reset_source);
while (1) {
sei();
sleep_cpu();
command();
pipe_poll();
if (rtc_tick) {
rtc_tick = 0;
if (config.cron)
pipe_config(cron_job);
}
}
}

View file

@ -20,6 +20,7 @@ SECTIONS
ee9_start = .;
*(.eeprom9)
ee9_end = .;
ee9_size = ee9_end - ee9_start;
} >eemap AT >eedef
.uumap 0x1300:
{

View file

@ -85,10 +85,9 @@ miscellanious
#include "config.h"
#include "flash.h"
#include "cmd.h"
#include "bch4369.h"
uint8_t flash_cmd_buffer[4];
uint8_t flash_status_bytes[2];
section_status(flash) uint8_t flash_cmd_buffer[4];
section_status(flash) uint8_t flash_status_bytes[2];
uint8_t flash_buffer[FB_SIZE];
uint8_t flash_cmd_na(uint16_t mode, uint16_t what)
@ -179,10 +178,8 @@ uint8_t flash_stream_submit(uint16_t mode, uint8_t size)
fs.page = ++p;
fs.npages--;
}
if (b==7 && r & FS_BCH) {
else if (b==7 && r & FS_528)
size |= 16;
memcpy(flash_buffer+64, bch_parity, 16);
}
}
else if ((r & FS_Dir) == FS_Erase) {
fs.page += (uint16_t) b + 1;
@ -250,17 +247,6 @@ uint8_t flash_burn_page()
return flash_stream_submit(config.burn_page, 0);
}
static inline
void bch_flash_buffer(uint8_t n)
{
bch4369_str(flash_buffer, n);
}
void bch_flash_init()
{
bch4369_init();
}
uint8_t flash_poll(uint8_t rr)
{
uint8_t r = fs.status;
@ -293,15 +279,6 @@ uint8_t flash_poll(uint8_t rr)
return r;
}
}
else if (r & FS_BCH) {
// checksum the received buffer
if (fs.block == 1)
bch_flash_init();
if (fs.block & 8)
bch_flash_buffer(80);
else
bch_flash_buffer(64);
}
ready:
r &= ~(FS_Busy | FS_StBsy);
@ -315,14 +292,8 @@ ready:
else if (!flash_stream_done()) {
if (r & (FS_Dir|FS_Ack) == (FS_Read|FS_Ack))
flash_read_next_block();
else if (r & (FS_Dir|FS_Ack) == (FS_Write|FS_Ack)) {
if (r & FS_BCH) {
if (!(fs.block & 7))
bch_flash_init();
bch_flash_buffer(64);
}
else if (r & (FS_Dir|FS_Ack) == (FS_Write|FS_Ack))
flash_write_next_block();
}
else if (r & FS_Dir == FS_Erase)
flash_erase_next_page();
fs.status &=~ FS_Ack;
@ -337,7 +308,7 @@ uint8_t flash_start_stream(uint16_t page, uint16_t npages, uint8_t flags)
return FS_Error;
r = flags | FS_Ready;
if (config.flash_page_size != FM_528)
r &=~ FS_BCH;
r &=~ FS_528;
fs.page = page;
fs.block = 0;
fs.npages = npages;

View file

@ -1,4 +1,7 @@
#ifndef _FLASH_H
#define _FLASH_H
#include "spi.h"
enum flash_mode_bits {
@ -45,6 +48,7 @@ enum {
FS_Dir = 12, // Mask for the last three
FS_Ack = 32, // Next buffer is provided, continue …
FS_StBsy = 64, // Waiting to Flash status register
FS_BCH = 128, // do 528 byte pages.
FS_528 = 128, // do 528 byte pages.
};
#endif

68
src/fpga.c Normal file
View file

@ -0,0 +1,68 @@
#include "pipe.h"
#include "fpga.h"
#include "spi.h"
void fpga_cmd(struct fpga_cmd *c)
{
if (fpga_reset_poll()) {
c->n |= 0x20; // busy flag
return;
}
if (c->n & 1 && spi_abort()) {
c->n |= 0x10; // aborted flag
return;
}
else if (spi_busy_p()) {
c->n |= 0x20; // busy flag
return;
}
c->n &=~ 0x10; // not busy
if (c->n & 0x40)
return;
c->n |= 0x40; // submitted flag
uint8_t n = c->n & 0x0e; // send up to seven cmd words
uint8_t z = c->z & 0x7e; // and up to 63 zeros
spi_select(0);
spi.zero = c->n & 0x80; // send nop: 0x8080 (please), or zeros
spi.csize = n;
spi.wdata = c->d;
spi.rdata = c->d;
if (c->z & 0x80) {
spi.isize = n + z>>3 & 0x0e; // ignore cmd ± (z[6:4])
spi.zsize = spi.rsize = z & 0x0e; // read x[3:1] words
spi.mask = 0xff; // start reading at the first nonzero byte after cmd
}
else {
spi.zsize = z; // send z zeros/nop after cmd
spi.rsize = 14; // save the last 7 words returned
if (n + z > 14)
spi.isize = n + z - 14;
else
spi.isize = 0;
}
spi_start();
}
void fpga_start(uint8_t write)
{
uint8_t mode = 0;
if (pipe.fpga.zero == SPI_CONFIG)
mode = SPI_CONFIG;
spi_select(mode);
_memcopy(&spi.csize, &pipe.fpga.csize, 6);
spi.cmd = pipe.fpga.cmd;
spi.wdata = flash_buffer;
spi.rdata = flash_buffer;
uint8_t n = 64;
if (n > pipe.fpga.size)
n = pipe.fpga.size;
pipe.fpga.size -= n;
if (!n)
return;
if (write)
spi.wsize = n;
else
spi.rsize = n;
spi_start();
}

27
src/fpga.h Normal file
View file

@ -0,0 +1,27 @@
#include "config.h"
struct fpga_cmd {
uint8_t n;
uint8_t z;
uint8_t d[14];
};
static inline
void fpga_reset()
{
nCONFIG_VPORT.OUT |= (1<<nCONFIG_PIN);
}
static inline
uint8_t fpga_reset_poll()
{
uint8_t r = !(nSTATUS_VPORT.IN & (1 << nSTATUS_PIN));
if (r)
nCONFIG_VPORT.OUT |= 1 << nCONFIG_PIN;
return r;
}
void fpga_cmd(struct fpga_cmd *c);
void fpga_start(uint8_t write);

View file

@ -1,26 +1,132 @@
#include "pipe.h"
#include "flash.h"
#include "bch4369.h"
#include "adc.h"
struct pipe pipe;
#ifdef HAVE_FPGA
#include "fpga.h"
#endif
struct pipe_config {
uint8_t source;
uint8_t dest;
uint16_t npages;
uint8_t flash_flags;
uint8_t flash_page;
};
#include <string.h>
uint8_t pipe_config(const uint8_t *)
{
return 0;
}
uint8_t pipe_poll(uint8_t flag)
section_status(pipe) struct pipe pipe;
uint8_t pipe_poll()
{
uint8_t r = pipe.status;
if (spi_busy_p() || flash_poll(0) & FS_Busy)
return r;
return 0;
uint8_t fl = flash_poll(0);
if (spi_busy_p() || fl & FS_Busy || adc_poll(0))
goto done;
#ifdef HAVE_FPGA
if (fpga_reset_poll())
goto done;
#endif
if (r & PS_OUT) {
if (pipe.dest & pipe_cmd && pipe.valid & 0x1f)
// cmd did not drain the buffer, yet
goto done;
if (pipe.dest & pipe_flash && !(fl & FS_Ready))
// flash did not finish successfully
goto done;
// fpga is OUT when the spi is ready.
// We are done with this buffer
pipe.valid = 0;
if (pipe.source & pipe_flash)
flash_poll(1);
else if (pipe.source & pipe_adc)
adc_poll(pipe.adc);
#ifdef HAVE_FPGA
else if (pipe.source & pipe_fpga)
fpga_start(0);
#endif
r |=~ PS_OUT;
r &= ~4;
r++;
goto done;
}
uint8_t bflgs = 0x0f;
if ((r & PS_5) == PS_5)
bflgs = 0x1f;
if (pipe.source & pipe_adc) {
uint8_t n = pipe.adc & 0x70;
if (!n)
goto adc_done;
uint8_t f = n-1;
uint8_t o = -16;
uint8_t v = pipe.valid;
#if 0
uint8_t c;
do {
o += 16;
f <<= 1;
c = v & 1;
v >>= 1;
} while (c); // please use the carry bit!
#else
// saves one instruction
__asm__ volatile
("\n"
"1: \n\t"
"subi %[O], -16 \n\t"
"lsl %[F] \n\t"
"lsr %[V] \n\t"
"brcs 1b \n"
: [O] "+r" (o),
[F] "+r" (f),
[V] "+r" (v)
);
#endif
if (o > 48)
goto adc_done;
if (o + n >= 64) {
f = 0xff;
n = 64-o;
}
pipe.valid |= f>>4;
_memcopy(flash_buffer+o, (void*)&magic, n);
}
adc_done:
if (pipe.source & pipe_flash && fl & FS_Ready)
pipe.valid = bflgs;
#ifdef HAVE_FPGA
else if (pipe.source & pipe_fpga)
pipe.valid = 0x0f;
#endif
if (~pipe.valid & 0x0f)
goto done;
if (r & PS_BCH) {
if (!(r&3))
bch4369_init();
uint8_t *bend = bch4369_stri(flash_buffer, 64);
if (!(~r & 3)) {
// reuse Y=bend
_memcopyyz(bend, bch_parity, 16);
pipe.valid = 0x01f;
}
}
if (~pipe.valid & bflgs)
goto done;
#ifdef HAVE_FPGA
if (pipe.dest & pipe_fpga)
fpga_start(1);
#endif
r |= PS_OUT;
done:
pipe.status = r;
return r;
}
void pipe_config(const struct pipe_config *c)
{
pipe = c->pipe;
if ((pipe.source | pipe.dest) & pipe_flash)
flash_start_stream(c->page, c->npages, c->flash);
if (pipe.source & pipe_adc)
adc_start_stream(pipe.adc);
}

View file

@ -1,14 +1,17 @@
#include <stdint.h>
uint8_t pipe_config(const uint8_t *);
uint8_t pipe_poll(uint8_t flag);
#include "flash.h"
enum pipe_ports {
pipe_cmd = 1,
pipe_hk = 2,
pipe_adc = 2,
pipe_flash = 4,
pipe_fpgs = 8,
pipe_fpga = 8,
PS_OUT = 0x80,
PS_BCH = 0x10,
PS_528 = 0x08,
PS_BLK = 0x03,
PS_5 = PS_BLK | PS_528, // need 16 bytes more
};
extern
@ -16,5 +19,29 @@ struct pipe {
uint8_t source;
uint8_t dest;
uint8_t status;
uint16_t size;
uint8_t valid;
uint8_t adc;
#ifdef HAVE_FPGA
struct {
uint16_t size;
uint8_t cmd[4];
uint8_t csize;
uint8_t zsize;
uint8_t isize;
uint8_t zero;
uint8_t wait;
uint8_t mask;
} fpga;
#endif
} pipe;
struct pipe_config {
struct pipe pipe;
uint16_t page;
uint16_t npages;
uint8_t flash;
};
uint8_t pipe_poll();
void pipe_cron();
void pipe_config(const struct pipe_config *c);

View file

@ -3,28 +3,15 @@
#include "pwm.h"
#ifdef NO_EE_CONFIG
void init_pwm(uint16_t period)
{
PWM.CTRLA = 0;
PWM.CTRLB = TCA_SINGLE_CMP0EN_bm | TCA_SINGLE_WGMODE_SINGLESLOPE_gc;
PWM.PER = period;
PWM.CMP0 = 0xffff;
PWM.CTRLA = 0x81;
D_PORT.OUT |= 1<<D_PIN;
D_PORT.DIR |= 1<<D_PIN;
}
#else
struct_ioconf(pwm_config) = {
conf_prefix(PWM),
conf_io(PWM.CTRLA, 0),
conf_io(PWM.CTRLB, TCA_SINGLE_CMP0EN_bm | TCA_SINGLE_WGMODE_SINGLESLOPE_gc),
conf_iow(PWM.PER, 0xfff),
conf_iow(PWM.CMP0, 0xffff),
conf_io(PWM.CTRLA, 0x81),
};
#ifdef HAVE_nFETs
conf_io(PWM.CTRLB, TCA_SINGLE_WGMODE_SINGLESLOPE_gc | TCA_SINGLE_CMP0EN_bm),
#else
conf_io(PWM.CTRLB, TCA_SINGLE_WGMODE_SINGLESLOPE_gc),
#endif
conf_iow(PWM.PER, 0x0fff),
conf_iow(PWM.CMP0, 0xffff),
conf_iow(PWM.CMP1, 0x00ff),
conf_io(PWM.CTRLA, TCA_SINGLE_ENABLE_bm),
};

View file

@ -3,7 +3,7 @@
#define PWM TCA0.SINGLE
void init_pwm(uint16_t period);
#ifdef HAVE_nFETs
static inline
void pwm_set(uint16_t dc, uint8_t d)
@ -22,11 +22,19 @@ void pwm_bias()
}
static inline
void pwm_step()
void pwm_step(uint16_t max)
{
uint16_t c = PWM.CMP0+1;
if (c > PWM.PER+1)
if (c > max)
pwm_bias();
else
pwm_set(c, 1);
}
static inline
uint8_t pwm_busy()
{
return DRAIN_VPORT.OUT & (1 << DRAIN_PIN);
}
#endif

View file

@ -9,7 +9,8 @@
#define Bit(x) (1<<(x))
volatile uint16_t clock;
section_status(rtc) uint32_t clock;
volatile uint16_t clockh;
volatile uint8_t pit_tick;
volatile uint8_t rtc_tick;
@ -68,12 +69,12 @@ ISR(RTC_CNT_vect, ISR_NAKED)
"1:" "\n\t"
"sbrs r24, 0" "\n\t"
"rjmp 2f" "\n\t"
"lds r24, clock" "\n\t"
"lds r24, clockh" "\n\t"
"subi r24, -1" "\n\t"
"sts clock, r24" "\n\t"
"lds r24, clock+1" "\n\t"
"sts clockh, r24" "\n\t"
"lds r24, clockh+1" "\n\t"
"sbci r24, -1" "\n\t"
"sts clock+1, r24" "\n\t"
"sts clockh+1, r24" "\n\t"
"2:" "\n\t"
"pop r24" "\n\t"
"out __SREG__, r24" "\n"
@ -105,16 +106,44 @@ ISR(RTC_CNT_vect)
}
#endif
#define NOINLINE_TICKS
#ifdef NOINLINE_TICKS
#undef time
#undef second_tick
#undef hour_tick
#undef day_tick
uint8_t time() { return timei(); }
uint8_t second_tick() { return second_ticki(); }
uint8_t hour_tick() { return hour_ticki(); }
uint8_t day_tick() { return day_ticki(); }
#if 0
uint32_t time()
{
uint16_t cl, ch;
do {
cli();
cl = RTC.CNT;
ch = clockh;
sei();
} while (cl != RTC.CMP);
return clock = cl | (uint32_t)ch << 16;
}
#else
__attribute__((naked))
uint32_t time()
{
__asm__ volatile("\n"
"1:" "\n\t"
"cli" "\n\t"
"lds r22, %[CNT]" "\n\t"
"lds r23, %[CNT]+1" "\n\t"
"lds r24, clockh" "\n\t"
"lds r25, clockh+1" "\n\t"
"sei" "\n\t"
"lds r18, %[CNT]" "\n\t"
"lds r19, %[CNT]+1" "\n\t"
"cp r18, r22" "\n\t"
"cpc r19, r23" "\n\t"
"brne 1b" "\n\t"
"ldi r30, lo8(clock)" "\n\t"
"ldi r31, hi8(clock)" "\n\t"
"st Z+, r22" "\n\t"
"st Z+, r23" "\n\t"
"st Z+, r24" "\n\t"
"st Z+, r25" "\n\t"
"ret" "\n"
:: [CNT] "n" (&RTC.CNT)
: "r18", "r19", "r30", "r31", "memory"
);
}
#endif

View file

@ -5,51 +5,8 @@
#include <stdint.h>
#include <avr/interrupt.h>
volatile extern uint16_t clock;
extern uint32_t clock;
volatile extern uint16_t clockh;
volatile extern uint8_t pit_tick;
volatile extern uint8_t rtc_tick;
void init_rtc(uint8_t p);
static inline
uint32_t timei()
{
cli();
uint16_t c = RTC.CNT;
sei();
return c | (uint32_t)clock << 16;
}
static inline
uint8_t second_ticki()
{
cli();
uint8_t c = pit_tick;
pit_tick = 0;
sei();
return c;
}
static inline
uint8_t hour_ticki()
{
cli();
uint8_t c = rtc_tick;
rtc_tick = c & ~2;
sei();
return c & 2;
}
static inline
uint8_t day_ticki()
{
cli();
uint8_t c = rtc_tick;
rtc_tick = c & ~1;
sei();
return c & 1;
}
#define time timei
#define second_tick second_ticki
#define hour_tick hour_ticki
#define day_tick day_ticki
uint32_t time();

View file

@ -7,23 +7,7 @@
#include "spi.h"
#include <string.h>
struct spi_job spi;
#ifdef NO_EE_CONFIG
void init_spi(uint8_t spi_div)
{
SSEL_PORT.OUT |= 1 << SSEL_PIN;
SSEL_PORT.DIR |= 1 << SSEL_PIN;
SPI.CTRLB = SPI_SSD_bm | SPI_BUFEN_bm; // Mode 0
SPI.CTRLA = SPI_MASTER_bm | SPI_ENABLE_bm | spi_div;
SPI.DATA;
SPI.DATA;
SPI.INTFLAGS = 0xff;
SPI.INTCTRL = 0;
}
#else
section_status(spi) struct spi_job spi;
struct_ioconf(spi_config) = {
conf_prefix(SPI),
@ -31,8 +15,6 @@ struct_ioconf(spi_config) = {
conf_io(SPI.CTRLA, SPI_MASTER_bm | SPI_ENABLE_bm | SPI_SPEED),
};
#endif
ISR(SPI0_INT_vect)
{
uint8_t ifg = SPI.INTFLAGS;

View file

@ -15,14 +15,14 @@ extern
struct spi_job {
uint8_t mode;
uint8_t status;
uint8_t csize;
uint8_t zsize;
uint8_t isize;
uint8_t csize; // pipe.fpga.…
uint8_t zsize; //
uint8_t isize; //
uint8_t zero; //
uint8_t wait; //
uint8_t mask; //
uint8_t rsize;
uint8_t wsize;
uint8_t zero;
uint8_t wait;
uint8_t mask;
const uint8_t *cmd;
const uint8_t *wdata;
uint8_t *rdata;

View file

@ -122,11 +122,11 @@ ISR(USART0_TXC_vect, ISR_ALIASOF(USART0_DRE_vect));
uint8_t uart_rx[32];
#define uart_rx_m (sizeof(uart_rx) - 1)
volatile uint8_t uart_rx_w;
volatile uint8_t uart_rx_s;
volatile uint8_t uart_rx_mes;
uint8_t uart_rx_err;
uint8_t uart_rx_errors;
section_status(uart.w) volatile uint8_t uart_rx_w;
section_status(uart.h) volatile uint8_t uart_rx_s;
section_status(uart.m) volatile uint8_t uart_rx_mes;
section_status(uart.e) uint8_t uart_rx_err;
section_status(uart.ee) uint8_t uart_rx_errors;
#if 0
ISR(USART0_RXC_vect)