Arianna autonomous DAQ firmware
Dependencies: mbed SDFileSystemFilinfo AriSnProtocol NetServicesMin AriSnComm MODSERIAL PowerControlClkPatch DS1820OW
main.cpp
- Committer:
- uci1
- Date:
- 2012-06-30
- Revision:
- 0:664899e0b988
- Child:
- 1:e392595b4b76
File content as of revision 0:664899e0b988:
#include "mbed.h" #include <stdint.h> #include "SDFileSystem.h" #include "MODSERIAL.h" #include "Watchdog.h" #include "SnConstants.h" #include "SnBitUtils.h" #include "SnSDUtils.h" #include "SnConfigFrame.h" #include "SnEventFrame.h" #include "SnStatusFrame.h" #include "SnCommWin.h" #include "SnCommAfar.h" #include "SnCommUsb.h" // // MBED PINS (ordered by number) // // leds (for debugging) DigitalOut led1(LED1); DigitalOut led2(LED2); DigitalOut led3(LED3); DigitalOut led4(LED4); // Set up power pins - Note that it's Zero for "on" DigitalOut PIN_turn_on_system(p17); DigitalOut PIN_turn_on_amps(p25); // Activate/select chip by falling edge DigitalOut PIN_ADC_CS( p9 ); // clock signal to activate PLA setting DigitalOut PIN_PLA_cs(p10); // To force a trigger DigitalOut PIN_forceTrigger(p11); //modification // To suppress thermal triggers DigitalOut PIN_enableThermTrig(p12); // Restart clock on all FPGAs. DigitalOut PIN_DoNotRestartAllClocks( p13 ); // This tells the DFPGAs to store the data on motherboard FPGA and // read it out. DigitalIn PIN_a_sf_clk( p14 ); DigitalIn PIN_rst_a_sf(p15); // Lock daughter card registeres (during data readout). DigitalOut PIN_lockRegisters( p20 ); // Majority logic pins DigitalOut PIN_MajLogHiBit(p22); DigitalOut PIN_MajLogLoBit(p23); // Tell FPGA to be ready to accept DAC values DigitalOut PIN_start_fpga(p26); // Two bits to the select the daughter card for readout DigitalOut PIN_selCardHiBit( p29 ); DigitalOut PIN_selCardLoBit( p30 ); // To launch a heartbeat pulse DigitalOut PIN_heartbeat(p24); // Setup SPI pins SPI PIN_spi( p5, p6, p7 ); // The SD card SDFileSystem sd(p5, p6, p7, p8, SnSDUtils::kSDsubDir+1); LocalFileSystem local("local"); // // fwd declare fcns // void ReadAllRegisters(); void ReadRegister(const uint8_t chan, int16_t* dev); void SaveEvent(const int32_t etms); void WaitTrigAndSendClock(); void SetConfig(); SnCommWin::ECommWinResult OpenCommWin(); // // globals // // readout objs static Ticker gForceTicker; static Ticker gIOticker; static Timer gEvtTimer; static SnConfigFrame gConf; static SnEventFrame gEvent; // parameters static bool gFirstEvt = true; static bool gReadingOut = false; static bool gCommWinOpen = false; // if it's open static bool gOpenCommWin = false; // if it should be opened static int32_t gEvtNum = 0; // num of evt written static int32_t gTrgNum[kNumTrgs] = {0}; // num of this type of trg received // i/o static Timer gIOtimer; static MODSERIAL gCpu( USBTX, USBRX ); // defined here so it might be used for debugging output static SnCommWin* gComms[kNcomms] = { new SnCommAfar, new SnCommUsb(&gCpu) }; // order => priority static FILE* gCurFile = 0; //static char gEvtBuf[SnEventFrame::kMaxSizeOf]; //static char gConfBuf[SnConfigFrame::kMaxSizeOf]; //static char gStatBuf[SnStatusFrame::kMaxSizeOf]; static char gGenBuf[SnStatusFrame::kMaxSizeOf]; // must be big enough for event or status or config! void procForceTrigger() { led1=!led1; if (gReadingOut==false && gCommWinOpen==false) { gEvent.SetTrgBit(kFrcTrg); gEvent.SetTrgNum((gTrgNum[kFrcTrg])++); PIN_forceTrigger = 1; // force a trigger } } void procCommWin() { if (gReadingOut==false && gCommWinOpen==false) { gOpenCommWin = true; } } // TODO: add block-id's to output file? (config block, event block, file header block, etc.) int main() { led2=1; //wait_ms(100); // a failsafe Watchdog::kick(kWDFailsafe); // Turn on all power // Note that zero means "on" PIN_turn_on_system=0; // block (thermal) triggers during configuration PIN_enableThermTrig = 0; PIN_ADC_CS = 1; PIN_DoNotRestartAllClocks = 1; PIN_forceTrigger = 0; wait_ms(20); // setup SPI PIN_spi.frequency( 10000000 ); // Max is 12.5 MHz gForceTicker.detach(); gFirstEvt = true; gConf.Reset(); // // get config // // TODO: communication window // TODO: call usb port setup //OpenCommWin(); // TODO: get config SetConfig(); // get ready to trigger PIN_spi.format( 16, 1 ); // change to data readout format // force a trigger every dForceTrigPeriod seconds gForceTicker.attach(&procForceTrigger, gConf.GetForceTrigPeriod()); led2=0; // the main event loop. wait for triggers in SendClock while( true ) { // in here, we wait for triggers from the MB-FPGA led4 = !led4; Watchdog::kick(); // don't reset! gEvtTimer.reset(); gEvtTimer.start(); PIN_lockRegisters = 0; // allow data to come from DFPGA WaitTrigAndSendClock(); PIN_lockRegisters = 1; // block registers during readout gEvtTimer.stop(); Watchdog::kick(); // don't reset! if (gOpenCommWin) { OpenCommWin(); gOpenCommWin=false; continue; } // // got trigger. read registers to mbed and build the event // // read data & calc CRC gEvent.ReadWaveforms(PIN_spi, PIN_selCardHiBit, PIN_selCardLoBit); gEvent.SetCurMbedTime(); // TODO: no way to check for external trigger? if (gEvent.IsForcedTrg()==false) { gEvent.SetTrgBit(kThmTrg); gEvent.SetTrgNum((gTrgNum[kThmTrg])++); } // else already set by procForceTrigger // (no need to calc if we throw this event away) Watchdog::kick(); // don't reset! const int32_t etms = gEvtTimer.read_ms(); if ( gEvent.IsForcedTrg() || (etms>gConf.GetEvtThrtlPeriodMs()) ) { PIN_lockRegisters = 0; // done reading, unlock so we can talk to SD card. SaveEvent(etms); } } } // // save the event // void SaveEvent(const int32_t etms) { // write the event // set the event number & dt gEvent.SetEvtNum(gEvtNum++); gEvent.SetDTms(etms); // save to SD SnSDUtils::WriteEventTo(gCurFile, gGenBuf, gEvent, gConf); // reset gEvent.ClearEvent(); if (gEvtNum==5) { fclose(gCurFile); while (1) { led3 = 1; wait(0.5); led3 = 0; wait(0.5); } } } // // set configuration // void SetConfig() { // restart watchdog Watchdog::kick(gConf.GetWatchdogPeriod()); // reset event, timers, trigger counters gEvent.ClearEvent(); gEvtNum = gConf.GetFirstEvt(); gEvtTimer.reset(); memset(gTrgNum, 0, sizeof(int32_t)*kNumTrgs); // make new output file SnSDUtils::CloseOutputFile(gCurFile); gCurFile = SnSDUtils::OpenNewOutputFile(gConf.GetMacAddress(), gConf.GetRun()); SnSDUtils::WriteFileHeader(gCurFile, gConf.GetMacAddress()); SnSDUtils::WriteConfig(gCurFile, gConf); // TODO: turn on amps individually, when that's possible if (gConf.IsEachAmpOn()) { PIN_turn_on_amps=0; } // Set PLA value(s) // TODO: send multiple values when FPGA code is ready for it // TODO: uncomment when using new version of FPGA code PIN_spi.format( 16, 0 ); // change mode for DAC & PLA value setting PIN_MajLogHiBit=1; PIN_MajLogLoBit=1; PIN_enableThermTrig=0; uint16_t hi, lo; PIN_PLA_cs=1; wait(3); for (uint8_t pi=0; pi<kNplas; pi++) { if (pi < gConf.GetNumPlas()) { SnConfigFrame::GetHiLoPlas(gConf.GetPla(pi), hi, lo); PIN_spi.write(hi); PIN_spi.write(lo); } else { PIN_spi.write(kNoTrigPla); // hi PIN_spi.write(kNoTrigPla); // lo } } wait(3); PIN_PLA_cs=0; wait(3); // DAC values // // first 12 bits = DAC value // next 2 bits = DAC ID // last 2 bits = dFPGA ID // // But FPGA uses "gray encoding" which means only 1 bit // can change at a time (of the last 4 bits). So even tho // the card/dac# is encoded, the order is also important // 0000 (dac0,card0), 0001 (dac0,card1), 0011 (dac0,card3), 0010 (dac0,card2), // 0110 (dac1,card2), 0111 (dac1,card3), 0101 (dac1,card1), etc. int dv=0; for (uint8_t i=0, gri=0; i<kTotDacs; i++) { // get the gray-codes for this iteration gri = SnBitUtils::binToGray(i); // build bit word dv = static_cast<int>(gConf.GetDac(gri & 0x0003u, gri >> 2u)); dv <<= 4u; dv |= gri; // send to FPGA PIN_start_fpga=1; PIN_spi.write(dv); PIN_start_fpga=0; } wait_ms(20); // Majority Logic Trigger selection (# of cards) SnBitUtils::SetChanNumBits(gConf.GetNumCardsMajLog() - 1u, PIN_MajLogHiBit, PIN_MajLogLoBit); // Enable thermal trigger? PIN_enableThermTrig = gConf.IsThermTrigEnabled(); PIN_spi.format( 16, 1 ); // back to trigger mode Watchdog::kick(); // don't reset! } // // readout functions // void WaitTrigAndSendClock() { if (gFirstEvt==false) { PIN_DoNotRestartAllClocks = 0; wait_us(1); PIN_DoNotRestartAllClocks = 1; //led3 = !led3; // toggle send clock led } else { gFirstEvt = false; } // // wait for a trigger here. // gReadingOut = false; // this will allow forced triggers (see procForceTrigger()) while ( PIN_a_sf_clk == 1 ) { if (gOpenCommWin) { // break out to open comms return; } } PIN_forceTrigger=0; // necessary for forced triggers, harmless for other triggers gReadingOut = true; // disallow new forced triggers // // collect data from daughter cards // // TODO: what if some card (set of channels) doesn't respond? // currently, will wait forever? // also, if ch1 is dead, will wait forever (due to FPGA code) for( uint8_t i = 0; i < kNsamps; i++ ) { if( PIN_a_sf_clk == 1 ) { if( i == 0 ) wait_us( 1 ); PIN_ADC_CS = 0; PIN_spi.write( 0x00 ); PIN_ADC_CS = 1; } else { i--; } } } SnCommWin::ECommWinResult OpenCommWin() { // loop through each comm mode: // a) try to connect // b) if connected, listen for config // c) if config requests data, send it gCommWinOpen = true; Watchdog::kick(); // don't reset! // TODO: power up comm systems gIOtimer.reset(); gIOtimer.start(); const uint32_t conto = (gConf.GetCommWinDuration() < kConnectTimeout) ? gConf.GetCommWinDuration() : kConnectTimeout; const uint32_t listo = (gConf.GetCommWinDuration() < kListenTimeout) ? gConf.GetCommWinDuration() : kListenTimeout; SnCommWin::ECommWinResult res = SnCommWin::kUndefFail; SnCommWin** cw = gComms; for (uint8_t i=0; (i<kNcomms) && (gIOtimer.read()<gConf.GetCommWinDuration()); i++, cw++) { // open window and (mabye) send status update const SnCommWin::ECommWinResult conres = (*cw)->OpenWindow( gIOtimer, conto, true, gConf, gEvent, gGenBuf, gGenBuf); if (conres>=SnCommWin::kConnected) { // connected. listen for config const SnCommWin::ECommWinResult cfgres = (*cw)->GetConfig( gConf, gIOtimer, listo, gGenBuf); if (cfgres>=SnCommWin::kOkWithMsg) { // got config. set it up. SetConfig(); // send data if need be (files, some events, etc) if (gConf.GetCommSendData()!=0) { res = (*cw)->SendData(gConf, gEvent, gGenBuf, gGenBuf); } else { // don't send anything res = cfgres; } break; } } Watchdog::kick(); // don't reset! } gCommWinOpen = false; return res; }