Compare commits
12 commits
ecc33261a2
...
93e1c3230e
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
93e1c3230e | ||
|
|
66525141bd | ||
|
|
36ffd2c4f6 | ||
|
|
6a2f5dc026 | ||
|
|
6b668578ea | ||
|
|
f18e923c96 | ||
|
|
e63764042f | ||
|
|
51d3e09dd3 | ||
|
|
890aabf955 | ||
|
|
2915785571 | ||
|
|
b3bb5396de | ||
|
|
367479409b |
13 changed files with 428 additions and 108 deletions
1
src/.gitignore
vendored
1
src/.gitignore
vendored
|
|
@ -1 +1,2 @@
|
|||
thhor.userrow
|
||||
*.s
|
||||
|
|
|
|||
44
src/Makefile
44
src/Makefile
|
|
@ -11,22 +11,13 @@ thhor_all: thhor.eeprom thhor.userrow
|
|||
CFLAGS_thhor = -Ibch4369 -DHAVE_FPGA -DSEND_HEX -DTHHOR
|
||||
MCU_thhor = attiny3224
|
||||
SN_thhor = 1
|
||||
C_FILES_thhor = config.c uart.c cmd.c base85.c rtc.c adc.c pwm.c spi.c flash.c bch4369.c pipe.c fpga.c
|
||||
# Link order defines ADC packet composition
|
||||
# main() is first, with .bss.magic
|
||||
# config.c includes .eeprom `port_config`, that should go second
|
||||
# .bss: rtc, adc, flash, uart, spi, pipe
|
||||
C_FILES_thhor = config.c rtc.c adc.c flash.c uart.c cmd.c base85.c pwm.c spi.c bch4369.c pipe.c fpga.c
|
||||
S_FILES_thhor = uart_tx.S base85a.S
|
||||
|
||||
dose_all: dose.eeprom dose.userrow
|
||||
SN_dose = 1
|
||||
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))
|
||||
OPT = -Os
|
||||
|
||||
|
|
@ -82,23 +73,24 @@ pMCU-attiny824 = t824
|
|||
pMCU-attiny3224 = t3224
|
||||
|
||||
# WDT
|
||||
fuse0_dose= 0x00
|
||||
fuse0_thhor= 0x00
|
||||
# BOD
|
||||
fuse1_dose= 0x00
|
||||
fuse1_thhor= 0x00
|
||||
# OSC, 20 MHz
|
||||
fuse2_dose= 0x7e
|
||||
# ???
|
||||
fuse4_dose= 0xff
|
||||
fuse2_thhor= 0x7e
|
||||
# Reserved
|
||||
fuse3_thhor= 0xff
|
||||
# Reserved
|
||||
fuse4_thhor= 0xff
|
||||
# SYS0 (default 0xf6) RESET, EEPROM erase
|
||||
fuse5_dose= 0xf7
|
||||
fuse5_thhor= 0xf7
|
||||
# SYS1 startup time (64ms)
|
||||
fuse6_dose= 0xff
|
||||
fuse6_thhor= 0xff
|
||||
# APPEND
|
||||
fuse7_dose= 0x00
|
||||
fuse7_thhor= 0x00
|
||||
# BOOTEND
|
||||
fuse8_dose= 0x00
|
||||
fuses_dose =$(patsubst %, 0x%, 00 00 7e ff ff f7 ff 00 00)
|
||||
fuses_thhor = $(fuses_dose)
|
||||
fuse8_thhor= 0x00
|
||||
fuses_thhor =$(patsubst %, 0x%, 00 00 7e ff ff f7 ff 00 00)
|
||||
|
||||
AVRDUDEPROG = avrdude
|
||||
AVRDUDE = $(AVRDUDEPROG)
|
||||
|
|
@ -107,8 +99,6 @@ AVRDUDE_PORT = /dev/ttyUSB0
|
|||
|
||||
AD = $(AVRDUDE) -p $(pMCU-$(MCU)) -P $(AVRDUDE_PORT) -c $(AVRDUDE_PROGRAMMER)
|
||||
|
||||
|
||||
|
||||
sig_dose = 0x1e 0x92 0x2c
|
||||
sig_thhor = 0x1e 0x95 0x28
|
||||
|
||||
|
|
|
|||
27
src/cmd.c
27
src/cmd.c
|
|
@ -244,17 +244,38 @@ void parse_command(const uint8_t *s, uint8_t n)
|
|||
goto send_buffer;
|
||||
break;
|
||||
case 'P':
|
||||
if (cmd_flag('!'))
|
||||
pipe.dest = 0;
|
||||
if (have_b)
|
||||
pipe_config((void*)cmd_buffer);
|
||||
pipe_config((void*)cmd_buffer, (void*)bptr);
|
||||
r = pipe_poll();
|
||||
break;
|
||||
#ifdef HAVE_FPGA
|
||||
case 'O':
|
||||
r = fpga_power();
|
||||
if (bflg == 1)
|
||||
if (bflg & 1)
|
||||
// "O1" power off
|
||||
fpga_power_off();
|
||||
else if (bflg == 2)
|
||||
if (bflg >= 2) {
|
||||
// "O2" power on
|
||||
fpga_power_on();
|
||||
if (!r) {
|
||||
fpga_reset();
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (bflg <= 2)
|
||||
break;
|
||||
if (bflg <= 8 && r==as_configured)
|
||||
// "O2": configure if unconfigured
|
||||
break;
|
||||
if (bflg & 8) {
|
||||
// "O3": power of if unconfigured
|
||||
fpga_power_off();
|
||||
break;
|
||||
}
|
||||
// "O4" configure unconditionally
|
||||
fpga_config(config.fpga_config_page, config.fpga_config_count);
|
||||
break;
|
||||
case 'C':
|
||||
if (cmd_flag('@')) {
|
||||
|
|
|
|||
43
src/config.h
43
src/config.h
|
|
@ -23,6 +23,8 @@ struct config {
|
|||
uint16_t pwm_min;
|
||||
uint16_t pwm_max;
|
||||
#endif
|
||||
uint16_t fpga_config_page;
|
||||
uint16_t fpga_config_count;
|
||||
};
|
||||
|
||||
enum magic_flags {
|
||||
|
|
@ -32,7 +34,7 @@ enum magic_flags {
|
|||
#endif
|
||||
#ifdef HAVE_FPGA
|
||||
MAGIC = 0xC5,
|
||||
VERSION = 0x01,
|
||||
VERSION = 0x00,
|
||||
#endif
|
||||
};
|
||||
|
||||
|
|
@ -159,6 +161,8 @@ extern struct magic {
|
|||
#if 0
|
||||
#define _memcopy memcpy
|
||||
#define _memcopyyz memcpy
|
||||
#define _memcopyzy memcpy
|
||||
#define _memcmpyz memcmp
|
||||
#else
|
||||
// avoid the avr-libc memcpy.
|
||||
// ¡ n must not be zero !
|
||||
|
|
@ -192,6 +196,43 @@ void _memcopyyz(uint8_t *d, uint8_t *s, uint8_t n)
|
|||
:: "r0", "memory");
|
||||
}
|
||||
|
||||
static inline
|
||||
void _memcopyzy(uint8_t *d, uint8_t *s, uint8_t n)
|
||||
{
|
||||
__asm__ volatile ("\n"
|
||||
"1:" "\n\t"
|
||||
"ld r0, Y+" "\n\t"
|
||||
"st Z+, r0" "\n\t"
|
||||
"dec %[N]" "\n\t"
|
||||
"brne 1b" "\n"
|
||||
: [D] "+z" (d),
|
||||
[S] "+y" (s),
|
||||
[N] "+r" (n)
|
||||
:: "r0", "memory");
|
||||
}
|
||||
|
||||
static inline
|
||||
uint8_t _memcmpyz(uint8_t *d, uint8_t *s, uint8_t n)
|
||||
{
|
||||
uint8_t r;
|
||||
__asm__ volatile (
|
||||
"\n"
|
||||
"1:" "\n\t"
|
||||
"ld %[R], Y+" "\n\t"
|
||||
"ld r0, Z+" "\n\t"
|
||||
"sub %[R], r0" "\n\t"
|
||||
"breq 1f" "\n\t"
|
||||
"dec %[N]" "\n\t"
|
||||
"brne 1b" "\n"
|
||||
"1:" "\n"
|
||||
: [D] "+x" (d),
|
||||
[S] "+y" (s),
|
||||
[N] "+r" (n),
|
||||
[R] "=r" (r)
|
||||
:
|
||||
: "r0", "memory");
|
||||
return r;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
|
|
|||
|
|
@ -4,14 +4,14 @@
|
|||
*/
|
||||
MEMORY
|
||||
{
|
||||
eemap : ORIGIN = 0x1400, LENGTH = 0x100
|
||||
eedef : ORIGIN = 0x810000, LENGTH = 0x100
|
||||
uumap : ORIGIN = 0x1300, LENGTH = 0x20
|
||||
uudef : ORIGIN = 0x850000, LENGTH = 0x20
|
||||
eemap (rw!x) : ORIGIN = 0x801400, LENGTH = 0x100
|
||||
eedef (rw!x) : ORIGIN = 0x810000, LENGTH = 0x100
|
||||
uumap (rw!x) : ORIGIN = 0x801300, LENGTH = 0x020
|
||||
uudef (rw!x) : ORIGIN = 0x850000, LENGTH = 0x020
|
||||
}
|
||||
SECTIONS
|
||||
{
|
||||
.eemap 0x1400:
|
||||
.eemap 0x801400:
|
||||
{
|
||||
ee1_start = .;
|
||||
*(.eeprom1)
|
||||
|
|
@ -22,7 +22,7 @@ SECTIONS
|
|||
ee9_end = .;
|
||||
ee9_size = ee9_end - ee9_start;
|
||||
} >eemap AT >eedef
|
||||
.uumap 0x1300:
|
||||
.uumap 0x801300:
|
||||
{
|
||||
*(.userrow)
|
||||
} >uumap AT >uudef
|
||||
|
|
|
|||
|
|
@ -28,6 +28,7 @@ uint8_t flash_cmd(uint16_t mode, uint16_t what, uint16_t page, uint16_t byte);
|
|||
extern uint8_t flash_buffer[FB_SIZE];
|
||||
uint8_t flash_submit_command(uint8_t *cmd);
|
||||
uint8_t flash_start_stream(uint16_t page, uint16_t npages, uint8_t flags);
|
||||
uint8_t flash_stream_done();
|
||||
uint8_t flash_poll(uint8_t rr);
|
||||
uint16_t flash_find_free();
|
||||
|
||||
|
|
@ -53,4 +54,6 @@ enum {
|
|||
FS_528 = 128, // do 528 byte pages.
|
||||
};
|
||||
|
||||
static inline uint8_t flash_current_block() { return fs.block; }
|
||||
|
||||
#endif
|
||||
|
|
|
|||
134
src/fpga.c
134
src/fpga.c
|
|
@ -2,6 +2,7 @@
|
|||
#include "pipe.h"
|
||||
#include "fpga.h"
|
||||
#include "spi.h"
|
||||
#include <string.h>
|
||||
|
||||
uint8_t fpga_reset_poll()
|
||||
{
|
||||
|
|
@ -12,6 +13,18 @@ uint8_t fpga_reset_poll()
|
|||
return r;
|
||||
}
|
||||
|
||||
uint8_t fpga_status()
|
||||
{
|
||||
uint8_t r = fpga_power();
|
||||
// all three altera pins must be on the same PORT
|
||||
if (r)
|
||||
r |= CRCERR_VPORT.IN &
|
||||
( 1<<nCONFIG_PIN
|
||||
| 1<<nSTATUS_PIN
|
||||
| 1<<CRCERR_PIN );
|
||||
return r;
|
||||
}
|
||||
|
||||
void fpga_reset()
|
||||
{
|
||||
nCONFIG_VPORT.OUT &=~ (1<<nCONFIG_PIN);
|
||||
|
|
@ -24,8 +37,8 @@ void fpga_cmd(struct fpga_cmd *c)
|
|||
{
|
||||
uint8_t n = c->n;
|
||||
uint8_t z = c->z;
|
||||
if (fpga_reset_poll()) {
|
||||
c->n = n | fpga_busy;
|
||||
if (fpga_status() != as_configured) {
|
||||
c->n = n | fpga_dead;
|
||||
return;
|
||||
}
|
||||
if (n & fpga_abort && spi_abort()) {
|
||||
|
|
@ -41,7 +54,7 @@ void fpga_cmd(struct fpga_cmd *c)
|
|||
return;
|
||||
c->n = n | fpga_submitted;
|
||||
|
||||
spi_select(n & fpga_config ? SPI_CONFIG : 0);
|
||||
spi_select(n & fpga_configure ? SPI_CONFIG : 0);
|
||||
spi.csize = n &= fpga_size;
|
||||
spi.zero = z & 0x80; // send 0x0000 or 0x8080
|
||||
spi.cmd = c->d;
|
||||
|
|
@ -62,25 +75,106 @@ void fpga_cmd(struct fpga_cmd *c)
|
|||
spi_start();
|
||||
}
|
||||
|
||||
void fpga_start(uint8_t write)
|
||||
struct pipe_fpga_cmd pipe_fpga_cmd;
|
||||
|
||||
uint8_t fpga_start_write()
|
||||
{
|
||||
uint8_t mode = 0;
|
||||
if (pipe.fpga.zero == SPI_CONFIG)
|
||||
mode = SPI_CONFIG;
|
||||
uint8_t mode = pipe.fpga.status & 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;
|
||||
uint8_t n = 32;
|
||||
if (pipe.fpga.count)
|
||||
pipe.fpga.count--;
|
||||
else {
|
||||
uint8_t nn = pipe.fpga.size;
|
||||
if (nn < n)
|
||||
n = nn;
|
||||
pipe.fpga.size -= n;
|
||||
if (!n)
|
||||
return;
|
||||
if (write)
|
||||
spi.wsize = n;
|
||||
else
|
||||
spi.rsize = n;
|
||||
spi_start();
|
||||
}
|
||||
spi.wsize = n<<1;
|
||||
if (n)
|
||||
spi_start();
|
||||
return n;
|
||||
}
|
||||
|
||||
uint8_t fpga_start_read()
|
||||
{
|
||||
/************************************************************
|
||||
* Send `counts` commands to the FPGA.
|
||||
* Read `size` Words from each command.
|
||||
* Fill the `flash_buffer` with 32 Words.
|
||||
* AS_CONT:
|
||||
* Continue reading Words after the buffer was used.
|
||||
* User resets spi.fpga.val when done.
|
||||
* Return the number of Words to be read now.
|
||||
***********************************************************/
|
||||
|
||||
if (spi_select(0))
|
||||
return 0;
|
||||
if (fpga_status() != as_configured)
|
||||
return 0;
|
||||
if (!pipe.fpga.val)
|
||||
memset(flash_buffer, 0, 64);
|
||||
uint8_t n = 64 - pipe.fpga.val;
|
||||
if (!n)
|
||||
return n;
|
||||
spi.rdata = flash_buffer + pipe.fpga.val;
|
||||
n >>= 1;
|
||||
if (~pipe.fpga.status & AS_CONT) {
|
||||
if (!pipe.fpga.count)
|
||||
return 0;
|
||||
pipe.fpga.count--;
|
||||
spi.cmd = pipe_fpga_cmd.cmd;
|
||||
_memcopy((void*)&spi.csize, (void*)&pipe_fpga_cmd, 6);
|
||||
pipe.fpga.pos = 0;
|
||||
pipe.fpga.status |= AS_CONT;
|
||||
}
|
||||
uint8_t nn = pipe.fpga.size - pipe.fpga.pos;
|
||||
if (nn && nn < n)
|
||||
n = nn;
|
||||
pipe.fpga.pos += n;
|
||||
if (pipe.fpga.pos == pipe.fpga.size)
|
||||
pipe.fpga.status &=~ AS_CONT;
|
||||
spi.rsize = n << 1;
|
||||
pipe.fpga.val += spi.rsize;
|
||||
spi_start();
|
||||
return n;
|
||||
}
|
||||
|
||||
uint8_t fpga_pipe_ready()
|
||||
{
|
||||
/************************************************************
|
||||
* Return the number of valid Words read in to the buffer,
|
||||
* when
|
||||
* - the FPGA is alive, and
|
||||
* - the buffer is full, or
|
||||
* - there is nothing more to read.
|
||||
* Reset pipe.fpga.val, when returning nonzero,
|
||||
* assuming those Words will be used now.
|
||||
***********************************************************/
|
||||
|
||||
uint8_t r = pipe.fpga.val;
|
||||
if (fpga_status() != as_configured)
|
||||
return 0;
|
||||
if (r >= 64 || !pipe.fpga.count && ~pipe.fpga.status & AS_CONT)
|
||||
pipe.fpga.val = 0;
|
||||
else
|
||||
r = 0;
|
||||
return r;
|
||||
}
|
||||
|
||||
const struct pipe pipe_config_fpga_config = {
|
||||
.source = pipe_flash,
|
||||
.dest = pipe_fpga,
|
||||
.fpga = {
|
||||
.status = AS_CONFIG,
|
||||
},
|
||||
};
|
||||
|
||||
void fpga_config(uint16_t page, uint16_t count)
|
||||
{
|
||||
fpga_reset();
|
||||
pipe = pipe_config_fpga_config;
|
||||
pipe.fpga.count = count;
|
||||
flash_start_stream(page, count>>8, FS_Read|FS_528);
|
||||
}
|
||||
|
|
|
|||
18
src/fpga.h
18
src/fpga.h
|
|
@ -13,7 +13,8 @@ enum fpga_flags {
|
|||
fpga_aborted = 0x10,
|
||||
fpga_busy = 0x20,
|
||||
fpga_submitted = 0x40,
|
||||
fpga_config = 0x80,
|
||||
fpga_configure = 0x80,
|
||||
fpga_dead = 0x80,
|
||||
|
||||
fpga_wait_nonzero = 0x01,
|
||||
};
|
||||
|
|
@ -21,8 +22,21 @@ enum fpga_flags {
|
|||
void fpga_reset();
|
||||
uint8_t fpga_reset_poll();
|
||||
void fpga_cmd(struct fpga_cmd *c);
|
||||
void fpga_start(uint8_t write);
|
||||
uint8_t fpga_start_read();
|
||||
uint8_t fpga_start_write();
|
||||
uint8_t fpga_pipe_ready();
|
||||
void fpga_config(uint16_t page, uint16_t count);
|
||||
|
||||
static inline uint8_t fpga_power() { return !!(PEN_VPORT.IN & (1<<PEN_PIN)); }
|
||||
static inline void fpga_power_on() { PEN_VPORT.OUT |= 1<<PEN_PIN; }
|
||||
static inline void fpga_power_off() { PEN_VPORT.OUT &=~ (1<<PEN_PIN); }
|
||||
|
||||
enum fpga_status_values {
|
||||
as_off = 0,
|
||||
as_on = 1,
|
||||
as_reset = as_on | 1<<CRCERR_PIN,
|
||||
as_configured = as_on | 1<<nCONFIG_PIN | 1<<nSTATUS_PIN,
|
||||
as_crcerror = as_configured | 1<<CRCERR_PIN,
|
||||
};
|
||||
|
||||
uint8_t fpga_status();
|
||||
|
|
|
|||
191
src/pipe.c
191
src/pipe.c
|
|
@ -11,51 +11,120 @@
|
|||
|
||||
section_status(pipe) struct pipe pipe;
|
||||
|
||||
__attribute__((noinline))
|
||||
uint8_t pipe_busy()
|
||||
{
|
||||
// Return true if anything is due to irq
|
||||
// call this with cli() before sei();sleep()
|
||||
if (spi_busy_p()) return 1;
|
||||
if (flash_poll(0) & FS_Busy) return 1;
|
||||
if (adc_poll(0)) return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint8_t pipe_poll()
|
||||
{
|
||||
/************************************************************
|
||||
* Drive data in `flash_buffer` from `source` to `dest`
|
||||
* `pipe_cmd`:
|
||||
* data comes and goes via cmd("B…")
|
||||
* `pipe.valid` controls if a buffer was fully transfered
|
||||
* `pipe_flash`:
|
||||
* read or write pages from,to flash
|
||||
* `PS_528`: use all 528 bytes
|
||||
* `PS_BCH`: compute or check the BCH codes
|
||||
* `pipe_adc`: (source)
|
||||
* Fill the buffer with ADC readings and further status
|
||||
* `pipe_fpga`:
|
||||
* Configure the FPGA
|
||||
* Write to the FPGA
|
||||
* Read from the FPGA, with commands
|
||||
***********************************************************/
|
||||
|
||||
// Return, if
|
||||
// any hardware is busy,
|
||||
// an FS_Error occured, or
|
||||
// the data goes nowhere.
|
||||
uint8_t r = pipe.status;
|
||||
uint8_t fl = flash_poll(0);
|
||||
if (spi_busy_p() || fl & FS_Busy || adc_poll(0))
|
||||
goto done;
|
||||
uint8_t dest = pipe.dest;
|
||||
|
||||
if (pipe_busy() || !dest)
|
||||
return r;
|
||||
#ifdef HAVE_FPGA
|
||||
if (fpga_reset_poll())
|
||||
goto done;
|
||||
// we need to wait at least until the FPGA raises nCONFIG
|
||||
if (dest & pipe_fpga && fpga_reset_poll())
|
||||
return r;
|
||||
#endif
|
||||
|
||||
uint8_t valid = pipe.valid;
|
||||
|
||||
if (r & PS_OUT) {
|
||||
if (pipe.dest & pipe_cmd && pipe.valid & 0x1f)
|
||||
// Sending the buffer to `dest`.
|
||||
// Return if we are not done sending to all destinations.
|
||||
|
||||
if (dest & pipe_cmd && 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;
|
||||
if (pipe.source & pipe_adc && !adc_poll(pipe.adc))
|
||||
if (dest & pipe_flash && ~fs.status & FS_Ready)
|
||||
// flash did not finish yet, 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)
|
||||
|
||||
r &=~ PS_OUT;
|
||||
|
||||
// Return if next ADC reading is not yet due.
|
||||
// Come back here, until is is.
|
||||
|
||||
if (pipe.source & pipe_adc && !adc_poll(pipe.adc))
|
||||
goto done;
|
||||
|
||||
// Continue the flash stream.
|
||||
// PS_BLK is the 64-Bytes buffer number in the page
|
||||
|
||||
valid = 0;
|
||||
if (pipe.source & pipe_flash) {
|
||||
r &= ~ PS_BLK;
|
||||
r |= flash_current_block() & PS_BLK;
|
||||
flash_poll(1);
|
||||
}
|
||||
#ifdef HAVE_FPGA
|
||||
else if (pipe.source & pipe_fpga)
|
||||
fpga_start(0);
|
||||
// Continue the FPGA stream.
|
||||
|
||||
else if (pipe.source & pipe_fpga) {
|
||||
if (~fpga_start_read())
|
||||
pipe.source &=~ pipe_fpga;
|
||||
}
|
||||
#endif
|
||||
r &=~ (PS_OUT|4);
|
||||
r++;
|
||||
goto done;
|
||||
}
|
||||
|
||||
// Waiting for the buffer to fill
|
||||
|
||||
// For 528 bytes pages, the last buffer must be 80 Bytes,
|
||||
// i.e., five cmd_buffers á 16 Bytes
|
||||
uint8_t bflgs = 0x0f;
|
||||
if ((r & PS_5) == PS_5)
|
||||
bflgs = 0x1f;
|
||||
|
||||
// Data from the ADC is in named .bss segments. We send
|
||||
// 16, 32, or 64 Bytes from the .bss segement for ead ADC reading.
|
||||
// The first named .bss segment is `magic`. Observe the link order
|
||||
// in the Makefile.
|
||||
//
|
||||
// Fun with assembly.
|
||||
// `n` is the number of bytes, [16, 32, 64]
|
||||
// `o` is the addr in the flash_buffer
|
||||
// `v` are the currently valid cmd_buffer flags
|
||||
// `f` are the fresh valid cmd_buffer flags
|
||||
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;
|
||||
uint8_t v = valid;
|
||||
#if 0
|
||||
uint8_t c;
|
||||
do {
|
||||
|
|
@ -84,49 +153,101 @@ uint8_t pipe_poll()
|
|||
f = 0xff;
|
||||
n = 64-o;
|
||||
}
|
||||
pipe.valid |= f>>4;
|
||||
valid |= f>>4;
|
||||
_memcopy(flash_buffer+o, (void*)&magic, n);
|
||||
}
|
||||
adc_done:
|
||||
|
||||
if (pipe.source & pipe_flash && fl & FS_Ready)
|
||||
pipe.valid = bflgs;
|
||||
// When the flash is done, flag the buffer valid,
|
||||
// including BCH Bytes.
|
||||
if (pipe.source & pipe_flash && fs.status & FS_Ready)
|
||||
valid = bflgs;
|
||||
#ifdef HAVE_FPGA
|
||||
else if (pipe.source & pipe_fpga)
|
||||
pipe.valid = 0x0f;
|
||||
// The FPGA delivers 64 Bytes.
|
||||
else if (pipe.source & pipe_fpga && fpga_pipe_ready())
|
||||
valid = 0x0f;
|
||||
#endif
|
||||
if (~pipe.valid & 0x0f)
|
||||
// The buffer is not here, yet. Nothing we can do now.
|
||||
if (~valid & 0x0f)
|
||||
goto done;
|
||||
|
||||
// The buffer shall include BCH Bytes.
|
||||
if (r & PS_BCH) {
|
||||
if (!(r&3))
|
||||
// First buffer of a page, clear the parity
|
||||
if (!(r & PS_BLK))
|
||||
bch4369_init(config.bch_salt);
|
||||
// Add the current buffer to the parity
|
||||
uint8_t *bend = bch4369_stri(flash_buffer, 64);
|
||||
if (!(~r & 3)) {
|
||||
// reuse Y=bend
|
||||
// Last buffer of the page:
|
||||
if (!(~r & PS_BLK)) {
|
||||
bch4369_fini();
|
||||
valid = 0x01f;
|
||||
// When the Flash is not the source,
|
||||
// copy the computed parity into the buffer.
|
||||
if (~pipe.source & pipe_flash)
|
||||
_memcopyyz(bend, bch_parity, 16);
|
||||
pipe.valid = 0x01f;
|
||||
// When the page as read from flash has invalid parity,
|
||||
// stop writing to the FPGA.
|
||||
else if (_memcmpyz(bch_parity, bend, 16)) {
|
||||
dest &=~ pipe_fpga;
|
||||
r |= PS_ERR;
|
||||
}
|
||||
}
|
||||
if (~pipe.valid & bflgs)
|
||||
}
|
||||
// We still do not have all data we need
|
||||
if (~valid & bflgs)
|
||||
goto done;
|
||||
|
||||
#ifdef HAVE_FPGA
|
||||
if (pipe.dest & pipe_fpga)
|
||||
fpga_start(1);
|
||||
#endif
|
||||
|
||||
// The buffer is full, send it.
|
||||
r |= PS_OUT;
|
||||
|
||||
#ifdef HAVE_FPGA
|
||||
// Resume the FPGA stream
|
||||
if (dest & pipe_fpga & ~fpga_start_write())
|
||||
dest &=~ pipe_fpga;
|
||||
else
|
||||
#endif
|
||||
// Resume the flash stream
|
||||
if (dest & pipe_flash) {
|
||||
r &= ~ PS_BLK;
|
||||
r |= flash_current_block() & PS_BLK;
|
||||
flash_poll(1);
|
||||
if (flash_stream_done())
|
||||
dest &=~ pipe_flash;
|
||||
}
|
||||
|
||||
done:
|
||||
pipe.dest = dest;
|
||||
pipe.valid = valid;
|
||||
pipe.status = r;
|
||||
return r;
|
||||
}
|
||||
|
||||
void pipe_config(const struct pipe_config *c)
|
||||
void pipe_config(const struct pipe_config *c, const struct pipe_fpga_cmd *a)
|
||||
{
|
||||
/************************************************************
|
||||
* cmd("B0!", «fpga-cmd») optionally configure an FPGA cmd
|
||||
* cmd("P0:, «pipe-cfg») with `AS_CMD` in `.status`
|
||||
***********************************************************/
|
||||
|
||||
if (c->pipe.dest) {
|
||||
pipe = c->pipe;
|
||||
if ((pipe.source | pipe.dest) & pipe_flash)
|
||||
flash_start_stream(c->page, c->npages, c->flash);
|
||||
}
|
||||
else {
|
||||
// new source (NOT flash)
|
||||
pipe.source = c->pipe.source;
|
||||
}
|
||||
if (pipe.source & pipe_adc)
|
||||
adc_start_stream(pipe.adc);
|
||||
#ifdef HAVE_FPGA
|
||||
if (pipe.source & pipe_fpga) {
|
||||
if (a && pipe.fpga.status & AS_CMD)
|
||||
_memcopyzy((void*)&pipe_fpga_cmd, (void*)a, sizeof(*a));
|
||||
else
|
||||
memset(&pipe_fpga_cmd, 0, sizeof(*a));
|
||||
fpga_start_read();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
|
|
|||
38
src/pipe.h
38
src/pipe.h
|
|
@ -8,10 +8,15 @@ enum pipe_ports {
|
|||
pipe_fpga = 8,
|
||||
|
||||
PS_OUT = 0x80,
|
||||
PS_BCH = 0x10,
|
||||
PS_528 = 0x08,
|
||||
PS_BLK = 0x03,
|
||||
PS_ERR = 0x40,
|
||||
PS_BCH = 0x20,
|
||||
PS_528 = 0x10,
|
||||
PS_BLK = 0x07,
|
||||
PS_5 = PS_BLK | PS_528, // need 16 bytes more
|
||||
|
||||
AS_CONT = 1,
|
||||
AS_CONFIG = SPI_CONFIG, // = 2
|
||||
AS_CMD = 4,
|
||||
};
|
||||
|
||||
extern
|
||||
|
|
@ -23,14 +28,11 @@ struct pipe {
|
|||
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;
|
||||
uint8_t status; // AS_…
|
||||
uint16_t count; // number of cmds(read), 64 Bytes(write)
|
||||
uint8_t size; // Words per cmd (read), extra Words (write), 0==256
|
||||
uint8_t val; // Valid Bytes in Buffer (read)
|
||||
uint8_t pos; // Words read from current cmd (read)
|
||||
} fpga;
|
||||
#endif
|
||||
} pipe;
|
||||
|
|
@ -42,6 +44,18 @@ struct pipe_config {
|
|||
uint8_t flash;
|
||||
};
|
||||
|
||||
extern
|
||||
struct pipe_fpga_cmd {
|
||||
uint8_t csize;
|
||||
uint8_t zsize;
|
||||
uint8_t isize;
|
||||
uint8_t zero;
|
||||
uint8_t wait;
|
||||
uint8_t mask;
|
||||
uint8_t cmd[10];
|
||||
} pipe_fpga_cmd;
|
||||
|
||||
uint8_t pipe_busy();
|
||||
uint8_t pipe_poll();
|
||||
void pipe_cron();
|
||||
void pipe_config(const struct pipe_config *c);
|
||||
void pipe_config(const struct pipe_config *c, const struct pipe_fpga_cmd *a);
|
||||
|
|
|
|||
|
|
@ -31,6 +31,11 @@ ISR(SPI0_INT_vect)
|
|||
d = spi.zero;
|
||||
}
|
||||
else if (spi.wsize) {
|
||||
// TODO:
|
||||
// spi.csize = spi.wsize;
|
||||
// spi.wsize = 0;
|
||||
// spi.cmd = spi.wdata;
|
||||
// goto repeat;
|
||||
spi.wsize--;
|
||||
d = *spi.wdata++;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -40,8 +40,17 @@ int main()
|
|||
send_hex_byte_eol(magic.reset_source);
|
||||
|
||||
while (1) {
|
||||
// The pipe may become idle before we reach sleep.
|
||||
// Make sure we have nothing to do before we sleep.
|
||||
// The sleep command will execute even when an irq
|
||||
// is pending. It will wake us immediately.
|
||||
cli();
|
||||
if (!command_pending() && (!pipe.dest || pipe_busy())) {
|
||||
sei();
|
||||
sleep_cpu();
|
||||
}
|
||||
sei();
|
||||
command();
|
||||
pipe_poll();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -26,3 +26,10 @@ void send_hex_long(uint32_t b)
|
|||
|
||||
extern uint8_t uart_rx_err;
|
||||
extern uint8_t uart_rx_errors;
|
||||
extern volatile uint8_t uart_rx_mes;
|
||||
|
||||
static inline
|
||||
uint8_t command_pending()
|
||||
{
|
||||
return uart_rx_mes;
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue