mirror of
https://codeberg.org/SiB64/turbo_weather.git
synced 2026-05-01 15:14:22 +02:00
Compare commits
2 commits
8f777af3ba
...
ed12ab2678
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ed12ab2678 | ||
|
|
5fa9fdb00b |
8 changed files with 398 additions and 117 deletions
|
|
@ -8,7 +8,7 @@ all: $(PROJ).hex
|
||||||
|
|
||||||
SN_bate = 1
|
SN_bate = 1
|
||||||
MCU_bate = attiny424
|
MCU_bate = attiny424
|
||||||
C_FILES_bate = uart.c
|
C_FILES_bate = uart.c rtc.c calib.c
|
||||||
|
|
||||||
BATE_PERIOD=76
|
BATE_PERIOD=76
|
||||||
bate_CFLAGS = -DPERIOD=$(BATE_PERIOD)
|
bate_CFLAGS = -DPERIOD=$(BATE_PERIOD)
|
||||||
|
|
|
||||||
295
src/bate.c
295
src/bate.c
|
|
@ -11,34 +11,81 @@
|
||||||
#include <avr/wdt.h>
|
#include <avr/wdt.h>
|
||||||
|
|
||||||
#include "uart.h"
|
#include "uart.h"
|
||||||
|
#include "rtc.h"
|
||||||
|
#include "calib.h"
|
||||||
|
|
||||||
#define Bit(x) (1<<(x))
|
#define Bit(x) (1<<(x))
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// LED on PA5
|
||||||
|
|
||||||
|
#define LED_P VPORTA
|
||||||
|
#define LED_B Bit(5)
|
||||||
|
|
||||||
|
static inline
|
||||||
|
void init_led()
|
||||||
|
{
|
||||||
|
LED_P.DIR |= LED_B;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline
|
||||||
|
void led(uint8_t on)
|
||||||
|
{
|
||||||
|
if (on)
|
||||||
|
LED_P.OUT |= LED_B;
|
||||||
|
else
|
||||||
|
LED_P.OUT &=~ LED_B;
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// RFEN on PB1, enable the LDO to power the RF transmitter
|
||||||
|
|
||||||
|
#define RFEN_P VPORTB
|
||||||
|
#define RFEN_B Bit(1)
|
||||||
|
|
||||||
|
static inline
|
||||||
|
void init_rfen()
|
||||||
|
{
|
||||||
|
RFEN_P.DIR |= RFEN_B;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline
|
||||||
|
void rfen(uint8_t on)
|
||||||
|
{
|
||||||
|
if (on)
|
||||||
|
RFEN_P.OUT |= RFEN_B;
|
||||||
|
else
|
||||||
|
RFEN_P.OUT &=~ RFEN_B;
|
||||||
|
}
|
||||||
|
|
||||||
|
/////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// BATE, read data from an MS5534C pressure sensor
|
||||||
|
|
||||||
#define BATE_PORT PORTA
|
#define BATE_PORT PORTA
|
||||||
#define SCK_PORT 3
|
#define SCK_PORT 3
|
||||||
#define DOUT_PORT 2
|
#define DOUT_PORT 2
|
||||||
#define DIN_PORT 1
|
#define DIN_PORT 1
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
// MCLK timer.
|
||||||
//
|
//
|
||||||
// Timer1 generates a 32768 Hz clock on OC0A, PB0, MCLK_PORT, RES_PORT
|
// The nominal f_{clk_per} is 10 MHz,
|
||||||
|
|
||||||
|
|
||||||
// The nominal f_{clkio} is 9.6 MHz,
|
|
||||||
// f_{MCLK} needs to be 32768 Hz
|
// f_{MCLK} needs to be 32768 Hz
|
||||||
// f_{tick} needs to be 2×f_{MCLK}
|
// f_{tick} needs to be 2×f_{MCLK}
|
||||||
// Timer 1 TOP needs to be f_{clkio}/65536
|
// Timer 1 TOP needs to be f_{clk_per}/65536
|
||||||
|
|
||||||
#ifndef PERIOD
|
#ifndef PERIOD
|
||||||
# define PERIOD 76
|
# define PERIOD 76
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Save the calibrated period in EEPROM
|
// user TCA0 in 16 bit mode. SPLIT mode is also viable.
|
||||||
|
|
||||||
#define MCLK TCA0.SINGLE
|
#define MCLK TCA0.SINGLE
|
||||||
|
|
||||||
static inline
|
static inline
|
||||||
void init_timer(uint8_t p)
|
void init_mclk(uint8_t p)
|
||||||
{
|
{
|
||||||
if (p < 120 || p > 200)
|
if (p < 120 || p > 200)
|
||||||
p = PERIOD;
|
p = PERIOD;
|
||||||
|
|
@ -49,6 +96,21 @@ void init_timer(uint8_t p)
|
||||||
MCLK.CTRLB = TCA_SINGLE_CMP0EN_bm | TCA_SINGLE_WGMODE_FRQ_gc;
|
MCLK.CTRLB = TCA_SINGLE_CMP0EN_bm | TCA_SINGLE_WGMODE_FRQ_gc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline
|
||||||
|
void mclk(uint8_t on)
|
||||||
|
{
|
||||||
|
if (on)
|
||||||
|
MCLK.CTRLA |= TCA_SINGLE_ENABLE_bm;
|
||||||
|
else
|
||||||
|
MCLK.CTRLA &=~ TCA_SINGLE_ENABLE_bm;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline
|
||||||
|
uint8_t mclk_status()
|
||||||
|
{
|
||||||
|
return MCLK.CTRLA & TCA_SINGLE_ENABLE_bm;
|
||||||
|
}
|
||||||
|
|
||||||
volatile uint8_t tick;
|
volatile uint8_t tick;
|
||||||
|
|
||||||
ISR(TCA0_CMP0_vect, ISR_NAKED)
|
ISR(TCA0_CMP0_vect, ISR_NAKED)
|
||||||
|
|
@ -62,29 +124,8 @@ ISR(TCA0_CMP0_vect, ISR_NAKED)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/////////////////////////////////////////////////////////////////////////////
|
union bate bate;
|
||||||
//
|
struct pressure pressure;
|
||||||
// Read data from an MS5534C pressure sensor
|
|
||||||
|
|
||||||
union {
|
|
||||||
uint8_t b[16];
|
|
||||||
uint16_t w[8];
|
|
||||||
struct {
|
|
||||||
uint16_t H[2];
|
|
||||||
uint16_t W[4];
|
|
||||||
uint16_t D[2];
|
|
||||||
};
|
|
||||||
struct {
|
|
||||||
uint16_t H1;
|
|
||||||
uint16_t H2;
|
|
||||||
uint16_t W1;
|
|
||||||
uint16_t W2;
|
|
||||||
uint16_t W3;
|
|
||||||
uint16_t W4;
|
|
||||||
uint16_t D1;
|
|
||||||
uint16_t D2;
|
|
||||||
};
|
|
||||||
} bate;
|
|
||||||
|
|
||||||
__attribute__ ((noinline, noclone))
|
__attribute__ ((noinline, noclone))
|
||||||
static
|
static
|
||||||
|
|
@ -92,52 +133,6 @@ uint8_t bate_bit(uint8_t r, uint8_t c, uint8_t ii)
|
||||||
{
|
{
|
||||||
#if 1
|
#if 1
|
||||||
__asm__(
|
__asm__(
|
||||||
/*
|
|
||||||
; bate.c:136: if (c&ii)
|
|
||||||
and r22,r20 ; _1, ii
|
|
||||||
; bate.c:137: BATE_PORT.OUTSET = Bit(DIN_PORT);
|
|
||||||
ldi r25,lo8(2) ; tmp53,
|
|
||||||
; bate.c:136: if (c&ii)
|
|
||||||
cp r22, __zero_reg__ ; _1
|
|
||||||
breq .L2 ; ,
|
|
||||||
; bate.c:137: BATE_PORT.OUTSET = Bit(DIN_PORT);
|
|
||||||
sts 1029,r25 ; MEM[(struct PORT_t *)1024B].OUTSET, tmp53
|
|
||||||
; bate.c:140: if (BATE_PORT.IN & Bit(DOUT_PORT))
|
|
||||||
lds r25,1032 ; _2, MEM[(struct PORT_t *)1024B].IN
|
|
||||||
; bate.c:140: if (BATE_PORT.IN & Bit(DOUT_PORT))
|
|
||||||
sbrs r25,2 ; _2,
|
|
||||||
rjmp .L4 ;
|
|
||||||
.L7:
|
|
||||||
; bate.c:141: r |= ii;
|
|
||||||
or r24,r20 ; <retval>, ii
|
|
||||||
; bate.c:144: BATE_PORT.OUTSET = Bit(SCK_PORT);
|
|
||||||
ldi r25,lo8(8) ; tmp60,
|
|
||||||
sts 1029,r25 ; MEM[(struct PORT_t *)1024B].OUTSET, tmp60
|
|
||||||
; bate.c:145: BATE_PORT.OUTCLR = Bit(SCK_PORT);
|
|
||||||
sts 1030,r25 ; MEM[(struct PORT_t *)1024B].OUTCLR, tmp60
|
|
||||||
; bate.c:149: }
|
|
||||||
ret
|
|
||||||
.L2:
|
|
||||||
; bate.c:139: BATE_PORT.OUTCLR = Bit(DIN_PORT);
|
|
||||||
sts 1030,r25 ; MEM[(struct PORT_t *)1024B].OUTCLR, tmp55
|
|
||||||
; bate.c:140: if (BATE_PORT.IN & Bit(DOUT_PORT))
|
|
||||||
lds r25,1032 ; _2, MEM[(struct PORT_t *)1024B].IN
|
|
||||||
; bate.c:140: if (BATE_PORT.IN & Bit(DOUT_PORT))
|
|
||||||
sbrc r25,2 ; _2,
|
|
||||||
rjmp .L7 ;
|
|
||||||
.L4:
|
|
||||||
; bate.c:143: r &=~ ii;
|
|
||||||
com r20 ; _4
|
|
||||||
; bate.c:143: r &=~ ii;
|
|
||||||
and r24,r20 ; <retval>, _4
|
|
||||||
; bate.c:144: BATE_PORT.OUTSET = Bit(SCK_PORT);
|
|
||||||
ldi r25,lo8(8) ; tmp60,
|
|
||||||
sts 1029,r25 ; MEM[(struct PORT_t *)1024B].OUTSET, tmp60
|
|
||||||
; bate.c:145: BATE_PORT.OUTCLR = Bit(SCK_PORT);
|
|
||||||
sts 1030,r25 ; MEM[(struct PORT_t *)1024B].OUTCLR, tmp60
|
|
||||||
; bate.c:149: }
|
|
||||||
ret
|
|
||||||
*/
|
|
||||||
"ldi r25, %[DI]" "\n\t"
|
"ldi r25, %[DI]" "\n\t"
|
||||||
"and %[c], %[ii]" "\n\t"
|
"and %[c], %[ii]" "\n\t"
|
||||||
"brne .+6" "\n\t"
|
"brne .+6" "\n\t"
|
||||||
|
|
@ -258,7 +253,6 @@ void bate_wait()
|
||||||
tick = 0;
|
tick = 0;
|
||||||
if (!timeout)
|
if (!timeout)
|
||||||
break;
|
break;
|
||||||
// wdt_reset();
|
|
||||||
timeout--;
|
timeout--;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -296,49 +290,142 @@ void read_bate()
|
||||||
# endif
|
# endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// Configutarion in USERROW
|
||||||
|
|
||||||
|
struct config {
|
||||||
|
uint8_t power;
|
||||||
|
uint8_t send;
|
||||||
|
uint8_t triggers;
|
||||||
|
uint8_t mclk_period;
|
||||||
|
uint16_t baud_div;
|
||||||
|
uint16_t mclk_delay;
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct config *config = (struct config *) & USERROW;
|
||||||
|
|
||||||
|
enum power_flags {
|
||||||
|
POWER_DOWN = 0x01,
|
||||||
|
POWER_DOWN_CLI = 0x02,
|
||||||
|
STOP_MCLK = 0x04,
|
||||||
|
};
|
||||||
|
enum send_flags {
|
||||||
|
SEND_BOOT_MESSAGE = 0x01,
|
||||||
|
SEND_CLOCK = 0x02,
|
||||||
|
SEND_HEX = 0x04,
|
||||||
|
SEND_CALIB = 0x08,
|
||||||
|
};
|
||||||
|
enum trigger_flags {
|
||||||
|
TRIGGER_ONCE = 0x01,
|
||||||
|
TRIGGER_CONT = 0x02,
|
||||||
|
TRIGGER_UART = 0x04,
|
||||||
|
TRIGGER_CLOCK = 0x08,
|
||||||
|
TRIGGER_BREAK = 0x10,
|
||||||
|
};
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// main()
|
||||||
|
|
||||||
int main()
|
int main()
|
||||||
{
|
{
|
||||||
CCP = CCP_IOREG_gc;
|
CCP = CCP_IOREG_gc;
|
||||||
CLKCTRL.MCLKCTRLB = CLKCTRL_PDIV_2X_gc | 1;
|
CLKCTRL.MCLKCTRLB = CLKCTRL_PDIV_2X_gc | 1;
|
||||||
BATE_PORT.DIRSET = Bit(SCK_PORT) | Bit(DIN_PORT);
|
BATE_PORT.DIRSET = Bit(SCK_PORT) | Bit(DIN_PORT);
|
||||||
init_timer(0);
|
init_mclk(config->mclk_period);
|
||||||
|
init_led();
|
||||||
|
init_rfen();
|
||||||
|
init_uart(config->baud_div);
|
||||||
|
init_rtc();
|
||||||
|
|
||||||
// send some MCLKs before we start
|
rfen(1);
|
||||||
uint8_t mclk_delay = 0xff;
|
|
||||||
|
|
||||||
set_sleep_mode(SLEEP_MODE_IDLE);
|
set_sleep_mode(SLEEP_MODE_IDLE);
|
||||||
|
sleep_enable();
|
||||||
|
sei();
|
||||||
|
|
||||||
|
if (config->send & SEND_BOOT_MESSAGE) {
|
||||||
|
send_str("V Turbo Weather V0.01\n");
|
||||||
|
send_hex('S', (uint8_t *)&SIGROW, sizeof(SIGROW_t));
|
||||||
|
send_hex('F', (uint8_t *)&FUSE, sizeof(FUSE_t));
|
||||||
|
send_hex('U', (uint8_t *)&USERROW, sizeof(USERROW_t));
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t trigger = TRIGGER_CONT | TRIGGER_ONCE;
|
||||||
|
uint8_t mclk_delay = config->mclk_delay;
|
||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
sleep_enable();
|
|
||||||
sei();
|
|
||||||
sleep_cpu();
|
sleep_cpu();
|
||||||
|
if (uart_busy()) {
|
||||||
|
uart_tick();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
wdt_reset();
|
||||||
|
|
||||||
|
rfen(0);
|
||||||
|
led(0);
|
||||||
|
|
||||||
|
if (uart_tick())
|
||||||
|
trigger |= TRIGGER_UART;
|
||||||
|
if (uart_break_p())
|
||||||
|
trigger |= TRIGGER_BREAK;
|
||||||
|
if (clock_tick)
|
||||||
|
trigger |= TRIGGER_CLOCK;
|
||||||
|
|
||||||
|
if (!(trigger & config->triggers)) {
|
||||||
|
if (config->power & POWER_DOWN) {
|
||||||
|
mclk(0);
|
||||||
|
if (config->power & POWER_DOWN_CLI)
|
||||||
|
cli();
|
||||||
|
set_sleep_mode(SLEEP_MODE_PWR_DOWN);
|
||||||
|
sleep_enable();
|
||||||
|
sleep_cpu();
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
if (!tick)
|
if (!tick)
|
||||||
continue;
|
continue;
|
||||||
tick = 0;
|
tick = 0;
|
||||||
wdt_reset();
|
|
||||||
|
if (!mclk_status()) {
|
||||||
|
mclk(1);
|
||||||
|
mclk_delay = config->mclk_delay;
|
||||||
|
}
|
||||||
if (mclk_delay) {
|
if (mclk_delay) {
|
||||||
mclk_delay--;
|
mclk_delay--;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
// if (!trigger) {
|
|
||||||
//# ifndef WDT_TRIGGERED
|
|
||||||
// // wait for PCINT on PORT_OUT
|
|
||||||
// continue;
|
|
||||||
//# else
|
|
||||||
// // power down, wait for the WDT
|
|
||||||
// MCUCR = Bit(SE) | SLEEP_MODE_PWR_DOWN;
|
|
||||||
// cli();
|
|
||||||
// sleep_cpu();
|
|
||||||
//# endif
|
|
||||||
// }
|
|
||||||
// trigger = 0;
|
|
||||||
// do a conversion and submit the result to uart()
|
|
||||||
read_bate();
|
|
||||||
sei();
|
|
||||||
send_hex(bate.b, sizeof(bate));
|
|
||||||
send_char_sleep('\n');
|
|
||||||
while (uart_busy())
|
|
||||||
sleep_cpu();
|
|
||||||
|
|
||||||
mclk_delay = 0xff;
|
trigger = TRIGGER_CONT;
|
||||||
|
led(1);
|
||||||
|
rfen(1);
|
||||||
|
cli();
|
||||||
|
uint32_t time = clock;
|
||||||
|
read_bate();
|
||||||
|
if (config->power & STOP_MCLK)
|
||||||
|
mclk(0);
|
||||||
|
sei();
|
||||||
|
set_sleep_mode(SLEEP_MODE_IDLE);
|
||||||
|
sleep_enable();
|
||||||
|
if (config->send & SEND_CLOCK) {
|
||||||
|
send_str("T 0x");
|
||||||
|
send_hex_long(time);
|
||||||
|
send_char_sleep('\n');
|
||||||
|
}
|
||||||
|
if (config->send & SEND_HEX)
|
||||||
|
send_hex('B', bate.b, sizeof(bate));
|
||||||
|
if (config->send & SEND_CALIB) {
|
||||||
|
bate_calib(&bate, &pressure);
|
||||||
|
send_str("P ");
|
||||||
|
send_decimal(pressure.p, 1);
|
||||||
|
send_str(" mbar, ");
|
||||||
|
send_decimal(pressure.T, 1);
|
||||||
|
send_str(" K\n");
|
||||||
|
}
|
||||||
|
uart_tick();
|
||||||
|
clock_tick = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
31
src/calib.c
Normal file
31
src/calib.c
Normal file
|
|
@ -0,0 +1,31 @@
|
||||||
|
//
|
||||||
|
// calib.c
|
||||||
|
//
|
||||||
|
|
||||||
|
// MS5534-CM.pdf
|
||||||
|
// https://media.digikey.com/pdf/Data%20Sheets/Measurement%20Specialties%20PDFs/MS5534-CM.pdf
|
||||||
|
|
||||||
|
#include "calib.h"
|
||||||
|
|
||||||
|
void bate_calib(union bate *bate, struct pressure *pt)
|
||||||
|
{
|
||||||
|
uint16_t C1 = bate->W1 >> 1;
|
||||||
|
uint16_t C5 = (bate->W1 & 1) << 13 | (bate->W2 & 0xffc0) >> 4;
|
||||||
|
uint8_t C6 = bate->W2 & 63;
|
||||||
|
uint16_t C4 = bate->W3 >> 6;
|
||||||
|
uint16_t C3 = bate->W4 >> 6;
|
||||||
|
uint16_t C2 = (bate->W3&63) << 8 | (bate->W4&63) << 2;
|
||||||
|
|
||||||
|
uint16_t D1 = bate->D1;
|
||||||
|
uint16_t D2 = bate->D2;
|
||||||
|
|
||||||
|
uint16_t UT1 = C5 + 20224;
|
||||||
|
int32_t dT = D2-UT1;
|
||||||
|
uint16_t TEMP = ((uint32_t)(dT*(C6 + 50) >> 2) >> 8) + 200;
|
||||||
|
uint16_t OFF = C2 + ((uint32_t)((C4 - 512LL)*dT >> 4) >> 8);
|
||||||
|
uint16_t SENS = C1 + ((uint32_t)(C3*dT >> 2) >> 8) + 24576;
|
||||||
|
uint16_t X = ((uint32_t)(SENS*(D1-7168LL) << 2) >> 16) - OFF;
|
||||||
|
uint16_t P = ((uint32_t)(X*80LL) >> 8) + 2500;
|
||||||
|
pt->T = TEMP - 2732;
|
||||||
|
pt->p = P;
|
||||||
|
}
|
||||||
30
src/calib.h
Normal file
30
src/calib.h
Normal file
|
|
@ -0,0 +1,30 @@
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
// !!! int = int8_t
|
||||||
|
|
||||||
|
union bate {
|
||||||
|
uint8_t b[16];
|
||||||
|
uint16_t w[8];
|
||||||
|
struct {
|
||||||
|
uint16_t H[2];
|
||||||
|
uint16_t W[4];
|
||||||
|
uint16_t D[2];
|
||||||
|
};
|
||||||
|
struct {
|
||||||
|
uint16_t H1;
|
||||||
|
uint16_t H2;
|
||||||
|
uint16_t W1;
|
||||||
|
uint16_t W2;
|
||||||
|
uint16_t W3;
|
||||||
|
uint16_t W4;
|
||||||
|
uint16_t D1;
|
||||||
|
uint16_t D2;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
struct pressure {
|
||||||
|
uint16_t T;
|
||||||
|
uint16_t p;
|
||||||
|
};
|
||||||
|
|
||||||
|
void bate_calib(union bate *bate, struct pressure *pt);
|
||||||
61
src/rtc.c
Normal file
61
src/rtc.c
Normal file
|
|
@ -0,0 +1,61 @@
|
||||||
|
//
|
||||||
|
// rtc.c
|
||||||
|
//
|
||||||
|
|
||||||
|
// !!! int = int8_t
|
||||||
|
|
||||||
|
#include "rtc.h"
|
||||||
|
|
||||||
|
#include <avr/io.h>
|
||||||
|
#include <avr/interrupt.h>
|
||||||
|
#include <avr/sleep.h>
|
||||||
|
|
||||||
|
#define Bit(x) (1<<(x))
|
||||||
|
|
||||||
|
uint32_t clock;
|
||||||
|
uint8_t clock_tick;
|
||||||
|
|
||||||
|
void init_rtc()
|
||||||
|
{
|
||||||
|
RTC.CLKSEL = RTC_CLKSEL_INT1K_gc;
|
||||||
|
RTC.PITINTCTRL = 1;
|
||||||
|
RTC.PITCTRLA = RTC_PERIOD_CYC1024_gc;
|
||||||
|
while (RTC.PITSTATUS & 1) ;
|
||||||
|
RTC.PITCTRLA = RTC_PERIOD_CYC1024_gc | 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if 1
|
||||||
|
ISR(RTC_PIT_vect, ISR_NAKED)
|
||||||
|
{
|
||||||
|
__asm__ ("push r24" "\n\t"
|
||||||
|
"in r24, __SREG__" "\n\t"
|
||||||
|
"push r24" "\n\t"
|
||||||
|
"ldi r24,1" "\n\t"
|
||||||
|
"sts %[tick], r24" "\n\t"
|
||||||
|
"lds r24, %[clock]" "\n\t"
|
||||||
|
"subi r24, -1" "\n\t"
|
||||||
|
"sts %[clock], r24" "\n\t"
|
||||||
|
"lds r24, %[clock]+1" "\n\t"
|
||||||
|
"sbci r24, -1" "\n\t"
|
||||||
|
"sts %[clock]+1, r24" "\n\t"
|
||||||
|
"lds r24, %[clock]+2" "\n\t"
|
||||||
|
"sbci r24, -1" "\n\t"
|
||||||
|
"sts %[clock]+2, r24" "\n\t"
|
||||||
|
"lds r24, %[clock]+3" "\n\t"
|
||||||
|
"sbci r24, -1" "\n\t"
|
||||||
|
"sts %[clock]+3, r24" "\n\t"
|
||||||
|
"pop r24" "\n\t"
|
||||||
|
"out __SREG__, r24" "\n\t"
|
||||||
|
"pop r24" "\n\t"
|
||||||
|
"reti" "\n"
|
||||||
|
:[tick] "+m" (clock_tick),
|
||||||
|
[clock] "+m" (clock)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
ISR(RTC_PIT_vect)
|
||||||
|
{
|
||||||
|
clock_tick = 1;
|
||||||
|
clock++;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
9
src/rtc.h
Normal file
9
src/rtc.h
Normal file
|
|
@ -0,0 +1,9 @@
|
||||||
|
//
|
||||||
|
// rtc.h
|
||||||
|
//
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
extern uint32_t clock;
|
||||||
|
extern uint8_t clock_tick;
|
||||||
|
void init_rtc();
|
||||||
62
src/uart.c
62
src/uart.c
|
|
@ -4,9 +4,8 @@
|
||||||
|
|
||||||
// !!! int = int8_t
|
// !!! int = int8_t
|
||||||
|
|
||||||
#include <uart.h>
|
#include "uart.h"
|
||||||
|
|
||||||
#include <avr/io.h>
|
|
||||||
#include <avr/interrupt.h>
|
#include <avr/interrupt.h>
|
||||||
#include <avr/sleep.h>
|
#include <avr/sleep.h>
|
||||||
|
|
||||||
|
|
@ -15,15 +14,41 @@
|
||||||
// 10 MHz / 2400 / 16 * 64
|
// 10 MHz / 2400 / 16 * 64
|
||||||
#define UART_DIV 16667
|
#define UART_DIV 16667
|
||||||
|
|
||||||
|
__attribute__ ((noinline, noclone))
|
||||||
void init_uart(uint16_t div)
|
void init_uart(uint16_t div)
|
||||||
{
|
{
|
||||||
if (div<64)
|
if (div<64)
|
||||||
div = UART_DIV;
|
div = UART_DIV;
|
||||||
USART0.BAUD = div;
|
USART0.BAUD = div;
|
||||||
PORTB.DIRSET = Bit(2);
|
PORTB.DIRSET = Bit(2);
|
||||||
PORTB.PIN3CTRL = PORT_PULLUPEN_bm;
|
PORTB.PIN3CTRL = PORT_PULLUPEN_bm | PORT_ISC_LEVEL_gc;
|
||||||
USART0.CTRLB = USART_RXEN_bm | USART_TXEN_bm | USART_SFDEN_bm;
|
USART0.CTRLB = USART_RXEN_bm | USART_TXEN_bm;
|
||||||
USART0.CTRLA = USART_RXCIE_bm | USART_RXSIE_bm;
|
USART0.CTRLA = USART_RXCIE_bm;
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint8_t rx_tick;
|
||||||
|
|
||||||
|
ISR(PORTB_PORT_vect, ISR_NAKED)
|
||||||
|
{
|
||||||
|
__asm__ ("push r24" "\n\t"
|
||||||
|
"lds r24,%[stat]" "\n\t"
|
||||||
|
"sts %[tick], r24" "\n\t"
|
||||||
|
"sts %[stat], r24" "\n\t"
|
||||||
|
"pop r24" "\n\t"
|
||||||
|
"reti" "\n"
|
||||||
|
:[tick] "+m" (rx_tick)
|
||||||
|
:[stat] "n" (&VPORTB.INTFLAGS)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
__attribute__ ((noinline, noclone))
|
||||||
|
uint8_t uart_tick()
|
||||||
|
{
|
||||||
|
cli();
|
||||||
|
uint8_t r = rx_tick;
|
||||||
|
rx_tick = 0;
|
||||||
|
sei();
|
||||||
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint8_t uart_tx[64];
|
static uint8_t uart_tx[64];
|
||||||
|
|
@ -57,6 +82,7 @@ uint8_t uart_busy()
|
||||||
return (uart_tx_w - uart_tx_r) & (sizeof(uart_tx) - 1);
|
return (uart_tx_w - uart_tx_r) & (sizeof(uart_tx) - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
__attribute__ ((noinline, noclone))
|
||||||
uint8_t send_char(uint8_t c)
|
uint8_t send_char(uint8_t c)
|
||||||
{
|
{
|
||||||
uint8_t ww = (uart_tx_w+1) & (sizeof(uart_tx)-1);
|
uint8_t ww = (uart_tx_w+1) & (sizeof(uart_tx)-1);
|
||||||
|
|
@ -100,6 +126,7 @@ ISR(USART0_RXC_vect)
|
||||||
uart_rx_n = n;
|
uart_rx_n = n;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
__attribute__ ((noinline, noclone))
|
||||||
void rx_dismiss(uint8_t n)
|
void rx_dismiss(uint8_t n)
|
||||||
{
|
{
|
||||||
cli();
|
cli();
|
||||||
|
|
@ -117,17 +144,32 @@ void rx_dismiss(uint8_t n)
|
||||||
sei();
|
sei();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
__attribute__ ((noinline, noclone))
|
||||||
void send_hex_word(uint16_t b)
|
void send_hex_word(uint16_t b)
|
||||||
{
|
{
|
||||||
send_hex_byte(b >> 8);
|
send_hex_byte(b >> 8);
|
||||||
send_hex_byte(b);
|
send_hex_byte(b);
|
||||||
}
|
}
|
||||||
void send_hex(uint8_t *s, uint8_t n)
|
|
||||||
|
__attribute__ ((noinline, noclone))
|
||||||
|
void send_hex_long(uint32_t b)
|
||||||
{
|
{
|
||||||
|
send_hex_word(b >> 16);
|
||||||
|
send_hex_word(b);
|
||||||
|
}
|
||||||
|
|
||||||
|
__attribute__ ((noinline, noclone))
|
||||||
|
void send_hex(uint8_t header, uint8_t *s, uint8_t n)
|
||||||
|
{
|
||||||
|
send_char_sleep(header);
|
||||||
|
send_char_sleep(' ');
|
||||||
while (n--)
|
while (n--)
|
||||||
send_hex_byte(*(s++));
|
send_hex_byte(*(s++));
|
||||||
|
send_char_sleep('\n');
|
||||||
}
|
}
|
||||||
void send_decimal(uint16_t b)
|
|
||||||
|
__attribute__ ((noinline, noclone))
|
||||||
|
void send_decimal(uint16_t b, uint8_t dec)
|
||||||
{
|
{
|
||||||
uint8_t c[5];
|
uint8_t c[5];
|
||||||
uint8_t n = 0;
|
uint8_t n = 0;
|
||||||
|
|
@ -137,8 +179,12 @@ void send_decimal(uint16_t b)
|
||||||
c[n++] = b - bbb + '0';
|
c[n++] = b - bbb + '0';
|
||||||
b = bb;
|
b = bb;
|
||||||
}
|
}
|
||||||
if (!n)
|
if (n <= dec)
|
||||||
send_char('0');
|
send_char('0');
|
||||||
|
while (n-->dec)
|
||||||
|
send_char(c[n]);
|
||||||
|
if (dec)
|
||||||
|
send_char('.');
|
||||||
while (n--)
|
while (n--)
|
||||||
send_char(c[n]);
|
send_char(c[n]);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
27
src/uart.h
27
src/uart.h
|
|
@ -3,9 +3,10 @@
|
||||||
//
|
//
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
#include <avr/io.h>
|
||||||
|
|
||||||
void init_uart(uint16_t div);
|
void init_uart(uint16_t div);
|
||||||
extern uint8_t portb_flags;
|
uint8_t uart_tick();
|
||||||
uint8_t uart_busy();
|
uint8_t uart_busy();
|
||||||
uint8_t send_char(uint8_t c);
|
uint8_t send_char(uint8_t c);
|
||||||
void send_char_sleep(uint8_t c);
|
void send_char_sleep(uint8_t c);
|
||||||
|
|
@ -14,16 +15,32 @@ extern uint8_t uart_rx_n;
|
||||||
extern uint8_t uart_rx_m;
|
extern uint8_t uart_rx_m;
|
||||||
void rx_dismiss(uint8_t n);
|
void rx_dismiss(uint8_t n);
|
||||||
|
|
||||||
|
static inline
|
||||||
|
uint8_t uart_break_p()
|
||||||
|
{
|
||||||
|
return VPORTB.IN & 0x08;
|
||||||
|
}
|
||||||
|
|
||||||
static inline void send_hex_nibble(uint8_t b)
|
static inline
|
||||||
|
void send_hex_nibble(uint8_t b)
|
||||||
{
|
{
|
||||||
send_char_sleep(b<10 ? b+'0' : b+'A'-'9'+1);
|
send_char_sleep(b<10 ? b+'0' : b+'A'-'9'+1);
|
||||||
}
|
}
|
||||||
static inline void send_hex_byte(uint8_t b)
|
static inline
|
||||||
|
void send_hex_byte(uint8_t b)
|
||||||
{
|
{
|
||||||
send_hex_nibble(b >> 4);
|
send_hex_nibble(b >> 4);
|
||||||
send_hex_nibble(b & 0xf);
|
send_hex_nibble(b & 0xf);
|
||||||
}
|
}
|
||||||
|
|
||||||
void send_hex_word(uint16_t b);
|
void send_hex_word(uint16_t b);
|
||||||
void send_hex(uint8_t *s, uint8_t n);
|
void send_hex_long(uint32_t b);
|
||||||
void send_decimal(uint16_t b);
|
void send_hex(uint8_t header, uint8_t *s, uint8_t n);
|
||||||
|
void send_decimal(uint16_t b, uint8_t dec);
|
||||||
|
|
||||||
|
static inline
|
||||||
|
void send_str(char *s)
|
||||||
|
{
|
||||||
|
while (*s)
|
||||||
|
send_char_sleep(*s++);
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue