mirror of
https://codeberg.org/SiB64/turbo_weather.git
synced 2026-05-01 15:14:22 +02:00
Compare commits
2 commits
65d615407c
...
977af7648b
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
977af7648b | ||
|
|
133f55edf6 |
22 changed files with 721 additions and 324 deletions
20
src/Makefile
20
src/Makefile
|
|
@ -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
|
||||
|
|
|
|||
85
src/adc.c
85
src/adc.c
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
23
src/adc.h
23
src/adc.h
|
|
@ -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,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
99
src/cmd.c
99
src/cmd.c
|
|
@ -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;
|
||||
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:
|
||||
|
|
|
|||
88
src/config.c
88
src/config.c
|
|
@ -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
|
||||
),
|
||||
};
|
||||
|
|
|
|||
164
src/config.h
164
src/config.h
|
|
@ -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
|
||||
|
|
|
|||
34
src/dose.c
34
src/dose.c
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@ SECTIONS
|
|||
ee9_start = .;
|
||||
*(.eeprom9)
|
||||
ee9_end = .;
|
||||
ee9_size = ee9_end - ee9_start;
|
||||
} >eemap AT >eedef
|
||||
.uumap 0x1300:
|
||||
{
|
||||
|
|
|
|||
39
src/flash.c
39
src/flash.c
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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
68
src/fpga.c
Normal 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
27
src/fpga.h
Normal 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);
|
||||
138
src/pipe.c
138
src/pipe.c
|
|
@ -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)
|
||||
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;
|
||||
return 0;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
|
|
|
|||
39
src/pipe.h
39
src/pipe.h
|
|
@ -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;
|
||||
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);
|
||||
|
|
|
|||
31
src/pwm.c
31
src/pwm.c
|
|
@ -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),
|
||||
};
|
||||
|
|
|
|||
14
src/pwm.h
14
src/pwm.h
|
|
@ -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
|
||||
|
|
|
|||
63
src/rtc.c
63
src/rtc.c
|
|
@ -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
|
||||
|
|
|
|||
49
src/rtc.h
49
src/rtc.h
|
|
@ -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();
|
||||
|
|
|
|||
20
src/spi.c
20
src/spi.c
|
|
@ -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;
|
||||
|
|
|
|||
12
src/spi.h
12
src/spi.h
|
|
@ -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;
|
||||
|
|
|
|||
10
src/uart.c
10
src/uart.c
|
|
@ -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)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue