PIC24 Support Libraries
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
adc4simul_dma.c
Go to the documentation of this file.
1 /*
2  * "Copyright (c) 2008 Robert B. Reese, Bryan A. Jones, J. W. Bruce ("AUTHORS")"
3  * All rights reserved.
4  * (R. Reese, reese_AT_ece.msstate.edu, Mississippi State University)
5  * (B. A. Jones, bjones_AT_ece.msstate.edu, Mississippi State University)
6  * (J. W. Bruce, jwbruce_AT_ece.msstate.edu, Mississippi State University)
7  *
8  * Permission to use, copy, modify, and distribute this software and its
9  * documentation for any purpose, without fee, and without written agreement is
10  * hereby granted, provided that the above copyright notice, the following
11  * two paragraphs and the authors appear in all copies of this software.
12  *
13  * IN NO EVENT SHALL THE "AUTHORS" BE LIABLE TO ANY PARTY FOR
14  * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
15  * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE "AUTHORS"
16  * HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
17  *
18  * THE "AUTHORS" SPECIFICALLY DISCLAIMS ANY WARRANTIES,
19  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
20  * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
21  * ON AN "AS IS" BASIS, AND THE "AUTHORS" HAS NO OBLIGATION TO
22  * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
23  *
24  * Please maintain this header in its entirety when copying/modifying
25  * these files.
26  *
27  *
28  */
29 
30 #include "pic24_all.h"
31 #include "stdio.h"
32 
33 
34 #ifndef _DMA0IF
35 #error "This processor selection does not have a DMA module; this code example is incompatible with a PIC24 CPU that does not have DMA."
36 
37 #endif
38 
39 // setup an output to help us measure ADC IRQ responses
40 #define CONFIG_LED2() CONFIG_RB5_AS_DIG_OUTPUT()
41 #define LED2 _LATB5
42 
43 #define ADC_LEN 10
44 #define ADC_NSTEPS 1024
45 #define ADC_12BIT_FLAG 0
46 
47 // set this to one of the values of
48 // 1, 2, 4, 8, 16, 32, 64, 128
49 #define CONVERSIONS_PER_INPUT 1 //for this example, assumed always to be '1'
50 #define MAX_CHANNELS 16
51 //DMA transfer size is in words.
52 #define MAX_TRANSFER (CONVERSIONS_PER_INPUT*MAX_CHANNELS) //make power of two for alignment to work
53 
54 //DMA buffers, alignment is based on number of bytes
55 /// \cond nodoxygen
56 // These attributes confuse Doxygen.
57 uint16_t au16_bufferA[MAX_TRANSFER] __attribute__((space(dma),aligned(MAX_TRANSFER*2)));
58 uint16_t au16_bufferB[MAX_TRANSFER] __attribute__((space(dma),aligned(MAX_TRANSFER*2)));
59 /// \endcond
60 
61 
62 //For this example, we will just use ordered conversion mode,
63 //and one conversion per ADC input
64 void configDMA_ADC(uint8_t u8_ch0Select, \
65  uint16_t u16_ch123SelectMask, \
66  uint16_t u16_numTcyMask) {
67 
68 
69  AD1CON1bits.ADON = 0; // turn off ADC (changing setting while ADON is not allowed)
70  /** Configure the internal ADC **/
71  AD1CON1 = ADC_CLK_TMR | ADC_SAMPLE_SIMULTANEOUS | ADC_ADDMABM_ORDER;
72  AD1CON3 = (u16_numTcyMask & 0x00FF);
73  AD1CON2 = ADC_VREF_AVDD_AVSS | ADC_CONVERT_CH0123;
74 #if (defined(__PIC24H__)|| defined(__dsPIC33F__))
75  AD1CHS0 = ADC_CH0_NEG_SAMPLEA_VREFN | (u8_ch0Select & 0x1F);
76  AD1CHS123 = u16_ch123SelectMask;
77 #else
78  AD1CHS = ADC_CH0_NEG_SAMPLEA_VREFN | (u8_ch0Select & 0x1F);
79 #endif
80  AD1CON4 = ADC_1_WORD_PER_INPUT;
81  AD1CSSL = 0;
82 
83  //configure the DMA channel 0 interrupt
84  DMA0PAD = (unsigned int) &ADC1BUF0;
85  DMA0REQ = DMA_IRQ_ADC1;
86  DMA0STA = __builtin_dmaoffset(au16_bufferA);
87  DMA0STB = __builtin_dmaoffset(au16_bufferB);
88  DMA0CNT = 4 - 1; //converting four inputs, so DMA0CNT = 3
89  DMA0CON = //configure and enable the module Module
90  (DMA_MODULE_ON |
91  DMA_SIZE_WORD |
92  DMA_DIR_READ_PERIPHERAL |
93  DMA_INTERRUPT_FULL |
94  DMA_NULLW_OFF |
95  DMA_AMODE_REGISTER_POSTINC |
96  DMA_MODE_CONTINUOUS_PING_PONG);
97 
98  _DMA0IF = 0;
99  _DMA0IP = 6;
100  _DMA0IE = 1;
101 
102 
103  AD1CON1bits.ADON = 1; // turn on the ADC
104 }
105 
106 uint16_t au16_buffer[MAX_TRANSFER];
107 volatile uint16_t au16_sum[MAX_TRANSFER];
108 volatile uint8_t u8_gotData;
109 volatile uint8_t u8_activeBuffer;
110 
111 void _ISRFAST _DMA0Interrupt(void) {
112  static uint8_t u8_adcCount=64;
113  uint8_t u8_i;
114  uint16_t* au16_adcHWBuff = (uint16_t*) &au16_bufferA;
115  _DMA0IF = 0;
116 
117  if (u8_activeBuffer) {
118  au16_adcHWBuff = (uint16_t*) &au16_bufferB;
119  u8_activeBuffer = 0;
120  } else {
121  au16_adcHWBuff = (uint16_t*) &au16_bufferA;
122  u8_activeBuffer = 1;
123  }
124 
125  //accumulate the sum
126  for ( u8_i=0; u8_i<MAX_TRANSFER; u8_i++) {
127  au16_buffer[u8_i] += au16_adcHWBuff[u8_i];
128  } //end for()
129 
130  // we got the data, so start the sampling process again
131  SET_SAMP_BIT_ADC1();
132  u8_adcCount--;
133  if (u8_adcCount==0) {
134  u8_adcCount = 64;
135  u8_gotData = 1;
136  for ( u8_i=0; u8_i<MAX_TRANSFER; u8_i++) {
137  au16_sum[u8_i] = au16_buffer[u8_i];
138  au16_buffer[u8_i] = 0;
139  } //end for()
140  }
141  // toggle a port pin so that we can measure how often DMA IRQs are coming in
142  LED2 = !LED2;
143 }
144 
145 
146 
147 /** \file
148  * Simultaneously samples four channels and uses a timer used to trigger conversions.
149  * Four channels are
150  * Ping-pong buffering is used.
151  * Conversion results are printed to screen.
152  * (HEX values and voltages are printed.)
153  * This is only for PIC24 CPUs without DMA.
154 */
155 
156 int main (void) {
157  uint8_t u8_i;
158  uint16_t u16_pot;
159  uint32_t u32_ticks;
160  float f_pot;
161 
162  configBasic(HELLO_MSG);
163 
164  // make RA0/AN0/VREF+ a digital input to kill the pullup and
165  // set the TRISA bit, then make it ANALOG so the ADC will work
166  CONFIG_AN0_AS_ANALOG();
167  CONFIG_AN1_AS_ANALOG();
168  CONFIG_AN2_AS_ANALOG();
169  CONFIG_AN12_AS_ANALOG();
170 
171  CONFIG_LED2();
172 
173  u8_gotData = 0;
174 
175  // configure T2/T3 as 32-bit timer to trigger every 1/64 second
176  T3CONbits.TON = 0;
177  T2CONbits.TON = 0;
178  T2CON = T2_32BIT_MODE_ON | T2_PS_1_1 | T2_SOURCE_INT;
179  TMR3 = 0;
180  TMR2 = 0;
181  u32_ticks = usToU32Ticks(15625, getTimerPrescale(T2CONbits)) - 1; // # of ticks for 1/64 seconds
182  PR3 = u32_ticks>>16;
183  PR2 = u32_ticks & 0xFFFF;
184  T2CONbits.TON = 1;
185 
186  configDMA_ADC(12, ADC_CH123_POS_SAMPLEA_AN0AN1AN2, ADC_CONV_CLK_10Tcy );
187  SET_SAMP_BIT_ADC1();
188 
189  while (1) {
190  while (!u8_gotData) {
191  doHeartbeat();
192  }
193  u8_gotData = 0;
194  for ( u8_i=0; u8_i<4; u8_i++) {
195  u16_pot = au16_sum[u8_i];
196  f_pot = (3.3 / 1023 / 64 ) * u16_pot;
197  printf("r");
198  outChar( '0'+u8_i );
199  printf(":0x%04X=%1.3fV ", u16_pot, (double) f_pot );
200  } //end for()
201  printf("\n");
202  } //endof while()
203 } // endof main()