/*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 } }