mirror of
https://codeberg.org/SiB64/turbo_weather.git
synced 2026-05-01 15:14:22 +02:00
Compare commits
7 commits
82b42966ba
...
7e13f07ada
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7e13f07ada | ||
|
|
e8109f6f5c | ||
|
|
d72beb7218 | ||
|
|
a2a77ae553 | ||
|
|
3a9c3b1741 | ||
|
|
20fa2135e7 | ||
|
|
ec97a8c498 |
6 changed files with 329 additions and 83 deletions
15
src/Makefile
15
src/Makefile
|
|
@ -9,12 +9,11 @@ all: $(PROJ).hex
|
||||||
SN_bate = 1
|
SN_bate = 1
|
||||||
MCU_bate = attiny424
|
MCU_bate = attiny424
|
||||||
C_FILES_bate = uart.c rtc.c spi.c adc.c calib.c mul.c cmd.c
|
C_FILES_bate = uart.c rtc.c spi.c adc.c calib.c mul.c cmd.c
|
||||||
|
S_FILES_bate = uart_tx.S
|
||||||
BATE_PERIOD=76
|
|
||||||
bate_CFLAGS = -DPERIOD=$(BATE_PERIOD)
|
|
||||||
|
|
||||||
MCU = $(MCU_$(PROJ))
|
MCU = $(MCU_$(PROJ))
|
||||||
OPT = -Os
|
# When flash gets tight, use `OPT=-Os`, or use more assembler :-)
|
||||||
|
OPT = -O2
|
||||||
|
|
||||||
CC=avr-gcc -Wall -Wno-parentheses -MMD -std=c99 $(OPT) \
|
CC=avr-gcc -Wall -Wno-parentheses -MMD -std=c99 $(OPT) \
|
||||||
-mmcu=$(MCU) \
|
-mmcu=$(MCU) \
|
||||||
|
|
@ -30,7 +29,8 @@ SN = $(SN_$(PROJ))
|
||||||
CFLAGS = $($*_CFLAGS) $(DEBUG) -I. -DSN="$(SN)"
|
CFLAGS = $($*_CFLAGS) $(DEBUG) -I. -DSN="$(SN)"
|
||||||
|
|
||||||
C_FILES = $(C_FILES_$(PROJ))
|
C_FILES = $(C_FILES_$(PROJ))
|
||||||
OBJS = $(patsubst %.c, %.o, $(C_FILES))
|
S_FILES = $(S_FILES_$(PROJ))
|
||||||
|
OBJS = $(patsubst %.c, %.o, $(C_FILES)) $(patsubst %.S, %.o, $(S_FILES))
|
||||||
|
|
||||||
%.s: %.c %.o
|
%.s: %.c %.o
|
||||||
$(CC) $(CFLAGS) -S $<
|
$(CC) $(CFLAGS) -S $<
|
||||||
|
|
@ -38,6 +38,9 @@ OBJS = $(patsubst %.c, %.o, $(C_FILES))
|
||||||
%.o: %.c
|
%.o: %.c
|
||||||
$(CC) -g $(CFLAGS) -c $<
|
$(CC) -g $(CFLAGS) -c $<
|
||||||
|
|
||||||
|
%.o: %.S
|
||||||
|
$(CC) -g $(CFLAGS) -c $<
|
||||||
|
|
||||||
-include *.d
|
-include *.d
|
||||||
|
|
||||||
LDFLAGS = -Teeprom.ld
|
LDFLAGS = -Teeprom.ld
|
||||||
|
|
@ -102,7 +105,7 @@ ad: $(PROJ).ad
|
||||||
$(AD) -v -t
|
$(AD) -v -t
|
||||||
|
|
||||||
%.burn: %.hex
|
%.burn: %.hex
|
||||||
$(AD) -U flash:w:$<
|
$(AD) -U flash:v:$< || $(AD) -U flash:w:$<
|
||||||
|
|
||||||
%.verify: %.hex %.eeprom
|
%.verify: %.hex %.eeprom
|
||||||
-$(AD) -qq -U fuses:v:"$(fuses_$*)":m
|
-$(AD) -qq -U fuses:v:"$(fuses_$*)":m
|
||||||
|
|
|
||||||
10
src/bate.c
10
src/bate.c
|
|
@ -412,9 +412,9 @@ int main()
|
||||||
|
|
||||||
uint8_t reset_source = RSTCTRL.RSTFR;
|
uint8_t reset_source = RSTCTRL.RSTFR;
|
||||||
RSTCTRL.RSTFR = reset_source;
|
RSTCTRL.RSTFR = reset_source;
|
||||||
send_str("\nV Turbo Weather V0.04\nR ");
|
send_str("\nV Turbo Weather V0.05\nB ");
|
||||||
send_hex_byte(reset_source);
|
send_hex_byte(reset_source);
|
||||||
send_char('\n');
|
send_eol();
|
||||||
|
|
||||||
uint8_t test_calib = config.calib_test;
|
uint8_t test_calib = config.calib_test;
|
||||||
if (test_calib > N_TESTDATA)
|
if (test_calib > N_TESTDATA)
|
||||||
|
|
@ -447,7 +447,7 @@ int main()
|
||||||
send_char('V');
|
send_char('V');
|
||||||
for (uint8_t i=0; i<n_adc; i++)
|
for (uint8_t i=0; i<n_adc; i++)
|
||||||
send_calib_adc(i);
|
send_calib_adc(i);
|
||||||
send_char('\n');
|
send_eol();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -531,12 +531,12 @@ int main()
|
||||||
start_adc();
|
start_adc();
|
||||||
|
|
||||||
if (config.send & SEND_CLOCK) {
|
if (config.send & SEND_CLOCK) {
|
||||||
|
send_str("T 0x");
|
||||||
cli();
|
cli();
|
||||||
uint32_t time = clock;
|
uint32_t time = clock;
|
||||||
sei();
|
sei();
|
||||||
send_str("T 0x");
|
|
||||||
send_hex_long(time);
|
send_hex_long(time);
|
||||||
send_char('\n');
|
send_eol();
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t send_test = 0;
|
uint8_t send_test = 0;
|
||||||
|
|
|
||||||
36
src/cmd.c
36
src/cmd.c
|
|
@ -15,9 +15,8 @@ uint8_t parse_hex_nibble(uint8_t c)
|
||||||
{
|
{
|
||||||
if (c >= '0' && c <= '9')
|
if (c >= '0' && c <= '9')
|
||||||
return c - '0';
|
return c - '0';
|
||||||
c |= 0x20;
|
|
||||||
if (c >= 'a' && c <= 'f')
|
if (c >= 'a' && c <= 'f')
|
||||||
return c - 'a';
|
return c - 'a' + 0x0a;
|
||||||
return 0xf0;
|
return 0xf0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -55,24 +54,31 @@ void parse_command(uint8_t *s, uint8_t n)
|
||||||
rx_params[p++] = (h<<4) | d;
|
rx_params[p++] = (h<<4) | d;
|
||||||
}
|
}
|
||||||
|
|
||||||
const char *m = "R?\n";
|
|
||||||
if (n && *s != '\n')
|
if (n && *s != '\n')
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
||||||
if (cmd == 'C' && p>=2 && rx_params[0] < sizeof(struct config)) {
|
uint8_t *a = (uint8_t *)(((uint16_t)rx_params[0] << 8) | rx_params[1]);
|
||||||
memcpy((uint8_t*)&config + rx_params[0], rx_params+1, p-1);
|
|
||||||
m = "RC!\n";
|
|
||||||
}
|
|
||||||
else if (cmd == 'M' && p==2) {
|
|
||||||
send_str("RM! ");
|
|
||||||
uint16_t a = (uint16_t)rx_params[0] << 8;
|
|
||||||
a |= rx_params[1];
|
|
||||||
send_hex_byte(*(uint8_t*)a);
|
|
||||||
m = "\n";
|
|
||||||
}
|
|
||||||
|
|
||||||
|
if (cmd == 'C' && p >= 2 && rx_params[0] + p <= sizeof(struct config))
|
||||||
|
memcpy((uint8_t*)&config + rx_params[0], rx_params+1, p-1);
|
||||||
|
else if (cmd == 'M' && p==2) {
|
||||||
|
rx_params[2] = *a;
|
||||||
|
p++;
|
||||||
|
}
|
||||||
|
else if (cmd == 'W' && p==3) {
|
||||||
|
rx_params[3] = *a;
|
||||||
|
*a = rx_params[2];
|
||||||
|
p++;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
goto fail;
|
||||||
|
|
||||||
|
send_char('R');
|
||||||
|
send_char('!');
|
||||||
|
send_hex(cmd, rx_params, p, 1);
|
||||||
|
return;
|
||||||
fail:
|
fail:
|
||||||
send_str(m);
|
send_str("R?\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
166
src/uart.c
166
src/uart.c
|
|
@ -58,12 +58,12 @@ uint8_t uart_tick()
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t uart_tx[128];
|
uint8_t uart_tx[128];
|
||||||
|
#define uart_tx_m (sizeof(uart_tx) - 1)
|
||||||
volatile uint8_t uart_tx_w;
|
volatile uint8_t uart_tx_w;
|
||||||
volatile uint8_t uart_tx_r;
|
volatile uint8_t uart_tx_r;
|
||||||
volatile uint8_t uart_tx_busy;
|
volatile uint8_t uart_tx_busy;
|
||||||
static const uint8_t uart_tx_m = sizeof(uart_tx) - 1;
|
|
||||||
|
|
||||||
#if 1
|
#if 0
|
||||||
|
|
||||||
__attribute__ ((noinline, noclone))
|
__attribute__ ((noinline, noclone))
|
||||||
void tx()
|
void tx()
|
||||||
|
|
@ -108,7 +108,7 @@ void tx()
|
||||||
// [STATUS] is prepared in advance, to avoid two branches and one memory load,
|
// [STATUS] is prepared in advance, to avoid two branches and one memory load,
|
||||||
// at the cost of one register on the ISR stack (r25)
|
// at the cost of one register on the ISR stack (r25)
|
||||||
__asm__("\n"
|
__asm__("\n"
|
||||||
" lds r18, uart_tx_r \n"
|
" lds r21, uart_tx_r \n"
|
||||||
" lds r19, uart_tx_w \n"
|
" lds r19, uart_tx_w \n"
|
||||||
" lds r25, %[CTRLA] \n"
|
" lds r25, %[CTRLA] \n"
|
||||||
" andi r25, ~0x20 ; clr DREIE \n"
|
" andi r25, ~0x20 ; clr DREIE \n"
|
||||||
|
|
@ -122,8 +122,8 @@ void tx()
|
||||||
" rjmp 2f \n"
|
" rjmp 2f \n"
|
||||||
" \n"
|
" \n"
|
||||||
"1: \n"
|
"1: \n"
|
||||||
" mov r30, r18 ; \n"
|
" mov r30, r21 ; \n"
|
||||||
" subi r18, 0xff ; r++ & uart_tx_m \n"
|
" subi r21, 0xff ; r++ & uart_tx_m \n"
|
||||||
" andi r30, 0x7f ; \n"
|
" andi r30, 0x7f ; \n"
|
||||||
" ldi r31, 0 \n"
|
" ldi r31, 0 \n"
|
||||||
" subi r30, lo8(-(uart_tx)) \n"
|
" subi r30, lo8(-(uart_tx)) \n"
|
||||||
|
|
@ -133,7 +133,7 @@ void tx()
|
||||||
" ldi r24, 0x40 \n"
|
" ldi r24, 0x40 \n"
|
||||||
" sts %[STATUS], r24 ; clr TXCIF \n"
|
" sts %[STATUS], r24 ; clr TXCIF \n"
|
||||||
"2: \n"
|
"2: \n"
|
||||||
" cp r18, r19 \n"
|
" cp r21, r19 \n"
|
||||||
" breq 3f \n"
|
" breq 3f \n"
|
||||||
" sts uart_tx_busy, r24 ; =0x40 \n"
|
" sts uart_tx_busy, r24 ; =0x40 \n"
|
||||||
" lds r24, %[STATUS] \n"
|
" lds r24, %[STATUS] \n"
|
||||||
|
|
@ -142,12 +142,12 @@ void tx()
|
||||||
" ori r25, 0x60 ; set DREIE TXCIE \n"
|
" ori r25, 0x60 ; set DREIE TXCIE \n"
|
||||||
"3: \n"
|
"3: \n"
|
||||||
" sts %[CTRLA], r25 \n"
|
" sts %[CTRLA], r25 \n"
|
||||||
" sts uart_tx_r, r18 \n"
|
" sts uart_tx_r, r21 \n"
|
||||||
:
|
:
|
||||||
: [STATUS] "n" (&USART0.STATUS),
|
: [STATUS] "n" (&USART0.STATUS),
|
||||||
[CTRLA] "n" (&USART0.CTRLA),
|
[CTRLA] "n" (&USART0.CTRLA),
|
||||||
[TXDATA] "n" (&USART0.TXDATAL)
|
[TXDATA] "n" (&USART0.TXDATAL)
|
||||||
: "r18", "r19",
|
: "r19", "r21",
|
||||||
"r24", "r25",
|
"r24", "r25",
|
||||||
"r30", "r31",
|
"r30", "r31",
|
||||||
"memory"
|
"memory"
|
||||||
|
|
@ -165,8 +165,8 @@ ISR(USART0_DRE_vect, ISR_NAKED)
|
||||||
" in r24, __SREG__ \n"
|
" in r24, __SREG__ \n"
|
||||||
" push r24 \n"
|
" push r24 \n"
|
||||||
" push r25 \n"
|
" push r25 \n"
|
||||||
" push r18 \n"
|
|
||||||
" push r19 \n"
|
" push r19 \n"
|
||||||
|
" push r21 \n"
|
||||||
" push r30 \n"
|
" push r30 \n"
|
||||||
" push r31 \n"
|
" push r31 \n"
|
||||||
" \n"
|
" \n"
|
||||||
|
|
@ -179,12 +179,13 @@ ISR(USART0_DRE_vect, ISR_NAKED)
|
||||||
" \n"
|
" \n"
|
||||||
" pop r31 \n"
|
" pop r31 \n"
|
||||||
" pop r30 \n"
|
" pop r30 \n"
|
||||||
|
" pop r21 \n"
|
||||||
" pop r19 \n"
|
" pop r19 \n"
|
||||||
" pop r18 \n"
|
|
||||||
" pop r25 \n"
|
" pop r25 \n"
|
||||||
" pop r24 \n"
|
" pop r24 \n"
|
||||||
" out __SREG__, r24 \n"
|
" out __SREG__, r24 \n"
|
||||||
" pop r24 \n"
|
" pop r24 \n"
|
||||||
|
" reti \n"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -192,16 +193,92 @@ ISR(USART0_DRE_vect, ISR_NAKED)
|
||||||
|
|
||||||
ISR(USART0_TXC_vect, ISR_ALIASOF(USART0_DRE_vect));
|
ISR(USART0_TXC_vect, ISR_ALIASOF(USART0_DRE_vect));
|
||||||
|
|
||||||
__attribute__ ((noinline, noclone))
|
uint8_t uart_rx[16];
|
||||||
uint8_t uart_busy()
|
#define uart_rx_m (sizeof(uart_rx) - 1)
|
||||||
{
|
|
||||||
cli();
|
|
||||||
tx();
|
|
||||||
sei();
|
|
||||||
return uart_tx_busy;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline
|
volatile uint8_t uart_rx_w;
|
||||||
|
volatile uint8_t uart_rx_mes;
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
ISR(USART0_RXC_vect)
|
||||||
|
{
|
||||||
|
DEBUG_COUNTER(rx_irqs);
|
||||||
|
// s/while/if/ !
|
||||||
|
if (USART0.STATUS & USART_RXCIF_bm) {
|
||||||
|
uint8_t c = USART0.RXDATAL;
|
||||||
|
DEBUG_POKE(rx_char, c);
|
||||||
|
uint8_t w = uart_rx_w;
|
||||||
|
uart_rx[w] = c;
|
||||||
|
if (w < uart_rx_m)
|
||||||
|
uart_rx_w = ++w;
|
||||||
|
if (!uart_rx_mes && c=='\n')
|
||||||
|
uart_rx_mes = w;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
ISR(USART0_RXC_vect, ISR_NAKED)
|
||||||
|
{
|
||||||
|
// The loop will in all cases execute exactly once.
|
||||||
|
// No need to avoid load and stores inside the loop.
|
||||||
|
// The volatileness is also irrelevant, we are the ISR,
|
||||||
|
// nobody else is looking.
|
||||||
|
// We could just have the ISR be called again
|
||||||
|
// in the unusual case there is backlog in the FIFO,
|
||||||
|
// and not loop here.
|
||||||
|
// We may not even need to test the RXCIF bit.
|
||||||
|
// Let's do that …
|
||||||
|
__asm__(
|
||||||
|
" push r24 \n"
|
||||||
|
" in r24, __SREG__ \n"
|
||||||
|
" push r24 \n"
|
||||||
|
" push r30 \n"
|
||||||
|
" push r31 \n"
|
||||||
|
#ifdef DEBUG
|
||||||
|
" lds r24, debug_data + 4 \n"
|
||||||
|
" subi r24, -1 \n"
|
||||||
|
" sts debug_data + 4, r24 \n"
|
||||||
|
#endif
|
||||||
|
" lds r24, %[STATUS] \n"
|
||||||
|
" sbrs r24, %[RXCIF] \n"
|
||||||
|
" rjmp 1f \n"
|
||||||
|
" lds r24, %[RXDATA] \n"
|
||||||
|
" lds r30, uart_rx_w \n"
|
||||||
|
" ldi r31, 0 \n"
|
||||||
|
" subi r30, lo8(-(uart_rx)) \n"
|
||||||
|
" sbci r31, hi8(-(uart_rx)) \n"
|
||||||
|
" st Z+, r24 \n"
|
||||||
|
#ifdef DEBUG
|
||||||
|
" sts debug_data + 5, r24 \n"
|
||||||
|
#endif
|
||||||
|
" subi r30, lo8(uart_rx) \n"
|
||||||
|
" sbrs r30, 4 \n"
|
||||||
|
" sts uart_rx_w, r30 \n"
|
||||||
|
" cpi r24, '\n' \n"
|
||||||
|
" brne 1f \n"
|
||||||
|
" lds r24, uart_rx_mes \n"
|
||||||
|
" tst r24 \n"
|
||||||
|
" brne 1f \n"
|
||||||
|
" sts uart_rx_mes, r30 \n"
|
||||||
|
"1: \n"
|
||||||
|
" pop r31 \n"
|
||||||
|
" pop r30 \n"
|
||||||
|
" pop r24 \n"
|
||||||
|
" out __SREG__, r24 \n"
|
||||||
|
" pop r24 \n"
|
||||||
|
" reti \n"
|
||||||
|
:
|
||||||
|
: [STATUS] "n" (&USART0.STATUS),
|
||||||
|
[RXCIF] "n" (USART_RXCIF_bp),
|
||||||
|
[RXDATA] "n" (&USART0.RXDATAL)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
// These are implemented in `uart_tx.S`
|
||||||
|
|
||||||
|
__attribute__ ((noinline, noclone))
|
||||||
uint8_t uart_put_char(uint8_t c)
|
uint8_t uart_put_char(uint8_t c)
|
||||||
{
|
{
|
||||||
uint8_t r = uart_tx_r;
|
uint8_t r = uart_tx_r;
|
||||||
|
|
@ -245,50 +322,34 @@ void send_str(const char *s)
|
||||||
uart_busy();
|
uart_busy();
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t uart_rx[16];
|
|
||||||
volatile uint8_t uart_rx_w;
|
|
||||||
volatile uint8_t uart_rx_n;
|
|
||||||
static const uint8_t uart_rx_m = sizeof(uart_rx) - 1;
|
|
||||||
volatile uint8_t uart_rx_mes;
|
|
||||||
|
|
||||||
ISR(USART0_RXC_vect)
|
|
||||||
{
|
|
||||||
DEBUG_COUNTER(rx_irqs);
|
|
||||||
uint8_t w = uart_rx_w;
|
|
||||||
uint8_t n = uart_rx_n;
|
|
||||||
while (USART0.STATUS & USART_RXCIF_bm) {
|
|
||||||
uint8_t c = USART0.RXDATAL;
|
|
||||||
uart_rx[w] = c;
|
|
||||||
n++;
|
|
||||||
if (w < uart_rx_m)
|
|
||||||
w++;
|
|
||||||
if (c=='\n')
|
|
||||||
uart_rx_mes = w;
|
|
||||||
DEBUG_POKE(rx_char, c);
|
|
||||||
}
|
|
||||||
uart_rx_w = w;
|
|
||||||
uart_rx_n = n;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline
|
static inline
|
||||||
void rx_dismiss(uint8_t n)
|
void rx_dismiss(uint8_t n)
|
||||||
{
|
{
|
||||||
cli();
|
cli();
|
||||||
uint8_t i = 0;
|
uint8_t i = 0;
|
||||||
uart_rx_mes = 0;
|
uint8_t m = 0;
|
||||||
uint8_t w = uart_rx_w;
|
uint8_t w = uart_rx_w;
|
||||||
if (w != uart_rx_m)
|
if (w != uart_rx_m)
|
||||||
while (n < w) {
|
while (n < w) {
|
||||||
uint8_t c = uart_rx[n++];
|
uint8_t c = uart_rx[n++];
|
||||||
uart_rx[i++] = c;
|
uart_rx[i++] = c;
|
||||||
if (c=='\n')
|
if (!m && c=='\n')
|
||||||
uart_rx_mes = i;
|
m = i;
|
||||||
}
|
}
|
||||||
|
uart_rx_mes = m;
|
||||||
uart_rx_w = i;
|
uart_rx_w = i;
|
||||||
uart_rx_n = i;
|
|
||||||
sei();
|
sei();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
__attribute__ ((noinline, noclone))
|
||||||
|
uint8_t uart_busy()
|
||||||
|
{
|
||||||
|
cli();
|
||||||
|
tx();
|
||||||
|
sei();
|
||||||
|
return uart_tx_busy;
|
||||||
|
}
|
||||||
|
|
||||||
static __attribute__ ((noinline, noclone))
|
static __attribute__ ((noinline, noclone))
|
||||||
void send_hex_nibble(uint8_t b)
|
void send_hex_nibble(uint8_t b)
|
||||||
{
|
{
|
||||||
|
|
@ -312,13 +373,6 @@ void send_hex_word(uint16_t b)
|
||||||
send_hex_byte(b);
|
send_hex_byte(b);
|
||||||
}
|
}
|
||||||
|
|
||||||
__attribute__ ((noinline, noclone))
|
|
||||||
void send_hex_long(uint32_t b)
|
|
||||||
{
|
|
||||||
send_hex_word(b >> 16);
|
|
||||||
send_hex_word(b);
|
|
||||||
}
|
|
||||||
|
|
||||||
__attribute__ ((noinline, noclone))
|
__attribute__ ((noinline, noclone))
|
||||||
void send_hex(uint8_t header, const uint8_t *s, uint8_t n, uint8_t words)
|
void send_hex(uint8_t header, const uint8_t *s, uint8_t n, uint8_t words)
|
||||||
{
|
{
|
||||||
|
|
@ -356,3 +410,5 @@ void command(void)
|
||||||
parse_command(uart_rx, m);
|
parse_command(uart_rx, m);
|
||||||
rx_dismiss(m);
|
rx_dismiss(m);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
|
||||||
18
src/uart.h
18
src/uart.h
|
|
@ -9,10 +9,6 @@
|
||||||
|
|
||||||
void init_uart(uint16_t div, uint8_t mode);
|
void init_uart(uint16_t div, uint8_t mode);
|
||||||
uint8_t uart_tick();
|
uint8_t uart_tick();
|
||||||
void send_char(uint8_t c);
|
|
||||||
void send_str(const char *s);
|
|
||||||
uint8_t uart_busy();
|
|
||||||
void command(void);
|
|
||||||
|
|
||||||
static inline
|
static inline
|
||||||
uint8_t uart_break_p()
|
uint8_t uart_break_p()
|
||||||
|
|
@ -20,10 +16,22 @@ uint8_t uart_break_p()
|
||||||
return !(VPORTB.IN & 0x08);
|
return !(VPORTB.IN & 0x08);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void send_char(uint8_t c);
|
||||||
|
void send_eol();
|
||||||
|
void send_str(const char *s);
|
||||||
void send_hex_byte(uint8_t b);
|
void send_hex_byte(uint8_t b);
|
||||||
void send_hex_word(uint16_t b);
|
void send_hex_word(uint16_t b);
|
||||||
void send_hex_long(uint32_t b);
|
|
||||||
void send_hex(uint8_t header, const uint8_t *s, uint8_t n, uint8_t words);
|
void send_hex(uint8_t header, const uint8_t *s, uint8_t n, uint8_t words);
|
||||||
|
uint8_t uart_busy();
|
||||||
|
void command(void);
|
||||||
|
|
||||||
void send_decimal(uint16_t b, uint8_t dec);
|
void send_decimal(uint16_t b, uint8_t dec);
|
||||||
|
|
||||||
void parse_command(uint8_t *s, uint8_t n);
|
void parse_command(uint8_t *s, uint8_t n);
|
||||||
|
|
||||||
|
static inline
|
||||||
|
void send_hex_long(uint32_t b)
|
||||||
|
{
|
||||||
|
send_hex_word(b >> 16);
|
||||||
|
send_hex_word(b);
|
||||||
|
}
|
||||||
|
|
|
||||||
173
src/uart_tx.S
Normal file
173
src/uart_tx.S
Normal file
|
|
@ -0,0 +1,173 @@
|
||||||
|
// avoid quite a few push and pops and jumps
|
||||||
|
|
||||||
|
.global send_hex_word
|
||||||
|
.global send_hex_byte
|
||||||
|
.global send_char
|
||||||
|
.global send_str
|
||||||
|
.global uart_busy
|
||||||
|
.global send_hex
|
||||||
|
.global send_eol
|
||||||
|
.global command
|
||||||
|
|
||||||
|
// `tx()` and `put_char()` do not gobble r18, r20, r23, r23, r26, and r27.
|
||||||
|
|
||||||
|
put_char:
|
||||||
|
// non-global, non-C
|
||||||
|
// arg: char r22
|
||||||
|
lds r23, uart_tx_r
|
||||||
|
lds r30, uart_tx_w
|
||||||
|
ldi r19, 1
|
||||||
|
add r19, r30
|
||||||
|
eor r23, r19
|
||||||
|
andi r23, 0x7f // uart_tx_m
|
||||||
|
breq 1f
|
||||||
|
andi r30, 0x7f // uart_tx_m
|
||||||
|
ldi r31, 0
|
||||||
|
subi r30, lo8(-(uart_tx))
|
||||||
|
sbci r31, hi8(-(uart_tx))
|
||||||
|
st Z, r22
|
||||||
|
sts uart_tx_w, r19
|
||||||
|
1:
|
||||||
|
// r22 preserved
|
||||||
|
// r23 full when zero
|
||||||
|
ret
|
||||||
|
|
||||||
|
// r18, r20, r26, and 27 must be preseved in the hex functions
|
||||||
|
// r22 and r23 must be preserved in `uart_busy()` and `put_char()'
|
||||||
|
|
||||||
|
send_hex_word:
|
||||||
|
push r24
|
||||||
|
mov r24, r25
|
||||||
|
rcall send_hex_byte
|
||||||
|
pop r24
|
||||||
|
send_hex_byte:
|
||||||
|
push r24
|
||||||
|
swap r24
|
||||||
|
rcall send_hex_nibble
|
||||||
|
pop r24
|
||||||
|
send_hex_nibble:
|
||||||
|
andi r24, 0x0f
|
||||||
|
subi r24, -'0'
|
||||||
|
cpi r24, '9'+1
|
||||||
|
brlo send_char
|
||||||
|
subi r24, '9'+1-'A'
|
||||||
|
|
||||||
|
send_char:
|
||||||
|
mov r22, r24
|
||||||
|
send_char22:
|
||||||
|
rcall put_char
|
||||||
|
rcall uart_busy
|
||||||
|
tst r23
|
||||||
|
brne 9f
|
||||||
|
sleep
|
||||||
|
rjmp send_char22
|
||||||
|
|
||||||
|
2:
|
||||||
|
rcall put_char
|
||||||
|
tst r23
|
||||||
|
brne 1f
|
||||||
|
rcall send_char22
|
||||||
|
1:
|
||||||
|
movw r24, r26
|
||||||
|
send_str:
|
||||||
|
movw r26, r24
|
||||||
|
ld r22, X+
|
||||||
|
tst r22
|
||||||
|
brne 2b
|
||||||
|
uart_busy:
|
||||||
|
cli
|
||||||
|
rcall tx ; gobbles only r19, r21, r24, r25, r30, and r31
|
||||||
|
sei
|
||||||
|
lds r24, uart_tx_busy
|
||||||
|
9:
|
||||||
|
ret
|
||||||
|
|
||||||
|
send_hex:
|
||||||
|
movw r26, r22
|
||||||
|
rcall send_char
|
||||||
|
rjmp 3f
|
||||||
|
|
||||||
|
1:
|
||||||
|
ldi r22, ' '
|
||||||
|
sbrc r18, 0
|
||||||
|
rcall send_char22
|
||||||
|
ld r24, X+
|
||||||
|
sbrs r18, 1
|
||||||
|
rjmp 2f
|
||||||
|
sbrs r20, 0
|
||||||
|
rjmp 2f
|
||||||
|
push r24
|
||||||
|
subi r20, 1
|
||||||
|
ld r24, X+
|
||||||
|
rcall send_hex_byte
|
||||||
|
pop r24
|
||||||
|
2:
|
||||||
|
rcall send_hex_byte
|
||||||
|
3:
|
||||||
|
subi r20, 1
|
||||||
|
brcc 1b
|
||||||
|
send_eol:
|
||||||
|
ldi r22, 10
|
||||||
|
rjmp send_char22
|
||||||
|
|
||||||
|
command:
|
||||||
|
lds r20, uart_rx_mes
|
||||||
|
tst r20
|
||||||
|
breq 9b
|
||||||
|
ldi r22, 'R'
|
||||||
|
rcall send_char22
|
||||||
|
ldi r22, ' '
|
||||||
|
rcall send_char22
|
||||||
|
ldi r26, lo8(uart_rx)
|
||||||
|
ldi r27, hi8(uart_rx)
|
||||||
|
mov r18, r20
|
||||||
|
1:
|
||||||
|
ld r22, X+
|
||||||
|
call send_char22
|
||||||
|
subi r18, 1
|
||||||
|
brcc 1b
|
||||||
|
cpi r22, '\n'
|
||||||
|
breq 2f
|
||||||
|
rcall send_eol
|
||||||
|
clz
|
||||||
|
2:
|
||||||
|
ldi r24, lo8(uart_rx)
|
||||||
|
ldi r25, hi8(uart_rx)
|
||||||
|
mov r22, r20
|
||||||
|
push r20
|
||||||
|
breq 3f
|
||||||
|
rcall parse_command
|
||||||
|
3:
|
||||||
|
pop r24
|
||||||
|
rx_dismiss:
|
||||||
|
cli
|
||||||
|
lds r18, uart_rx_w
|
||||||
|
clr r19
|
||||||
|
clr r20
|
||||||
|
cpi r18, 15
|
||||||
|
brcc 3f
|
||||||
|
sub r18, r24
|
||||||
|
breq 3f
|
||||||
|
brcs 3f // TCNH, n > w
|
||||||
|
ldi r26, lo8(uart_rx)
|
||||||
|
ldi r27, hi8(uart_rx)
|
||||||
|
movw r30, r26
|
||||||
|
add r30, r24
|
||||||
|
adc r31, r1
|
||||||
|
1:
|
||||||
|
ld r25, Z+
|
||||||
|
st X+, r25
|
||||||
|
subi r19, -1
|
||||||
|
cpi r25, '\n'
|
||||||
|
brne 2f
|
||||||
|
tst r20
|
||||||
|
brne 2f
|
||||||
|
mov r20, r19
|
||||||
|
2:
|
||||||
|
cp r19, r18
|
||||||
|
brne 1b
|
||||||
|
3:
|
||||||
|
sts uart_rx_mes, r20
|
||||||
|
sts uart_rx_w, r19
|
||||||
|
sei
|
||||||
|
ret
|
||||||
Loading…
Add table
Add a link
Reference in a new issue