From 3297d58715e540998dde6d2fde3777c24c5137c6 Mon Sep 17 00:00:00 2001 From: Sebastien Binet Date: Tue, 25 May 2021 13:26:52 +0200 Subject: [PATCH] eda: add I2C + INJ handling --- eda/device.go | 223 +++++++++++++++++++++++++++++++++++++++++++++++++- eda/pio.go | 80 ++++++++++++++++-- go.mod | 1 + go.sum | 2 + 4 files changed, 299 insertions(+), 7 deletions(-) diff --git a/eda/device.go b/eda/device.go index 7f7b43f..cbf0129 100644 --- a/eda/device.go +++ b/eda/device.go @@ -366,6 +366,9 @@ func (dev *Device) initFPGA() error { dev.msg.Printf("trigger mode: %v", dev.cfg.daq.mode) switch dev.cfg.daq.mode { + default: + return fmt.Errorf("eda: invalid trigger mode: %v", dev.cfg.daq.mode) + case "dcc": err = dev.syncSelectCmdDCC() if err != nil { @@ -379,14 +382,40 @@ func (dev *Device) initFPGA() error { if err != nil { return fmt.Errorf("eda: could not enable DCC RAM-full: %w", err) } + case "noise": err = dev.syncSelectCmdSoft() if err != nil { return fmt.Errorf("eda: could not select SOFT cmd: %w", err) } - default: - return fmt.Errorf("eda: invalid trigger mode: %v", dev.cfg.daq.mode) + case "inj": + // set injector DAC + const injDAC = 100 + dev.msg.Printf("setting injector DAC with value %d", injDAC) + for _, rfm := range dev.rfms { + dev.msg.Printf("rfm %d...", rfm) + err = dev.injDACSelect(rfm) + if err != nil { + return fmt.Errorf( + "eda: could select injector DAC for rfm=%d: %w", + rfm, err, + ) + } + + err = dev.injDACSet(rfm, injDAC) + if err != nil { + return fmt.Errorf( + "eda: could not set injector DAC for rfm=%d: %w", + rfm, err, + ) + } + } + + err = dev.syncSelectCmdSoft() + if err != nil { + return fmt.Errorf("eda: could not select SOFT cmd: %w", err) + } } return nil @@ -406,6 +435,18 @@ func (dev *Device) initHRFromDB() error { dev.hrscSetRShaper(0, dev.cfg.hr.rshaper) dev.hrscSetCShaper(0, dev.cfg.hr.cshaper) + if dev.cfg.mode == "inj" { + dev.hrscSetCtest(0, 31, 1) + dev.hrscSetCtest(1, 31, 1) + dev.hrscSetCtest(2, 31, 1) + dev.hrscSetCtest(3, 31, 1) + dev.hrscSetCtest(4, 31, 1) + dev.hrscSetCtest(5, 31, 1) + dev.hrscSetCtest(6, 31, 1) + dev.hrscSetCtest(7, 31, 1) + dev.hrscSetCtest(8, 31, 1) + } + // set chip IDs for hr := uint32(0); hr < nHR; hr++ { dev.hrscSetChipID(hr, hr+1) @@ -592,6 +633,8 @@ func (dev *Device) Start(run uint32) error { return dev.startRunDCC(run) case "noise": return dev.startRunNoise(run) + case "inj": + return dev.startRunInj(run) default: err := fmt.Errorf("eda: unknown trig-mode %q", dev.cfg.daq.mode) dev.msg.Printf("%+v", err) @@ -693,6 +736,47 @@ func (dev *Device) startRunNoise(run uint32) error { return nil } +func (dev *Device) startRunInj(run uint32) error { + var err error + + err = dev.injStartCTestPulser(25000, 0) // 100Hz + if err != nil { + return fmt.Errorf("eda: could not start ctest pulser: %w", err) + } + + for _, rfm := range dev.rfms { + err = dev.daqFIFOInit(rfm) + if err != nil { + return fmt.Errorf("eda: could not initialize DAQ FIFO (RFM=%d): %w", rfm, err) + } + } + + err = dev.cntReset() + if err != nil { + return fmt.Errorf("eda: could not reset counters: %w", err) + } + + err = dev.syncResetBCID() + if err != nil { + return fmt.Errorf("eda: could not reset BCID: %w", err) + } + + err = dev.syncStart() + if err != nil { + return fmt.Errorf("eda: could not start acquisition: %w", err) + } + + err = dev.syncArmFIFO() + if err != nil { + return fmt.Errorf("eda: could not arm FIFO: %w", err) + } + + dev.daq.done = make(chan int) + + go dev.loop() + return nil +} + func (dev *Device) initRun(run uint32) error { // save run-dependant settings dev.msg.Printf( @@ -767,6 +851,8 @@ func (dev *Device) loop() { dev.loopDCC() case "noise": dev.loopNoise() + case "inj": + dev.loopInj() default: err := fmt.Errorf("eda: invalid trig-mode %q", dev.cfg.daq.mode) panic(err) @@ -996,6 +1082,126 @@ func (dev *Device) loopNoise() { } } +func (dev *Device) loopInj() { + var ( + w = dev.msg.Writer() + printf = fmt.Fprintf + errorf = func(format string, args ...interface{}) { + dev.err = fmt.Errorf(format, args...) + dev.msg.Printf("%+v", dev.err) + } + cycle int + err error + ) + + if len(dev.daq.rfm) != 0 { + for i := range dev.daq.rfm { + rfm := &dev.daq.rfm[i] + if !rfm.valid() { + continue + } + defer rfm.sck.Close() + } + } + + for i := range dev.daq.rfm { + rfm := &dev.daq.rfm[i] + rfm.w = &wbuf{ + p: make([]byte, daqBufferSize), + } + } + + for { + printf(w, "trigger %07d, state: acq-", cycle) + // wait until readout is done + readout: + for { + state := dev.syncState() + switch { + case state >= regs.S_RAMFULL: + break readout + default: + select { + case <-dev.daq.done: + dev.daq.done <- 1 + return + default: + } + } + } + printf(w, "ramfull-") + err = dev.syncRAMFullExt() + if err != nil { + errorf("could not set RAMFULL: %+v", err) + return + } + + dataReady: + for { + state := dev.syncState() + switch { + case state >= regs.S_FIFO_READY: + break dataReady + default: + select { + case <-dev.daq.done: + dev.daq.done <- 1 + return + default: + } + } + } + + printf(w, "cp-") // copy + + // read hardroc data + for i, rfm := range dev.rfms { + dev.daqWriteDIFData(dev.daq.rfm[i].w, rfm) + } + err = dev.syncAckFIFO() + if err != nil { + errorf("eda: could not ACK FIFO: %w", err) + return + } + printf(w, "tx-") + var grp errgroup.Group + for i := range dev.daq.rfm { + if !dev.daq.rfm[i].valid() { + continue + } + ii := i + grp.Go(func() error { + err := dev.daqSendDIFData(ii) + if err != nil { + errorf("eda: could not send DIF data (RFM=%d): %w", dev.rfms[ii], err) + return err + } + return nil + }) + } + err = grp.Wait() + if err != nil { + errorf("eda: could not send DIF data: %w", err) + return + } + + printf(w, "\n") + cycle++ + + select { + case <-dev.daq.done: + dev.daq.done <- 1 + return + default: + err = dev.syncStart() + if err != nil { + errorf("eda: could not start acquisition: %w", err) + return + } + } + } +} + func (dev *Device) Stop() error { const timeout = 10 * time.Second tck := time.NewTimer(timeout) @@ -1028,6 +1234,19 @@ func (dev *Device) Stop() error { if err != nil { return fmt.Errorf("eda: could not stop counters: %w", err) } + case "inj": + err = dev.syncStop() + if err != nil { + return fmt.Errorf("eda: could not stop acquisition: %w", err) + } + err = dev.cntStop() + if err != nil { + return fmt.Errorf("eda: could not stop counters: %w", err) + } + err = dev.injStopCTestPulser() + if err != nil { + return fmt.Errorf("eda: could not stop ctest pulser: %w", err) + } } err = dev.cntReset() diff --git a/eda/pio.go b/eda/pio.go index e9ea8f5..cf3c4ff 100644 --- a/eda/pio.go +++ b/eda/pio.go @@ -15,6 +15,7 @@ import ( "strings" "time" + "github.com/go-daq/smbus" "github.com/go-lpc/mim/eda/internal/regs" "github.com/go-lpc/mim/internal/eformat" "github.com/go-lpc/mim/internal/mmap" @@ -1164,11 +1165,11 @@ func (dev *Device) hrscWriteConfHRs(fname string) error { return nil } -// // hrscSetCtest switches the test capacitor (1=closed). -// func (dev *Device) hrscSetCtest(hr, ch, v uint32) { -// dev.hrscSetBit(hr, ch, v&0x01) -// } -// +// hrscSetCtest switches the test capacitor (1=closed). +func (dev *Device) hrscSetCtest(hr, ch, v uint32) { + dev.hrscSetBit(hr, ch, v&0x01) +} + // func (dev *Device) hrscSetAllCtestOff() { // for hr := uint32(0); hr < nHR; hr++ { // for ch := uint32(0); ch < nChans; ch++ { @@ -2006,3 +2007,72 @@ func (dev *Device) daqSendDIFData(i int) error { return nil } + +// --- test injector --- + +func (dev *Device) i2c(rfm int) (*smbus.Conn, error) { + addr := 0b00100000 + (uint8(rfm) & 0x3) + conn, err := smbus.Open(0, addr) + if err != nil { + return nil, fmt.Errorf("eda: could not connect to I2C bus(0,rfm=%d): %w", rfm, err) + } + + return conn, nil +} + +func (dev *Device) injDACSelect(rfm int) error { + conn, err := dev.i2c(rfm) + if err != nil { + return err + } + defer conn.Close() + + return nil +} + +func (dev *Device) injDACSet(rfm int, v uint32) error { + conn, err := dev.i2c(rfm) + if err != nil { + return err + } + defer conn.Close() + + _, err = conn.Write([]byte{ + 0, // command byte + uint8(v % 0x100), // lsb + uint8(v >> 8), // msb + }) + if err != nil { + return fmt.Errorf("eda: could not write 3 bytes to LTC1668 DAC: %w", err) + } + + time.Sleep(200 * time.Microsecond) // for stabilization. + return nil +} + +func (dev *Device) injStartCTestPulser(halfPeriod, phase uint32) error { + // half period unit = 200 ns + // phase unit = 6.25 ns + v := (phase&0x1f)<<16 | (halfPeriod & 0xffff) + dev.regs.pio.pulser.w(v) // set timing registers + time.Sleep(1 * time.Microsecond) + dev.regs.pio.ctrl.w(dev.regs.pio.ctrl.r() | regs.O_CTEST) // enable + + if dev.err != nil { + return fmt.Errorf("eda: could not start ctest pulser: %w", dev.err) + } + return nil +} + +func (dev *Device) injStopCTestPulser() error { + ctrl := dev.regs.pio.ctrl.r() + ctrl &= ^uint32(regs.O_CTEST) + dev.regs.pio.ctrl.w(ctrl) + + dev.regs.pio.pulser.w(0) + + if dev.err != nil { + return fmt.Errorf("eda: could not stop ctest pulser: %w", dev.err) + } + return nil +} diff --git a/go.mod b/go.mod index 3c7d912..b36cb3d 100644 --- a/go.mod +++ b/go.mod @@ -3,6 +3,7 @@ module github.com/go-lpc/mim go 1.19 require ( + github.com/go-daq/smbus v0.0.0-20201216173259-5725b4593606 github.com/go-daq/tdaq v0.14.2 github.com/go-sql-driver/mysql v1.7.0 github.com/peterh/liner v1.2.2 diff --git a/go.sum b/go.sum index 724a6db..74cdd27 100644 --- a/go.sum +++ b/go.sum @@ -19,6 +19,8 @@ github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs github.com/fogleman/gg v1.2.1-0.20190220221249-0403632d5b90/go.mod h1:R/bRT+9gY/C5z7JzPU0zXsXHKM4/ayA+zqcVNZzPa1k= github.com/fogleman/gg v1.3.0/go.mod h1:R/bRT+9gY/C5z7JzPU0zXsXHKM4/ayA+zqcVNZzPa1k= github.com/gdamore/optopia v0.2.0/go.mod h1:YKYEwo5C1Pa617H7NlPcmQXl+vG6YnSSNB44n8dNL0Q= +github.com/go-daq/smbus v0.0.0-20201216173259-5725b4593606 h1:1lyGjYJXpYkF6fGQbhAIOdIaeymKQuS6RJVLVlTzc5w= +github.com/go-daq/smbus v0.0.0-20201216173259-5725b4593606/go.mod h1:KDYiP7UvrtHRqnVLE6ziKupbojinMHjFUdo+1VA7r/Q= github.com/go-daq/tdaq v0.14.2 h1:17hEikzmQfLl57mSTxwMaILszGjm+jHSj49/RYPPbEs= github.com/go-daq/tdaq v0.14.2/go.mod h1:oiqGEED+dzinsAHVJ1Lq/HZf7RYbaTB8KpHTRDUhxNc= github.com/go-fonts/dejavu v0.1.0/go.mod h1:4Wt4I4OU2Nq9asgDCteaAaWZOV24E+0/Pwo0gppep4g=