This commit is contained in:
commit
81d6c2537f
1 changed files with 161 additions and 0 deletions
161
Cosmic Pi ADCtrigger
Normal file
161
Cosmic Pi ADCtrigger
Normal file
|
|
@ -0,0 +1,161 @@
|
|||
/*notes to Team Cosmic Pi
|
||||
I just got this working in Cosimo's lab using a TTi TG5011 LXI function generator and a Tektronix TDS2024 scope.
|
||||
It took a lot of fine tuning to get the right buffer read out, so that the rising edge can be consistently seen in the samples.
|
||||
The buffer index (i.e. how many buffers back in time you need to go) will definitely change based on the rest of the code, but the principle is here
|
||||
Don't forget that we're interleaving channels 1 and 2, therefore the nth sample is channel 1 and the n+1th sample is channel 2 etc. and if we're reading out 50, it's actually 25 from channel A etc.
|
||||
Also note that the ADC seems to top out (4096) around 2.3V, I was expecting 3.3V, so maybe there's another setting to tweak here.
|
||||
|
||||
If you are testing this code independently here are your parameters for connection:
|
||||
Set up a SAW wave, with a vertical rising edge, then monotonically decreasing
|
||||
Amplitude (max) 2.3V, never above 3.3V or you'll cook the DUE
|
||||
Frequency - Tested up to 10Hz, our specification max is 5 Hz.
|
||||
Pinouts:
|
||||
Saw wave goes in to D2 (trigger), A6 and A7 (ADC channels)
|
||||
|
||||
Unexplained - when I hook up one of the ADC inputs to 0V it crashes. I think it might be due to an offset somewhere in the signal generator/earthing mess/laptop USB grounding...
|
||||
*/
|
||||
|
||||
volatile int bufn,obufn,pbufn,qbufn; //obuf, pbuf and qbuf are the previously filled buffers (i.e. going backwards in time)
|
||||
uint16_t buf[8][256]; // 8 buffers of 256 readings
|
||||
bool bufferdump=false; //flag for event, when the buffer should be dumped
|
||||
|
||||
void ADC_Handler(){ // move DMA pointers to next buffer
|
||||
int f=ADC->ADC_ISR;
|
||||
if (f&(1<<27)){
|
||||
//memcpy(lastbuf, buf[bufn], 256);
|
||||
bufn=(bufn+1)&7;
|
||||
ADC->ADC_RNPR=(uint32_t)buf[bufn];
|
||||
ADC->ADC_RNCR=256;
|
||||
}
|
||||
}
|
||||
|
||||
void setup(){
|
||||
Serial.begin(115200); //serial output at high speed, tested up to 10Hz with this configuration (for a minute or two)
|
||||
//while(!Serial);
|
||||
pmc_enable_periph_clk(ID_ADC);
|
||||
adc_init(ADC, SystemCoreClock, ADC_FREQ_MAX, ADC_STARTUP_FAST);
|
||||
|
||||
|
||||
REG_ADC_MR = 0x10380080; // Free run as fast as you can - ADC settings as current core Cosmic Pi code
|
||||
REG_ADC_CHER = 3; // Channels 0 and 1
|
||||
|
||||
NVIC_EnableIRQ(ADC_IRQn);
|
||||
ADC->ADC_IDR=~(1<<27);
|
||||
ADC->ADC_IER=1<<27;
|
||||
ADC->ADC_RPR=(uint32_t)buf[0]; // DMA buffer
|
||||
ADC->ADC_RCR=256;
|
||||
ADC->ADC_RNPR=(uint32_t)buf[1]; // next DMA buffer
|
||||
ADC->ADC_RNCR=256;
|
||||
bufn=obufn=1;
|
||||
ADC->ADC_PTCR=1;
|
||||
ADC->ADC_CR=2;
|
||||
TimersStart();
|
||||
}
|
||||
|
||||
//Routine copied out of Cosmic Pi core code, only using one interrupt on Pin 2 for this test.
|
||||
void TimersStart() {
|
||||
|
||||
uint32_t config = 0;
|
||||
|
||||
// Set up the power management controller for TC0 and TC2
|
||||
|
||||
pmc_set_writeprotect(false); // Enable write access to power management chip
|
||||
pmc_enable_periph_clk(ID_TC0); // Turn on power for timer block 0 channel 0
|
||||
pmc_enable_periph_clk(ID_TC6); // Turn on power for timer block 2 channel 0
|
||||
|
||||
// Timer block zero channel zero is connected only to the PPS
|
||||
// We set it up to load regester RA on each PPS and reset
|
||||
// So RA will contain the number of clock ticks between two PPS, this
|
||||
// value should be very stable +/- one tick
|
||||
|
||||
config = TC_CMR_TCCLKS_TIMER_CLOCK1 | // Select fast clock MCK/2 = 42 MHz
|
||||
TC_CMR_ETRGEDG_RISING | // External trigger rising edge on TIOA0
|
||||
TC_CMR_ABETRG | // Use the TIOA external input line
|
||||
TC_CMR_LDRA_RISING; // Latch counter value into RA
|
||||
|
||||
TC_Configure(TC0, 0, config); // Configure channel 0 of TC0
|
||||
TC_Start(TC0, 0); // Start timer running
|
||||
|
||||
TC0->TC_CHANNEL[0].TC_IER = TC_IER_LDRAS; // Enable the load AR channel 0 interrupt each PPS
|
||||
TC0->TC_CHANNEL[0].TC_IDR = ~TC_IER_LDRAS; // and disable the rest of the interrupt sources
|
||||
NVIC_EnableIRQ(TC0_IRQn); // Enable interrupt handler for channel 0
|
||||
|
||||
// Timer block 2 channel zero is connected to the OR of the PPS and the RAY event
|
||||
|
||||
config = TC_CMR_TCCLKS_TIMER_CLOCK1 | // Select fast clock MCK/2 = 42 MHz
|
||||
TC_CMR_ETRGEDG_RISING | // External trigger rising edge on TIOA1
|
||||
TC_CMR_ABETRG | // Use the TIOA external input line
|
||||
TC_CMR_LDRA_RISING; // Latch counter value into RA
|
||||
|
||||
TC_Configure(TC2, 0, config); // Configure channel 0 of TC2
|
||||
TC_Start(TC2, 0); // Start timer running
|
||||
|
||||
TC2->TC_CHANNEL[0].TC_IER = TC_IER_LDRAS; // Enable the load AR channel 0 interrupt each PPS
|
||||
TC2->TC_CHANNEL[0].TC_IDR = ~TC_IER_LDRAS; // and disable the rest of the interrupt sources
|
||||
NVIC_EnableIRQ(TC6_IRQn); // Enable interrupt handler for channel 0
|
||||
|
||||
// Set up the PIO controller to route input pins for TC0 and TC2
|
||||
|
||||
PIO_Configure(PIOC,PIO_INPUT,
|
||||
PIO_PB25B_TIOA0, // D2 Input
|
||||
PIO_DEFAULT);
|
||||
|
||||
PIO_Configure(PIOC,PIO_INPUT,
|
||||
PIO_PC25B_TIOA6, // D5 Input
|
||||
PIO_DEFAULT);
|
||||
}
|
||||
|
||||
// Timer chip interrupt handlers try to get time stamps to within 4 system clock ticks
|
||||
|
||||
static uint32_t displ = 0; // Display values in loop
|
||||
|
||||
static uint32_t ppsfl = LOW, // PPS Flag boolean
|
||||
rega0 = 0, // RA reg
|
||||
stsr0 = 0, // Interrupt status register
|
||||
ppcnt = 0; // PPS count
|
||||
|
||||
// Handle the PPS interrupt in counter block 0 ISR
|
||||
|
||||
|
||||
void TC0_Handler() {
|
||||
|
||||
// This ISR is connected only to the PPS (Pulse Per Second) GPS event
|
||||
// Each time this runs, set the flag to tell the TC6 ISR we have seen it
|
||||
// This logic only works if the TC0 handler gets called before the TC6 handler
|
||||
// hence the debug flag which I look at with a scope to be sure.
|
||||
// I may introduce a small delay line to ensure this is true, so far it is.
|
||||
|
||||
|
||||
rega0 = TC0->TC_CHANNEL[0].TC_RA; // Read the RA reg (PPS period)
|
||||
stsr0 = TC_GetStatus(TC0, 0); // Read status and clear load bits
|
||||
|
||||
//Custom code for read out of ADC on trigger is here
|
||||
bufferdump=true; //set the buffer dump flag
|
||||
Serial.println("trigint"); //announce trigger over serial
|
||||
Serial.println(rega0); //write out the counter value (how many clock counts since last trigger)
|
||||
Serial.print(bufn); //write out the ADC buffer position at the time of the trigger, note that the lab configuration with this code meant the rising edge was 2 buffers back from the one in use.
|
||||
}
|
||||
|
||||
|
||||
void loop(){
|
||||
if (bufferdump) {
|
||||
Serial.println(" bufferdump"); //confirm this part of the code is running
|
||||
|
||||
//obufn=(bufn+7)&7; //look in the previous buffer (n-1)
|
||||
//pbufn=(bufn+6)&7; //look in the one before that (n-2)
|
||||
qbufn=(bufn+5)&7; // and look in the buffer before that (n-3)
|
||||
|
||||
//SerialUSB.write((uint8_t *)buf[obufn],512); // send it - 512 bytes = 256 uint16_t - this was the original code, converted to serialise and int the buffer for simplicity
|
||||
Serial.println("n-2 buffer"); //the buffer index, i.e. qbufn
|
||||
for (int s=0; s < 50; s++){
|
||||
Serial.print(int(s)); //sample index within buffer
|
||||
Serial.print(' ');
|
||||
Serial.println(int(buf[qbufn][s])); //print the value from the buffer
|
||||
}
|
||||
Serial.println();
|
||||
|
||||
|
||||
bufferdump = false;//reset flag
|
||||
}
|
||||
|
||||
}
|
||||
Loading…
Reference in a new issue