mirror of
https://codeberg.org/SiB64/turbo_weather.git
synced 2026-05-01 15:14:22 +02:00
Compare commits
2 commits
46809f6fac
...
97d00bc908
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
97d00bc908 | ||
|
|
90aaf8d48e |
12 changed files with 474 additions and 148 deletions
|
|
@ -8,7 +8,7 @@ all: $(PROJ).hex
|
||||||
|
|
||||||
SN_dose = 1
|
SN_dose = 1
|
||||||
MCU_dose = attiny424
|
MCU_dose = attiny424
|
||||||
C_FILES_dose = config.c cmd.c pwm.c uart.c base85.c bch4369.c rtc.c spi.c flash.c adc.c
|
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
|
||||||
S_FILES_dose = uart_tx.S base85a.S
|
S_FILES_dose = uart_tx.S base85a.S
|
||||||
|
|
||||||
MCU = $(MCU_$(PROJ))
|
MCU = $(MCU_$(PROJ))
|
||||||
|
|
|
||||||
|
|
@ -49,9 +49,16 @@ void bch4369(uint8_t d)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void bch4369_str(uint8_t *b, uint8_t n)
|
||||||
|
{
|
||||||
|
do
|
||||||
|
bch4369(*b++);
|
||||||
|
while (--n);
|
||||||
|
}
|
||||||
|
|
||||||
#else
|
#else
|
||||||
|
|
||||||
__attribute__ ((noinline, noclone))
|
__attribute__ ((noinline, naked))
|
||||||
void bch4369(uint8_t d)
|
void bch4369(uint8_t d)
|
||||||
{
|
{
|
||||||
__asm__ __volatile__(
|
__asm__ __volatile__(
|
||||||
|
|
@ -65,7 +72,7 @@ void bch4369(uint8_t d)
|
||||||
"adiw r30, 16" "\n\t"
|
"adiw r30, 16" "\n\t"
|
||||||
"ldi r26, lo8(bch_genpoly+16)" "\n\t"
|
"ldi r26, lo8(bch_genpoly+16)" "\n\t"
|
||||||
"ldi r27, hi8(bch_genpoly+16)" "\n\t"
|
"ldi r27, hi8(bch_genpoly+16)" "\n\t"
|
||||||
"rol %[D]" "\n\t" // move next input bit → r25.7
|
"rol r24" "\n\t" // move next input bit → r25.7
|
||||||
"ror r25" "\n\t"
|
"ror r25" "\n\t"
|
||||||
"2:" "\n\t"
|
"2:" "\n\t"
|
||||||
"rol r25" "\n\t" // Move r25.7 → C-bit
|
"rol r25" "\n\t" // Move r25.7 → C-bit
|
||||||
|
|
@ -81,13 +88,27 @@ void bch4369(uint8_t d)
|
||||||
"brne 2b" "\n\t"
|
"brne 2b" "\n\t"
|
||||||
"bst r25, 6" "\n\t" // copy MSB r25.6 → T-bit
|
"bst r25, 6" "\n\t" // copy MSB r25.6 → T-bit
|
||||||
"subi r20, 1" "\n\t"
|
"subi r20, 1" "\n\t"
|
||||||
"brne 1b" "\n"
|
"brne 1b" "\n\t"
|
||||||
: [D] "+w" (d)
|
"ret" "\n"
|
||||||
:
|
);
|
||||||
: "memory", "cc",
|
}
|
||||||
"r0", "r20", "r21", "r25",
|
|
||||||
"r26", "r27", "r30", "r31"
|
__attribute__ ((noinline, naked))
|
||||||
);
|
void bch4369_str(const uint8_t *b, uint8_t n)
|
||||||
|
{
|
||||||
|
// _bch4369 preserves r22, r23, r18, r19
|
||||||
|
__asm__ __volatile__ (
|
||||||
|
""
|
||||||
|
"movw r18, r28" "\n\t"
|
||||||
|
"movw r28, r24" "\n"
|
||||||
|
"1:" "\n\t"
|
||||||
|
"ld r24, Y+" "\n\t"
|
||||||
|
"rcall bch4369" "\n\t"
|
||||||
|
"subi r22, 1" "\n\t"
|
||||||
|
"brne 1b" "\n\t"
|
||||||
|
"mov r28, r18" "\n\t"
|
||||||
|
"ret" "\n"
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -4,3 +4,4 @@
|
||||||
extern uint8_t bch_parity[16];
|
extern uint8_t bch_parity[16];
|
||||||
void bch4369(uint8_t d);
|
void bch4369(uint8_t d);
|
||||||
static inline void bch4369_init() { memset(bch_parity, 0 , 16); }
|
static inline void bch4369_init() { memset(bch_parity, 0 , 16); }
|
||||||
|
void bch4369_str(const uint8_t *b, uint8_t n);
|
||||||
|
|
|
||||||
226
src/cmd.c
226
src/cmd.c
|
|
@ -8,85 +8,14 @@
|
||||||
#include "bch4369.h"
|
#include "bch4369.h"
|
||||||
#include "base85.h"
|
#include "base85.h"
|
||||||
#include "uart.h"
|
#include "uart.h"
|
||||||
|
#include "pipe.h"
|
||||||
|
|
||||||
void base85_send_buffer(const uint8_t *buf);
|
void base85_send_buffer(const uint8_t *buf);
|
||||||
const uint8_t *base85_fill_buffer(const uint8_t *s);
|
|
||||||
const uint8_t *skip_space(const uint8_t *s);
|
const uint8_t *skip_space(const uint8_t *s);
|
||||||
uint8_t cmd_buffer[16];
|
uint8_t cmd_buffer[16];
|
||||||
uint8_t uart_stream_source;
|
uint8_t cmd_buffer_valid;
|
||||||
|
|
||||||
void parse_command(const uint8_t *s, uint8_t n)
|
|
||||||
{
|
|
||||||
uint8_t cmd = *s++;
|
|
||||||
if (*s =='|')
|
|
||||||
return;
|
|
||||||
s = skip_space(s);
|
|
||||||
uint8_t flag = *s++;
|
|
||||||
uint8_t r = 0;
|
|
||||||
send_char(cmd);
|
|
||||||
send_char('|');
|
|
||||||
if (cmd == 'A') {
|
|
||||||
r = adc_current;
|
|
||||||
if (r >= N_ADC) {
|
|
||||||
if (flag == '>') {
|
|
||||||
base85_send_buffer((void*)adc_readings);
|
|
||||||
flag = *s++;
|
|
||||||
}
|
|
||||||
if (flag == '+')
|
|
||||||
start_adc();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (cmd == 'W') {
|
|
||||||
s = base85_fill_buffer(s);
|
|
||||||
r = base85_error;
|
|
||||||
}
|
|
||||||
else if (cmd == 'B') {
|
|
||||||
if (flag == '<') {
|
|
||||||
s = base85_fill_buffer(s);
|
|
||||||
flag = *s - '0';
|
|
||||||
if (flag < 4) {
|
|
||||||
s++;
|
|
||||||
if (!(uart_stream_source & 0xe0)) {
|
|
||||||
memcpy(flash_buffer+16*flag, cmd_buffer, 16);
|
|
||||||
uart_stream_source = flag;
|
|
||||||
}
|
|
||||||
r = uart_stream_source;
|
|
||||||
}
|
|
||||||
flag = *s++;
|
|
||||||
}
|
|
||||||
r = base85_error;
|
|
||||||
if (!r && flag == '%') {
|
|
||||||
if (*s=='>')
|
|
||||||
base85_send_buffer(bch_parity);
|
|
||||||
else if (*s=='<')
|
|
||||||
bch4369_feed_buffer(*++s);
|
|
||||||
r = bch4369_feed_n;
|
|
||||||
}
|
|
||||||
else if (flag == '>') {
|
|
||||||
uint8_t *b = cmd_buffer;
|
|
||||||
flag = *s - '0';
|
|
||||||
if (flag < 4)
|
|
||||||
b = flash_buffer + 16*flag;
|
|
||||||
base85_send_buffer(b);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (cmd=='F') {
|
|
||||||
base85_fill_buffer(s);
|
|
||||||
r = base85_error;
|
|
||||||
if (!r)
|
|
||||||
r = flash_submit_command(cmd_buffer);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
send_char('?');
|
|
||||||
send_hex_byte_eol(r);
|
|
||||||
}
|
|
||||||
|
|
||||||
const uint8_t *skip_space(const uint8_t *s) {
|
|
||||||
while (*s == ' ')
|
|
||||||
s++;
|
|
||||||
return s;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
static inline
|
||||||
const uint8_t *base85_fill_buffer(const uint8_t *s) {
|
const uint8_t *base85_fill_buffer(const uint8_t *s) {
|
||||||
base85_error = 0;
|
base85_error = 0;
|
||||||
s = skip_space(s);
|
s = skip_space(s);
|
||||||
|
|
@ -96,6 +25,151 @@ const uint8_t *base85_fill_buffer(const uint8_t *s) {
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint8_t * poke_addr;
|
||||||
|
uint8_t peek_size;
|
||||||
|
struct peak_poke {
|
||||||
|
uint8_t *addr;
|
||||||
|
uint8_t size;
|
||||||
|
uint8_t ccp;
|
||||||
|
uint8_t data[12];
|
||||||
|
};
|
||||||
|
|
||||||
|
static inline
|
||||||
|
uint8_t poke(struct peak_poke *p, uint8_t hp, 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;
|
||||||
|
if (poke) {
|
||||||
|
if (p->ccp)
|
||||||
|
NVMCTRL.CTRLA = NVMCTRL_CMD_PAGEBUFCLR_gc;
|
||||||
|
memcpy(a, p->data, s);
|
||||||
|
if (p->ccp && !(0x8000 & (uint16_t)a))
|
||||||
|
__asm__(
|
||||||
|
"out %[ccp], %[key] \n\t"
|
||||||
|
"sts %[ctrla], %[cmd] \n"
|
||||||
|
:: [ccp] "n" (&CCP),
|
||||||
|
[ctrla] "n" (&NVMCTRL.CTRLA),
|
||||||
|
[key] "r" (p->ccp),
|
||||||
|
[cmd] "r" (NVMCTRL_CMD_PAGEERASEWRITE_gc)
|
||||||
|
: "memory", "r0"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
memcpy(p->data, a, s);
|
||||||
|
return s && !poke;
|
||||||
|
}
|
||||||
|
|
||||||
|
void parse_command(const uint8_t *s, uint8_t n)
|
||||||
|
{
|
||||||
|
uint8_t cmd = *s++;
|
||||||
|
if (*s =='`')
|
||||||
|
return;
|
||||||
|
uint8_t r = 0x08|cmd;
|
||||||
|
send_char('`');
|
||||||
|
send_char(cmd);
|
||||||
|
uint8_t have_b = !(cmd & 0x20);
|
||||||
|
cmd |= 0x20;
|
||||||
|
if (cmd > 'z')
|
||||||
|
goto error;
|
||||||
|
if (have_b) {
|
||||||
|
s = base85_fill_buffer(s);
|
||||||
|
if (base85_error) {
|
||||||
|
r = base85_error;
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
cmd_buffer_valid |= 0x80;
|
||||||
|
}
|
||||||
|
s = skip_space(s);
|
||||||
|
uint8_t flag = *s++;
|
||||||
|
switch(cmd) {
|
||||||
|
case 'a':
|
||||||
|
r = adc_current;
|
||||||
|
if (r >= N_ADC) {
|
||||||
|
if (flag=='=') {
|
||||||
|
memcpy(cmd_buffer, adc_readings, 16);
|
||||||
|
cmd_buffer_valid |= 0x40;
|
||||||
|
flag = *s++;
|
||||||
|
}
|
||||||
|
if (flag == '<') {
|
||||||
|
base85_send_buffer((void*)adc_readings);
|
||||||
|
flag = *s++;
|
||||||
|
}
|
||||||
|
if (flag == '+')
|
||||||
|
start_adc();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'b':
|
||||||
|
r = cmd_buffer_valid;
|
||||||
|
if (have_b) {
|
||||||
|
flag -= '0';
|
||||||
|
if (flag < 5 && flag==cmd_buffer_valid) {
|
||||||
|
memcpy(flash_buffer+16*flag, cmd_buffer, 16);
|
||||||
|
r = cmd_buffer_valid |= 1<<flag;
|
||||||
|
flag = *++s;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (flag == '%') {
|
||||||
|
if (*s=='<')
|
||||||
|
base85_send_buffer(bch_parity);
|
||||||
|
if (have_b)
|
||||||
|
bch4369_feed_buffer(*++s);
|
||||||
|
r = bch4369_feed_n;
|
||||||
|
}
|
||||||
|
else if (flag == '<') {
|
||||||
|
flag = *s - '0';
|
||||||
|
uint8_t *b;
|
||||||
|
if (flag < 5)
|
||||||
|
b = flash_buffer + 16*flag;
|
||||||
|
else {
|
||||||
|
b = cmd_buffer;
|
||||||
|
}
|
||||||
|
base85_send_buffer(b);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'f':
|
||||||
|
if (have_b) {
|
||||||
|
r = flash_submit_command(cmd_buffer);
|
||||||
|
cmd_buffer_valid &=~ 0x80;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
r = flash_poll(flag=='!');
|
||||||
|
break;
|
||||||
|
case 'p':
|
||||||
|
if (have_b) {
|
||||||
|
r = pipe_config(cmd_buffer, flag);
|
||||||
|
cmd_buffer_valid &= ~0x80;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
r = pipe_poll(flag=='!');
|
||||||
|
break;
|
||||||
|
case 'm':
|
||||||
|
if (poke((void*)cmd_buffer, have_b, have_b && flag=='!'))
|
||||||
|
base85_send_buffer(cmd_buffer);
|
||||||
|
default:
|
||||||
|
error:
|
||||||
|
send_char('?');
|
||||||
|
}
|
||||||
|
send_hex_byte_eol(r);
|
||||||
|
}
|
||||||
|
|
||||||
|
const uint8_t *skip_space(const uint8_t *s) {
|
||||||
|
while (*s == ' ')
|
||||||
|
s++;
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
void base85_send_buffer(const uint8_t *buf)
|
void base85_send_buffer(const uint8_t *buf)
|
||||||
{
|
{
|
||||||
uint8_t s[6];
|
uint8_t s[6];
|
||||||
|
|
@ -113,7 +187,7 @@ void bch4369_feed_buffer(uint8_t flag)
|
||||||
bch4369_feed_n = 0;
|
bch4369_feed_n = 0;
|
||||||
memset(bch_parity, 0, 16);
|
memset(bch_parity, 0, 16);
|
||||||
}
|
}
|
||||||
for (int i=0; i<16; i++)
|
bch4369_str(cmd_buffer,16);
|
||||||
bch4369(cmd_buffer[i]);
|
|
||||||
bch4369_feed_n++;
|
bch4369_feed_n++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
25
src/config.c
25
src/config.c
|
|
@ -1,5 +1,30 @@
|
||||||
|
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
#include "flash.h"
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// Configuration in USERROW
|
||||||
|
|
||||||
|
__attribute__((section(".userrow")))
|
||||||
|
const struct config config = {
|
||||||
|
.magic = USE_USERROW,
|
||||||
|
.version = USE_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
|
||||||
|
.write_buffer = 0x84 | FM_WRITE>>8, // Buffer 1 Write
|
||||||
|
.read_array = 0x03 | FM_READ>>8, // Continuous Array Read (Low-Frequency)
|
||||||
|
.read_buffer = {
|
||||||
|
[0] = 0xd1 | FM_READ>>8, // Buffer 1 Read (Low-Frequency)
|
||||||
|
[1] = 0xd3 | FM_READ>>8, // Buffer 2 Read (Low-Frequency)
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// Configuration in EEPROM
|
||||||
|
|
||||||
|
|
||||||
struct_ioconf(port_config) = {
|
struct_ioconf(port_config) = {
|
||||||
conf_prefix(PORTA),
|
conf_prefix(PORTA),
|
||||||
|
|
|
||||||
23
src/config.h
23
src/config.h
|
|
@ -4,6 +4,29 @@
|
||||||
#include <avr/io.h>
|
#include <avr/io.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
|
// USERROW
|
||||||
|
|
||||||
|
struct config {
|
||||||
|
uint8_t magic;
|
||||||
|
uint8_t version;
|
||||||
|
uint8_t cpu_clk;
|
||||||
|
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];
|
||||||
|
};
|
||||||
|
|
||||||
|
enum magic_flags {
|
||||||
|
USE_USERROW = 0xD0,
|
||||||
|
USE_VERSION = 0x01,
|
||||||
|
};
|
||||||
|
|
||||||
|
extern const struct config config;
|
||||||
|
|
||||||
|
// EEPROM
|
||||||
|
|
||||||
struct io_config {
|
struct io_config {
|
||||||
uint8_t addr;
|
uint8_t addr;
|
||||||
uint8_t val;
|
uint8_t val;
|
||||||
|
|
|
||||||
12
src/dose.c
12
src/dose.c
|
|
@ -21,18 +21,6 @@
|
||||||
#include "pwm.h"
|
#include "pwm.h"
|
||||||
#include "flash.h"
|
#include "flash.h"
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
//
|
|
||||||
// Configuration in USERROW
|
|
||||||
|
|
||||||
__attribute__((section(".userrow")))
|
|
||||||
const struct config config = {
|
|
||||||
.magic = USE_USERROW,
|
|
||||||
.version = USE_VERSION,
|
|
||||||
.cpu_clk = CLKCTRL_PDIV_2X_gc | 1, // 10MHz (max @ 3V)
|
|
||||||
.flash_page_size = FM_528,
|
|
||||||
};
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
//
|
//
|
||||||
// main()
|
// main()
|
||||||
|
|
|
||||||
14
src/dose.h
14
src/dose.h
|
|
@ -9,17 +9,3 @@
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <avr/io.h>
|
#include <avr/io.h>
|
||||||
|
|
||||||
struct config {
|
|
||||||
uint8_t magic;
|
|
||||||
uint8_t version;
|
|
||||||
uint8_t cpu_clk;
|
|
||||||
uint8_t flash_page_size;
|
|
||||||
};
|
|
||||||
|
|
||||||
enum magic_flags {
|
|
||||||
USE_USERROW = 0xD0,
|
|
||||||
USE_VERSION = 0x01,
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
extern const struct config config;
|
|
||||||
|
|
|
||||||
252
src/flash.c
252
src/flash.c
|
|
@ -82,8 +82,10 @@ miscellanious
|
||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
#include "flash.h"
|
#include "flash.h"
|
||||||
#include "cmd.h"
|
#include "cmd.h"
|
||||||
|
#include "bch4369.h"
|
||||||
|
|
||||||
uint8_t flash_cmd_buffer[4];
|
uint8_t flash_cmd_buffer[4];
|
||||||
uint8_t flash_status_bytes[2];
|
uint8_t flash_status_bytes[2];
|
||||||
|
|
@ -98,7 +100,6 @@ uint8_t flash_cmd(uint16_t mode, uint16_t what, uint16_t page, uint16_t byte)
|
||||||
{
|
{
|
||||||
uint8_t spi_mode = SPI_FLASH | mode & FM_SPI;
|
uint8_t spi_mode = SPI_FLASH | mode & FM_SPI;
|
||||||
uint8_t op = mode;
|
uint8_t op = mode;
|
||||||
mode >>= 8;
|
|
||||||
uint8_t size = what;
|
uint8_t size = what;
|
||||||
what >>= 8;
|
what >>= 8;
|
||||||
uint8_t s = spi_select(spi_mode);
|
uint8_t s = spi_select(spi_mode);
|
||||||
|
|
@ -124,11 +125,16 @@ uint8_t flash_cmd(uint16_t mode, uint16_t what, uint16_t page, uint16_t byte)
|
||||||
case FM_PAD2: pads += 1;
|
case FM_PAD2: pads += 1;
|
||||||
case FM_PAD1: pads += 1;
|
case FM_PAD1: pads += 1;
|
||||||
}
|
}
|
||||||
|
if (size >= 128) {
|
||||||
|
// for read of the security register
|
||||||
|
pads += size-64;
|
||||||
|
size = 64;
|
||||||
|
}
|
||||||
spi.zsize = pads;
|
spi.zsize = pads;
|
||||||
if (what + size <= 64)
|
if (what + size <= 80)
|
||||||
b = flash_buffer + what;
|
b = flash_buffer + what;
|
||||||
else if (what+size <= 80)
|
else if (what>=96 && what+size <= 112)
|
||||||
b = cmd_buffer + (what-64);
|
b = cmd_buffer + (what-96);
|
||||||
else if (size <= 2)
|
else if (size <= 2)
|
||||||
b = flash_status_bytes;
|
b = flash_status_bytes;
|
||||||
else
|
else
|
||||||
|
|
@ -148,58 +154,6 @@ uint8_t flash_cmd(uint16_t mode, uint16_t what, uint16_t page, uint16_t byte)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
uint16_t flash_page, flash_block, n_blocks;
|
|
||||||
uint8_t flash_stream_status;
|
|
||||||
|
|
||||||
enum {
|
|
||||||
FS_IDLE = 0,
|
|
||||||
FS_Rdy = 1,
|
|
||||||
FS_Bsy = 2,
|
|
||||||
FS_Read = 4,
|
|
||||||
FS_Write = 8,
|
|
||||||
FS_Erase = 12,
|
|
||||||
FS_Buff = 32,
|
|
||||||
FS_StBsy = 64,
|
|
||||||
FS_TxBCH = 128,
|
|
||||||
};
|
|
||||||
|
|
||||||
uint8_t flash_poll()
|
|
||||||
{
|
|
||||||
uint8_t r = spi_busy_p();
|
|
||||||
if (r)
|
|
||||||
// SPI is shifting something
|
|
||||||
return 0x80 | r;
|
|
||||||
r = flash_stream_status;
|
|
||||||
if (r & FS_StBsy) {
|
|
||||||
// status bytes arrived
|
|
||||||
if (flash_status_bytes[0] & 0x80)
|
|
||||||
// flash is still busy burning
|
|
||||||
goto rd_status;
|
|
||||||
// not busy any more, move Bsy → Rdy
|
|
||||||
if (r & FS_Bsy)
|
|
||||||
r |= FS_Rdy;
|
|
||||||
goto rdy;
|
|
||||||
}
|
|
||||||
if (!(r & FS_Bsy))
|
|
||||||
goto rdy;
|
|
||||||
if (r & FS_Write) {
|
|
||||||
rd_status:
|
|
||||||
// request status bytes for pending Tx od Er
|
|
||||||
r |= FS_StBsy;
|
|
||||||
flash_stream_status = r;
|
|
||||||
flash_cmd_na(0xd7, 0xff02);
|
|
||||||
return r & FS_Bsy;
|
|
||||||
}
|
|
||||||
// Rx is Rdy when SPI is idle
|
|
||||||
rdy:
|
|
||||||
// clear the Bsy bits
|
|
||||||
r &= ~(FS_Bsy | FS_StBsy);
|
|
||||||
// return the ready bits
|
|
||||||
flash_stream_status = r;
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct flash_cmd {
|
struct flash_cmd {
|
||||||
uint16_t mode, what, page, byte;
|
uint16_t mode, what, page, byte;
|
||||||
uint8_t buffer[8];
|
uint8_t buffer[8];
|
||||||
|
|
@ -210,3 +164,189 @@ uint8_t flash_submit_command(uint8_t *cmd)
|
||||||
struct flash_cmd *c = (void*)cmd;
|
struct flash_cmd *c = (void*)cmd;
|
||||||
return flash_cmd(c->mode, c->what, c->page, c->byte);
|
return flash_cmd(c->mode, c->what, c->page, c->byte);
|
||||||
}
|
}
|
||||||
|
struct flash_stream fs;
|
||||||
|
|
||||||
|
__attribute__ ((noinline, noclone))
|
||||||
|
uint8_t flash_stream_submit(uint16_t mode, uint8_t size)
|
||||||
|
{
|
||||||
|
uint8_t b = fs.block;
|
||||||
|
uint16_t p = fs.page;
|
||||||
|
uint8_t r = fs.status & ~FS_Ready;
|
||||||
|
mode |= (uint16_t)config.flash_page_size << 8;
|
||||||
|
if (size) {
|
||||||
|
if (b & 8) {
|
||||||
|
b = 0;
|
||||||
|
fs.page = ++p;
|
||||||
|
fs.npages--;
|
||||||
|
}
|
||||||
|
if (b==7 && r & FS_BCH) {
|
||||||
|
size |= 16;
|
||||||
|
memcpy(flash_buffer+64, bch_parity, 16);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if ((r & FS_Dir) == FS_Erase) {
|
||||||
|
fs.page += (uint16_t) b + 1;
|
||||||
|
fs.npages -= (uint16_t) b + 1;
|
||||||
|
b = 8;
|
||||||
|
}
|
||||||
|
fs.block = b+1;
|
||||||
|
|
||||||
|
uint8_t e = flash_cmd(mode, size, p, (uint16_t)(b&7) << 6);
|
||||||
|
if (e)
|
||||||
|
r |= FS_Ready; // FS_Error
|
||||||
|
r |= FS_Busy;
|
||||||
|
fs.status = r;
|
||||||
|
return e;
|
||||||
|
}
|
||||||
|
|
||||||
|
__attribute__ ((noinline, noclone))
|
||||||
|
uint8_t flash_stream_done()
|
||||||
|
{
|
||||||
|
uint8_t r = fs.status & FS_Error;
|
||||||
|
if (!r || r == FS_Error)
|
||||||
|
return 1;
|
||||||
|
if (fs.npages || !(fs.block & 8))
|
||||||
|
return 0;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline
|
||||||
|
uint8_t flash_write_next_block()
|
||||||
|
{
|
||||||
|
return flash_stream_submit(config.write_buffer, 64);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline
|
||||||
|
uint8_t flash_read_next_block()
|
||||||
|
{
|
||||||
|
uint16_t mode;
|
||||||
|
if (fs.page & 0x1000)
|
||||||
|
mode = config.read_buffer[fs.page&1];
|
||||||
|
else
|
||||||
|
mode = config.read_array;
|
||||||
|
return flash_stream_submit(mode, 64);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline
|
||||||
|
uint8_t flash_erase_next_page()
|
||||||
|
{
|
||||||
|
uint16_t mode = 0x81; // Page Erase
|
||||||
|
uint8_t n = 0;
|
||||||
|
if (fs.page && !(fs.page & 0xff) && fs.npages & 0xff00) {
|
||||||
|
mode = 0x7c; // Sector 1…15 Erase
|
||||||
|
n = 0xff;
|
||||||
|
}
|
||||||
|
else if (!(fs.page & 7) && fs.npages >= 8) {
|
||||||
|
mode = 0x50; // Block Erase
|
||||||
|
n = 7;
|
||||||
|
}
|
||||||
|
fs.block = n;
|
||||||
|
return flash_stream_submit(mode, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline
|
||||||
|
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;
|
||||||
|
if (spi_busy_p()) {
|
||||||
|
if (rr)
|
||||||
|
goto collision;
|
||||||
|
fs.status = r | FS_Busy;
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
if ((r & FS_Error) == FS_Error)
|
||||||
|
return r;
|
||||||
|
if (r & FS_StBsy) {
|
||||||
|
// status bytes arrived
|
||||||
|
if (flash_status_bytes[0] & 0x80)
|
||||||
|
// flash is still busy burning
|
||||||
|
goto rd_status;
|
||||||
|
// not busy any more, move Bsy → Rdy
|
||||||
|
if (r & FS_Busy)
|
||||||
|
r |= FS_Ready;
|
||||||
|
goto ready;
|
||||||
|
}
|
||||||
|
if (!(r & FS_Busy))
|
||||||
|
goto ready;
|
||||||
|
if (rr) {
|
||||||
|
collision:
|
||||||
|
r |= FS_Error;
|
||||||
|
fs.status = r;
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
if (r & FS_Write) {
|
||||||
|
if (fs.block == 9) {
|
||||||
|
rd_status:
|
||||||
|
// request status bytes for pending Write or Error
|
||||||
|
r |= FS_StBsy;
|
||||||
|
fs.status = r;
|
||||||
|
flash_cmd_na(0xd7, 0xff02);
|
||||||
|
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:
|
||||||
|
if (rr)
|
||||||
|
r |= FS_Ack;
|
||||||
|
// clear the Bsy bits
|
||||||
|
r &= ~(FS_Busy | FS_StBsy);
|
||||||
|
fs.status = r;
|
||||||
|
if (r & FS_Dir == FS_Write && fs.block == 8)
|
||||||
|
flash_burn_page();
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
flash_write_next_block();
|
||||||
|
}
|
||||||
|
else if (r & FS_Dir == FS_Erase)
|
||||||
|
flash_erase_next_page();
|
||||||
|
}
|
||||||
|
return fs.status;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t flash_start_stream(uint16_t page, uint16_t npages, uint8_t flags)
|
||||||
|
{
|
||||||
|
uint8_t r = flash_poll(0);
|
||||||
|
if ((r & FS_Error) == FS_Busy)
|
||||||
|
return FS_Error;
|
||||||
|
r = flags | FS_Ready;
|
||||||
|
if (config.flash_page_size != FM_528)
|
||||||
|
r &=~ FS_BCH;
|
||||||
|
fs.page = page;
|
||||||
|
fs.block = 0;
|
||||||
|
fs.npages = npages;
|
||||||
|
fs.status = r;
|
||||||
|
flash_status_bytes[0] = 0xff;
|
||||||
|
return flash_poll(0);
|
||||||
|
}
|
||||||
|
|
|
||||||
54
src/flash.h
54
src/flash.h
|
|
@ -2,23 +2,49 @@
|
||||||
#include "spi.h"
|
#include "spi.h"
|
||||||
|
|
||||||
enum flash_mode_bits {
|
enum flash_mode_bits {
|
||||||
FM_PAD1 = 0x01,
|
FM_PAD1 = 0x0100,
|
||||||
FM_PAD2 = 0x02,
|
FM_PAD2 = 0x0200,
|
||||||
FM_PAD4 = 0x03,
|
FM_PAD4 = 0x0300,
|
||||||
FM_PAD = 0x03,
|
FM_PAD = 0x0300,
|
||||||
FM_512 = 0x04,
|
FM_512 = 0x0400,
|
||||||
FM_528 = 0x08,
|
FM_528 = 0x0800,
|
||||||
FM_SEC = 0x0c,
|
FM_SEC = 0x0c00,
|
||||||
FM_ADDR = 0x0c,
|
FM_ADDR = 0x0c00,
|
||||||
FM_WRITE = 0x10,
|
FM_WRITE = 0x1000,
|
||||||
FM_READ = 0x20,
|
FM_READ = 0x2000,
|
||||||
FM_WAIT = 0x30,
|
FM_WAIT = 0x3000,
|
||||||
FM_START = 0x30,
|
FM_START = 0x3000,
|
||||||
FM_CONT = SPI_CONT,
|
FM_CONT = (uint16_t)SPI_CONT << 8,
|
||||||
FM_SPI = FM_CONT,
|
FM_SPI = FM_CONT,
|
||||||
|
FM_NSTR = 0x8000,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
uint8_t flash_cmd_na(uint16_t mode, uint16_t what);
|
||||||
uint8_t flash_cmd(uint16_t mode, uint16_t what, uint16_t page, uint16_t byte);
|
uint8_t flash_cmd(uint16_t mode, uint16_t what, uint16_t page, uint16_t byte);
|
||||||
#define FB_SIZE 64
|
#define FB_SIZE 80
|
||||||
extern uint8_t flash_buffer[FB_SIZE];
|
extern uint8_t flash_buffer[FB_SIZE];
|
||||||
uint8_t flash_submit_command(uint8_t *cmd);
|
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_poll(uint8_t rr);
|
||||||
|
|
||||||
|
extern
|
||||||
|
struct flash_stream {
|
||||||
|
uint16_t page; // page address of buffer number
|
||||||
|
uint16_t npages; // more pages to read
|
||||||
|
uint8_t block; // next block to read 0…9
|
||||||
|
uint8_t status; // FS_… flags
|
||||||
|
} fs;
|
||||||
|
|
||||||
|
enum {
|
||||||
|
FS_Ready = 1, // ready for the next buffer
|
||||||
|
FS_Busy = 2, // processing …
|
||||||
|
FS_Error = 3, // Aborted
|
||||||
|
FS_Read = 4, // array read
|
||||||
|
FS_Write = 8, // buffer write and burn
|
||||||
|
FS_Erase = 12, // Erase
|
||||||
|
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.
|
||||||
|
};
|
||||||
|
|
||||||
|
|
|
||||||
22
src/pipe.c
Normal file
22
src/pipe.c
Normal file
|
|
@ -0,0 +1,22 @@
|
||||||
|
|
||||||
|
#include <pipe.h>
|
||||||
|
|
||||||
|
struct pipe pipe;
|
||||||
|
|
||||||
|
struct pipe_config {
|
||||||
|
uint8_t source;
|
||||||
|
uint8_t dest;
|
||||||
|
uint16_t npages;
|
||||||
|
uint8_t flash_flags;
|
||||||
|
uint8_t flash_page;
|
||||||
|
};
|
||||||
|
|
||||||
|
uint8_t pipe_config(const uint8_t *, uint8_t flag)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
uint8_t pipe_poll(uint8_t flag)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
20
src/pipe.h
Normal file
20
src/pipe.h
Normal file
|
|
@ -0,0 +1,20 @@
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
uint8_t pipe_config(const uint8_t *, uint8_t flag);
|
||||||
|
uint8_t pipe_poll(uint8_t flag);
|
||||||
|
|
||||||
|
enum pipe_ports {
|
||||||
|
pipe_cmd = 1,
|
||||||
|
pipe_hk = 2,
|
||||||
|
pipe_flash = 4,
|
||||||
|
pipe_fpgs = 8,
|
||||||
|
};
|
||||||
|
|
||||||
|
extern
|
||||||
|
struct pipe {
|
||||||
|
uint8_t source;
|
||||||
|
uint8_t dest;
|
||||||
|
uint8_t status;
|
||||||
|
uint16_t size;
|
||||||
|
} pipe;
|
||||||
Loading…
Add table
Add a link
Reference in a new issue