//From http://cache.freescale.com/files/32bit/doc/quick_ref_guide/KQRUG.pdf
// Page 174
// Various PJRC forum posts that I've proceeded to butcher
#define PDB_CH0C1_TOS 0x0100
#define PDB_CH0C1_EN 0x01
uint8_t channels[] = {1,2,3,4,5,6};
volatile uint16_t samples[] = {0,0,0,0,0,0};
uint16_t sample_buffer[6];
volatile boolean samples_flag;
void setup(){
while(!Serial){}
channelSetup(channels, 6);
for(int i = 0; i < 6; i++){
Serial.println(channels[i]);
}
INIT_ADC();
INIT_PDB();
INIT_DMA_CH1();
INIT_DMA_CH0();
// Start PDB
Serial.println("Starting PDB SWTRIG");
PDB0_SC |= PDB_SC_SWTRIG;
}
void loop(){
if(samples_flag){
Serial.print("Samples present: ");
for(int i = 0; i < 6; i++){
noInterrupts();
sample_buffer[i] = samples[i];
interrupts();
}
for(int i = 0; i < 6; i++){
Serial.print(" ");
Serial.print(samples[i]);
Serial.print(" ");
}
Serial.println("");
noInterrupts();
samples_flag = false;
interrupts();
}
}
void pdb_isr(){
PDB0_SC &= ~PDB_SC_PDBIF;
}
void pdb_error_isr(){
PDB0_SC &= ~PDB_SC_PDBEN; // disable PDB
PDB0_CH0S &= ~1; // reset error CH0
PDB0_SC |= PDB_SC_PDBEN; // Enable PDB
Serial.println("PDB ERROR! RESTARTING!");
}
void adc0_isr(){
int res = ADC0_RA;
Serial.print(ADC0_SC1A & ~ADC_SC1_AIEN);
Serial.print(":");
Serial.print("ADC ISR: ");
Serial.print(res);
Serial.println("");
}
void dma_ch1_isr(){
// set samples flag for further processing
samples_flag = true;
// Clear interrupt request for channel 1
DMA_CINT = 1;
}
void dma_ch0_isr(){
// Clear interrupt request for channel 0
DMA_CINT = 0;
}
// Slow down PDB so we can see it.
#define PDB_PERIOD (F_BUS)
#define PDB_CONFIG (PDB_SC_TRGSEL(15) | PDB_SC_PDBEN | PDB_SC_PDBIE \
| PDB_SC_CONT | PDB_SC_PRESCALER(6) | PDB_SC_MULT(1))
void INIT_PDB(){
SIM_SCGC6 |= SIM_SCGC6_PDB;
PDB0_MOD = PDB_PERIOD;
PDB0_IDLY = 0;
PDB0_CH0C1 = PDB_CH0C1_TOS | PDB_CH0C1_EN;
PDB0_SC = PDB_CONFIG | PDB_SC_LDOK | PDB_SC_PDBEIE;
NVIC_ENABLE_IRQ(IRQ_PDB);
}
void INIT_ADC(){
analogReadRes(12);
analogReadAveraging(1);
analogReference('DEFAULT');
// run a few conversions
int sum = 0;
for(int i = 0; i <1024; i++){
sum += analogRead(A0);
sum += analogRead(A1);
sum += analogRead(A2);
sum += analogRead(A3);
sum += analogRead(A4);
sum += analogRead(A5);
}
// Enable ADC conversion complete interrupt, configure the pin to read.
ADC0_SC1A = ADC_SC1_AIEN | channels[0];
int res = ADC0_RA;
// Enable ADC conversion complete flag to request DMA transfer
ADC0_SC2 |= ADC_SC2_DMAEN;
// Enable hardware interrupt, need this enabled to allow for PDB to trigger ADC.
ADC0_SC2 |= ADC_SC2_ADTRG;
// Enable interrupts for ADC
NVIC_ENABLE_IRQ(IRQ_ADC0);
}
void INIT_DMA_CH1(){
// Enable DMA, DMAMUX clocks
SIM_SCGC7 |= SIM_SCGC7_DMA;
SIM_SCGC6 |= SIM_SCGC6_DMAMUX;
// Source address
DMA_TCD1_SADDR = &ADC0_RA;
// Increment source address by 2 bytes per iteration.
DMA_TCD1_SOFF = 0;
// After loop complete, return to start.
DMA_TCD1_SLAST = 0;
DMA_TCD1_DADDR = &samples[0];
DMA_TCD1_DOFF = 0x02;
DMA_TCD1_DLASTSGA = -0xC;
// Both Source and Dest size are 16 bit.
DMA_TCD1_ATTR = DMA_TCD_ATTR_SSIZE(1) | DMA_TCD_ATTR_DSIZE(1);
// Number of bytes to transfer (in each service request)
DMA_TCD1_NBYTES_MLOFFNO = DMA_TCD_NBYTES_MLOFFNO_NBYTES(2);
// Set loop counts
DMA_TCD1_CITER_ELINKYES = 6 | DMA_TCD_CITER_ELINK;
DMA_TCD1_BITER_ELINKYES = 6 | DMA_TCD_BITER_ELINK;
// Enable interrupt (end-of-major loop)
DMA_TCD1_CSR = (DMA_TCD_CSR_MAJORLINKCH(0)|DMA_TCD_CSR_MAJORELINK)
| DMA_TCD_CSR_INTMAJOR;
// Set ADC0 as source of transfer request, turn mux on.
DMAMUX0_CHCFG1 = DMAMUX_SOURCE_ADC0 | DMAMUX_ENABLE;
// Enable request input signal for channel 1
DMA_SERQ = 1;
DMA_ERQ |= DMA_ERQ_ERQ1;
// Enable interrupt request
NVIC_ENABLE_IRQ(IRQ_DMA_CH1);
}
void INIT_DMA_CH0(){
// Transfer request sent by DMA CH 1 to eventually move new setup data into ADC0_SC1A
// To change the sampled pin.
// Enable CH0, make it always requestor.
DMAMUX0_CHCFG0 = DMAMUX_ENABLE
| DMAMUX_SOURCE_ALWAYS0;
DMA_TCD0_SADDR = &channels[0];
DMA_TCD0_SOFF = 0x01;
DMA_TCD0_SLAST = -0x06;
DMA_TCD0_DADDR = &ADC0_SC1A;
DMA_TCD0_DOFF = 0x00;
DMA_TCD0_DLASTSGA = 0x00;
DMA_TCD0_NBYTES_MLNO = 0x01;
DMA_TCD0_BITER_ELINKNO = 0x6;
DMA_TCD0_CITER_ELINKNO = 0x6;
DMA_TCD0_ATTR = DMA_TCD_ATTR_SSIZE(0) | DMA_TCD_ATTR_DSIZE(0);
DMA_TCD0_CSR = DMA_TCD_CSR_INTMAJOR;
NVIC_ENABLE_IRQ(IRQ_DMA_CH0);
}
void channelSetup(uint8_t input_channels[], int num_channels){
uint8_t channel2sc1a[] = {
5, 14, 8, 9, 13, 12, 6, 7, 15, 4,
0, 19, 3, 21, 26, 22};
short temp = input_channels[0];
for(int i = 1; i < num_channels; i++){
input_channels[i-1] = channel2sc1a[input_channels[i]] | ADC_SC1_AIEN;
}
input_channels[num_channels-1] = channel2sc1a[temp] | ADC_SC1_AIEN;
}