Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Fork of DSP_200kHz by
DMA_sampling/adc.cpp@74:ebc9f09fda11, 2017-06-01 (annotated)
- Committer:
- baxterja
- Date:
- Thu Jun 01 22:12:31 2017 +0000
- Revision:
- 74:ebc9f09fda11
- Parent:
- 55:2526b3317bc8
Working after updating mbed.bld
Who changed what in which revision?
| User | Revision | Line number | New contents of line |
|---|---|---|---|
| timmey9 | 39:82dc3daecf32 | 1 | #include "adc.h" |
| timmey9 | 45:d591d138cdeb | 2 | |
| timmey9 | 44:41c262caf898 | 3 | /* |
| bmazzeo | 53:83a90a47c1fd | 4 | From page 869 of the user manual: |
| bmazzeo | 53:83a90a47c1fd | 5 | |
| bmazzeo | 53:83a90a47c1fd | 6 | Before the ADC module can be used to complete conversions, an initialization procedure |
| bmazzeo | 53:83a90a47c1fd | 7 | must be performed. A typical sequence is: |
| bmazzeo | 53:83a90a47c1fd | 8 | 1. Calibrate the ADC by following the calibration instructions in Calibration function. |
| bmazzeo | 53:83a90a47c1fd | 9 | 2. Update CFG to select the input clock source and the divide ratio used to generate |
| bmazzeo | 53:83a90a47c1fd | 10 | ADCK. This register is also used for selecting sample time and low-power |
| bmazzeo | 53:83a90a47c1fd | 11 | configuration. |
| bmazzeo | 53:83a90a47c1fd | 12 | 3. Update SC2 to select the conversion trigger, hardware or software, and compare |
| bmazzeo | 53:83a90a47c1fd | 13 | function options, if enabled. |
| bmazzeo | 53:83a90a47c1fd | 14 | 4. Update SC3 to select whether conversions will be continuous or completed only once |
| bmazzeo | 53:83a90a47c1fd | 15 | (ADCO) and whether to perform hardware averaging. |
| bmazzeo | 53:83a90a47c1fd | 16 | 5. Update SC1:SC1n registers to select whether conversions will be single-ended or |
| bmazzeo | 53:83a90a47c1fd | 17 | differential and to enable or disable conversion complete interrupts. Also, select the |
| bmazzeo | 53:83a90a47c1fd | 18 | input channel which can be used to perform conversions. |
| timmey9 | 44:41c262caf898 | 19 | */ |
| timmey9 | 45:d591d138cdeb | 20 | DigitalOut green(LED_GREEN); |
| timmey9 | 45:d591d138cdeb | 21 | DigitalOut red(LED_RED); |
| timmey9 | 51:43143a3fc2d7 | 22 | |
| bmazzeo | 54:1697dc574b96 | 23 | Serial debug(USBTX, USBRX); |
| timmey9 | 51:43143a3fc2d7 | 24 | |
| timmey9 | 39:82dc3daecf32 | 25 | |
| timmey9 | 45:d591d138cdeb | 26 | void adc_init() |
| bmazzeo | 53:83a90a47c1fd | 27 | { |
| bmazzeo | 53:83a90a47c1fd | 28 | |
| timmey9 | 39:82dc3daecf32 | 29 | // Turn on the ADC0 and ADC1 clocks |
| baxterja | 74:ebc9f09fda11 | 30 | SIM->SCGC6 |= SIM_SCGC6_ADC0_MASK; |
| baxterja | 74:ebc9f09fda11 | 31 | SIM->SCGC3 |= SIM_SCGC3_ADC1_MASK; |
| timmey9 | 40:bd6d8c35e822 | 32 | |
| timmey9 | 45:d591d138cdeb | 33 | // Set ADC hardware trigger to PDB0 |
| baxterja | 74:ebc9f09fda11 | 34 | SIM->SOPT7 = SIM_SOPT7_ADC0TRGSEL(0); // Select triggering by PDB and select pre-trigger A |
| baxterja | 74:ebc9f09fda11 | 35 | SIM->SOPT7 = SIM_SOPT7_ADC1TRGSEL(0); // Select triggering by PDB and select pre-trigger A |
| bmazzeo | 53:83a90a47c1fd | 36 | |
| bmazzeo | 53:83a90a47c1fd | 37 | // turn on the clock to the PDB |
| bmazzeo | 53:83a90a47c1fd | 38 | // SIM->SCGC6 |= SIM_SCGC6_PDB_MASK; |
| timmey9 | 39:82dc3daecf32 | 39 | |
| bmazzeo | 53:83a90a47c1fd | 40 | // set ADC trigger to PDB0 |
| bmazzeo | 53:83a90a47c1fd | 41 | // SIM_SOPT7 = SIM_SOPT7_ADC0TRGSEL(0); |
| bmazzeo | 53:83a90a47c1fd | 42 | |
| bmazzeo | 53:83a90a47c1fd | 43 | // This lets the clocks go to the ADC |
| bmazzeo | 53:83a90a47c1fd | 44 | // SIM_SCGC6 |= SIM_SCGC6_ADC0_MASK; |
| bmazzeo | 53:83a90a47c1fd | 45 | // SIM_SCGC3 |= SIM_SCGC3_ADC1_MASK; |
| timmey9 | 45:d591d138cdeb | 46 | |
| bmazzeo | 53:83a90a47c1fd | 47 | /* // This lets the clocks go to the PDB |
| bmazzeo | 53:83a90a47c1fd | 48 | SIM_SCGC6 |= SIM_SCGC6_PDB_MASK; |
| bmazzeo | 53:83a90a47c1fd | 49 | |
| bmazzeo | 53:83a90a47c1fd | 50 | // Set PDB to be enabled and have continous triggers |
| bmazzeo | 53:83a90a47c1fd | 51 | PDB0_SC = PDB_SC_DMAEN_MASK // DMA Enable |
| bmazzeo | 53:83a90a47c1fd | 52 | | PDB_SC_TRGSEL(0xf) // Software trigger |
| bmazzeo | 53:83a90a47c1fd | 53 | | PDB_SC_PDBEN_MASK // Set to continuous mode |
| bmazzeo | 53:83a90a47c1fd | 54 | | PDB_SC_LDOK_MASK; // Loading mask |
| bmazzeo | 53:83a90a47c1fd | 55 | |
| bmazzeo | 53:83a90a47c1fd | 56 | PDB0_SC |= PDB_SC_SWTRIG_MASK; // enable software trigger (start the PDB) |
| timmey9 | 50:33524a27e08c | 57 | |
| timmey9 | 39:82dc3daecf32 | 58 | |
| bmazzeo | 53:83a90a47c1fd | 59 | // This now routes the triggers |
| bmazzeo | 53:83a90a47c1fd | 60 | SIM_SOPT7 = SIM_SOPT7_ADC0TRGSEL(0); |
| bmazzeo | 53:83a90a47c1fd | 61 | SIM_SOPT7 = SIM_SOPT7_ADC1TRGSEL(0); |
| bmazzeo | 53:83a90a47c1fd | 62 | */ |
| bmazzeo | 53:83a90a47c1fd | 63 | |
| bmazzeo | 53:83a90a47c1fd | 64 | /* From page 853 of the user manual |
| bmazzeo | 53:83a90a47c1fd | 65 | Prior to calibration, the user must configure the ADC's clock source and frequency, low |
| bmazzeo | 53:83a90a47c1fd | 66 | power configuration, voltage reference selection, sample time, and high speed |
| bmazzeo | 53:83a90a47c1fd | 67 | configuration according to the application's clock source availability and needs. |
| bmazzeo | 53:83a90a47c1fd | 68 | */ |
| baxterja | 74:ebc9f09fda11 | 69 | ADC0->SC1[0] = 0x0C; //AIEN = 0, DIFF = 0, Channel = AD12 (PTB2) |
| baxterja | 74:ebc9f09fda11 | 70 | ADC1->SC1[0] = 0x0E; //AIEN = 0, DIFF = 0, Channel = AD14 (PTB10) |
| bmazzeo | 53:83a90a47c1fd | 71 | |
| baxterja | 74:ebc9f09fda11 | 72 | ADC0->CFG1 = 0x0C; //ADLPC = 0, ADIV = 0, ADLSMP = 0, MODE = 0b11, ADICLK = 00 (16-bit single-ended) |
| baxterja | 74:ebc9f09fda11 | 73 | ADC1->CFG1 = 0x0C; //ADLPC = 0, ADIV = 0, ADLSMP = 0, MODE = 0b11, ADICLK = 00 (16-bit single-ended) |
| bmazzeo | 54:1697dc574b96 | 74 | |
| bmazzeo | 54:1697dc574b96 | 75 | // ADC0_CFG1 = 0x00; //ADLPC = 0, ADIV = 0, ADLSMP = 0, MODE = 0b00, ADICLK = 00 (16-bit single-ended) |
| bmazzeo | 54:1697dc574b96 | 76 | // ADC1_CFG1 = 0x00; //ADLPC = 0, ADIV = 0, ADLSMP = 0, MODE = 0b00, ADICLK = 00 (16-bit single-ended) |
| bmazzeo | 54:1697dc574b96 | 77 | |
| timmey9 | 45:d591d138cdeb | 78 | |
| bmazzeo | 53:83a90a47c1fd | 79 | // It is necessary not to have hardware trigger for calbiration |
| baxterja | 74:ebc9f09fda11 | 80 | ADC0->CFG2 = 0x00; // MUXSEL = 0, ADACKEN = 0, ADHSC = 0, ADLSTS = 0 (does not matter - short sample time) |
| baxterja | 74:ebc9f09fda11 | 81 | ADC1->CFG2 = 0x00; // MUXSEL = 0, ADACKEN = 0, ADHSC = 0, ADLSTS = 0 (does not matter - short sample time) |
| bmazzeo | 53:83a90a47c1fd | 82 | |
| bmazzeo | 53:83a90a47c1fd | 83 | // Use averaging to make calibration better |
| baxterja | 74:ebc9f09fda11 | 84 | ADC0->SC3 = 0x07; // CAL = 0, CALF = 0, res[5:4], ADCO = 0 (continuous conversion), AVGE = 1, AVGS = 11 |
| baxterja | 74:ebc9f09fda11 | 85 | ADC1->SC3 = 0x07; // CAL = 0, CALF = 0, res[5:4], ADCO = 0 (continuous conversion), AVGE = 1, AVGS = 11 |
| timmey9 | 39:82dc3daecf32 | 86 | |
| bmazzeo | 53:83a90a47c1fd | 87 | |
| bmazzeo | 53:83a90a47c1fd | 88 | // calibrate the ADC (following Joey's code example) |
| baxterja | 74:ebc9f09fda11 | 89 | ADC0->SC3 |= ADC_SC3_CAL_MASK; // start calibration |
| baxterja | 74:ebc9f09fda11 | 90 | while(ADC0->SC3&ADC_SC3_CALF_MASK) {} // wait for calibration to complete |
| baxterja | 74:ebc9f09fda11 | 91 | ADC1->SC3 |= ADC_SC3_CAL_MASK; // start calibration |
| baxterja | 74:ebc9f09fda11 | 92 | while(ADC1->SC3&ADC_SC3_CALF_MASK) {} // wait for calibration to complete |
| bmazzeo | 54:1697dc574b96 | 93 | |
| baxterja | 74:ebc9f09fda11 | 94 | debug.printf("ADC0_CLP0:%d\r\n", ADC0->CLP0); |
| baxterja | 74:ebc9f09fda11 | 95 | debug.printf("ADC0_CLP1:%d\r\n", ADC0->CLP1); |
| baxterja | 74:ebc9f09fda11 | 96 | debug.printf("ADC0_CLP2:%d\r\n", ADC0->CLP2); |
| baxterja | 74:ebc9f09fda11 | 97 | debug.printf("ADC0_CLP3:%d\r\n", ADC0->CLP3); |
| baxterja | 74:ebc9f09fda11 | 98 | debug.printf("ADC0_CLPS:%d\r\n", ADC0->CLPS); |
| bmazzeo | 53:83a90a47c1fd | 99 | |
| timmey9 | 45:d591d138cdeb | 100 | // calculate the gains (see user manual page 864) |
| baxterja | 74:ebc9f09fda11 | 101 | int16_t gain = (ADC0->CLP0+ADC0->CLP1+ADC0->CLP2+ADC0->CLP3+ADC0->CLP4+ADC0->CLPS); |
| bmazzeo | 53:83a90a47c1fd | 102 | gain = gain / 2; // divide by 2 |
| timmey9 | 45:d591d138cdeb | 103 | gain |= 0x8000; // set the MSB |
| baxterja | 74:ebc9f09fda11 | 104 | ADC0->PG = gain; |
| timmey9 | 45:d591d138cdeb | 105 | |
| baxterja | 74:ebc9f09fda11 | 106 | gain = (ADC1->CLP0+ADC1->CLP1+ADC1->CLP2+ADC1->CLP3+ADC1->CLP4+ADC1->CLPS); |
| bmazzeo | 53:83a90a47c1fd | 107 | gain = gain / 2; // divide by 2 |
| timmey9 | 46:a015ebf4663b | 108 | gain |= 0x8000; // set the MSB |
| baxterja | 74:ebc9f09fda11 | 109 | ADC1->PG = gain; |
| timmey9 | 46:a015ebf4663b | 110 | |
| baxterja | 74:ebc9f09fda11 | 111 | gain = (ADC0->CLM0+ADC0->CLM1+ADC0->CLM2+ADC0->CLM3+ADC0->CLM4+ADC0->CLMS); |
| bmazzeo | 53:83a90a47c1fd | 112 | gain = gain / 2; // divide by 2 |
| timmey9 | 45:d591d138cdeb | 113 | gain |= 0x8000; // set the MSB |
| baxterja | 74:ebc9f09fda11 | 114 | ADC0->MG = gain; |
| timmey9 | 39:82dc3daecf32 | 115 | |
| baxterja | 74:ebc9f09fda11 | 116 | gain = (ADC1->CLM0+ADC1->CLM1+ADC1->CLM2+ADC1->CLM3+ADC1->CLM4+ADC1->CLMS); |
| bmazzeo | 53:83a90a47c1fd | 117 | gain = gain / 2; // divide by 2 |
| timmey9 | 46:a015ebf4663b | 118 | gain |= 0x8000; // set the MSB |
| baxterja | 74:ebc9f09fda11 | 119 | ADC1->MG = gain; |
| timmey9 | 46:a015ebf4663b | 120 | |
| bmazzeo | 54:1697dc574b96 | 121 | // ADC0_SC3 &= ~ADC_SC3_CAL_MASK; // stop calibration |
| bmazzeo | 54:1697dc574b96 | 122 | // ADC1_SC3 &= ~ADC_SC3_CAL_MASK; // stop calibration |
| bmazzeo | 54:1697dc574b96 | 123 | |
| bmazzeo | 53:83a90a47c1fd | 124 | |
| bmazzeo | 54:1697dc574b96 | 125 | // Now set up for use in the rest of the program - software trigger |
| baxterja | 74:ebc9f09fda11 | 126 | ADC0->SC2 = 0x04; // ADACT = 0, ADTRG = 0 (HW trigger), ACFE = 0, ACFGT = 0, ACREN = 0, DMAEN = 1, REFSEL = 00 (DMAEN needs to be asserted) |
| baxterja | 74:ebc9f09fda11 | 127 | ADC1->SC2 = 0x04; // ADACT = 0, ADTRG = 0 (HW trigger), ACFE = 0, ACFGT = 0, ACREN = 0, DMAEN = 1, REFSEL = 00 (DMAEN needs to be asserted) |
| bmazzeo | 54:1697dc574b96 | 128 | |
| bmazzeo | 54:1697dc574b96 | 129 | |
| bmazzeo | 55:2526b3317bc8 | 130 | // ADC0_SC3 = 0x08; // CAL = 0, CALF = 0, res[5:4], ADCO = 1 (continuous conversion), AVGE = 0, AVGS = 00 |
| bmazzeo | 55:2526b3317bc8 | 131 | // ADC1_SC3 = 0x08; // CAL = 0, CALF = 0, res[5:4], ADCO = 1 (continuous conversion), AVGE = 0, AVGS = 00 |
| bmazzeo | 54:1697dc574b96 | 132 | |
| baxterja | 74:ebc9f09fda11 | 133 | ADC0->SC3 = 0x00; // CAL = 0, CALF = 0, res[5:4], ADCO = 0 (continuous conversion), AVGE = 0, AVGS = 00 |
| baxterja | 74:ebc9f09fda11 | 134 | ADC1->SC3 = 0x00; // CAL = 0, CALF = 0, res[5:4], ADCO = 0 (continuous conversion), AVGE = 0, AVGS = 00 |
| bmazzeo | 54:1697dc574b96 | 135 | |
| bmazzeo | 54:1697dc574b96 | 136 | |
| timmey9 | 45:d591d138cdeb | 137 | |
| baxterja | 74:ebc9f09fda11 | 138 | // A write to SC1[0] is necessary as a software trigger |
| baxterja | 74:ebc9f09fda11 | 139 | ADC0->SC1[0] = 0x0C; //AIEN = 0, DIFF = 0, Channel = AD12 (PTB2) |
| baxterja | 74:ebc9f09fda11 | 140 | ADC1->SC1[0] = 0x0E; //AIEN = 0, DIFF = 0, Channel = AD14 (PTB10) |
| bmazzeo | 54:1697dc574b96 | 141 | |
| baxterja | 74:ebc9f09fda11 | 142 | while( (ADC1->SC1[0]&ADC_SC1_COCO_MASK)) {} |
| baxterja | 74:ebc9f09fda11 | 143 | //gain = ADC0_R[0]; // read the register to clear SC1[0][COCO] |
| baxterja | 74:ebc9f09fda11 | 144 | debug.printf("ADC0_R[0]:%i\r\n", ADC0->R[0]); |
| baxterja | 74:ebc9f09fda11 | 145 | debug.printf("ADC0_R[1]:%i\r\n", ADC0->R[1]); |
| baxterja | 74:ebc9f09fda11 | 146 | debug.printf("ADC1_R[0]:%i\r\n", ADC1->R[0]); |
| baxterja | 74:ebc9f09fda11 | 147 | debug.printf("ADC1_R[1]:%i\r\n", ADC1->R[1]); |
| bmazzeo | 54:1697dc574b96 | 148 | |
| bmazzeo | 54:1697dc574b96 | 149 | /* |
| bmazzeo | 54:1697dc574b96 | 150 | |
| baxterja | 74:ebc9f09fda11 | 151 | ADC0_SC1[0] = 0x0C; //AIEN = 0, DIFF = 0, Channel = AD12 (PTB2) |
| baxterja | 74:ebc9f09fda11 | 152 | ADC1_SC1[0] = 0x0E; //AIEN = 0, DIFF = 0, Channel = AD14 (PTB10) |
| bmazzeo | 54:1697dc574b96 | 153 | |
| baxterja | 74:ebc9f09fda11 | 154 | while( (ADC1_SC1[0]&ADC_SC1_COCO_MASK)) {} |
| baxterja | 74:ebc9f09fda11 | 155 | debug.printf("ADC1_R[0]:%i\r\n", ADC1_R[0]); |
| bmazzeo | 54:1697dc574b96 | 156 | |
| baxterja | 74:ebc9f09fda11 | 157 | ADC0_SC1[0] = 0x0C; //AIEN = 0, DIFF = 0, Channel = AD12 (PTB2) |
| baxterja | 74:ebc9f09fda11 | 158 | ADC1_SC1[0] = 0x0E; //AIEN = 0, DIFF = 0, Channel = AD14 (PTB10) |
| bmazzeo | 54:1697dc574b96 | 159 | |
| bmazzeo | 54:1697dc574b96 | 160 | |
| baxterja | 74:ebc9f09fda11 | 161 | while( (ADC1_SC1[0]&ADC_SC1_COCO_MASK)) {} |
| baxterja | 74:ebc9f09fda11 | 162 | debug.printf("ADC1_R[0]:%i\r\n", ADC1_R[0]); |
| bmazzeo | 54:1697dc574b96 | 163 | */ |
| bmazzeo | 55:2526b3317bc8 | 164 | |
| bmazzeo | 55:2526b3317bc8 | 165 | // Now set up for use in the rest of the program - HARDWARE trigger |
| baxterja | 74:ebc9f09fda11 | 166 | ADC0->SC2 = 0x44; // ADACT = 0, ADTRG = 1 (HW trigger), ACFE = 0, ACFGT = 0, ACREN = 0, DMAEN = 1, REFSEL = 00 (DMAEN needs to be asserted) |
| baxterja | 74:ebc9f09fda11 | 167 | ADC1->SC2 = 0x44; // ADACT = 0, ADTRG = 1 (HW trigger), ACFE = 0, ACFGT = 0, ACREN = 0, DMAEN = 1, REFSEL = 00 (DMAEN needs to be asserted) |
| bmazzeo | 55:2526b3317bc8 | 168 | |
| bmazzeo | 54:1697dc574b96 | 169 | |
| bmazzeo | 54:1697dc574b96 | 170 | // adebug.printf("Calbiration complete. Hardware continuous conversion running.\r\n"); |
| bmazzeo | 53:83a90a47c1fd | 171 | // The ADCs are now just continuously converting and generating DMA signals after each conversion |
| timmey9 | 51:43143a3fc2d7 | 172 | } |
| timmey9 | 51:43143a3fc2d7 | 173 |

