diff --git a/firmware/adc.c b/firmware/adc.c new file mode 100644 index 0000000..8bdf8af --- /dev/null +++ b/firmware/adc.c @@ -0,0 +1,83 @@ +#include "config.h" +#include "adc.h" +#include "timer.h" + +/* Layout of buffer: + adc_dmabuf[x] contains 16 samples of channel AN0 +*/ +uint16_t adc_dmabuf[16] __attribute__((space(dma))); + +void (*adc_adc_callback)(void) = 0; +void (*adc_dma_callback)(void) = 0; + +/* ADC1 interrupt after each sample (if enabled) */ +void __attribute__((__interrupt__,auto_psv)) _ADC1Interrupt(void) +{ + if (adc_adc_callback) + (*adc_adc_callback)(); + IFS0bits.AD1IF = 0; +} + +/* DMA0 interrupt after 16 samples */ +void __attribute__((__interrupt__,auto_psv)) _DMA0Interrupt(void) +{ + if (adc_dma_callback) + (*adc_dma_callback)(); + IFS0bits.DMA0IF = 0; +} + +/* Initialize ADC1 to constantly DMA AN0. */ +void adc_init(void) +{ + /* AD1CON1 */ + AD1CON1bits.ADDMABM = 1; /* Scatter-gather DMA */ + AD1CON1bits.AD12B = 1; /* 12-bit, 1 channel */ + AD1CON1bits.FORM = 0; /* Integer output 0000dddddddddddd */ + AD1CON1bits.SSRC = 2; /* Convert on Timer3 */ + AD1CON1bits.ASAM = 1; /* Automatically start sampling */ + AD1CON1bits.SIMSAM = 0; /* Simul sampling, N/A when AD12B=1 */ + + /* AD1CON2 */ + AD1CON2bits.VCFG = 0; /* Ref: AVDD / AVSS */ +// AD1CON2bits.VCFG = 3; /* Ref: VREF+ / VREF- */ + AD1CON2bits.CSCNA = 0; /* Do not scan inputs on Mux A */ + AD1CON2bits.CHPS = 0; /* Convert CH0 only, N/A when AD12B=1 */ + AD1CON2bits.SMPI = 0; /* Increase DMA address at each sample */ + AD1CON2bits.BUFM = 0; /* Fill buffer from start */ + AD1CON2bits.ALTS = 0; /* Always use Mux A settings */ + + /* AD1CON3 */ + AD1CON3bits.ADRC = 0; /* Use system clock, not internal RC */ + AD1CON3bits.SAMC = 0; /* Sample time, N/A when ADRC = 0 */ + AD1CON3bits.ADCS = 0x7; /* Tad = 8 * Tcy */ + + /* AD1CON4 */ + AD1CON4bits.DMABL = 4; /* Each input gets 16 words in DMA buf */ + + /* Channel 0 setup */ + AD1CHS0bits.CH0NA = 0; /* CH0-: Vrefl */ + AD1CHS0bits.CH0SA = 0; /* CH0+: AN0 */ + + /* Set Timer3 to trigger conversion at 128KHz */ + timer_setup_16bit(3, 128000, 0); + + /* Turn it on */ + AD1PCFGL = 0xfffe; /* Analog = AN0 */ + AD1PCFGH = 0xffff; + AD2PCFGL = 0xffff; + AD1CON1bits.ADON = 1; + + /* DMA0 setup */ + DMA0CONbits.AMODE = 0; /* Register indirect, post-increment */ + DMA0CONbits.MODE = 0; /* Continuous, no ping-pong */ + DMA0PAD = (int)&ADC1BUF0; /* Get addresses from ADC1 */ + DMA0CNT = 15; /* 16 transfers before wraparound */ + DMA0STA = __builtin_dmaoffset(&adc_dmabuf); + DMA0REQbits.IRQSEL = 13; /* Triggered by ADC1 */ + IFS0bits.DMA0IF = 0; + IEC0bits.DMA0IE = 1; /* DMA interrupt (every 16 samples) */ + DMA0CONbits.CHEN = 1; /* enable this DMA channel */ + + IFS0bits.AD1IF = 0; + IEC0bits.AD1IE = 0; /* No ADC interrupt (every sample) */ +} diff --git a/firmware/adc.h b/firmware/adc.h new file mode 100644 index 0000000..bba82c5 --- /dev/null +++ b/firmware/adc.h @@ -0,0 +1,14 @@ +#ifndef ADC_H +#define ADC_H + +/* DMA region for the ADC */ +extern uint16_t adc_dmabuf[16]; + +/* Initialize internal ADC */ +void adc_init(void); + +/* Callback functions */ +extern void (*adc_adc_callback)(void); +extern void (*adc_dma_callback)(void); + +#endif diff --git a/firmware/adcext.c b/firmware/adcext.c index 916ae6d..6da2f4d 100644 --- a/firmware/adcext.c +++ b/firmware/adcext.c @@ -12,7 +12,7 @@ interrupt notification if desired */ /* Since the ADC is 5v, ADC SDO must be on a digital-only pin. - All exposed pins on B D and E are digital, so use SPI pins: + All exposed pins on B D and E are analog, so use SPI pins: ADC SDO = PIC SDI1 = RF7 ADC SCK = PIC SCK1 = RF6 */ @@ -30,16 +30,22 @@ /* Initialize ADC */ void adcext_init(void) { - int i; + int32_t i; TRIS_SDO = 1; LAT_SCK = 0; TRIS_SCK = 0; - + /* Startup delay CS down to SCK high t4 = 5000ns */ for (i = 0; i < 5000 / 25; i++) wait_25ns(); + /* We need to monitor BUSY, I think. With the 2-wire + interface, we never know if we start in the middle of + a data output phase. For now, consider reading broken.. + just return early. XXXX */ + return; + /* Trigger a dummy read so we're prepared for the next conversion */ (void) adcext_read(); @@ -118,7 +124,7 @@ void adcext_start_conversion(void) LAT_SCK = 0; /* Wait tKQMAX for SCK down to SDO valid in case we - call adc_is_conversion_finished right away. */ + call adcext_is_conversion_ready right away. */ wait_200ns(); } diff --git a/firmware/adcext.h b/firmware/adcext.h index 8b113fc..eb308aa 100644 --- a/firmware/adcext.h +++ b/firmware/adcext.h @@ -1,5 +1,5 @@ -#ifndef ADC_H -#define ADC_H +#ifndef ADCEXT_H +#define ADCEXT_H /* Initialize ADC */ void adcext_init(void); diff --git a/firmware/config.h b/firmware/config.h index fb63bfa..38a7652 100644 --- a/firmware/config.h +++ b/firmware/config.h @@ -13,7 +13,6 @@ typedef signed long long int64_t; typedef unsigned long long uint64_t; #define FCY 40000000 -#define TMR1_RATE 8000 void config_init(void); diff --git a/firmware/uart.c b/firmware/uart.c index 288a215..aa5aa87 100644 --- a/firmware/uart.c +++ b/firmware/uart.c @@ -12,7 +12,7 @@ void uart_init(int uart, int32_t rate) if (uart == 1) { U1MODE = 0; - U1MODEbits.BRGH = 0; + U1MODEbits.BRGH = 0; // errata: BRGH=1 is broken U1BRG = brg; U1STA = 0; U1MODEbits.UARTEN = 1; diff --git a/firmware/zoom.c b/firmware/zoom.c index 7466494..a73007b 100644 --- a/firmware/zoom.c +++ b/firmware/zoom.c @@ -1,39 +1,37 @@ #include "config.h" #include "adc.h" +#include "adcext.h" #include "dac.h" #include "uart.h" #include "timer.h" #include <stdio.h> #include <math.h> -int32_t tmr1_ms = 0; -void TISR_HANDLER(1) +int new_data = 0; +uint16_t data; + +void callback(void) { + /* Send most recent sample to PC */ + data = adc_dmabuf[15]; + new_data = 1; } int main(void) { config_init(); - uart1_init(1000000); + uart1_init(500000); adcext_init(); dac_init(); - timer_setup_16bit(1, 1000, 1); - - TRISDbits.TRISD0 = 0; - TRISDbits.TRISD1 = 1; - TRISDbits.TRISD2 = 1; + adc_init(); + adc_dma_callback = callback; while(1) { - /* these are ints, so it should be atomic */ -/* - tmp = output_count; - tmp2 = dacval; - - uart1_put_hex((tmp & 0x7F) | (LATDbits.LATD0 ? 0x80 : 0x00)); - uart1_put_hex((tmp2 & 0xFF00) >> 8); - uart1_put_hex((tmp2 & 0x00FF)); - uart1_put('\r'); -*/ + if (new_data) { + uart1_put_hex16(data); + uart1_crlf(); + new_data = 0; + } } for(;;) continue; diff --git a/firmware/zoom.mcp b/firmware/zoom.mcp index 4d3822c..b6b477b 100644 --- a/firmware/zoom.mcp +++ b/firmware/zoom.mcp @@ -31,6 +31,8 @@ file_010=no file_011=no file_012=no file_013=no +file_014=no +file_015=no [FILE_INFO] file_000=zoom.c file_001=config.c @@ -39,13 +41,15 @@ file_003=util.c file_004=dac.c file_005=timer.c file_006=adcext.c -file_007=config.h -file_008=uart.h -file_009=util.h -file_010=dac.h -file_011=timer.h -file_012=adcext.h -file_013=p33fj256gp710.gld +file_007=adc.c +file_008=config.h +file_009=uart.h +file_010=util.h +file_011=dac.h +file_012=timer.h +file_013=adcext.h +file_014=adc.h +file_015=p33fj256gp710.gld [SUITE_INFO] suite_guid={479DDE59-4D56-455E-855E-FFF59A3DB57E} suite_state=