avr: port analog input sampling + power calculation and implement gd [get delta] command
This commit is contained in:
parent
b63f36cba0
commit
381e235af3
|
@ -42,6 +42,8 @@ extern uint8_t phy_to_log[MAX_SENSORS];
|
||||||
extern volatile struct sensor_struct EEMEM EEPROM_sensor[MAX_SENSORS];
|
extern volatile struct sensor_struct EEMEM EEPROM_sensor[MAX_SENSORS];
|
||||||
extern volatile struct sensor_struct sensor[MAX_SENSORS];
|
extern volatile struct sensor_struct sensor[MAX_SENSORS];
|
||||||
|
|
||||||
|
extern volatile struct state_struct state[MAX_SENSORS];
|
||||||
|
|
||||||
void ctrlInit(void)
|
void ctrlInit(void)
|
||||||
{
|
{
|
||||||
// initialize the CTRL receive buffer
|
// initialize the CTRL receive buffer
|
||||||
|
@ -223,7 +225,7 @@ void ctrlDecode(void)
|
||||||
void ctrlCmdGet(uint8_t cmd)
|
void ctrlCmdGet(uint8_t cmd)
|
||||||
{
|
{
|
||||||
uint8_t i;
|
uint8_t i;
|
||||||
uint32_t tmp32;
|
uint32_t tmp32, tmp32_bis;
|
||||||
|
|
||||||
switch (cmd) {
|
switch (cmd) {
|
||||||
case 'p':
|
case 'p':
|
||||||
|
@ -254,6 +256,24 @@ void ctrlCmdGet(uint8_t cmd)
|
||||||
case 'b':
|
case 'b':
|
||||||
ctrlWriteShortToTxBuffer(event.brown_out);
|
ctrlWriteShortToTxBuffer(event.brown_out);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case 'd':
|
||||||
|
for (i = 0 ; i < MAX_SENSORS; i++) {
|
||||||
|
if (state[i].flags & (STATE_PULSE | STATE_POWER)) {
|
||||||
|
ctrlWriteCharToTxBuffer(i);
|
||||||
|
|
||||||
|
cli();
|
||||||
|
tmp32 = sensor[i].counter;
|
||||||
|
tmp32_bis = (i < 3) ? state[i].power : state[i].timestamp;
|
||||||
|
sei();
|
||||||
|
|
||||||
|
ctrlWriteLongToTxBuffer(tmp32);
|
||||||
|
ctrlWriteLongToTxBuffer(tmp32_bis);
|
||||||
|
|
||||||
|
state[i].flags &= ~(STATE_PULSE | STATE_POWER);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -19,6 +19,8 @@
|
||||||
//
|
//
|
||||||
// $Id$
|
// $Id$
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
#include <avr/io.h>
|
#include <avr/io.h>
|
||||||
#include <avr/interrupt.h>
|
#include <avr/interrupt.h>
|
||||||
#include <avr/eeprom.h>
|
#include <avr/eeprom.h>
|
||||||
|
@ -47,6 +49,11 @@ volatile struct sensor_struct sensor[MAX_SENSORS];
|
||||||
|
|
||||||
volatile struct state_struct state[MAX_SENSORS];
|
volatile struct state_struct state[MAX_SENSORS];
|
||||||
|
|
||||||
|
volatile uint8_t muxn = 0;
|
||||||
|
volatile uint16_t timer = 0;
|
||||||
|
|
||||||
|
volatile struct time_struct time = {0, 0};
|
||||||
|
|
||||||
ISR(SPI_STC_vect)
|
ISR(SPI_STC_vect)
|
||||||
{
|
{
|
||||||
uint8_t spi_rx, rx, tx;
|
uint8_t spi_rx, rx, tx;
|
||||||
|
@ -140,7 +147,39 @@ ISR(SPI_STC_vect)
|
||||||
|
|
||||||
ISR(TIMER1_COMPA_vect)
|
ISR(TIMER1_COMPA_vect)
|
||||||
{
|
{
|
||||||
/* void */
|
uint8_t muxn_l = phy_to_log[muxn];
|
||||||
|
|
||||||
|
MacU16X16to32(state[muxn_l].nano, sensor[muxn_l].meterconst, ADC);
|
||||||
|
|
||||||
|
if (state[muxn_l].nano > WATT) {
|
||||||
|
sensor[muxn_l].counter++;
|
||||||
|
|
||||||
|
state[muxn_l].flags |= STATE_PULSE;
|
||||||
|
state[muxn_l].nano -= WATT;
|
||||||
|
state[muxn_l].pulse_count++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((timer == SECOND) && (muxn == muxn_l)) {
|
||||||
|
state[muxn].nano_start = state[muxn].nano_end;
|
||||||
|
state[muxn].nano_end = state[muxn].nano;
|
||||||
|
state[muxn].pulse_count_final = state[muxn].pulse_count;
|
||||||
|
state[muxn].pulse_count = 0;
|
||||||
|
state[muxn].flags |= STATE_POWER_CALC;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Cycle through the available ADC input channels (0/1/2). */
|
||||||
|
muxn++;
|
||||||
|
if (!(muxn %= 3)) timer++;
|
||||||
|
if (timer > SECOND) timer = 0;
|
||||||
|
|
||||||
|
/* In order to map this to 1000Hz (=ms) we have to skip every second interrupt. */
|
||||||
|
if (!time.skip) time.ms++ ;
|
||||||
|
time.skip ^= 1;
|
||||||
|
|
||||||
|
ADMUX &= 0xF8;
|
||||||
|
ADMUX |= muxn;
|
||||||
|
/* Start a new ADC conversion. */
|
||||||
|
ADCSRA |= (1<<ADSC);
|
||||||
}
|
}
|
||||||
|
|
||||||
ISR(ANALOG_COMP_vect)
|
ISR(ANALOG_COMP_vect)
|
||||||
|
@ -216,8 +255,43 @@ void setup_analog_comparator(void)
|
||||||
ACSR |= (1<<ACBG) | (1<<ACIE) | (1<<ACIS1) | (1<<ACIS0);
|
ACSR |= (1<<ACBG) | (1<<ACIE) | (1<<ACIS1) | (1<<ACIS0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void calculate_power(struct state_struct *pstate)
|
||||||
|
{
|
||||||
|
int32_t rest, power = 0;
|
||||||
|
uint8_t pulse_count;
|
||||||
|
|
||||||
|
cli();
|
||||||
|
rest = pstate->nano_end - pstate->nano_start;
|
||||||
|
pulse_count = pstate->pulse_count_final;
|
||||||
|
sei();
|
||||||
|
|
||||||
|
// Since the AVR has no dedicated floating-point hardware, we need
|
||||||
|
// to resort to fixed-point calculations for converting nWh/s to W.
|
||||||
|
// 1W = 10^6/3.6 nWh/s
|
||||||
|
// value[watt] = 3.6/10^6 * rest[nWh/s]
|
||||||
|
// value[watt] = 3.6/10^6 * 65536 * (rest[nWh/s] / 65536)
|
||||||
|
// value[watt] = 3.6/10^6 * 65536 * 262144 / 262144 * (rest[nWh/s] / 65536)
|
||||||
|
// value[watt] = 61847.53 / 262144 * (rest[nWh/s] / 65536)
|
||||||
|
// We round the constant down to 61847 to prevent 'underflow' in the
|
||||||
|
// consecutive else statement.
|
||||||
|
// The error introduced in the fixed-point rounding equals 8.6*10^-6.
|
||||||
|
MacU16X16to32(power, (uint16_t)(labs(rest)/65536), 61847);
|
||||||
|
power /= 262144;
|
||||||
|
|
||||||
|
if (rest >= 0) {
|
||||||
|
power += pulse_count*3600;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
power = pulse_count*3600 - power;
|
||||||
|
}
|
||||||
|
|
||||||
|
pstate->power = power;
|
||||||
|
}
|
||||||
|
|
||||||
int main(void)
|
int main(void)
|
||||||
{
|
{
|
||||||
|
uint8_t i;
|
||||||
|
|
||||||
// RS-485: Configure PD5=DE as output pin with low as default
|
// RS-485: Configure PD5=DE as output pin with low as default
|
||||||
DDRD |= (1<<DDD5);
|
DDRD |= (1<<DDD5);
|
||||||
// set high to transmit
|
// set high to transmit
|
||||||
|
@ -243,6 +317,14 @@ int main(void)
|
||||||
spi_status &= ~SPI_NEW_CTRL_MSG;
|
spi_status &= ~SPI_NEW_CTRL_MSG;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < 3; i++) {
|
||||||
|
if (state[i].flags & STATE_POWER_CALC) {
|
||||||
|
calculate_power((struct state_struct *)&state[i]);
|
||||||
|
state[i].flags &= ~STATE_POWER_CALC;
|
||||||
|
state[i].flags |= STATE_POWER;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// toggle the LED=PB0 pin
|
// toggle the LED=PB0 pin
|
||||||
_delay_ms(50);
|
_delay_ms(50);
|
||||||
DDRB ^= (1<<PB0);
|
DDRB ^= (1<<PB0);
|
||||||
|
|
|
@ -21,9 +21,13 @@ struct sensor_struct {
|
||||||
uint16_t meterconst;
|
uint16_t meterconst;
|
||||||
};
|
};
|
||||||
|
|
||||||
#define STATE_PULSE = 1
|
# define WATT 1000000000
|
||||||
#define STATE_TOGGLE = 2
|
# define SECOND 666 // 667Hz - 1
|
||||||
#define STATE_POWER = 4
|
|
||||||
|
#define STATE_PULSE 1
|
||||||
|
#define STATE_SKIP 2
|
||||||
|
#define STATE_POWER_CALC 4
|
||||||
|
#define STATE_POWER 8
|
||||||
|
|
||||||
struct state_struct {
|
struct state_struct {
|
||||||
uint8_t flags;
|
uint8_t flags;
|
||||||
|
@ -38,6 +42,11 @@ struct state_struct {
|
||||||
uint32_t timestamp;
|
uint32_t timestamp;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct time_struct {
|
||||||
|
uint8_t skip;
|
||||||
|
uint32_t ms;
|
||||||
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This macro performs a 16x16 -> 32 unsigned MAC in 37 cycles with operands and results in memory
|
* This macro performs a 16x16 -> 32 unsigned MAC in 37 cycles with operands and results in memory
|
||||||
* based on http://www2.ife.ee.ethz.ch/~roggend/publications/wear/DSPMic_v1.1.pdf par 3.4 and table 31.
|
* based on http://www2.ife.ee.ethz.ch/~roggend/publications/wear/DSPMic_v1.1.pdf par 3.4 and table 31.
|
||||||
|
|
|
@ -123,7 +123,7 @@ CDEFS += -DUART_DEFAULT_BAUD_RATE=115200
|
||||||
|
|
||||||
# override default CTRL buffer sizes
|
# override default CTRL buffer sizes
|
||||||
CDEFS += -DCTRL_RX_BUFFER_SIZE=32
|
CDEFS += -DCTRL_RX_BUFFER_SIZE=32
|
||||||
CDEFS += -DCTRL_TX_BUFFER_SIZE=32
|
CDEFS += -DCTRL_TX_BUFFER_SIZE=128
|
||||||
|
|
||||||
# Place -I options here
|
# Place -I options here
|
||||||
CINCS =
|
CINCS =
|
||||||
|
|
Loading…
Reference in New Issue