Browse Source

All the changes I made on Friday before my computer blew up

git-svn-id: https://bucket.mit.edu/svn/nilm/zoom@6896 ddd99763-3ecb-0310-9145-efcb8ce7c51f
tags/zoom-1.0
jim 15 years ago
parent
commit
c5c949c509
6 changed files with 150 additions and 218 deletions
  1. +29
    -83
      firmware/adc.c
  2. +4
    -9
      firmware/adc.h
  3. +14
    -15
      firmware/adcext.c
  4. +5
    -0
      firmware/config.h
  5. +8
    -5
      firmware/dac.c
  6. +90
    -106
      firmware/zoom.c

+ 29
- 83
firmware/adc.c View File

@@ -2,93 +2,39 @@
#include "adc.h" #include "adc.h"
#include "timer.h" #include "timer.h"
/* Layout of buffer:
adc_dmabuf[x] contains 16 samples of channel AN0
*/
uint16_t adc_dmabuf[16] __attribute__((space(dma)));
/* Currently using software SPI because it's easy.
Consider using hardware SPI with DMA on a timer, though. */
/* Stores the offset of the most recently written DMA sample */
int adc_offset = 0;
#define TRIS_SDATA TRISFbits.TRISF7
#define R_SDATA PORTFbits.RF7
#define TRIS_SCLK TRISFbits.TRISF6
#define LAT_SCLK LATFbits.LATF6
#define TRIS_CS TRISBbits.TRISB2
#define LAT_CS LATBbits.LATB2
void (*adc_adc_callback)(void) = 0;
void (*adc_dma_callback)(void) = 0;
/* ADC1 interrupt after each sample */
void __attribute__((__interrupt__,auto_psv)) _ADC1Interrupt(void)
{
static int next_adc_offset = 0;
adc_offset = next_adc_offset;
/* DMA0STA points to the next sample that will be written.
Convert that into a buffer offset that we'll for next time */
next_adc_offset = (DMA0STA - __builtin_dmaoffset(adc_dmabuf)) >> 1;
IFS0bits.AD1IF = 0;
if (adc_adc_callback)
(*adc_adc_callback)();
}
/* DMA0 interrupt after 16 samples */
void __attribute__((__interrupt__,auto_psv)) _DMA0Interrupt(void)
void adc_init(void)
{ {
IFS0bits.DMA0IF = 0;
if (adc_dma_callback)
(*adc_dma_callback)();
TRIS_SDATA = 1;
LAT_CS = IO_HIGH;
TRIS_CS = 0;
LAT_SCLK = IO_HIGH;
TRIS_SCLK = 0;
} }
/* Initialize ADC1 to constantly DMA AN0. */
void adc_init(void)
uint16_t adc_get(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 = 1; /* ADC interrupt (every sample) */
uint16_t v = 0;
int i;
LAT_CS = 0;
for (i = 0; i < 16; i++) {
if (R_SDATA)
v |= 1;
v <<= 1;
LAT_SCLK = 0;
nop();
LAT_SCLK = 1;
}
LAT_CS = 1;
return v;
} }

+ 4
- 9
firmware/adc.h View File

@@ -1,17 +1,12 @@
#ifndef ADC_H #ifndef ADC_H
#define ADC_H #define ADC_H
/* adc_dmabuf[x] contains 16 samples of channel AN0 */
extern uint16_t adc_dmabuf[16];
#include "config.h"
/* Stores the offset of the most recently written DMA sample */
extern int adc_offset;
/* Initialize internal ADC */
/* Initialize external 12-bit ADC (AD7450R) */
void adc_init(void); void adc_init(void);
/* Callback functions */
extern void (*adc_adc_callback)(void);
extern void (*adc_dma_callback)(void);
/* Trigger conversion and return it */
uint16_t adc_get(void);
#endif #endif

+ 14
- 15
firmware/adcext.c View File

@@ -11,15 +11,12 @@
tie ADC SDI for rate selection, tie /CS low, use BUSY for tie ADC SDI for rate selection, tie /CS low, use BUSY for
interrupt notification if desired */ 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 analog, so use SPI pins:
ADC SDO = PIC SDI1 = RF7
ADC SCK = PIC SCK1 = RF6
*/
#define TRIS_SDO TRISFbits.TRISF7
#define R_SDO PORTFbits.RF7
#define TRIS_SCK TRISFbits.TRISF6
#define LAT_SCK LATFbits.LATF6
#define TRIS_SDO TRISBbits.TRISB5
#define R_SDO PORTBbits.RB5
#define TRIS_SCK TRISBbits.TRISB4
#define LAT_SCK LATBbits.LATB4
#define TRIS_SCS TRISBbits.TRISB3
#define LAT_SCS LATBbits.LATB3
/* Short delays */ /* Short delays */
#define wait_200ns() do { \ #define wait_200ns() do { \
@@ -33,8 +30,10 @@ void adcext_init(void)
int32_t i; int32_t i;
TRIS_SDO = 1; TRIS_SDO = 1;
LAT_SCK = 0;
LAT_SCK = IO_HIGH;
TRIS_SCK = 0; TRIS_SCK = 0;
LAT_SCS = IO_LOW;
TRIS_SCS = 0;
/* Startup delay CS down to SCK high t4 = 5000ns */ /* Startup delay CS down to SCK high t4 = 5000ns */
for (i = 0; i < 5000 / 25; i++) for (i = 0; i < 5000 / 25; i++)
@@ -60,13 +59,13 @@ uint32_t adcext_read(void)
int i; int i;
/* Start conversion by completing previous read */ /* Start conversion by completing previous read */
LAT_SCK = 0;
LAT_SCK = IO_LOW;
/* Wait tKQMAX for SCK down to SDO valid */ /* Wait tKQMAX for SCK down to SDO valid */
wait_200ns(); wait_200ns();
/* Wait for conversion to finish */ /* Wait for conversion to finish */
while (R_SDO == 1)
while (R_SDO == IO_HIGH)
continue; continue;
/* Read it out */ /* Read it out */
@@ -74,7 +73,7 @@ uint32_t adcext_read(void)
for (i = 0; i < 32; i++) { for (i = 0; i < 32; i++) {
/* SCK low tLESCK = 25ns */ /* SCK low tLESCK = 25ns */
wait_25ns(); wait_25ns();
LAT_SCK = 1;
LAT_SCK = IO_HIGH;
/* SCK high tHESCK = 25ns, but /* SCK high tHESCK = 25ns, but
we also have SCK down to SDO valid tKQMAX = 200ns? we also have SCK down to SDO valid tKQMAX = 200ns?
@@ -82,11 +81,11 @@ uint32_t adcext_read(void)
wait_200ns(); wait_200ns();
val <<= 1; val <<= 1;
if (R_SDO)
if (R_SDO == IO_HIGH)
val |= 1; val |= 1;
/* Leave SCK high on final bit to delay new conversion */ /* Leave SCK high on final bit to delay new conversion */
if (i < 31) if (i < 31)
LAT_SCK = 0;
LAT_SCK = IO_LOW;
} }
/* Done */ /* Done */


+ 5
- 0
firmware/config.h View File

@@ -14,6 +14,11 @@ typedef unsigned long long uint64_t;


#define FCY 40000000 #define FCY 40000000


/* define as 0/1 to invert I/O polarity for optocouplers
define as 1/0 for normal polarity */
#define IO_HIGH 0
#define IO_LOW 1

void config_init(void); void config_init(void);


#define nop() __asm("nop") #define nop() __asm("nop")


+ 8
- 5
firmware/dac.c View File

@@ -13,7 +13,7 @@ void dac_init(void)
SPI2CON1bits.SMP = 0; SPI2CON1bits.SMP = 0;
SPI2CON1bits.CKE = 0; SPI2CON1bits.CKE = 0;
SPI2CON1bits.SSEN = 0; SPI2CON1bits.SSEN = 0;
SPI2CON1bits.CKP = 1;
SPI2CON1bits.CKP = IO_HIGH;
SPI2CON1bits.MSTEN = 1; SPI2CON1bits.MSTEN = 1;
SPI2CON1bits.SPRE = 4; SPI2CON1bits.SPRE = 4;
SPI2CON1bits.PPRE = 3; SPI2CON1bits.PPRE = 3;
@@ -21,7 +21,7 @@ void dac_init(void)
/* There's no framed mode that does the normal /* There's no framed mode that does the normal
"chip select" behavior, so control /SS2 manually */ "chip select" behavior, so control /SS2 manually */
SPI2CON2bits.FRMEN = 0; SPI2CON2bits.FRMEN = 0;
LATGbits.LATG9 = 1;
LATGbits.LATG9 = IO_HIGH;
TRISGbits.TRISG9 = 0; TRISGbits.TRISG9 = 0;
SPI2STATbits.SPISIDL = 0; SPI2STATbits.SPISIDL = 0;
@@ -37,10 +37,13 @@ void dac_init(void)
*/ */
void dac_write(uint16_t val) void dac_write(uint16_t val)
{ {
LATGbits.LATG9 = 0;
SPI2BUF = val;
LATGbits.LATG9 = IO_LOW;
if (IO_HIGH == 1)
SPI2BUF = val;
else
SPI2BUF = ~val;
while (!SPI2STATbits.SPIRBF) while (!SPI2STATbits.SPIRBF)
continue; continue;
(void) SPI2BUF; (void) SPI2BUF;
LATGbits.LATG9 = 1;
LATGbits.LATG9 = IO_HIGH;
} }

+ 90
- 106
firmware/zoom.c View File

@@ -22,66 +22,41 @@ uint16_t send_adc, send_dac;


uint16_t dac_cmd = ((uint32_t)DAC_MAX + DAC_MIN) / 2; uint16_t dac_cmd = ((uint32_t)DAC_MAX + DAC_MIN) / 2;


/* 128 KHz, after each ADC sample */
void fast_callback(void)
/* 64 KHz */
void timer(void)
{ {
/* Run at 64 KHz */
static int count = 0; static int count = 0;
if (count++ < 1) return;
count = 0;

/* Get most recent sample. */
uint16_t v = adc_dmabuf[adc_offset];
uint16_t v;
int32_t adjustment;
int32_t newdac;

/* Get most recent sample from 12-bit ADC. */
v = adc_get();

/* Send data to PC at 8 KHz */
if (count++ >= 8) {
count = 0;
/* Send most recent sample and old DAC value */
send_adc = v;
send_dac = dac_cmd;
send_data = 1;
}


#if 1
/* Update DAC. Add whatever is necessary to cause the ADC /* Update DAC. Add whatever is necessary to cause the ADC
to change by 150% towards the center of 0x0800 to change by 150% towards the center of 0x0800
(intentional overshoot to increase slew rate capability) */ (intentional overshoot to increase slew rate capability) */
{
int32_t adjustment = ((int32_t) v - 0x0800) * 1.50 * ADC_DAC_SCALING;
int32_t newdac = dac_cmd + adjustment;
//if (adjustment) {
if (newdac < DAC_MIN)
dac_cmd = DAC_MIN;
else if (newdac > DAC_MAX)
dac_cmd = DAC_MAX;
else
dac_cmd = newdac;
dac_write(dac_cmd);
//}
adjustment = ((int32_t) v - 0x0800) * 1.50 * ADC_DAC_SCALING;
newdac = dac_cmd + adjustment;
if (1 || adjustment) {
if (newdac < DAC_MIN)
dac_cmd = DAC_MIN;
else if (newdac > DAC_MAX)
dac_cmd = DAC_MAX;
else
dac_cmd = newdac;
dac_write(dac_cmd);
} }
#endif
#if 0
/* Update DAC if necessary */
if (v < ADC_BIGMIN && dac_cmd < (DAC_MAX - DAC_BIGSTEP))
dac_cmd += DAC_BIGSTEP;
else if (v < ADC_MIN && dac_cmd < (DAC_MAX - DAC_STEP))
dac_cmd += DAC_STEP;
else if (v > ADC_BIGMAX && dac_cmd > (DAC_MIN + DAC_BIGSTEP))
dac_cmd -= DAC_BIGSTEP;
else if (v > ADC_MAX && dac_cmd > (DAC_MIN + DAC_STEP))
dac_cmd -= DAC_STEP;
else
return;
dac_write(dac_cmd);
#endif
}

/* 8 KHz, after DMA buffer filled */
void slow_callback(void)
{
/* Get most recent sample. */
uint16_t v = adc_dmabuf[adc_offset];

/* Send most recent sample to PC */
send_adc = v;
send_dac = dac_cmd;
send_data = 1;
}

void debug_callback(void)
{
send_adc = adc_dmabuf[adc_offset];
} }


void send_to_pc(void) void send_to_pc(void)
@@ -97,65 +72,74 @@ void send_to_pc(void)
uart1_put((send_dac & 0x007F)); uart1_put((send_dac & 0x007F));
} }


void run_debug(void)
{
uint16_t dac = 32768;
uart1_init(115200);

while (1) {
dac_write(dac);
uart1_put_dec(dac);
uart1_put(' ');
uart1_put_hex16(adc_get());
uart1_crlf();
switch (uart1_get()) {
case '[':
dac--;
break;
case ']':
dac++;
break;
case '-':
dac -= 16;
break;
case '+':
case '=':
dac += 16;
break;
case ',':
case '<':
dac -= 1024;
break;
case '.':
case '>':
dac += 1024;
break;
case '0':
dac = 32768;
break;
}
}
}

void run_normal(void)
{
uart1_init(500000);

while(1) {
if (send_data) {
send_to_pc();
send_data = 0;
}
}
}

int main(void) int main(void)
{ {
int debug = 0;
int i;
config_init(); config_init();
adcext_init(); adcext_init();
dac_init(); dac_init();
adc_init(); adc_init();


if (debug) {
uart1_init(115200);
adc_dma_callback = debug_callback;

uint16_t dac = 32768;
while (1) {
dac_write(dac);
uart1_put_dec(dac);
uart1_put(' ');
uart1_put_dec(send_adc);
uart1_crlf();
switch (uart1_get()) {
case '[':
dac--;
break;
case ']':
dac++;
break;
case '-':
dac -= 16;
break;
case '+':
case '=':
dac += 16;
break;
case ',':
case '<':
dac -= 1024;
break;
case '.':
case '>':
dac += 1024;
break;
case '0':
dac = 32768;
break;
}
}
} else {
uart1_init(500000);

adc_adc_callback = fast_callback;
adc_dma_callback = slow_callback;
/* Pull PGD high internally. If it is externally tied
to ground, run in special debug mode. */
TRISCbits.TRISC13 = 1;
CNPU1bits.CN1PUE = 1;
if (PORTCbits.RC13 == 0)
run_debug();
else
run_normal();


while(1) {
if (send_data) {
send_to_pc();
send_data = 0;
}
}
}
for (;;)
continue;
} }

Loading…
Cancel
Save