This commit is contained in:
commit
3645d1eec9
1 changed files with 273 additions and 0 deletions
273
CosmicOscilloscope
Normal file
273
CosmicOscilloscope
Normal file
|
|
@ -0,0 +1,273 @@
|
|||
#undef HID_ENABLED
|
||||
|
||||
// Arduino Due ADC->DMA->USB 1MSPS
|
||||
// by stimmer
|
||||
// from http://forum.arduino.cc/index.php?topic=137635.msg1136315#msg1136315
|
||||
// Input: Analog in A0
|
||||
// Output: Raw stream of uint16_t in range 0-4095 on Native USB Serial/ACM
|
||||
|
||||
// on linux, to stop the OS cooking your data:
|
||||
// stty -F /dev/ttyACM0 raw -iexten -echo -echoe -echok -echoctl -echoke -onlcr
|
||||
|
||||
volatile int bufn,obufn;
|
||||
uint16_t buf[4][256]; // 4 buffers of 256 readings
|
||||
|
||||
//HV PSU init
|
||||
const int SS_pin = 42; //tbc
|
||||
const int SCK_pin = 44;
|
||||
const int MISO_pin = 22;
|
||||
const int MOSI_pin = 43;
|
||||
byte sendValue; // Value we are going to send
|
||||
|
||||
|
||||
void ADC_Handler(){ // move DMA pointers to next buffer
|
||||
int f=ADC->ADC_ISR;
|
||||
if (f&(1<<27)){
|
||||
bufn=(bufn+1)&3;
|
||||
ADC->ADC_RNPR=(uint32_t)buf[bufn];
|
||||
ADC->ADC_RNCR=256;
|
||||
}
|
||||
}
|
||||
|
||||
void setup(){
|
||||
//HV Setup
|
||||
digitalWrite(SS, HIGH); // Start with SS high
|
||||
pinMode(SS_pin, OUTPUT);
|
||||
pinMode(SCK_pin, OUTPUT);
|
||||
pinMode(MISO_pin, INPUT); //this is the avalanche pin, not implemented yet
|
||||
pinMode(MOSI_pin, OUTPUT);
|
||||
|
||||
sendValue = 0xFF; //Set the HV here onetime
|
||||
sendValue = bitBang(sendValue); // Transmit data
|
||||
|
||||
|
||||
//set up the thresholds
|
||||
pinMode(35, OUTPUT); //setup for the MAX5387 - later set to 0. signal PA0
|
||||
pinMode(36, OUTPUT);//setup for the MAX5387 - later set to 0. signal PA1
|
||||
pinMode(37, OUTPUT);//setup for the MAX5387 - later set to 0. signal PA2
|
||||
digitalWrite(35, LOW);//configure the address of the MAX5387 pot
|
||||
digitalWrite(36, LOW);//configure the address of the MAX5387 pot
|
||||
digitalWrite(37, LOW);//configure the address of the MAX5387 pot
|
||||
pinMode(5, INPUT); //set the interrupt pin for trigger as high impedance, probably not required
|
||||
|
||||
Wire.begin();
|
||||
Wire.beginTransmission(byte(0x28)); // transmit to device #112
|
||||
Wire.write(byte(B00010011)); //set both registers
|
||||
//Wire.write(byte(B00010001)); //set both register A only
|
||||
//Wire.write(byte(B00010010)); //set both register B only
|
||||
Wire.write(byte(0x50));// sets registers to this value (1 step = 13mV)
|
||||
Wire.endTransmission(); // stop transmitting
|
||||
|
||||
|
||||
//ADC setup
|
||||
|
||||
|
||||
SerialUSB.begin(0);
|
||||
while(!SerialUSB);
|
||||
|
||||
pmc_enable_periph_clk(ID_ADC);
|
||||
adc_init(ADC, SystemCoreClock, ADC_FREQ_MAX, ADC_STARTUP_FAST);
|
||||
ADC->ADC_MR |=0x80; // free running
|
||||
|
||||
ADC->ADC_CHER=0x80;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
void loop(){
|
||||
while(obufn==bufn); // wait for buffer to be full
|
||||
SerialUSB.write((uint8_t *)buf[obufn],512); // send it - 512 bytes = 256 uint16_t
|
||||
SerialUSB.write((uint8_t *)buf[obufn],512); // send it - 512 bytes = 256 uint16_t
|
||||
obufn=(obufn+1)&3;
|
||||
}
|
||||
|
||||
byte bitBang(byte _send) // This function is what bitbangs the data
|
||||
{
|
||||
|
||||
//reception isn't implemented in this version.
|
||||
byte _receive = 0;
|
||||
digitalWrite(SS_pin, LOW); // SS low
|
||||
for(int i=0; i<8; i++) // There are 8 bits in a byte
|
||||
{
|
||||
digitalWrite(MOSI_pin, bitRead(_send, 7-i)); // Set MOSI
|
||||
//delay(1);
|
||||
digitalWrite(SCK_pin, HIGH); // SCK high
|
||||
//bitWrite(_receive, i, digitalRead(MISO_pin)); // Capture MISO
|
||||
digitalWrite(SCK_pin, LOW); // SCK low
|
||||
//digitalWrite(MOSI_pin, LOW); // Set MOSI
|
||||
|
||||
}
|
||||
digitalWrite(SS_pin, HIGH); // SS high again
|
||||
|
||||
//return _receive; // Return the received data
|
||||
}
|
||||
|
||||
//timing system
|
||||
|
||||
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_TC3); // Turn on power for timer block 1 channel 0
|
||||
pmc_enable_periph_clk(ID_TC6); // Turn on power for timer block 2 channel 0
|
||||
|
||||
// Timer block 0 channel 0 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 is the clock frequency and 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 1 channel 0 is the PLL for when the GPS chip isn't providing the PPS
|
||||
// it has the frequency loaded in reg C and is triggered from the TC0 ISR
|
||||
|
||||
config = TC_CMR_TCCLKS_TIMER_CLOCK1 | // Select fast clock MCK/2 = 42 MHz
|
||||
TC_CMR_CPCTRG; // Compare register C with count value
|
||||
|
||||
TC_Configure(TC1, 0, config); // Configure channel 0 of TC1
|
||||
TC_SetRC(TC1, 0, FREQ); // One second approx initial PLL value
|
||||
TC_Start(TC1, 0); // Start timer running
|
||||
|
||||
TC1->TC_CHANNEL[0].TC_IER = TC_IER_CPCS; // Enable the C register compare interrupt
|
||||
TC1->TC_CHANNEL[0].TC_IDR = ~TC_IER_CPCS; // and disable the rest
|
||||
NVIC_EnableIRQ(TC3_IRQn); // Enable interrupt handler for channel 0
|
||||
|
||||
// Timer block 2 channel 0 is connected to the RAY event
|
||||
// It is kept in phase by the PPS comming from TC0 when the PPS arrives
|
||||
// or from TC1 when the PLL is active (This is the so called software diode logic)
|
||||
|
||||
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 rega0 = FREQ, // RA reg
|
||||
stsr0 = 0, // Interrupt status register
|
||||
ppcnt = 0, // PPS count
|
||||
delcn = 0; // Synthetic PPS ms
|
||||
|
||||
static uint32_t rega1, stsr1 = 0;
|
||||
|
||||
static uint32_t stsr2 = 0;
|
||||
|
||||
boolean pll_flag = false;
|
||||
|
||||
int old_ra = 0;
|
||||
int new_ra = 0;
|
||||
#define DEAD_TIME 42000 // 1ms
|
||||
|
||||
// Handle the PPS interrupt in counter block 0 ISR
|
||||
|
||||
void TC0_Handler() {
|
||||
|
||||
// In principal we could connect a diode
|
||||
// to pass on the PPS to counter blocks 1 & 2. However for some unknown
|
||||
// reason this pulls down the PPS voltage level to less than 1V and
|
||||
// the trigger becomes unreliable !!
|
||||
// In any case the PPS is 100ms wide !! Introducing a blind spot when
|
||||
// the diode creates the OR of the event trigger and the PPS.
|
||||
// So this is a software diode
|
||||
|
||||
TC2->TC_CHANNEL[0].TC_CCR = TC_CCR_SWTRG; // Forward PPS to counter block 2
|
||||
TC1->TC_CHANNEL[0].TC_CCR = TC_CCR_SWTRG; // Forward PPS to counter block 1
|
||||
|
||||
rega0 = TC0->TC_CHANNEL[0].TC_RA; // Read the RA reg (PPS period)
|
||||
stsr0 = TC_GetStatus(TC0, 0); // Read status and clear load bits
|
||||
|
||||
if (rega0 < MFRQ) // Sanity check against noise
|
||||
rega0 = FREQ; // Use nominal value
|
||||
|
||||
TC_SetRC(TC1, 0, rega0); // Set the PLL count to what we just counted
|
||||
|
||||
SwapBufs(); // Every PPS swap the read/write buffers
|
||||
ppcnt++; // PPS count
|
||||
displ = 1; // Display stuff in the loop
|
||||
gps_ok = true; // Its OK because we got a PPS
|
||||
pll_flag = true; // Inhibit PLL, dont take over PPS arrived
|
||||
|
||||
old_ra = 0; // Dead time counters
|
||||
new_ra = 0;
|
||||
|
||||
IncDateTime(); // Next second
|
||||
|
||||
if (pps_led) {
|
||||
digitalWrite(PPS_PIN,HIGH);
|
||||
pps_led = false;
|
||||
} else {
|
||||
digitalWrite(PPS_PIN,LOW);
|
||||
pps_led = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Handle PLL interrupts
|
||||
// When/If the PPS goes missing due to a lost lock we carry on with the last measured
|
||||
// value for the second from TC0
|
||||
|
||||
void TC3_Handler() {
|
||||
|
||||
stsr2 = TC_GetStatus(TC1, 0); // Read status and clear interrupt
|
||||
#if FLG_PIN
|
||||
digitalWrite(FLG_PIN,HIGH); // Flag set (for debug)
|
||||
digitalWrite(FLG_PIN,LOW);
|
||||
#endif
|
||||
|
||||
if (pll_flag == false) { // Only take over when no PPS
|
||||
|
||||
TC2->TC_CHANNEL[0].TC_CCR = TC_CCR_SWTRG; // Forward PPS to counter block 2
|
||||
SwapBufs(); // Every PPS swap the read/write buffers
|
||||
ppcnt++; // PPS count
|
||||
displ = 1; // Display stuff in the loop
|
||||
gps_ok = false; // PPS missing
|
||||
|
||||
IncDateTime(); // Next second
|
||||
}
|
||||
pll_flag = false; // Take over until PPS comes back
|
||||
}
|
||||
|
||||
// We need a double buffer, one is being written by the ISR while
|
||||
// the other is read from user space within one second.
|
||||
Loading…
Reference in a new issue