CCS C Software and Maintenance Offers
FAQFAQ   FAQForum Help   FAQOfficial CCS Support   SearchSearch  RegisterRegister 

ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

CCS does not monitor this forum on a regular basis.

Please do not post bug reports on this forum. Send them to CCS Technical Support

dsPIC33FJ32MC304 ADC1 transfer to DMA0

 
Post new topic   Reply to topic    CCS Forum Index -> Code Library
View previous topic :: View next topic  
Author Message
Tom Smith



Joined: 21 Oct 2010
Posts: 2
Location: Orlando, FL

View user's profile Send private message

dsPIC33FJ32MC304 ADC1 transfer to DMA0
PostPosted: Thu Mar 29, 2012 11:55 am     Reply with quote

I had trouble getting my project working with ADC conversion data stored using DMA. So that I thought that others might like to see my working code. I found the Microchip datasheet and Family Reference Manual to be of limited help. Sometimes contradictory or inconsistent. Certainly, they were confusing.

The accompanying file does compile with PCD of a recent version.

The file scans five analog inputs, AN4 through AN8 of dsPIC33FJ32MC304.

The file uses scatter/gather storage in DMA0, with one storage word per analog input. This gives a result in DMA RAM that should be about the same as I would have obtained with conversion-order storage. But I was not able to get that to work. But maybe I did something stupid. It happens.

But I did get the scatter/gather working, by persistence and guessing.

Enjoy.
Code:

/*----------------------------------------------------------------------------
--
--                    Fern Creek Electronics Inc   
--         PROJECT: Servo Control for Gimbal Stabilized Tilt Axis
-----------------------------------------------------------------------------
--
File is ADC1_DMA0_4.c     March 29, 2012

//-----------------------------------------------

Version 4
3-29-2012 4 Create new file by copy and rename from Version 3 of 3-29-2012
            Seem to have a successful combination of code lines.
            Now clean up the file: take out unused/unneeded lines.
            ROM = 5%,  RAM = 4% - 4%
           
//-----------------------------------------------

File Operation:
Timer2 controls the simple PWM output.
  Timer2 interrupts at rate of 32 KHz.
Every 16th Timer2 interrupt starts a ADC1 conversion scan of inputs AN4 - AN8.
 So that ADC1 conversion scans should happen at 2 KHz, or .5 mSec between scans
Do 12 bit conversions.
Do storage in scatter/gather in DMA0 storage buffer, beginning at 0x1400.
  Store one word per analog input, ANx.
  (Resulting storage pattern should equal conversion order storage pattern.)
Use peripheral indirect addressing.
  ANx data is stored in DMA RAM base address + x. Base address = 0x1400.
Want DMA0 interrupt to occur after the 5th A-D conversion.
 DMA0_isr() updates system data processing then terminates.
 DMA0_isr() also updates a counter to determine when to do a 200Hz update
   within the while(1) loop after every 10th DMA0_isr() execution.


----------------------------------------------------------------------
*/

#include <33FJ32MC304.h>  // Has 2X UART

#device adc=16
#fuses EC, NOWDT, PR_PLL, ICSP2, NOJTAG

#use delay (clock=64000000)// 8x 8.0 MHz ext osc, by PLL

#CASE
#ZERO_RAM

#use fast_io(A)
#use fast_io(B)   
#use fast_io(C)   
#PIN_SELECT OC1 = PIN_B4      // uP pin 33  local PWM signal to LMD18201 DIR



#PIN_SELECT U1TX = PIN_B6    // pin 42  for reprogrammable pins of PIC33F
#PIN_SELECT U1RX = PIN_B5    // pin 41
#PIN_SELECT U2TX = PIN_B8    // pin 44  for reprogrammable pins of PIC33F
#PIN_SELECT U2RX = PIN_B7    // pin 43

#USE rs232(stream =SER_OUT, UART1, baud= 57600) // Get 58.1 kBd, J9,pin 3

//For '304 UART #1 ---------------------------------
#BIT  U1STA_TRMT = 0x0222.8 // bit=0 -> tx1 register not empty
#BIT  U1STA_OERR = 0x0222.1     //
#WORD U1STA = 0x0222
#BIT  UT1INV = U1STA.14

#WORD U1MODE = 0x0220
#BIT  UR1INV = U1MODE.4

//-----------------------------------
#WORD OC1RS = 0x0180    //
#WORD OC1R = 0x0182     //
#WORD OC1CON = 0x0184
#WORD T2CON = 0x0110
#WORD PR2 = 0x010C       //
#BIT  T2CON_TON = T2CON.15
//------

#WORD IFS0 = 0x0084   // Interrupt Flag Status Register 0
#WORD IFS3 = 0x008A
#BIT  T2IF = 0x0084.7  // Timer 2 Interrupt Flag
#BIT  AD1IF = IFS0.13

// Declarations for DMA Interrupts for access to ADC data
#WORD IEC0 = 0x0094
#BIT  DMA0IE = IEC0.4
#BIT  DMA0IF = IFS0.4


#WORD ADC1BUF0 = 0x0300    // only one data buffer
#word AD1CON1 = 0x0320
#word AD1CON2 = 0x0322
#word AD1CON3 = 0x0324
#WORD AD1CHS123 = 0x0326
#WORD AD1CHS0 = 0x0328
#WORD AD1PCFGL = 0x032C
#WORD AD1CSSL = 0x0330
#WORD AD1CON4 = 0x0332    // for DMABL<2:0>

#BIT AD1_ADON = AD1CON1.15
#BIT AD1_AD12B = AD1CON1.10
#BIT AD1_DONE = AD1CON1.0
#BIT AD1_SAMP = AD1CON1.1
#BIT AD1_ASAM = AD1CON1.2
#BIT AD1_CSCNA = AD1CON2.10

// Declarations for DMA CHanel 0, for getting outputs from ADC1
#WORD DMA0CON = 0x0380
#WORD DMA0REQ = 0x0382
#WORD DMA0STA = 0x0384
#WORD DMA0STB = 0x0386
#WORD DMA0PAD = 0x0388
#WORD DMA0CNT = 0x038A
#BIT DMA0_CHEN = DMA0CON.15
//#WORD DMA0_0 = 0x1400
//#WORD DMA0_1 = 0x1402
//#WORD DMA0_2 = 0x1404
//#WORD DMA0_3 = 0x1406
#WORD DMA0_4 = 0x1408 // 5th DMA0 storage position, for data from AN4 input
#WORD DMA0_5 = 0x140A
#WORD DMA0_6 = 0x140C
#WORD DMA0_7 = 0x140E
#WORD DMA0_8 = 0x1410 // 9th DMA0 storage position, for data from AN8 input


signed int16 Vtest =0;
signed int16 PS_Sample =0;
signed int16 cur_sense16 =0;
signed int16 cs_vref16 =0;
signed int16 gain_adj_pot16 =0;
signed int16 Vcontrol16 =0;

unsigned int8 dma0INTRcnt =0;
unsigned int8 stabUpdate =0;
unsigned int16 bellCount =0;
unsigned int8 LED_count = 201;
unsigned int8 t2INTcount;

// Function prototypes:

void Setup(void);             // Setup the dsPIC33F 
void setup_MC304_ADC(void);   // Setup for dsPIC33FJ32MC304  ADC1
void setup_MC304_DMA0(void);  // Setup DMA0 channel for storing data from ADC1.


//---------  TIMER1 ISR   ------------
//
#int_TIMER1
void TIMER1_isr() 

}  // End of TIMER1 ISR

//---------------------------------------------------------------------
//
#int_TIMER2 FAST LEVEL=7   
void TIMER2_isr()  // come here at PWM freq, 32.0 KHz
                   //start ADC conversions at 2000 Hz, every 16th TMR2interrupt
 { 
   if (t2INTcount++ == 15)
    {
      t2INTcount =0;
      // Reset the DMA0 counter
      DMA0IF = 0;
      DMA0_CHEN = 0; // disable DMA Ch 0.
                  // this process resets the DMA transfer count
                  // to zero and sets the active DMA buffer
                  // to the primary buffer.
      DMA0_CHEN = 1;
     // DMA0IF = 1; // TEST  force a run thru DMA0_isr() 3-2702012
                    // With this test, got a blinking LED = DMA0_isr() works

      // Start the ADC1 scan and convert process
      AD1IF = FALSE;        // Reset the interrupt flag for ADC1

      AD1CON1  = 0b1000010011100110 ; // Set to TRUE ASAM and SAMP bits, 2:1
      //AD1_ADON = TRUE     AD1CON1.15
      //AD1_ADSIDL = FALSE  AD1CON1.13
      //AD1_ADDMABM = FALSE  AD1CON1.12 DMA buffers are scatter/gather order
      //AD1_AD12B  = TRUE   AD1CON1.10
      // FORM <1:0> = 0b00  AD1CON1 9:8   Integer: 0000 dddd dddd dddd
      // AD1 SSRC = AD1CON1<7:5> = 0b111  Auto convert
      // AD1_SIMSMA = FALSE AD1CON1.3 no simultaneous sampling: do sequential
      // AD1_ASAM = TRUE    AD1CON1.2 Sampling auto begins after last conversion
      // AD1_SAMP = TRUE    AD1CON1.1  S&H amplifier is sampling
      //AD1_DONE = FALSE    AD1CON1.0  Clear the Done bit

    } // End of if(t2INTcount...)...
 
 } // End of Timer2 isr...

//
//--------------------------------------------------------------------------
//
#int_DMA0  Level=4
void DMA0_isr(void)
{ // Want to come here after scanning 5 ADC inputs via ADC CH0: AN4-AN8

   // Stop the automatic scanning and sampling
    AD1_ASAM = FALSE;     // Disable automatic sampling
 
   // begin DMA0_isr signal flag. See it at TP5.
    output_high(PIN_B12); // Duration = 560 nSec, period = 500.0 microSec
   
 // 16-bit ADC result is 0000 dddd dddd dddd. Value range is 0 -> 4096
 
 // Copy converted data from ADC buffer locations to system variable locations
    Vtest = DMA0_4;       // from AN4, uProc pin 23, U3, dsPIC33FJ32MC304
    PS_Sample = DMA0_5;   // From AN5, uProc pin 24
    cur_sense16 = DMA0_6; // from AN6, uProc pin 25
    cs_vref16 = DMA0_7;      // from AN7, uProc pin 26
    gain_adj_pot16 = DMA0_8;// from AN8, uProc pin 27  Via J2 pin 6

    Vcontrol16 = DMA0_8; // periph ind, SMPI=4, see AN8 Pot data ! 8:11 AM
     
   //   Vcontrol16 = DMA0_4; //  periph ind, SMPI=4, see AN4 data, Vtest 8:12
                          //
  //   Vcontrol16 = DMA0_5; // periph ind, SMPI=4, see AN5 data, Pwr Sup samp
    Vcontrol16 -= 2048;   //value range is - 2048 to +2047
       // For test send this value out through UART1.
       // fputc is done in main() while(1) loop, within if(stabUpdate){ }

//
// Other system code lines here
//

// Update counter for determining when to do the low-freq updates in main()
      if ( ++dma0INTRcnt == 10) {dma0INTRcnt =0;  stabUpdate = TRUE;}
//

   DMA0_CHEN = FALSE; // disable DMA Ch 0.
                      // this process resets the DMA transfer count
                      // to zero and sets the active DMA buffer
                      // to the primary buffer.
   DMA0_CHEN = TRUE;
   DMA0IF = FALSE;
  // AD1IF = FALSE;        // Reset the interrupt flag for ADC1
   output_low(PIN_B12);  // begin DMA0_isr signal flag. See it at TP5
                         // 3-29-2012 Duration = 560 nSec
                         //           Period = 500.0 uSec
 //  DMA0IF = 0;           // new here, 3-28
     
}  // End of DMA0_isr()
//-----------------------------------------------------------------

void setup_MC304_ADC(void) // Called in Setup()
    // For use with FCE CCA with dsPIC33FJ32MC304 and PWM LMD18201T
 {
 // Disable the ADC1
  AD1_ADON = FALSE;  // bit 15 in AD1CON1

 // Declare which ANx inputs should be digital I/O ( '304 User Manual pg 286)
  AD1PCFGL = 0b0000000000001111 ; // AN0, AN1,AN2, AN3 are digital pins( 1)
                                  // AN4,AN5, AN6, AN7,AN8 are analog pins(0)

 // Select the way conversion results are presented, in AD1CON1
  AD1CON1  = 0b0000010011100000 ; //
 //            x                  ADC disable  bit: ADON=0, a.k.a. AD1_ADON
 //              0                bit 13 = ADSIDL =0 contine op in idle mode
 //               0               bit 12 =ADDMABM: scatter/gather mode
 //                x              bit 11 unimplemented
 //                 1             bit 10 = AD12B = 1, for 12-bit operation
 //                  00           bits 9,8 = Format = 00 = unsigned integer
 //                                 0000 dddd dddd dddd   = 0->4K
 //                    111        bits 7:5 SSRC =automatic conversion trigger
 //                       0       bit 4: unimplemented
 //                        0      bit 3: SIMSAM = 0 = sequential sampling
 //                         0     ASAM=0, sampling begins when SAMP is set
 //                          0    SAMP set this bit to 1 to begin sampling
 //                                 with SSRC not=000, hdw auto clears the bit
 //                           x   Done bit
 
 // Select voltage reference in AD1CON2
  AD1CON2 = 0b0000010000010000 ; //
 //           000               15:13 VCFG RefVoltConfg Vrefh=AVDD, Vrefl=AVSS
 //                1            10 CSCNA Scan the inputs
 //                 00          9:8 CHPS is Ignored for AD12B = 1 = 12 bit conv.
 //                     0000    5:2 SMPI Interrupts end every sample/conv. seq.
 //                     0100    5:2 SMPI Interrupts after 5 sample/conv. seq.
 //                         0   1 BUFM  Start filling buffer from beginning
 //                          0  0 ALTS Always use MUXA input select
 //
 //
 //
 //
 // Select analog conversion clock, in AD1CON3
  AD1CON3 = 0b1000000000001111 ;
  //          0                   15  ADRC =0 = Use fosc = 64 MHz
  //                                  (Use RC osc for converting in sleep mode.)
  //                                  (nom freq of RC osc is 4 MHz, 250 nSec.)
  //             00010            12:8  SAMC  2 Tad
  //                  00001111    7:0   ADCS  15+1 = 16 -> 1/16 -> Tad = 250 nS
 
 // Configure DMA buffer words per analog input
  AD1CON4 = 0b0000000000000000; // One buffer word per analog input.
 //                        000  // DMABL (UM page 281) (FRM ADC page 47)
 //                             // 000 -> allocate one word of buffer per ANx
 //                             // AD1CON4 is ignored for conversion-order mode.
 
 
 AD1CHS0 =0b0000000000001000; 
 //         0                     15 CH0NB= 0 = Ch0 neg input = Vref- = Vss
 //          00                   14:13  unimplemented
 //            00000              12:8  CH0SB positive input select AN0 - AN8
 //                 0             7 CH0NA = 0 Ch 0 neg input is Vref-
 //                  00           6:5 unimplemented
 //                    01000      4:0 CH0SA positive input select = AN8
 //                               4:0 ignored for CSCNA = 1, do scanning
 
 // AD1CH123 is not used for AD12B = 1
 // AD1CSSH is not available for 'MC304
 
   AD1CSSL =0b0000000111110000;  // ADC1 Input Scan Select Register Low
 //                  87654  10     Scan inputs at AN8, AN7, AN6, AN5, AN4

 // Turn on the AD Converter
  AD1_ADON = TRUE;                // Turn on the AD converter
 
 }  // End of setup_MC304_ADC();
 
//----------------------------------------------------------------------

void setup_MC304_DMA0(void)
{
 DMA0CON = 0b0000000000100001;  //
 //          0                   15 CHEN  1= Channel enabled, 0 =disabled
 //           0                  14 SIZE = word
 //            0                 13 DIR, from peripheral to DMA
 //             0                12 HALF
 //              0               11 NULLW
 //                    10        5:4  AMODE=10 peripheral indirect addressing
 //                    01        5:4  AMODE=01 Register indirect wo/ post-incr
 //                    00        5:4  AMODE=00 Register indirect w/ post-incr
 //                        01    1:2  MODE = one-shot, no ping-pong
 //                        00    1:2  MODE = continuous, no ping-pong

 DMA0REQ = 0b0000000000001101;   // IRQ comes from ADC1 convert done bit
 //          0                   // 15 FORCE = 0
 //                   0001101    // IRQSEL 6:0 DMA reads from ADC1BUF0 ( 0x0300)
                                 //  value = 0x0D,per Table 8-1 & FMR:DMA p38-6
 
 DMA0STA = 0x0000;             // Offset Start RAM at location 0x1400 DMA RAM
 DMA0STB = 0x0020;
 DMA0PAD = 0x0300;             // address of data source from peripheral
                               // is address of ADC1BUF0 register
 DMA0CNT = 0b0000000000000100; // DMA0 transfer count register
                               // DMA0CNT =4 get DMA IRQ after fifth DMA
                               // DMA0CNT =0 get DMA IRQ each DMA


 DMA0_CHEN = TRUE;   // Enable the DMA channel 0 after getting it setup.
 
}  // End of setup_MC304_DMA()


//-----------------------------------------------------------------

void main()
  {
 
  Setup(); // Setup the PIC33F Hardware etc.  See line 1112.
           // Enables the interrupts
           // Calls a function to set up the 12-bit ADC
           // Calls a function to setuo DMA0
           
//-- Begin interative part of Main() --------------
   while (1)
     {
      if(stabUpdate)   // stabUpdate is set TRUE in DMA0_isr()
                       // Come here once every 5 mSec
      {
       stabUpdate = FALSE;
       bellCount++; // bellCount is int16, rolls over every ... bells or loops

// Lines of system data processing code here
// Do a slow 200Hz update of system data here, per counter in DMA0_isr()

// Send test data message via UART1 and CCA J9 ------------------------
    if ((bellCount+1)%2)
     {
      fputc( make8(Vcontrol16,1),SER_OUT); // Use to see conversion data
      fputc( make8(Vcontrol16,0),SER_OUT);
     }

 // Heartbeat LED blinking -------------------------------------
      if (LED_count++ >200) LED_count =0;
     
      output_bit(PIN_B14,(LED_count<11));
      output_bit(PIN_C5,(LED_count<11));


      }  // End of if(stabUpdate)...
     }   // End of while(1)...

   }     // End of main()...


//----------------------------------------------------------------------

void Setup(void)  // for PIC33FJ32MC304 on FCE motor controller CCA
{
  // Set up the uP inputs and outputs
  output_a (0b0000010010011111);  // Have A0 - A4,A7,A9,A10
  set_tris_a (0b0000001000000100);
                                //  A0   pin 19 out    IMU_RST\
                                //  A1   pin 20 out    IMU_CS\
                                //  A2   pin 30 input  oscillator input
                                //  A3   pin 31 out    clkout
                                //  A4   pin 34 out    BRAKE
                                //  A7   pin 13 out    not used
                                //  A8   pin 32 out    Enable to LMD18201
                                //  A9   pin 35 input  PWM_Overtemp
                                //  A10  pin 12 out    not used
 
  output_b  (0b0000000000000000);
  set_tris_b(0b1000001010101100);  //Have B0 - B15
                                // RB0  pin 21   output uP_SDO  SPI  PPS
                                // RB1  pin 22   output uP_SCLK  SPI  PPS
                                // RB2  pin 23   AN4,analog TEST_ANALOG
                                // RB3  pin 24   AN5,analog PS Sample
                                // RB4  pin 33  RP4 output  OC1 to PWM PPS
                                // RB5  pin 41  RP5 input   UART1RX PPS
                                // RB6  pin 42  RP6 output  UART1TX PPS
                                // RB7  pin 42  input NC RP7  to U8-R2OUT 10
                                // RB8  pin 44  output NC RP8  to U8-T2IN 9
                                // RB9  pin 1   input QEA
                                // RB10  pin 8   output   PGED2
                                // RB11  pin 9   output   PGEC2
                                // RB12  pin 10  RP12 output TP5 testpoint
                                // RB13  pin 11  RP13 output NC
                                // RB14  pin 14  RP14 output LED2
                                // RB15  pin 15  RP15 input uP_SDI  SPI
                                // Oct.18,2011: RB15 used for input an RC pulse
                               
  output_c  (0b0000000000000000);
  set_tris_c(0b0000000011011111);  //Have C0 - C9
                                // RC0  pin 25   input AN6,Analog,current sense
                                // RC1  pin 26   input AN7,Analog,  V_REF
                                // RC2  pin 27   input AN8,Analog,GAIN_ADJUST
                                // RC3  pin 36   input  LIMIT_CW_NOT
                                // RC4  pin 37   input  LIMIT_CCW_NOT
                                // RC5  pin 38   output LED_ON
                                // RC6  pin 2    input  QEB
                                // RC7  pin 3    input QE_INDX
                                // RC8  pin 4    output TP7 QE DIR
                                // RC9  pin 5    output NC
                                 
                               
   setup_oscillator(OSC_CRYSTAL,64000000,8000000);
           // target freq = 64 MHz, source freq = 8 MHz

   setup_MC304_ADC();    // an FCE-created routine for setting up the ADC
   setup_MC304_DMA0();
   

   disable_interrupts(INT_RDA);
   
   setup_timer1(TMR_INTERNAL|TMR_DIV_BY_8);
      // Fcy = Fosc/2 = 64 MHx/2 = 32MHz
      // T1 clock = 32MHz/8 = 4 MHz (next possible divisor is 64)

   setup_timer2(TMR_INTERNAL|TMR_DIV_BY_1, 1000) ; // reset after 1000 cycles,
  // Setup the Output Compare 1 operation
  // Per Microchip PIC24F FRM, Sec 16, page 16-25
   OC1CON = 0x0000;  // Mode, OC1 disabled
   OC1R = 0x01f4;    // initial duty cycle = 500
   OC1RS = 0x01f4;   // duty cycle = 500
   OC1CON = 0x0006;  // Mode for simple PWM, OC mode bits
   PR2 = 0x03E8;     // PWM period = 1000
   T2CON_TON  = TRUE; // Enable Timer2
   
   setup_timer3(TMR_DISABLED|TMR_DIV_BY_1);
   
   DMA0_CHEN = 0; // disable DMA Ch 0. 
                  // this process resets the DMA transfer count
                  // to zero and sets the active DMA buffer
                  // to the primary buffer.
   DMA0IF = 0;  // reset the DMA0 interrupt flag.
   AD1IF = FALSE;        // Reset the interrupt flag for ADC1
   
   enable_interrupts(INT_TIMER2);
  // enable_interrupts(INT_ADC1);
   enable_interrupts (INT_DMA0);
 //  enable_interrupts (INTR_NESTING);
 //  enable_interrupts (INTR_NORMAL);
   enable_interrupts(INTR_GLOBAL);

   DMA0_CHEN = TRUE;

}  // End of Setup()...

//----------------------------------------------------------------------

/////////////// END //////////////////////// END /////////

_________________
Tom Smith
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> Code Library All times are GMT - 6 Hours
Page 1 of 1

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum


Powered by phpBB © 2001, 2005 phpBB Group