• AVR Freaks

AnsweredHot!dsPIC33EV256GM002 ADC/DMA issue

Author
mpgmike
Super Member
  • Total Posts : 252
  • Reward points : 0
  • Joined: 2014/01/23 17:27:06
  • Location: NJ
  • Status: offline
2019/05/24 12:53:34 (permalink)
0

dsPIC33EV256GM002 ADC/DMA issue

Credentials: MPLABX v5.15 (had issues trying to compile with the new 5.20), XC16 v1.36b, dsPIC33EV256GM002, Windows 10, ICD4 (tried Snap & PICkit3 also).
 
PGD1, AN0 = Analog. ADC is 12-bit, using DMA to transfer ADC1BUF0 to AdcVal.  I have a 10uF + .1uF cap on Vcap. 4.7k ohms pull-up on !MCLR. This is on a breadboard.
 
I'm trying to get ADC1 to transfer to a variable, AdcVal, through DMA0 and ADC1BUF0. On the Watches Window, I can see:
 
AdcVal       (@ Address 0x1054) = 0x0000 (Test 1), 0x052D (Test 2), 0x0000 (Test 3)
ADC1BUF0 (@ Address 0x300) = 0x000F (Test 1), 0x0018 (Test 2), 0x0045 (Test 3)
 
This is my first dsPIC33 project (and really my first 16-bit project outside learning from "Learning to Fly the PIC24", by Lucio Di Jasio). It's embarrassing to be struggling with a "simple" ADC read!  This is not a school project, I'm 52 years old. I'm new to XC8_16 and dsPIC33 architecture. I've worked with 8-bit PICs using PBP3 for the past 8 years now. Any clues to where I might find answers is appreciated more than you can know. (I hope I commented everything sufficiently.)

#include <xc.h>
#include <stdint.h>
#include "Targs.h"
//#define _XTAL_FREQ 168000000
// FSEC
#pragma config BWRP = OFF // Boot Segment Write-Protect Bit (Boot Segment may be written)
#pragma config BSS = DISABLED // Boot Segment Code-Protect Level bits (No Protection (other than BWRP))
#pragma config BSS2 = OFF // Boot Segment Control Bit (No Boot Segment)
#pragma config GWRP = OFF // General Segment Write-Protect Bit (General Segment may be written)
#pragma config GSS = DISABLED // General Segment Code-Protect Level bits (No Protection (other than GWRP))
#pragma config CWRP = OFF // Configuration Segment Write-Protect Bit (Configuration Segment may be written)
#pragma config CSS = DISABLED // Configuration Segment Code-Protect Level bits (No Protection (other than CWRP))
#pragma config AIVTDIS = DISABLE // Alternate Interrupt Vector Table Disable Bit (Disable Alternate Vector Table)
// FBSLIM
#pragma config BSLIM = 0x1FFF // Boot Segment Code Flash Page Address Limit Bits (Enter Hexadecimal value)
// FOSCSEL
#pragma config FNOSC = FRCPLL // Initial oscillator Source Selection Bits (Internal Fast RC (FRC))
#pragma config IESO = OFF // Two Speed Oscillator Start-Up Bit (Start up device with FRC,then automatically switch to user selected oscillator source)
// FOSC
#pragma config POSCMD = NONE // Primary Oscillator Mode Select Bits (Primary Oscillator disabled)
#pragma config OSCIOFNC = OFF // OSC2 Pin I/O Function Enable Bit (OSC2 is clock output)
#pragma config IOL1WAY = OFF // Peripheral Pin Select Configuration Bit (Allow Multiple reconfigurations)
#pragma config FCKSM = CSDCMD // Clock Switching Mode Bits (Both Clock Switching and Fail-safe Clock Monitor are disabled)
#pragma config PLLKEN = ON // PLL Lock Enable Bit (Clock switch to PLL source will wait until the PLL lock signal is valid)
// FWDT
#pragma config WDTPOST = PS32768 // Watchdog Timer Postscaler Bits (1:32,768)
#pragma config WDTPRE = PR128 // Watchdog Timer Prescaler Bit (1:128)
#pragma config FWDTEN = OFF // Watchdog Timer Enable Bits (WDT and SWDTEN Disabled)
#pragma config WINDIS = OFF // Watchdog Timer Window Enable Bit (Watchdog timer in Non-Window Mode)
#pragma config WDTWIN = WIN25 // Watchdog Window Select Bits (WDT Window is 25% of WDT period)
// FPOR
#pragma config BOREN0 = OFF // Brown Out Reset Detection Bit (BOR is Enabled)
// FICD
#pragma config ICS = PGD1 // ICD Communication Channel Select Bits (Communicate on PGEC1 and PGED1)
// FDMTINTVL
#pragma config DMTIVTL = 0xFFFF // Lower 16 Bits of 32 Bit DMT Window Interval (Enter Hexadecimal value)
// FDMTINTVH
#pragma config DMTIVTH = 0xFFFF // Upper 16 Bits of 32 Bit DMT Window Interval (Enter Hexadecimal value)
// FDMTCNTL
#pragma config DMTCNTL = 0xFFFF // Lower 16 Bits of 32 Bit DMT Instruction Count Time-Out Value (Enter Hexadecimal value)
// FDMTCNTH
#pragma config DMTCNTH = 0xFFFF // Upper 16 Bits of 32 Bit DMT Instruction Count Time-Out Value (Enter Hexadecimal value)
// FDMT
#pragma config DMTEN = DISABLE // Dead Man Timer Enable Bit (Dead Man Timer is Disabled and can be enabled by software)
// FDEVOPT
#pragma config PWMLOCK = OFF // PWM Lock Enable Bit (PWM registers may be written without key sequence)
#pragma config ALTI2C1 = OFF // Alternate I2C1 Pins Selection Bit (I2C1 mapped to SDA1/SCL1 pins)
// FALTREG
#pragma config CTXT1 = NONE // Interrupt Priority Level (IPL) Selection Bits For Alternate Working Register Set 1 (Not Assigned)
#pragma config CTXT2 = NONE // Interrupt Priority Level (IPL) Selection Bits For Alternate Working Register Set 2 (Not Assigned)
uint16_t AdcVal;
void InitMain(void) {
// -=- Oscillator Related SFRs: -=-
OSCCON = 0x0100; //FRC/PLL,
CLKDIV = 0x0000; //Fcy = 1:1
PLLFBD = 0x01FF; //PLL = 513X (Max)
REFOCON = 0x0000; //Ref Clk = 1:1
// -=- PORT Related SFRs: -=-
TRISA = 0x0001; //RA0 = Input
TRISB = 0x000C; //RB3_4 Inputs
LATA = 0x0000;
LATB = 0x0000;
ANSELA = 0x0001; //AN0 = Analog
ANSELB = 0x0000; //All Digital
ODCA = 0; //Open Drain Disabled
ODCB = 0; //Open Drain Disabled
CNPUA = 0; //Weak Pull-Up Disabled
CNPUB = 0; //Weak Pull-Up Disabled
CNPDA = 0; //Weak Pull-Down Disabled
CNPDB = 0; //Weak Pull-Down Disabled
CNENA = 0; //Interrupt on Change Disabled
CNENB = 0; //Interrupt on Change Disabled
// -=- ADC Related SFRs: -=-
AD1CON1 = 0x14E0; //.15=ADON, .12=ADDMABM .10=AD12B, <7:5>=Auto Sample, .1 = SAMP (GO/DONE)
AD1CON2 = 0x0000;
AD1CON3 = 0x8F07; //.15=ADRC, <12:8>=Max Sample Time, <7:0>=4Tad
AD1CON4 = 0x0100; //.8=DMA
AD1CHS123 = 0x0000; //Channel 1 = AN0
AD1CHS0 = 0x0000; //Channel 0 VREF- = Vss, Input = AN0
AD1CSSL = 0x0000; //No Input Scan
//IPC3bits.AD1IP0 = 1;
//Reuslt = ADC1BUF0
// -=- Timer 1 Related SFRs: Used for Interrupt to Trigger ADC Read -=-
T1CON = 0x0034; //.15 = TON
PR1 = 0x1800;
IPC0bits.T1IP = 1;
//IFS0.3 = T1IF
//IEC0.3 = T1IE
//INTCON2.GIE
// -=- DMA1 Related SFRs: -=-
DMA0CON = 0x8023; //.15=CHEN, <5:4>=Peripheral Indirect mode, <1:0>=One-Shot Ping-Pong modes are enabled
DMA0PAD = 0x0300; //ADC1BUF0
DMA0REQ = 0x000D; //ADC1
DMA0CNT = 0; //Only 1 uint16 to transfer
DMA0STAH = 0x0000; //Target address
DMA0STAL = &AdcVal; //Tried 0x1054
DMA0STBH = 0x0000; //Redundant, but doesn't seem to work without it
DMA0STBL = &AdcVal; //Tried 0x1054
// -=- Get Started -=-
Rst = RCON; //Used to determine cause of RESETs
RCON = 0;
INTCON1bits.NSTDIS = 1; //No Interrupt Nesting
AD1CON1bits.ADON = 1; //Turn ADC1 Module ON
int main(void) {
extern uint16_t AdcVal;
InitMain();
TMR1 = 0;
IFS0bits.T1IF = 0;
IEC0bits.T1IE = 1;
T1CONbits.TON = 1;
INTCON2bits.GIE = 1;
while(1) {
}
}
void __attribute__ ((interrupt,no_auto_psv)) _T1Interrupt(void) {
IFS0bits.T1IF = 0; //Clear Timer 1 Interrupt Flag
TMR1 = 0; //Reset Timer 1 Counter
IFS0bits.AD1IF = 0;
IFS0bits.DMA0IF = 0;
AD1CON1bits.DONE = 0;
AD1CON1bits.SAMP = 1; //Start the ADC Conversion
}

 

I don't need the world to know my name, but I want to live a life so all my great-grandchildren proudly remember me.
#1
mpgmike
Super Member
  • Total Posts : 252
  • Reward points : 0
  • Joined: 2014/01/23 17:27:06
  • Location: NJ
  • Status: offline
Re: dsPIC33EV256GM002 ADC/DMA issue 2019/05/26 08:45:04 (permalink)
0
I guess if I don't get an answer, it's probably because I asked the wrong question (or asked the question incorrectly). Here is a more specific approach. For brevity, I omitted the PWM code (except where "Equi[TargCnt] = MDC;" in the Main loop). If I comment everything else out, the PWM & Timer 1 code works flawlessly.  My real issue is the program runs for awhile then quits. I'm getting random INTCON1.STKERR or _ADDRERR on lock-up (viewed in Debug Mode in the Watch Window).
 
My immediate question is, am I properly reading a single ADC value the way it would be done on an 8-bit PIC? If not, what have I missed? (Spent much time reading "16-ADC" in the Reference Manual.)

// --- *** Variable Declarations *** ---
unsigned int Rst; //For Debugging RCON
unsigned int TargCnt;
unsigned int TargVolts;
unsigned int AdcVal;
//uint16_t AdcRot;
const unsigned int TargValH[100] = {4089,4088,4087,...(100 entries)};
const unsigned int TargValE[116] = {240,248,256,265,...(116 entries)};
unsigned int Hyper[100];
unsigned int Equi[116];
struct {
unsigned Dir : 1; //0 = Equi; MDC += 1 || 1 = Hyper; MDC -= 1
} Work;
 
void InitMain(void) {
// -=- Oscillator Related SFRs: -=-
(Same as Previous)
// -=- PORT Related SFRs: -=-
(Same as Previous)
// -=- ADC Related SFRs: -=-
AD1CON1 = 0x04E0; //.15=ADON, .12=ADDMABM .10=AD12B, <7:5>=Auto Sample, .1 = SAMP (GO/DONE)
AD1CON2 = 0x0000;
AD1CON3 = 0x8E00; //.15=ADRC, <12:8>=Max Sample Time, <7:0>=4Tad
AD1CON4 = 0x0100; //.8=DMA
AD1CHS123 = 0x0000; //Channel 1 = AN0
AD1CHS0 = 0x0000; //Channel 0 VREF- = Vss, Input = AN0
AD1CSSL = 0x0000; //No Input Scan
//IPC3bits.AD1IP0 = 1;
//Reuslt = ADC1BUF0
// -=- Timer 1 Related SFRs: Used for Interrupt to Trigger ADC Read -=-
(Same as Previous)
// -=- DMA1 Related SFRs: -=-
(Commented Out)
// -=- Get Started -=-
Rst = RCON; //Used to determine cause of RESETs
RCON = 0;
INTCON1bits.NSTDIS = 1; //No Interrupt Nesting
AD1CON1bits.ADON = 1; //Turn ADC1 Module ON
 
int main(void) {
extern unsigned int TargVolts;
extern unsigned int TargCnt;
extern unsigned int AdcVal;
// extern unsigned int TargValE[116]; //Had to comment these out
// extern unsigned int TargValH[100]; // when I changed them to "const"
extern unsigned int Equi[116];
extern unsigned int Hyper[100];
 
InitMain();
TargCnt = 0;
AdcVal = 0;
TMR1 = 0;
IFS0bits.T1IF = 0;
IEC0bits.T1IE = 1;
T1CONbits.TON = 1;
TargVolts = TargValE[0];
Work.Dir = 0;
AD1CON1bits.DONE = 0;
IFS0bits.AD1IF = 0;
INTCON2bits.GIE = 1;
while(1) {
  if(Work.Dir == 0) {
    if(AdcVal >= TargVolts) {
      Equi[TargCnt] = MDC;
      TargCnt += 1;
      TargVolts = TargValE[TargCnt];
    }
    If((MDC == 0xFFFE) || (TargCnt == 116)) {
      Work.Dir = 1;
      TargCnt = 0;
      MDC = 0xFFFE;
      TargVolts = TargValH[TargCnt];
      }
  }
  else if(Work.Dir == 1) {
    if(AdcVal <= TargVolts) {
      Hyper[TargCnt] = MDC;
      TargCnt += 1;
      TargVolts = TargValH[TargCnt];
      if(TargCnt == 100) {
        IFS0bits.T1IF = 0;
        IEC0bits.T1IE = 0;
        T1CONbits.TON = 0;
        INTCON2bits.GIE = 0;
        LATAbits.LATA1 = 1;
        PTCONbits.PTEN = 0;
        MDC = 0;
        while(1);
        }
      }
    }
  }
}
 
void __attribute__ ((interrupt,no_auto_psv)) _T1Interrupt(void) {
  IFS0bits.T1IF = 0; //Clear Timer 1 Interrupt Flag
  TMR1 = 0; //Reset Timer 1 Counter
  IFS0bits.AD1IF = 0;
  IEC0bits.AD1IE = 1;
  AD1CON1bits.DONE = 0;
  AD1CON1bits.SAMP = 1;
}
 
void __attribute__ ((interrupt,no_auto_psv)) _AD1Interrupt(void) {
  extern unsigned int AdcVal;
  IFS0bits.AD1IF = 0;
  IEC0bits.AD1IE = 0;
  AD1CON1bits.DONE = 0;
  AdcVal = ADC1BUF0;
}

 

I don't need the world to know my name, but I want to live a life so all my great-grandchildren proudly remember me.
#2
Aussie Susan
Super Member
  • Total Posts : 3612
  • Reward points : 0
  • Joined: 2008/08/18 22:20:40
  • Location: Melbourne, Australia
  • Status: offline
Re: dsPIC33EV256GM002 ADC/DMA issue 2019/05/26 19:28:56 (permalink) ☼ Best Answerby mpgmike 2019/05/27 10:07:40
+3 (3)
That is not the correct way to change the OSCCON register. As stated in "Note 1" in the OSCCON register description, you need to execute an unlock procedure. The best way to do that is with the __builtin_write_OSCCONx macros as outlined in the Section 7 of the Family Reference Manual (FRM) on the CPU (check the dMCU's web page under documents for a link). Don't be put off by the reference to the C30 compiler - the macros are in XC16 as well.
You should configure all of the oscillator registers and then initiate the clock switch.
To get things started I would NOT use the ADC interrupts, not trigger the conversion with a timer. In the main loop I would trigger the sampling, block until the conversion is complete and read a value. Then, using the debugger, I would examine the value to make sure that it is what I want.
Once the ADC is reading correctly, then start building back the remaining code that you need.
Susan
#3
mpgmike
Super Member
  • Total Posts : 252
  • Reward points : 0
  • Joined: 2014/01/23 17:27:06
  • Location: NJ
  • Status: offline
Re: dsPIC33EV256GM002 ADC/DMA issue 2019/05/27 07:53:26 (permalink)
0
THANK YOU SUSAN!!! At last, a starting point!

I don't need the world to know my name, but I want to live a life so all my great-grandchildren proudly remember me.
#4
mpgmike
Super Member
  • Total Posts : 252
  • Reward points : 0
  • Joined: 2014/01/23 17:27:06
  • Location: NJ
  • Status: offline
Re: dsPIC33EV256GM002 ADC/DMA issue 2019/05/27 10:07:03 (permalink)
0
I'd been fighting this for 2 weeks!  Susan, you nailed it.  It was an oscillator issue.  Know that you have a not-so-secret admirer from afar (professionally speaking, of course)!  May your winter months be warm & cozy!!  THANK YOU MORE THAN YOU COULD POSSIBLY KNOW!!!
 
I need 16-bit PWM for my current project.  I started with a PIC12F1572, but the resultant PWM frequency was under 200 Hz; too slow.  The dsPIC33EV gave me 2.7 kHz (while it was working) which is right in the range needed.

I don't need the world to know my name, but I want to live a life so all my great-grandchildren proudly remember me.
#5
Jump to:
© 2019 APG vNext Commercial Version 4.5