Independent ADC and DAC sample rates

This commit is contained in:
Mark Qvist 2019-01-05 13:47:46 +01:00
parent 8b2e66eb57
commit 79aa4620ba
6 changed files with 78 additions and 47 deletions

View File

@ -22,6 +22,7 @@
#define TX_MAXWAIT 2UL #define TX_MAXWAIT 2UL
// CSMA Settings // CSMA Settings
#define CONFIG_FULL_DUPLEX false // TODO: Actually implement fdx
#define CONFIG_CSMA_P 255 #define CONFIG_CSMA_P 255
// Packet settings // Packet settings

View File

@ -22,6 +22,36 @@ int afsk_putchar(char c, FILE *stream);
// ADC and clock setup // ADC and clock setup
void AFSK_hw_init(void) { void AFSK_hw_init(void) {
// Run ADC initialisation
AFSK_adc_init();
// Run DAC initialisation
AFSK_dac_init();
// Run LED initialisation
LED_TX_INIT();
LED_RX_INIT();
}
void AFSK_dac_init(void) {
// DAC uses all 8 pins of one port,
// so set all to output
DAC_DDR |= 0xFF;
// Set Timer3 to normal operation
TCCR3A = 0;
TCCR3B = _BV(CS10) |
_BV(WGM33)|
_BV(WGM32);
ICR3 = DAC_TICKS_BETWEEN_SAMPLES;
//OCR3A = DAC_TICKS_BETWEEN_SAMPLES;
TIMSK3 = _BV(ICIE3);
}
void AFSK_adc_init(void) {
// Set Timer1 to normal operation // Set Timer1 to normal operation
TCCR1A = 0; TCCR1A = 0;
@ -31,7 +61,7 @@ void AFSK_hw_init(void) {
// Set ICR1 register to the amount of ticks needed between // Set ICR1 register to the amount of ticks needed between
// each sample capture/synthesis // each sample capture/synthesis
ICR1 = TICKS_BETWEEN_SAMPLES; ICR1 = ADC_TICKS_BETWEEN_SAMPLES;
// Set ADMUX register to use external AREF, channel ADC0 // Set ADMUX register to use external AREF, channel ADC0
// and left adjust result // and left adjust result
@ -60,12 +90,6 @@ void AFSK_hw_init(void) {
_BV(ADPS2); // Set ADC prescaler bits to 0b101 = 32 _BV(ADPS2); // Set ADC prescaler bits to 0b101 = 32
// At 20MHz, this gives an ADC clock of 625 KHz // At 20MHz, this gives an ADC clock of 625 KHz
// Run DAC initialisation
AFSK_DAC_INIT();
// Run LED initialisation
LED_TX_INIT();
LED_RX_INIT();
} }
void AFSK_init(Afsk *afsk) { void AFSK_init(Afsk *afsk) {
@ -82,7 +106,7 @@ void AFSK_init(Afsk *afsk) {
fifo_init(&afsk->txFifo, afsk->txBuf, sizeof(afsk->txBuf)); fifo_init(&afsk->txFifo, afsk->txBuf, sizeof(afsk->txBuf));
// Fill delay FIFO with zeroes // Fill delay FIFO with zeroes
for (int i = 0; i<SAMPLESPERBIT / 2; i++) { for (int i = 0; i<ADC_SAMPLESPERBIT / 2; i++) {
fifo_push(&afsk->delayFifo, 0); fifo_push(&afsk->delayFifo, 0);
} }
@ -185,7 +209,7 @@ uint8_t AFSK_dac_isr(Afsk *afsk) {
afsk->txBit <<= 1; afsk->txBit <<= 1;
} }
afsk->sampleIndex = SAMPLESPERBIT; afsk->sampleIndex = DAC_SAMPLESPERBIT;
} }
afsk->phaseAcc += afsk->phaseInc; afsk->phaseAcc += afsk->phaseInc;
@ -375,7 +399,7 @@ void AFSK_adc_isr(Afsk *afsk, int8_t currentSample) {
afsk->iirX[0] = afsk->iirX[1]; afsk->iirX[0] = afsk->iirX[1];
#if CONFIG_SAMPLERATE == 9600 #if CONFIG_ADC_SAMPLERATE == 9600
#if FILTER_CUTOFF == 500 #if FILTER_CUTOFF == 500
#define IIR_GAIN 4 // Really 4.082041675 #define IIR_GAIN 4 // Really 4.082041675
#define IIR_POLE 2 // Really Y[0] * 0.5100490981 #define IIR_POLE 2 // Really Y[0] * 0.5100490981
@ -387,7 +411,7 @@ void AFSK_adc_isr(Afsk *afsk, int8_t currentSample) {
#error Unsupported filter cutoff! #error Unsupported filter cutoff!
#endif #endif
#elif CONFIG_SAMPLERATE == 19200 #elif CONFIG_ADC_SAMPLERATE == 19200
#if FILTER_CUTOFF == 150 #if FILTER_CUTOFF == 150
#define IIR_GAIN 2 // Really 2.172813446e #define IIR_GAIN 2 // Really 2.172813446e
#define IIR_POLE 2 // Really Y[0] * 0.9079534415 #define IIR_POLE 2 // Really Y[0] * 0.9079534415
@ -570,17 +594,21 @@ void AFSK_adc_isr(Afsk *afsk, int8_t currentSample) {
} }
ISR(ADC_vect) { ISR(TIMER3_CAPT_vect) {
TIFR1 = _BV(ICF1);
if (hw_afsk_dac_isr) { if (hw_afsk_dac_isr) {
DAC_PORT = AFSK_dac_isr(AFSK_modem); DAC_PORT = AFSK_dac_isr(AFSK_modem);
LED_TX_ON(); LED_TX_ON();
} else { } else {
// TODO: Enable full duplex if possible
AFSK_adc_isr(AFSK_modem, (ADCH - 128));
DAC_PORT = 127;
LED_TX_OFF(); LED_TX_OFF();
DAC_PORT = 127;
}
}
ISR(ADC_vect) {
TIFR1 = _BV(ICF1);
if (CONFIG_FULL_DUPLEX || !hw_afsk_dac_isr) {
AFSK_adc_isr(AFSK_modem, (ADCH - 128));
} }
++_clock; ++_clock;

View File

@ -38,8 +38,8 @@ inline static uint8_t sinSample(uint16_t i) {
#define CPU_FREQ F_CPU #define CPU_FREQ F_CPU
#define CONFIG_AFSK_RX_BUFLEN CONFIG_SAMPLERATE/150 #define CONFIG_AFSK_RX_BUFLEN CONFIG_ADC_SAMPLERATE/150
#define CONFIG_AFSK_TX_BUFLEN CONFIG_SAMPLERATE/150 #define CONFIG_AFSK_TX_BUFLEN CONFIG_ADC_SAMPLERATE/150
#define CONFIG_AFSK_RXTIMEOUT 0 #define CONFIG_AFSK_RXTIMEOUT 0
#define CONFIG_AFSK_TXWAIT 0UL #define CONFIG_AFSK_TXWAIT 0UL
#define CONFIG_AFSK_PREAMBLE_LEN 150UL #define CONFIG_AFSK_PREAMBLE_LEN 150UL
@ -49,20 +49,24 @@ inline static uint8_t sinSample(uint16_t i) {
#define BITRATE 1200 #define BITRATE 1200
#if BITRATE == 1200 #if BITRATE == 1200
#define CONFIG_SAMPLERATE 9600UL #define CONFIG_ADC_SAMPLERATE 9600UL
#define CONFIG_DAC_SAMPLERATE 19200UL
#elif BITRATE == 2400 #elif BITRATE == 2400
#define CONFIG_SAMPLERATE 19200UL #define CONFIG_ADC_SAMPLERATE 19200UL
#define CONFIG_DAC_SAMPLERATE 38400UL
#endif #endif
#define SAMPLESPERBIT (CONFIG_SAMPLERATE / BITRATE) #define ADC_SAMPLESPERBIT (CONFIG_ADC_SAMPLERATE / BITRATE)
#define TICKS_BETWEEN_SAMPLES ((((CPU_FREQ+FREQUENCY_CORRECTION)) / CONFIG_SAMPLERATE) - 1) #define ADC_TICKS_BETWEEN_SAMPLES ((((CPU_FREQ+FREQUENCY_CORRECTION)) / CONFIG_ADC_SAMPLERATE) - 1)
#define DAC_SAMPLESPERBIT (CONFIG_DAC_SAMPLERATE / BITRATE)
#define DAC_TICKS_BETWEEN_SAMPLES ((((CPU_FREQ+FREQUENCY_CORRECTION)) / CONFIG_DAC_SAMPLERATE) - 1)
// TODO: Maybe revert to only looking at two samples // TODO: Maybe revert to only looking at two samples
#if BITRATE == 1200 #if BITRATE == 1200
#if CONFIG_SAMPLERATE == 19200 #if CONFIG_ADC_SAMPLERATE == 19200
#define SIGNAL_TRANSITIONED(bits) QUAD_XOR((bits), (bits) >> 4) #define SIGNAL_TRANSITIONED(bits) QUAD_XOR((bits), (bits) >> 4)
#elif CONFIG_SAMPLERATE == 9600 #elif CONFIG_ADC_SAMPLERATE == 9600
#define SIGNAL_TRANSITIONED(bits) DUAL_XOR((bits), (bits) >> 2) #define SIGNAL_TRANSITIONED(bits) DUAL_XOR((bits), (bits) >> 2)
#endif #endif
#elif BITRATE == 2400 #elif BITRATE == 2400
@ -73,14 +77,14 @@ inline static uint8_t sinSample(uint16_t i) {
#define PHASE_BITS 8 // Sub-sample phase counter resolution #define PHASE_BITS 8 // Sub-sample phase counter resolution
#define PHASE_INC 1 // Nudge by above resolution for each adjustment #define PHASE_INC 1 // Nudge by above resolution for each adjustment
#define PHASE_MAX (SAMPLESPERBIT * PHASE_BITS) // Size of our phase counter #define PHASE_MAX (ADC_SAMPLESPERBIT * PHASE_BITS) // Size of our phase counter
// TODO: Test which target is best in real world // TODO: Test which target is best in real world
// For 1200, this seems a little better // For 1200, this seems a little better
#if BITRATE == 1200 #if BITRATE == 1200
#if CONFIG_SAMPLERATE == 19200 #if CONFIG_ADC_SAMPLERATE == 19200
#define PHASE_THRESHOLD (PHASE_MAX / 2)+3*PHASE_BITS // Target transition point of our phase window #define PHASE_THRESHOLD (PHASE_MAX / 2)+3*PHASE_BITS // Target transition point of our phase window
#elif CONFIG_SAMPLERATE == 9600 #elif CONFIG_ADC_SAMPLERATE == 9600
#define PHASE_THRESHOLD (PHASE_MAX / 2) // 64 // Target transition point of our phase window #define PHASE_THRESHOLD (PHASE_MAX / 2) // 64 // Target transition point of our phase window
#endif #endif
#elif BITRATE == 2400 #elif BITRATE == 2400
@ -88,8 +92,8 @@ inline static uint8_t sinSample(uint16_t i) {
#endif #endif
#define DCD_TIMEOUT_SAMPLES CONFIG_SAMPLERATE/100 #define DCD_TIMEOUT_SAMPLES CONFIG_ADC_SAMPLERATE/100
#define DCD_MIN_COUNT CONFIG_SAMPLERATE/1600 #define DCD_MIN_COUNT CONFIG_ADC_SAMPLERATE/1600
// TODO: Revamp filtering // TODO: Revamp filtering
#if BITRATE == 1200 #if BITRATE == 1200
@ -155,10 +159,10 @@ typedef struct Afsk
FIFOBuffer delayFifo; // Delayed FIFO for frequency discrimination FIFOBuffer delayFifo; // Delayed FIFO for frequency discrimination
#if BITRATE == 1200 #if BITRATE == 1200
// TODO: Clean this up // TODO: Clean this up
#if CONFIG_SAMPLERATE == 19200 #if CONFIG_ADC_SAMPLERATE == 19200
int8_t delayBuf[SAMPLESPERBIT / 2 + 1]; // Actual data storage for said FIFO int8_t delayBuf[ADC_SAMPLESPERBIT / 2 + 1]; // Actual data storage for said FIFO
#elif CONFIG_SAMPLERATE == 9600 #elif CONFIG_ADC_SAMPLERATE == 9600
int8_t delayBuf[SAMPLESPERBIT / 2 + 1]; // Actual data storage for said FIFO int8_t delayBuf[ADC_SAMPLESPERBIT / 2 + 1]; // Actual data storage for said FIFO
#endif #endif
#elif BITRATE == 2400 #elif BITRATE == 2400
int8_t delayBuf[7 + 1]; // Actual data storage for said FIFO int8_t delayBuf[7 + 1]; // Actual data storage for said FIFO
@ -170,7 +174,7 @@ typedef struct Afsk
int16_t iirX[2]; // IIR Filter X cells int16_t iirX[2]; // IIR Filter X cells
int16_t iirY[2]; // IIR Filter Y cells int16_t iirY[2]; // IIR Filter Y cells
#if SAMPLESPERBIT < 17 #if ADC_SAMPLESPERBIT < 17
uint16_t sampledBits; // Bits sampled by the demodulator (at ADC speed) uint16_t sampledBits; // Bits sampled by the demodulator (at ADC speed)
#else #else
// TODO: Enable error and set up correct size buffers // TODO: Enable error and set up correct size buffers
@ -185,16 +189,12 @@ typedef struct Afsk
} Afsk; } Afsk;
#define DIV_ROUND(dividend, divisor) (((dividend) + (divisor) / 2) / (divisor)) #define DIV_ROUND(dividend, divisor) (((dividend) + (divisor) / 2) / (divisor))
#define MARK_INC (uint16_t)(DIV_ROUND(SIN_LEN * (uint32_t)MARK_FREQ, CONFIG_SAMPLERATE)) #define MARK_INC (uint16_t)(DIV_ROUND(SIN_LEN * (uint32_t)MARK_FREQ, CONFIG_DAC_SAMPLERATE))
#define SPACE_INC (uint16_t)(DIV_ROUND(SIN_LEN * (uint32_t)SPACE_FREQ, CONFIG_SAMPLERATE)) #define SPACE_INC (uint16_t)(DIV_ROUND(SIN_LEN * (uint32_t)SPACE_FREQ, CONFIG_DAC_SAMPLERATE))
#define AFSK_DAC_IRQ_START() do { extern bool hw_afsk_dac_isr; hw_afsk_dac_isr = true; } while (0) #define AFSK_DAC_IRQ_START() do { extern bool hw_afsk_dac_isr; hw_afsk_dac_isr = true; } while (0)
#define AFSK_DAC_IRQ_STOP() do { extern bool hw_afsk_dac_isr; hw_afsk_dac_isr = false; } while (0) #define AFSK_DAC_IRQ_STOP() do { extern bool hw_afsk_dac_isr; hw_afsk_dac_isr = false; } while (0)
// DAC uses all 8 pins of one port, set all pins to
// output direction
#define AFSK_DAC_INIT() do { DAC_DDR |= 0xFF; } while (0)
// Here's some macros for controlling the RX/TX LEDs // Here's some macros for controlling the RX/TX LEDs
// THE _INIT() functions writes to the DDR registers // THE _INIT() functions writes to the DDR registers
// to configure the pins as output pins, and the _ON() // to configure the pins as output pins, and the _ON()
@ -209,6 +209,8 @@ typedef struct Afsk
#define LED_RX_OFF() do { LED_PORT &= ~_BV(2); } while (0) #define LED_RX_OFF() do { LED_PORT &= ~_BV(2); } while (0)
void AFSK_init(Afsk *afsk); void AFSK_init(Afsk *afsk);
void AFSK_adc_init(void);
void AFSK_dac_init(void);
void AFSK_transmit(char *buffer, size_t size); void AFSK_transmit(char *buffer, size_t size);
void AFSK_poll(Afsk *afsk); void AFSK_poll(Afsk *afsk);

View File

@ -4,8 +4,8 @@ uint8_t adcReference = CONFIG_ADC_REF;
uint8_t dacReference = CONFIG_DAC_REF; uint8_t dacReference = CONFIG_DAC_REF;
void VREF_init(void) { void VREF_init(void) {
//DDRD |= _BV(7); // Enable output for OC2A and OC2B (PD7 and PD6)
DDRD = 0xFF; DDRD |= _BV(7) | _BV(6);
TCCR2A = _BV(WGM20) | TCCR2A = _BV(WGM20) |
_BV(WGM21) | _BV(WGM21) |

View File

@ -28,7 +28,7 @@ void kiss_init(AX25Ctx *ax25, Afsk *afsk, Serial *ser) {
} }
// TODO: Remove debug functions // TODO: Remove debug functions
//size_t decodes = 0; // size_t decodes = 0;
void kiss_messageCallback(AX25Ctx *ctx) { void kiss_messageCallback(AX25Ctx *ctx) {
// decodes++; // decodes++;
// printf("%d\r\n", decodes); // printf("%d\r\n", decodes);
@ -60,7 +60,7 @@ void kiss_csma(AX25Ctx *ctx, uint8_t *buf, size_t len) {
} }
} }
while (!sent) { while (!sent) {
if(!channel->hdlc.dcd) { if(CONFIG_FULL_DUPLEX || !channel->hdlc.dcd) {
uint8_t tp = rand() & 0xFF; uint8_t tp = rand() & 0xFF;
if (tp < p) { if (tp < p) {
ax25_sendRaw(ctx, buf, len); ax25_sendRaw(ctx, buf, len);

View File

@ -4,7 +4,7 @@
#include <util/atomic.h> #include <util/atomic.h>
#define DIV_ROUND(dividend, divisor) (((dividend) + (divisor) / 2) / (divisor)) #define DIV_ROUND(dividend, divisor) (((dividend) + (divisor) / 2) / (divisor))
#define CLOCK_TICKS_PER_SEC CONFIG_SAMPLERATE #define CLOCK_TICKS_PER_SEC CONFIG_ADC_SAMPLERATE
typedef int32_t ticks_t; typedef int32_t ticks_t;
typedef int32_t mtime_t; typedef int32_t mtime_t;