avr: port analog input sampling + power calculation and implement gd [get delta] command

This commit is contained in:
Bart Van Der Meerssche 2010-12-28 23:23:16 +01:00
parent b63f36cba0
commit 381e235af3
4 changed files with 118 additions and 7 deletions

View File

@ -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 sensor[MAX_SENSORS];
extern volatile struct state_struct state[MAX_SENSORS];
void ctrlInit(void)
{
// initialize the CTRL receive buffer
@ -223,7 +225,7 @@ void ctrlDecode(void)
void ctrlCmdGet(uint8_t cmd)
{
uint8_t i;
uint32_t tmp32;
uint32_t tmp32, tmp32_bis;
switch (cmd) {
case 'p':
@ -254,6 +256,24 @@ void ctrlCmdGet(uint8_t cmd)
case 'b':
ctrlWriteShortToTxBuffer(event.brown_out);
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;
}
}

View File

@ -19,6 +19,8 @@
//
// $Id$
#include <stdlib.h>
#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/eeprom.h>
@ -47,6 +49,11 @@ volatile struct sensor_struct sensor[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)
{
uint8_t spi_rx, rx, tx;
@ -140,7 +147,39 @@ ISR(SPI_STC_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)
@ -216,8 +255,43 @@ void setup_analog_comparator(void)
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)
{
uint8_t i;
// RS-485: Configure PD5=DE as output pin with low as default
DDRD |= (1<<DDD5);
// set high to transmit
@ -242,7 +316,15 @@ int main(void)
ctrlDecode();
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
_delay_ms(50);
DDRB ^= (1<<PB0);

View File

@ -21,9 +21,13 @@ struct sensor_struct {
uint16_t meterconst;
};
#define STATE_PULSE = 1
#define STATE_TOGGLE = 2
#define STATE_POWER = 4
# define WATT 1000000000
# define SECOND 666 // 667Hz - 1
#define STATE_PULSE 1
#define STATE_SKIP 2
#define STATE_POWER_CALC 4
#define STATE_POWER 8
struct state_struct {
uint8_t flags;
@ -38,6 +42,11 @@ struct state_struct {
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
* based on http://www2.ife.ee.ethz.ch/~roggend/publications/wear/DSPMic_v1.1.pdf par 3.4 and table 31.

View File

@ -123,7 +123,7 @@ CDEFS += -DUART_DEFAULT_BAUD_RATE=115200
# override default CTRL buffer sizes
CDEFS += -DCTRL_RX_BUFFER_SIZE=32
CDEFS += -DCTRL_TX_BUFFER_SIZE=32
CDEFS += -DCTRL_TX_BUFFER_SIZE=128
# Place -I options here
CINCS =