bbdcc1e623
- main.c: file-header comment describing the hardware and operation, logic split into named phases (sleep_until_interrupt, wake_peripheral_rails, take_counts_snapshot, send_wheel_counts_report, handle_minute_alarm, init_all_hardware); shared state renamed to say what it is and made static. - rfm69.c: reorganized into six labeled sections; cond_1/2/3 and hash scratch globals replaced by a reply_acknowledges() helper with clear locals; packet layout and every init register write documented. - LOG() macro (compiled out when DO_UART is off) replaces the #if DO_UART blocks that obscured the logic. - Drivers: file-header comments; named RTC_REG_*/RTC_ALM_MASK_BIT constants; EEPROM spool scheme documented; ADC_CHANNEL_BANDGAP named; repeated pin if/else helpers collapsed to SET_PIN_TO(). - Removed unused globals/buffers and commented-out code; ran clang-format with the project style. Register writes and radio protocol are byte-identical. Builds clean under -Wall -Wextra on gnu17 and c23; flash 13028 -> 12830 B, static RAM 1038 -> 999 B. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01YVJKatfeMJjAmuH9KYiLuv
73 lines
1.9 KiB
C
73 lines
1.9 KiB
C
#include "adc.h"
|
|
|
|
#define ADC_CONVERSION_TIMEOUT 1000U
|
|
|
|
// The ADC needs a 50-200 kHz clock. At F_CPU = 8 MHz that is a /64 prescaler
|
|
// (125 kHz); the old /2 ran it at 4 MHz, far out of spec.
|
|
#define ADC_PRESCALER_64 ((1 << ADPS2) | (1 << ADPS1))
|
|
|
|
// The 1.1 V bandgap reference needs time to settle after the mux is switched.
|
|
#define ADC_SETTLE_US 200
|
|
|
|
int8_t adc_Initialize(void)
|
|
{
|
|
// REFS VAL_0x01; ADLAR disabled; MUX adc0;
|
|
ADMUX = 0x40;
|
|
|
|
// ACME disabled; ADTS VAL_0x00;
|
|
ADCSRB = 0x00;
|
|
|
|
ADCSRA = (1 << ADEN) | ADC_PRESCALER_64;
|
|
|
|
return 0;
|
|
}
|
|
|
|
void adc_Disable(void) { ADCSRA &= ~(1 << ADEN); }
|
|
|
|
void adc_Enable(void) { ADCSRA |= (1 << ADEN); }
|
|
|
|
void adc_StartConversion(uint8_t channel)
|
|
{
|
|
if (channel == 0) {
|
|
|
|
ADMUX = 0b01000000;
|
|
} else if (channel == ADC_CHANNEL_BANDGAP) {
|
|
// ADMUX=0b01001110;
|
|
ADMUX = (0x01 << REFS0) | (0 << ADLAR) | (0x0e << MUX0);
|
|
} else {
|
|
ADMUX &= ~0x0f;
|
|
ADMUX |= channel;
|
|
}
|
|
_delay_us(ADC_SETTLE_US);
|
|
ADCSRA |= (1 << ADSC);
|
|
}
|
|
|
|
bool adc_IsConversionDone(void) { return ((ADCSRA & (1 << ADIF))); }
|
|
|
|
uint16_t adc_GetConversionResult(void)
|
|
{
|
|
// ADC reads ADCL then ADCH in the right order. Reading the two volatile
|
|
// registers in one expression leaves the order unspecified, and taking ADCH
|
|
// first breaks the data-register lock and corrupts the result.
|
|
return ADC;
|
|
}
|
|
|
|
uint16_t adc_GetConversion(uint8_t channel)
|
|
{
|
|
adc_StartConversion(channel);
|
|
|
|
// A conversion is 13 ADC clocks (~104 us at 125 kHz); bail out rather than
|
|
// hang if the ADC is disabled or its clock is gated off.
|
|
uint16_t attempts = 0;
|
|
while (!adc_IsConversionDone()) {
|
|
if (++attempts > ADC_CONVERSION_TIMEOUT) {
|
|
return 0;
|
|
}
|
|
_delay_us(10);
|
|
}
|
|
|
|
uint16_t res = adc_GetConversionResult();
|
|
ADCSRA |= (1 << ADIF);
|
|
return res;
|
|
}
|