Cell PhonesComputersConsumer ElectronicsGraphic Design & Video EditingHome Theater & AudioIndustrial TechnologyInternet

How to Use ADCs in dspic30f and dspic33f

Updated on June 12, 2017
alikhan3 profile image

The author is currently doing his final year engineering project with the dspic micro-controllers.

The dsPic devices offer a powerful ADC (Analogue to Digital Converter) module which can sample at speeds up to 1 Msps. It can be used in variety of different ways and modes to suite the needs of your project.

This tutorial is aimed at teaching the basics of A/D conversion modules to all those who are beginning their projects with the dsPics.

dsPic30f4011 micro-controller along-with its programmer.
dsPic30f4011 micro-controller along-with its programmer. | Source

How to Give Input to the ADC

The first step is to set up the required hardware to give input to the ADC.

Sampling a DC signal:

For initial testing you may use a potentiometer connected across a 5 V supply and give input to the ADC analogue pins directly.

Sampling an AC Signal with ADC:

To sample an AC signal (line voltages or currents), you will have to:

  1. Step down the signal to the required voltage level with the help of transformers.
  2. Level-shift the signal so that negative values below zero are shifted up. The ADCs in Pics are not able to sample negative signals.

This reference circuit design may help you with the level shifting circuits:

Sampling an AC signal with ADC. (Gain of Op-amp may be tuned through the variable resistor to achieve an output in the range of 0 - 5V, I however use a value of 2.7 kOhms in its place.)(Click to enlarge).
Sampling an AC signal with ADC. (Gain of Op-amp may be tuned through the variable resistor to achieve an output in the range of 0 - 5V, I however use a value of 2.7 kOhms in its place.)(Click to enlarge). | Source

Testing the ADC

After setting up the required code and hardware, their must be a way to test if the ADC is actually sampling correctly in the required way or not. Since you cannot peek inside the MCU to see if all things are going correctly, I suggest two ways:

  1. You can connect a debugger with the Pic like the one pictured above. In debug mode you can check the value in registers ADCBUF0 through 10 to see if they are being loaded with correctly sampled values.
  2. You can send the values of ADCBUF register thorough UART and monitor them on a PC with the help of serial monitor.

ADC Example Code for dsPic

#include "xc.h"

#define FCY 20000000
#define FPWM 3600

#include <xc.h>
#include <stdio.h>
#include <delay.h>
#include <libpic30.h>
#include <dsp.h>
#include <math.h>

_FOSC( CSW_FSCM_OFF & XT_PLL8 ); // External Oscillator, PLLx8
_FWDT( WDT_OFF );                // Watchdog timer off
_FBORPOR( MCLR_DIS );            // Disable reset

int ADCValue;

void init_ADC( void )
{
    TRISB = 0xFFFF;   //Set as Input Port
    ADPCFG = 0x0000;  //Selecting all analogue pins to analogue mode
    
    ADCHSbits.CH0SA = 1;
    ADCHSbits.CH0NA = 0;
    //ADCHSbits.CH123SA = 0;
    //ADCHSbits.CH123NA = 0;
     
    IEC0bits.ADIE = 1;       //Enable ADC Interrupt       
    IPC2bits.ADIP = 1;       //set interrupt priorty-6  
                    
    ADCSSLbits.CSSL0 = 0;    //Skip input scan for analoge pin AN0,AN1,AN2
    ADCSSLbits.CSSL1 = 0;
    ADCSSLbits.CSSL2 = 0;
     
    ADCON3bits.SAMC = 0;     //Auto sample time 6TAD//max sample time
    ADCON3bits.ADRC = 0;     //selecting Conversion clock source derived from system clock
    ADCON3bits.ADCS = 9;     //Selecting conversion clock 6Tcy
     
    ADCON1bits.ADSIDL = 0;   //Selecting continue mode operation in idle mode
    ADCON1bits.FORM = 1;     //Selecting data output in signed integer format
    ADCON1bits.SSRC = 0;     //Selecting Motor Control PWM interval ends sampling and starts conversion
    ADCON1bits.SIMSAM = 0;   // Samples CH0, CH1, CH2, CH3 simultaneously 
    ADCON1bits.ASAM = 0;     //Selecting Sampling begins immediately after last conversion completes. SAMP bit is auto set
    ADCON1bits.SAMP = 0;     // At least one A/D sample/hold amplifier is sampling
     
    ADCON2bits.VCFG = 0;     //Voltage Reference Configuration bits
    ADCON2bits.CSCNA = 0;    //Disable input scan
    ADCON2bits.CHPS  = 0;    //Selecting conversion channel CH0
    ADCON2bits.SMPI = 0;     //Selecting 1 conversion sample per interrupt
    ADCON2bits.ALTS = 0;     //Uses MUX A input multiplexer settings
    ADCON2bits.BUFM = 0;     // Buffer configured as one 16-word buffer ADCBUF(15...0)
     
    ADCON1bits.ADON = 1;     //A/D converter is ON  
}
    
void readADC( )
{                      
    //ADCON1bits.SAMP = 1;  // start sampling, automatic conversion will follow
    //__delay_ms( 100 );
    ADCON1bits.SAMP = 0;        // start sampling, automatic conversion will follow
    while ( !ADCON1bits.DONE ); // wait to complete the conversion
    ADCValue = ADCBUF0;         // read the conversion result
}

void main( void ) 
{     
    init_ADC();
    int data;
    
    while( 1 )
    {
        readADC();
        data = ADCValue;      
    } 
}

Configuring the ADC Module

The ADC module may be initialized and configured with the help of the code given above. A step by step guide follows:

  • Steps 1 through 7 are essential. After 7 any or all of them may be skipped.

1) Set the Port as Input and in Analogue Mode

  1. Port B, on which the ADC input pins are present must be set as an input port. (line - 21).
  2. They must be set in the analogue input mode by the ADPCFG register. (line - 22).

2) Select Analogue Inputs for Sampling

Analogue inputs must be connected to an 'ADC channel' for sampling. There are usually more number of analogue inputs as compared to channels, for example: dsPic30f4011 has 09 analogue inputs but only 04 ADC channels. Therefore you must now select which analogue input pin is connected to which ADC channel. This is done with the help of ADCHS register.

  • Here AN1 is selected as the analogue pin input to channel 0. (line - 2).
  • Number of channels determine the number of simultaneous samples possible.
  • The controller can sample alternately between Mux A and Mux B.

Possible Configurations of ADCHS
Resulting Analouge Input Pin Configuaration
Code line
Channel 0 -> Mux A
Any anlouge pin from AN0 - AN8 can be selected to give input to channel 0 through Mux A.
ADCHSbits.CH0SA = 1; or any other number depending on pin
Channel 1, 2 and 3 -> Mux A
Channel 1 input is AN3, Channel 2 -> AN4, Channel 3 -> AN5
ADCHSbits.CH123SA = 1;
Channel 0 -> Mux B
Any anlouge pin from AN0 - AN8 can be selected to give input to channel 0 through Mux B
ADCHSbits.CH0SB = 1; or any other number depending on pin
Channel 1, 2 and 3 -> Mux B
Channel 1 input is AN3, Channel 2 -> AN4, Channel 3 -> AN5
ADCHSbits.CH123SB = 1;
Selecting different combinations of ADC analogue inputs and channels for dspic30f devices. (dspic33f devices may have more channels and inputs available)

3) Select the Voltage Reference

A voltage refernce must be selected to match the input range of the analogue inputs. There are two options for this.

  1. Either the Vcc and Gnd can be made upper and lower reference limits.
  2. Or an external reference voltage may be applied on the AVref pin.

This is done with the help of VCFG bit in the ADCON2 register. (line - 47)

VCFG
Vref (higher)
Vref (lower)
0
AVdd
AVss
1
External Vref +
AVss
2
AVdd
External Vref -
3
External Vref +
External Vref -

4) Select the Output Format of Data

The output format of the data sampled through ADC can also be specified with the help of FORM bit in the ADCON1 register, according to the table below:

FORM
Data Output Format
0
integer
1
signed integer
2
fractional
3
signed fractional

5) Select the Conversion Trigger Source

Analogue to digital conversion inside the ADC module may be initiated by a number of trigger sources, determined by the SSRC bits in the ADCON1 register according to the following table:

SSRC
Conversion Trigger Source
0
Manually clearing the SAMP bit ends sampling and starts conversion.
1
Active transition on INT0 pin ends sampling and starts conversion.
2
Timer 3 compare match ends sampling and starts conversion.
3
Ending of PWM cycle ends sampling and starts conversion.
7
Automatic conversion triggered by internal counter.

6) Select the Mode of Sampling

Sampling on ADC channels can be initiated with either:

  1. Setting the SAMP bit manually in the code, or:
  2. Automatically after the end of last conversion.

This is decided by the ASAM bit in ADCON1 register.

ASAM
Mode
0
Sampling begins when SAMP bit set
1
Sampling begins immediately after the end of last conversion.

7) Select the Conversion Clock

Any Analouge to Digital conversion with the A/D module requires 12 clock periods. The period of a single clock cycle can be configured with the help of ADCS bits in the ADCON3 register. The value placed in ADCS is a six bit value. This can be calculated from the following formulas:

Minimum value of Tad that can be used is 154 nanoseconds.

8) Decide if Simultaneous Sampling is Required or Not

(Optional step)

Simultaneous sampling can be enabled by the SIMSAM bit in the ADCON1 register. Simultaneous sampling captures the samples of all input channels at precisely the same instant. If Simultaneous sampling is disabled, the channels will be sampled one after the other.

9) Select the Conversion Clock Source

(Optional step)

In most cases the conversion clock source is selected to be the system clock by setting the ADRC bit in the ADCON3 register to 0.

10) Determine if Input Scanning is Required

(Optional step)

  • This step can be skipped in most applications.
  • Input scanning can be enabled by the CSNA bit in the ADCON2 register.

Channel 0 of the ADC module can be configured to scan multiple analogue inputs. This can be used if their are multiple input sources and not all of them are active at the same time.

The ADC Interrupt in dspic30f and dspic33f

Instead of using the readADC() function in main body to read the values from the ADC module, an interrupt is used to perform the same function in most advanced applications.

Interrupt based code for ADCs in dspic30f and dspic33f

#define FCY 30000000

#include <xc.h>
#include <stdio.h>
#include <delay.h>
#include <libpic30.h>
#include <math.h>
#include <p30F4011.h>


_FOSC(CSW_FSCM_OFF & FRC_PLL16); // Fosc=16x7.5MHz, i.e. 30 MIPS
_FWDT(WDT_OFF);                  // Watchdog timer off
_FBORPOR(MCLR_DIS);

void Interrupt_Init( void )
{
    IEC0bits.ADIE = 1;       //Enable ADC Interrupt       
    IPC2bits.ADIP = 6;       //set interrupt priority = 6
}

void __attribute__((interrupt, auto_psv))_ADCInterrupt (void) 
{                      
    while ( !ADCON1bits.DONE );   // wait to complete the conversion
    sample.Va = ADCBUF0;
    sample.Vb = ADCBUF1;
        
    IFS0bits.ADIF = 0;
}

int main( void )
{
    // Make RD0 a digital output
    _TRISD0 = 0;

    Interrupt_Init();
    ADC_Init();
    
    while( 1 )
    {
        _LATD0 = 1;
        __delay32(15000000);
        _LATD0 = 0;
        __delay32(15000000);
    }
}
  • A conversion trigger source should be selected for the ADC interrupt to function properly as directed in step 5.
  • Sampling should be done in automatic mode. (ASAM bit)
  • Frequency of the triggering of ADC interrupt may be controlled with the help of SMPI bits in the ADCON2 register. (line 50).

© 2017 StormsHalted

Comments

    0 of 8192 characters used
    Post Comment

    No comments yet.

    Click to Rate This Article