Set up 128 KHz 12-bit ADC sampling with DMA, and send to UART at 0.5 Mbps.
Seems to work well. Next step is to process ADC data at 128 KHz to determine DAC stepping, and send DAC + ADC to PC at 8 KHz. git-svn-id: https://bucket.mit.edu/svn/nilm/zoom@5931 ddd99763-3ecb-0310-9145-efcb8ce7c51f
This commit is contained in:
parent
136fb77276
commit
b95491274d
83
firmware/adc.c
Normal file
83
firmware/adc.c
Normal file
|
@ -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) */
|
||||
}
|
14
firmware/adc.h
Normal file
14
firmware/adc.h
Normal file
|
@ -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
|
|
@ -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();
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
#ifndef ADC_H
|
||||
#define ADC_H
|
||||
#ifndef ADCEXT_H
|
||||
#define ADCEXT_H
|
||||
|
||||
/* Initialize ADC */
|
||||
void adcext_init(void);
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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=
|
||||
|
|
Loading…
Reference in New Issue
Block a user