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
- Committer:
- baxterja
- Date:
- 2017-06-01
- Revision:
- 74:ebc9f09fda11
- Parent:
- 55:2526b3317bc8
File content as of revision 74:ebc9f09fda11:
#include "adc.h"
/*
From page 869 of the user manual:
Before the ADC module can be used to complete conversions, an initialization procedure
must be performed. A typical sequence is:
1. Calibrate the ADC by following the calibration instructions in Calibration function.
2. Update CFG to select the input clock source and the divide ratio used to generate
ADCK. This register is also used for selecting sample time and low-power
configuration.
3. Update SC2 to select the conversion trigger, hardware or software, and compare
function options, if enabled.
4. Update SC3 to select whether conversions will be continuous or completed only once
(ADCO) and whether to perform hardware averaging.
5. Update SC1:SC1n registers to select whether conversions will be single-ended or
differential and to enable or disable conversion complete interrupts. Also, select the
input channel which can be used to perform conversions.
*/
DigitalOut green(LED_GREEN);
DigitalOut red(LED_RED);
Serial debug(USBTX, USBRX);
void adc_init()
{
// Turn on the ADC0 and ADC1 clocks
SIM->SCGC6 |= SIM_SCGC6_ADC0_MASK;
SIM->SCGC3 |= SIM_SCGC3_ADC1_MASK;
// Set ADC hardware trigger to PDB0
SIM->SOPT7 = SIM_SOPT7_ADC0TRGSEL(0); // Select triggering by PDB and select pre-trigger A
SIM->SOPT7 = SIM_SOPT7_ADC1TRGSEL(0); // Select triggering by PDB and select pre-trigger A
// turn on the clock to the PDB
// SIM->SCGC6 |= SIM_SCGC6_PDB_MASK;
// set ADC trigger to PDB0
// SIM_SOPT7 = SIM_SOPT7_ADC0TRGSEL(0);
// This lets the clocks go to the ADC
// SIM_SCGC6 |= SIM_SCGC6_ADC0_MASK;
// SIM_SCGC3 |= SIM_SCGC3_ADC1_MASK;
/* // This lets the clocks go to the PDB
SIM_SCGC6 |= SIM_SCGC6_PDB_MASK;
// Set PDB to be enabled and have continous triggers
PDB0_SC = PDB_SC_DMAEN_MASK // DMA Enable
| PDB_SC_TRGSEL(0xf) // Software trigger
| PDB_SC_PDBEN_MASK // Set to continuous mode
| PDB_SC_LDOK_MASK; // Loading mask
PDB0_SC |= PDB_SC_SWTRIG_MASK; // enable software trigger (start the PDB)
// This now routes the triggers
SIM_SOPT7 = SIM_SOPT7_ADC0TRGSEL(0);
SIM_SOPT7 = SIM_SOPT7_ADC1TRGSEL(0);
*/
/* From page 853 of the user manual
Prior to calibration, the user must configure the ADC's clock source and frequency, low
power configuration, voltage reference selection, sample time, and high speed
configuration according to the application's clock source availability and needs.
*/
ADC0->SC1[0] = 0x0C; //AIEN = 0, DIFF = 0, Channel = AD12 (PTB2)
ADC1->SC1[0] = 0x0E; //AIEN = 0, DIFF = 0, Channel = AD14 (PTB10)
ADC0->CFG1 = 0x0C; //ADLPC = 0, ADIV = 0, ADLSMP = 0, MODE = 0b11, ADICLK = 00 (16-bit single-ended)
ADC1->CFG1 = 0x0C; //ADLPC = 0, ADIV = 0, ADLSMP = 0, MODE = 0b11, ADICLK = 00 (16-bit single-ended)
// ADC0_CFG1 = 0x00; //ADLPC = 0, ADIV = 0, ADLSMP = 0, MODE = 0b00, ADICLK = 00 (16-bit single-ended)
// ADC1_CFG1 = 0x00; //ADLPC = 0, ADIV = 0, ADLSMP = 0, MODE = 0b00, ADICLK = 00 (16-bit single-ended)
// It is necessary not to have hardware trigger for calbiration
ADC0->CFG2 = 0x00; // MUXSEL = 0, ADACKEN = 0, ADHSC = 0, ADLSTS = 0 (does not matter - short sample time)
ADC1->CFG2 = 0x00; // MUXSEL = 0, ADACKEN = 0, ADHSC = 0, ADLSTS = 0 (does not matter - short sample time)
// Use averaging to make calibration better
ADC0->SC3 = 0x07; // CAL = 0, CALF = 0, res[5:4], ADCO = 0 (continuous conversion), AVGE = 1, AVGS = 11
ADC1->SC3 = 0x07; // CAL = 0, CALF = 0, res[5:4], ADCO = 0 (continuous conversion), AVGE = 1, AVGS = 11
// calibrate the ADC (following Joey's code example)
ADC0->SC3 |= ADC_SC3_CAL_MASK; // start calibration
while(ADC0->SC3&ADC_SC3_CALF_MASK) {} // wait for calibration to complete
ADC1->SC3 |= ADC_SC3_CAL_MASK; // start calibration
while(ADC1->SC3&ADC_SC3_CALF_MASK) {} // wait for calibration to complete
debug.printf("ADC0_CLP0:%d\r\n", ADC0->CLP0);
debug.printf("ADC0_CLP1:%d\r\n", ADC0->CLP1);
debug.printf("ADC0_CLP2:%d\r\n", ADC0->CLP2);
debug.printf("ADC0_CLP3:%d\r\n", ADC0->CLP3);
debug.printf("ADC0_CLPS:%d\r\n", ADC0->CLPS);
// calculate the gains (see user manual page 864)
int16_t gain = (ADC0->CLP0+ADC0->CLP1+ADC0->CLP2+ADC0->CLP3+ADC0->CLP4+ADC0->CLPS);
gain = gain / 2; // divide by 2
gain |= 0x8000; // set the MSB
ADC0->PG = gain;
gain = (ADC1->CLP0+ADC1->CLP1+ADC1->CLP2+ADC1->CLP3+ADC1->CLP4+ADC1->CLPS);
gain = gain / 2; // divide by 2
gain |= 0x8000; // set the MSB
ADC1->PG = gain;
gain = (ADC0->CLM0+ADC0->CLM1+ADC0->CLM2+ADC0->CLM3+ADC0->CLM4+ADC0->CLMS);
gain = gain / 2; // divide by 2
gain |= 0x8000; // set the MSB
ADC0->MG = gain;
gain = (ADC1->CLM0+ADC1->CLM1+ADC1->CLM2+ADC1->CLM3+ADC1->CLM4+ADC1->CLMS);
gain = gain / 2; // divide by 2
gain |= 0x8000; // set the MSB
ADC1->MG = gain;
// ADC0_SC3 &= ~ADC_SC3_CAL_MASK; // stop calibration
// ADC1_SC3 &= ~ADC_SC3_CAL_MASK; // stop calibration
// Now set up for use in the rest of the program - software trigger
ADC0->SC2 = 0x04; // ADACT = 0, ADTRG = 0 (HW trigger), ACFE = 0, ACFGT = 0, ACREN = 0, DMAEN = 1, REFSEL = 00 (DMAEN needs to be asserted)
ADC1->SC2 = 0x04; // ADACT = 0, ADTRG = 0 (HW trigger), ACFE = 0, ACFGT = 0, ACREN = 0, DMAEN = 1, REFSEL = 00 (DMAEN needs to be asserted)
// ADC0_SC3 = 0x08; // CAL = 0, CALF = 0, res[5:4], ADCO = 1 (continuous conversion), AVGE = 0, AVGS = 00
// ADC1_SC3 = 0x08; // CAL = 0, CALF = 0, res[5:4], ADCO = 1 (continuous conversion), AVGE = 0, AVGS = 00
ADC0->SC3 = 0x00; // CAL = 0, CALF = 0, res[5:4], ADCO = 0 (continuous conversion), AVGE = 0, AVGS = 00
ADC1->SC3 = 0x00; // CAL = 0, CALF = 0, res[5:4], ADCO = 0 (continuous conversion), AVGE = 0, AVGS = 00
// A write to SC1[0] is necessary as a software trigger
ADC0->SC1[0] = 0x0C; //AIEN = 0, DIFF = 0, Channel = AD12 (PTB2)
ADC1->SC1[0] = 0x0E; //AIEN = 0, DIFF = 0, Channel = AD14 (PTB10)
while( (ADC1->SC1[0]&ADC_SC1_COCO_MASK)) {}
//gain = ADC0_R[0]; // read the register to clear SC1[0][COCO]
debug.printf("ADC0_R[0]:%i\r\n", ADC0->R[0]);
debug.printf("ADC0_R[1]:%i\r\n", ADC0->R[1]);
debug.printf("ADC1_R[0]:%i\r\n", ADC1->R[0]);
debug.printf("ADC1_R[1]:%i\r\n", ADC1->R[1]);
/*
ADC0_SC1[0] = 0x0C; //AIEN = 0, DIFF = 0, Channel = AD12 (PTB2)
ADC1_SC1[0] = 0x0E; //AIEN = 0, DIFF = 0, Channel = AD14 (PTB10)
while( (ADC1_SC1[0]&ADC_SC1_COCO_MASK)) {}
debug.printf("ADC1_R[0]:%i\r\n", ADC1_R[0]);
ADC0_SC1[0] = 0x0C; //AIEN = 0, DIFF = 0, Channel = AD12 (PTB2)
ADC1_SC1[0] = 0x0E; //AIEN = 0, DIFF = 0, Channel = AD14 (PTB10)
while( (ADC1_SC1[0]&ADC_SC1_COCO_MASK)) {}
debug.printf("ADC1_R[0]:%i\r\n", ADC1_R[0]);
*/
// Now set up for use in the rest of the program - HARDWARE trigger
ADC0->SC2 = 0x44; // ADACT = 0, ADTRG = 1 (HW trigger), ACFE = 0, ACFGT = 0, ACREN = 0, DMAEN = 1, REFSEL = 00 (DMAEN needs to be asserted)
ADC1->SC2 = 0x44; // ADACT = 0, ADTRG = 1 (HW trigger), ACFE = 0, ACFGT = 0, ACREN = 0, DMAEN = 1, REFSEL = 00 (DMAEN needs to be asserted)
// adebug.printf("Calbiration complete. Hardware continuous conversion running.\r\n");
// The ADCs are now just continuously converting and generating DMA signals after each conversion
}

