Compare commits

...

6 commits

Author SHA1 Message Date
Stephan I. Böttcher
55f5008540 fpga_config_p(): success 2026-04-08 18:03:22 +02:00
Stephan I. Böttcher
2575504fce fpga_* fixes 2026-04-08 16:38:42 +02:00
Stephan I. Böttcher
1f18bebdd9 spi: fix ~ ! confusion 2026-04-08 16:38:04 +02:00
Stephan I. Böttcher
5bf152eab7 fpga_power_off(): nCONFIG=0 2026-04-08 16:36:49 +02:00
Stephan I. Böttcher
68e5849e2a pipe: fix fpga_start_* return value test 2026-04-08 16:35:43 +02:00
Stephan I. Böttcher
190f8741d4 cmd("O") return fpga_status() 2026-04-08 16:34:17 +02:00
6 changed files with 127 additions and 21 deletions

View file

@ -261,7 +261,7 @@ void parse_command(const uint8_t *s, uint8_t n)
break;
#ifdef HAVE_FPGA
case 'O':
r = fpga_power();
r = fpga_status();
if (bflg & 1)
// "O1" power off
fpga_power_off();

View file

@ -1,6 +1,6 @@
#! /usr/bin/ipython3 --profile=thhor
import sys, time, getopt, fileinput, struct
import sys, os, time, getopt, fileinput, struct
import uart
from base85 import base85_encode, base85_decode
from map import memmap
@ -383,18 +383,21 @@ class dose_cmd(uart.uart):
self.cmd(c, page[16*i:16*(i+1)])
return self.cmd("B4<!")
FPGA_STAT = {
"POWER": 1,
"nCONFIG": 0x40,
"nSTATUS": 0x10,
"CRCERR": 0x20,
}
def power(self, on=None):
if on==True:
c = 'O1'
elif on==False:
c = 'O0'
elif on is None:
if on is None:
c = 'O'
else:
raise ValueError(f".power expects True or False, got {on!r}")
c = f'O{on:d}'
r = self.cmd(c)
print(f"Power was {("off", "ON")[r[1]]}", file=sys.stderr)
return r
print(f"Power was {("off", "ON")[r[1]&1]}", file=sys.stderr)
return int2flags(self.FPGA_STAT, r[1])
def fpga_reset(self):
return self.cmd("C@")
@ -427,7 +430,7 @@ class dose_cmd(uart.uart):
print(f"FPGA cmd status {s!r}", file=sys.stderr)
return d
def fpga_config(self, filename="../fpga/quartus/thhor_crs.rbf"):
def fpga_config_c(self, filename="../fpga/quartus/thhor_crs.rbf"):
self.fpga_reset()
n = 0
nn = 0
@ -559,7 +562,7 @@ class dose_cmd(uart.uart):
}
def pipe(self, source=None, dest=None,
fpga_cmd=4, psize=64, n=0,
fpga_cmd=4, psize=0, n=0,
page=0, npages=0,
poll=True, stop=False):
astatus = flags2int(self.PIPE, dest)
@ -580,6 +583,22 @@ class dose_cmd(uart.uart):
if poll:
c += '!'
if n and not psize:
if dest & self.PIPE["FPGA"]:
psize = (n % 64) & 0xfe
n //= 64
else:
psize = 64
if n and not npages:
if dest & self.PIPE["FPGA"]:
npages = (n*64 + psize + 511)//512
else:
npages = (n*psize + 511)//512
if not npages:
npages = 1
if source & self.PIPE["FLASH"]:
source = self.PIPE["FLASH"]
flash |= 4
@ -595,7 +614,7 @@ class dose_cmd(uart.uart):
d = struct.pack("<6BH3B2HB",
source, dest, status, 0, 0,
astatus, n, psize, 0, 0,
astatus, n, psize//2, 0, 0,
page, npages-1, flash)
return self.cmd(c, d)
@ -670,6 +689,82 @@ class dose_cmd(uart.uart):
f.close()
return result
def write_pipe(self, data=[], timeout=2, n=None, parity=False, bfill=b'\0', pfill=b'\xff'):
if isinstance(data, str):
f = open(data, "rb")
data = []
else:
f = None
if not isinstance(data, list):
data = [data]
i = 0
t = time.time()
s = 1/256
while True:
if f:
page = f.read(512)
elif data:
page = data[0]
data[0:1] = []
else:
page = None
if not page:
break
if len(page) < 512:
j = len(page) % 64
if self._verbose:
print(f"short page {len(page)} bytes", file=sys.stderr)
if j and bfill:
page += (64-j)*bfill
if pfill:
page = (page + 512*pfill)[:512]
if len(page)==512 and parity:
page += bch.page_parity(page)
page = [page[j:j+64] for j in range(0,len(page),64)]
for b in range(8):
while True:
cc, nn, dd = self.cmd("B")
tt = time.time()
nn &= 0xf
if not nn:
t = tt
s = 1/256
break
if tt > t+timeout:
if self._verbose:
print(f"write_pipe timeout {i=} {b=}", file=sys.stderr)
break
time.sleep(s)
s *= 2
if s > 1:
s = 1
if nn:
break
if parity and b==7:
self.cmd("B@4", page[8])
if b >= len(page):
break
for j in range(4):
self.cmd(f"B{j}", page[b][16*j:16*(j+1)])
if self._verbose >= 2:
self.peek("pipe", 11)
i += 1
if n and i >= n:
break
if n and i >= n:
break
if nn:
break
if f:
f.close()
return i
def fpga_config_p(self, filename="../fpga/quartus/thhor_crs.rbf"):
self.fpga_reset()
n = (os.stat(filename).st_size + 63) // 64
self.pipe("CMD", "CONFIG", n=n*64)
self.write_pipe(filename, n=n)
def fix_page(self, page):
if self.load_galois():
page = bch.fix_page(page)

View file

@ -30,7 +30,7 @@ void fpga_reset()
nCONFIG_VPORT.OUT &=~ (1<<nCONFIG_PIN);
uint8_t n = 10;
// nSTATUS will go low within 500ns
while (n-- && ~fpga_reset_poll());
while (!fpga_reset_poll() && --n);
}
void fpga_cmd(struct fpga_cmd *c)
@ -74,7 +74,12 @@ struct pipe_fpga_cmd pipe_fpga_cmd;
uint8_t fpga_start_write()
{
uint8_t s = fpga_status();
uint8_t mode = pipe.fpga.status & SPI_CONFIG;
if (!mode && s != as_configured)
return 0;
if (~s & as_rconfig)
return 0;
spi_select(mode);
spi.wdata = flash_buffer;
uint8_t n = 32;
@ -163,6 +168,7 @@ uint8_t fpga_pipe_ready()
const struct pipe pipe_config_fpga_config = {
.source = pipe_flash,
.dest = pipe_fpga,
.status = PS_BCH | PS_528,
.fpga = {
.status = AS_CONFIG,
},
@ -173,5 +179,5 @@ 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);
flash_start_stream(page, count >> 3, FS_Read|FS_528);
}

View file

@ -27,7 +27,11 @@ 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); }
static inline void fpga_power_off()
{
nCONFIG_VPORT.OUT &=~ (1<<nCONFIG_PIN);
PEN_VPORT.OUT &=~ (1<<PEN_PIN);
}
enum fpga_status_values {
as_off = 0,
@ -35,6 +39,7 @@ enum fpga_status_values {
as_reset = as_on | 1<<CRCERR_PIN,
as_configured = as_on | 1<<nCONFIG_PIN | 1<<nSTATUS_PIN,
as_crcerror = as_configured | 1<<CRCERR_PIN,
as_rconfig = as_on | 1<<nCONFIG_PIN | 1<<nSTATUS_PIN,
};
uint8_t fpga_status();

View file

@ -51,7 +51,7 @@ uint8_t pipe_poll()
if (pipe_busy() || !dest)
return r;
#ifdef HAVE_FPGA
// we need to wait at least until the FPGA raises nCONFIG
// we need to wait at least until the FPGA raises nSTATUS
if (dest & pipe_fpga && fpga_reset_poll())
return r;
#endif
@ -93,7 +93,7 @@ uint8_t pipe_poll()
// Continue the FPGA stream.
else if (pipe.source == pipe_fpga) {
if (~fpga_start_read())
if (!fpga_start_read())
pipe.source = 0;
}
#endif
@ -204,7 +204,7 @@ adc_done:
#ifdef HAVE_FPGA
// Resume the FPGA stream
if (dest & pipe_fpga && ~fpga_start_write())
if (dest & pipe_fpga && !fpga_start_write())
dest &=~ pipe_fpga;
else
#endif

View file

@ -26,7 +26,7 @@ uint8_t spi_poll_delay()
uint8_t ifg;
do {
ifg = SPI.INTFLAGS & SPI_RXCIF_bm;
} while (~ifg && t--);
} while (!ifg && t--);
return ifg;
}