Page 2 of 3

Re: Laser trigger

Posted: October 9th, 2015, 11:30 am
by embmicro
Your IDLE state requires you to send some random byte. This byte will be lost. So to send a command you need to send "?dxx" or "?mx" where ? is literally anything. Is this what you want?

Re: Laser trigger

Posted: October 12th, 2015, 7:11 am
by rojhann
Hmm oki, that indeed works much better that way! Somehow I thought when going from idle to listen the flag was still up.

In the mean time I solved my issue with the pulse length. I was sending highbyte and lowbyte in the wrong order...

thanks a lot for your time!

Re: Laser trigger

Posted: October 12th, 2015, 4:25 pm
by embmicro
You should be able to collapse your IDLE and LISTEN states together so you don't need to send the junk byte. The new data flag only stays high for one cycle so once you switch states it a new cycle and it's low (unless there is another new byte).

No problem and best of luck!

Re: Laser trigger

Posted: November 16th, 2015, 11:56 am
by rojhann
Hey!

I finally got the time to try out with the lasers. Unfortunately, something that I didn't notice but that I can actually see with the oscilloscope is that it is skipping some triggers... Something like:

I use what you wrote:

Code: Select all

module triggerToPulse (
    input clk,  // clock
    input rst,  // reset
    input trigger, // trigger from camera
    output pulse,  // output pulse
    input mode[3], // mode of trigger
    input duration[24] // duration of pulse
  ) {
  
  .clk(clk), .rst(rst) {
    dff ctr[24];    // counter for pulse
    dff oldTrigger; // dff to detect edges
  }
  
  // modes of operation
  const OFF = 0;
  const ON = 1;
  const RISE = 2;
  const FALL = 3;
  const FOLLOW = 4;
  
  always {
    pulse = 0; // default to 0
    
    // save the trigger value so we can detect edges
    oldTrigger.d = trigger; 
    
    if (!&ctr.q) // if not maxed out
      ctr.d = ctr.q + 1; // increment
    
    case (mode) {
      OFF:
        pulse = 0;
      ON:
        pulse = 1;
      RISE:
        // if trigger was low but is now high...
        if (oldTrigger.q == 0 && trigger == 1)
          ctr.d = 0; // reset counter
        // set pulse high while ctr is less than duration
        pulse = ctr.q < duration;
      FALL:
        if (oldTrigger.q == 1 && trigger == 0)
          ctr.d = 0; // reset counter
        pulse = ctr.q < duration;
      FOLLOW:
        pulse = trigger;
    }
  }
}
I also tried with just the RISE part:

Code: Select all

module triggerToPulse (
    input clk,  // clock
    input rst,  // reset
    input trigger, // trigger from camera
    output pulse,  // output pulse
    input duration[24] // duration of pulse
  ) {
  
  .clk(clk), .rst(rst) {
    dff ctr[24];    // counter for pulse
    dff oldTrigger; // dff to detect edges
  }
  
  always {
    pulse = 0; // default to 0
    
    // save the trigger value so we can detect edges
    oldTrigger.d = trigger; 
    
    if (!&ctr.q) // if not maxed out
      ctr.d = ctr.q + 1; // increment

        // if trigger was low but is now high...
        if (oldTrigger.q == 0 && trigger == 1)
          ctr.d = 0; // reset counter
        // set pulse high while ctr is less than duration
        pulse = ctr.q < duration;

  }
}
It looks to me like (oldTrigger.q == 1 && trigger == 0) does not manage to see every rising edge. Knowing that the "on" phase of the trigger last tens of ms, I really don't understand how it can miss it.

I don't see any regularity on the missed edge :s

Do you have any idea of what could happen? And if there would be a way to get all the edges detected?

thanks a lot!

cheers

Re: Laser trigger

Posted: November 16th, 2015, 3:27 pm
by embmicro
If I had to guess it's a meta stability issue. See https://embeddedmicro.com/tutorials/luc ... o-tutorial for more info on it.

Basically try to pass your trigger input through two flip-flops before using the value. Yea, it'll delay the signal a little, but it'll be synchronized to the FPGAs clock.

Code: Select all

module triggerToPulse (
    input clk,  // clock
    input rst,  // reset
    input trigger, // trigger from camera
    output pulse,  // output pulse
    input mode[3], // mode of trigger
    input duration[24] // duration of pulse
  ) {
  
  .clk(clk), .rst(rst) {
    dff ctr[24];    // counter for pulse
    dff oldTrigger; // dff to detect edges
    dff trigSync[2]; // sync dffs
  }
  
  // modes of operation
  const OFF = 0;
  const ON = 1;
  const RISE = 2;
  const FALL = 3;
  const FOLLOW = 4;
  
  always {
    pulse = 0; // default to 0
    
    trigSync.d[0] = trigger;
    trigSync.d[1] = trigSync.q[0];
    
    // save the trigger value so we can detect edges
    oldTrigger.d = trigSync.q[1]; 
    
    if (!&ctr.q) // if not maxed out
      ctr.d = ctr.q + 1; // increment
    
    case (mode) {
      OFF:
        pulse = 0;
      ON:
        pulse = 1;
      RISE:
        // if trigger was low but is now high...
        if (oldTrigger.q == 0 && trigSync.q[1] == 1)
          ctr.d = 0; // reset counter
        // set pulse high while ctr is less than duration
        pulse = ctr.q < duration;
      FALL:
        if (oldTrigger.q == 1 && trigSync.q[1] == 0)
          ctr.d = 0; // reset counter
        pulse = ctr.q < duration;
      FOLLOW:
        pulse = trigSync.q[1]; // could use trigger here if pulse isn't used internally
    }
  }
}

Re: Laser trigger

Posted: January 19th, 2016, 8:31 am
by rojhann
Hey!

Worked like a charm! I didn't have time to implement it on the microscope until now, it is really great. Much better than the Arduinos I had. Now people are using it daily for the lasers.

Which bring me to another step. Because I bought another Mojo and want to expand its functionalities. Basically I would like to have a "sequence" of triggers. In a simpler case, I consider only the "FOLLOW" case. The user sends a 16bits number which encode the sequence (0 for not trigger and 1 for a trigger).

I tried implementing that but it reacts odly. If the sequence is only 0s, then I get no triggering, if the sequence is only 1s I get all the triggers (so all fine). But when I give another pattern, like 1010101010101010, I don't get the expected pattern. I can't really find the mistake. I thought maybe the counter for the sequence does not really follow 0-1-2-3-4-5-6-7-8-9-10-11-12-13-14-15-0-1-... I get for instance three triggers in a row, then alternating not trigger and trigger, then again to "no-trigger" in a row. Can't really find the pattern though.

Here are the modules:

Code: Select all

module userinput (
    input clk,         // clock
    input rst,         // reset
    input new_rx,      // new RX flag
    input rx_data[8],  // RX data
    output mode1[8],
    output duration1[16],
    output sequence1[16],
    output mode2[8],
    output duration2[16],
    output sequence2[16],
    output mode3[8],
    output duration3[16],
    output sequence3[16],
    output mode4[8],
    output duration4[16],
    output sequence4[16]
  ) {
  
 .clk(clk) {
    .rst(rst) {
      fsm state = {IDLE, LASER, FLAG, MODE, DURATION, SEQUENCE}; // our state machine
    }
 
    dff duration_count;
    dff sequence_count;
    dff laser_count[2];
    dff duration_memory[4][16];
    dff sequence_memory[4][16];
    dff mode_memory[4][8];
                          
  }
  
  
  always { 
  
      duration1 = duration_memory.q[0][15:0];                     
      mode1 = mode_memory.q[0][7:0];  
      sequence1 = sequence_memory.q[0][15:0];  
      duration2 = duration_memory.q[1][15:0];                     
      mode2 = mode_memory.q[1][7:0];  
      sequence2 = sequence_memory.q[1][15:0]; 
      duration3 = duration_memory.q[2][15:0];                     
      mode3 = mode_memory.q[2][7:0]; 
      sequence3 = sequence_memory.q[2][15:0]; 
      duration4 = duration_memory.q[3][15:0];                     
      mode4 = mode_memory.q[3][7:0];  
      sequence4 = sequence_memory.q[3][15:0]; 
    
      case (state.q) { // our FSM
      // IDLE: Reset everything and wait for a new byte.
      state.IDLE:
        duration_count.d = 0;
        sequence_count.d = 0;
        if (new_rx){ // wait for any bit
          state.d = state.LASER;
        }

      state.LASER:
        if (new_rx) {   
          if(rx_data <= 3){
              laser_count.d = rx_data[1:0];  
              state.d = state.FLAG; 
          } else {
              state.d = state.IDLE;
          }
        } 
       
      // LISTEN: Listen to the flag.
      state.FLAG:
        if (new_rx && rx_data=="m") {                                                             
              state.d = state.MODE;
        } else if (new_rx && rx_data=="d") { 
              state.d = state.DURATION;
        } else if (new_rx && rx_data=="s") { 
              state.d = state.SEQUENCE;
        }
        
      // LISTEN: Listen to the duration.
      state.DURATION:
        if (new_rx) { // wait for a new byte
          if(duration_count.q == 0){
            duration_memory.d[laser_count.q][7:0]=rx_data;
          } else if(duration_count.q == 1){
            duration_memory.d[laser_count.q][15:8]=rx_data;
          }
          duration_count.d = duration_count.q + 1; // increment the address
 
          // if we run out of space
          if (&duration_count.q) {
            state.d = state.IDLE;
            duration_count.d = 0; // reset duration_count
          }
       }
    
      // LISTEN: Listen to the flag.
      state.MODE:
        if (new_rx) { // wait for a new byte
          mode_memory.d[laser_count.q][7:0] = rx_data;        // write the received letter to RAM
          state.d = state.IDLE;
       }
        
      // LISTEN: Listen to the sequence.
      state.SEQUENCE:
        if (new_rx) { // wait for a new byte
          if(sequence_count.q == 0){
            sequence_memory.d[laser_count.q][7:0]=rx_data;
          } else if(sequence_count.q == 1){
            sequence_memory.d[laser_count.q][15:8]=rx_data;
          }
          sequence_count.d = sequence_count.q + 1; // increment the address
 
          // if we run out of space
          if (&sequence_count.q) {
            state.d = state.IDLE;
            sequence_count.d = 0; // reset duration_count
          }
       }
    }
    
  }
}

Code: Select all

module triggerToPulse (
    input clk,  // clock
    input rst,  // reset
    input trigger, // trigger from camera
    output pulse,  // output pulse
    input mode[3], // mode of trigger
    input duration[16], // duration of pulse
    input sequence[16], //sequence of triggering
    output ledout[8]
  ) {
  
  .clk(clk){ 
    .rst(rst) {
    dff ctr[22];    // counter for pulse
    dff ctr_s[4];    // counter for sequence
    dff trigger_sync[2];
    dff oldTrigger; // dff to detect edges
  }  }
  
  // modes of operation
  const OFF = 0;
  const ON = 1;
  const RISE = 2;
  const FALL = 3;
  const FOLLOW = 4;
  
  // number of cycles for 1us
  const NM_CYCLES = 50;
  var length;
  
  always {
    pulse = 0; // default to 0
    
    ledout[3:0] = ctr_s.q;

    length = duration*NM_CYCLES;
    
    // save the trigger value so we can detect edges, 2 flip-flops (metastability)
    trigger_sync.d[0] =  trigger;
    trigger_sync.d[1] =  trigger_sync.q[0];
    oldTrigger.d = trigger_sync.q[1]; 
    
    if (!&ctr.q) // if not maxed out
      ctr.d = ctr.q + 1; // increment
            
    if (!&ctr_s.q && oldTrigger.q == 0 && trigger == 1) // if not maxed out and rising edge
      ctr_s.d = ctr_s.q+1; // increment sequence status
    
    if(&ctr_s.q && trigger == 0) // if all 1111 and trigger went down (avoid going down right after the edge when 1111)
      ctr_s.d = 0;
    
    case (mode) {
      OFF:
        pulse = 0;
      ON:
        pulse = 1;
      RISE:
        // if trigger was low but is now high...
        if (oldTrigger.q == 0 && trigger == 1)
          ctr.d = 0; // reset counter
  
        // set pulse high while ctr is less than duration
        pulse = ctr.q < length;
        
      FALL:
        if (oldTrigger.q == 1 && trigger == 0)
          ctr.d = 0; // reset counter
        
        pulse = ctr.q < length;

      FOLLOW:
        pulse = trigger & sequence[ctr_s.q];
    }
  }
}

Code: Select all

module mojo_top(
    input clk,              // 50MHz clock
    input rst_n,            // reset button (active low)
    output led [8],         // 8 user controllable LEDs
    input cclk,             // configuration clock, AVR ready when high
    output spi_miso,        // AVR SPI MISO
    input spi_ss,           // AVR SPI Slave Select
    input spi_mosi,         // AVR SPI MOSI
    input spi_sck,          // AVR SPI Clock
    output spi_channel [4], // AVR general purpose pins (used by default to select ADC channel)
    input avr_tx,           // AVR TX (FPGA RX)
    output avr_rx,          // AVR RX (FPGA TX)
    input avr_rx_busy,       // AVR RX buffer full
    input camera,
    output laser1,
    output laser2,
    output laser3,
    output laser4
  ) {
 
  .clk(clk), .rst(~rst_n){
    // the avr_interface module is used to talk to the AVR for access to the USB port and analog pins
    avr_interface avr;
 
    userinput user; // instance of our user
    triggerToPulse trigger1;
    triggerToPulse trigger2;
    triggerToPulse trigger3;
    triggerToPulse trigger4;
    
  }
 
  always {
    // connect inputs of avr
    avr.cclk = cclk;
    avr.spi_ss = spi_ss;
    avr.spi_mosi = spi_mosi;
    avr.spi_sck = spi_sck;
    avr.rx = avr_tx;        
 
    // connect outputs of avr
    spi_miso = avr.spi_miso;
    spi_channel = avr.spi_channel;
    avr_rx = avr.tx;
 
    avr.channel = hf; // ADC is unused so disable
    avr.tx_block = avr_rx_busy; // block TX when AVR is busy
 
    user.new_rx = avr.new_rx_data;
    user.rx_data = avr.rx_data;
    avr.tx_data = avr.rx_data;
    avr.new_tx_data = 0;
    
    // Laser1
    trigger1.mode = user.mode1[2:0];
    trigger1.duration = user.duration1[15:0];
    trigger1.sequence = user.sequence1[15:0];
    trigger1.trigger = camera;
    laser1 = trigger1.pulse;
    
    // Laser2
    trigger2.mode = user.mode2[2:0];
    trigger2.duration = user.duration2[15:0];
    trigger2.sequence = user.sequence2[15:0];
    trigger2.trigger = camera;
    laser2 = trigger2.pulse;
    
    // Laser3
    trigger3.mode = user.mode3[2:0];
    trigger3.duration = user.duration3[15:0];
    trigger3.sequence = user.sequence3[15:0];
    trigger3.trigger = camera;
    laser3 = trigger3.pulse;
    
    // Laser4
    trigger4.mode = user.mode4[2:0];
    trigger4.duration = user.duration4[15:0];
    trigger4.sequence = user.sequence4[15:0];
    trigger4.trigger = camera;
    laser4 = trigger4.pulse;
        
    led = trigger1.ledout;             // turn LEDs off
  }
}
Do you have any idea of what could go wrong?

I will try to see if I haven't done a conceptual mistake somewhere...

thanks a lot!

cheers,
j

Re: Laser trigger

Posted: January 19th, 2016, 4:10 pm
by embmicro
I didn't notice anything out of place. Have you tried outputting the sequence values to the LEDs to see if they are getting transferred correctly? You could also try using a constant for the sequence input on your triggerToPulse module to see if it works as expected then.

One thing I didn't understand was your IDLE state could be combined with the LASER state. The way it currently is, you have to send a junk byte to get it into LASER and then send a real value. You could just use the following instead.

Code: Select all

state.IDLE:
        duration_count.d = 0;
        sequence_count.d = 0;
        if (new_rx) {   
          if(rx_data <= 3){
              laser_count.d = rx_data[1:0];  
              state.d = state.FLAG; 
          }
        }         

Re: Laser trigger

Posted: January 20th, 2016, 4:31 am
by rojhann
This is true, you mentionned that earlier and I didn't take the time to modify it. But I'll take your advice.

Concerning the led and the constant sequence, I tried that. The sequence I send via usb is correctly understood. When using a constant sequence the problem stay the same, therefore I believe it lies on the "ctr_s" that does not increment correctly with the rising triggers.

Re: Laser trigger

Posted: January 21st, 2016, 5:12 am
by rojhann
So i tried a new approach (more adapted to the synchronization of four lasers):

A distributor module modifies the trigger sent to each laser according to a 16bits sequence.

Code: Select all

module userinput (
    input clk,         // clock
    input rst,         // reset
    input new_rx,      // new RX flag
    input rx_data[8],  // RX data
    output mode1[8],
    output duration1[16],
    output sequence1[16],
    output mode2[8],
    output duration2[16],
    output sequence2[16],
    output mode3[8],
    output duration3[16],
    output sequence3[16],
    output mode4[8],
    output duration4[16],
    output sequence4[16]
  ) {
  
 .clk(clk) {
    .rst(rst) {
      fsm state = {IDLE, FLAG, MODE, DURATION, SEQUENCE}; // our state machine
    }
 
    dff duration_count;
    dff sequence_count;
    dff laser_count[2];
    dff duration_memory[4][16];
    dff sequence_memory[4][16];
    dff mode_memory[4][8];
                          
  }
  
  
  always { 
  
      duration1 = duration_memory.q[0][15:0];                     
      mode1 = mode_memory.q[0][7:0];  
      sequence1 = sequence_memory.q[0][15:0];  
      duration2 = duration_memory.q[1][15:0];                     
      mode2 = mode_memory.q[1][7:0];  
      sequence2 = sequence_memory.q[1][15:0]; 
      duration3 = duration_memory.q[2][15:0];                     
      mode3 = mode_memory.q[2][7:0]; 
      sequence3 = sequence_memory.q[2][15:0]; 
      duration4 = duration_memory.q[3][15:0];                     
      mode4 = mode_memory.q[3][7:0];  
      sequence4 = sequence_memory.q[3][15:0]; 
    
      case (state.q) { // our FSM
      // IDLE: Reset everything and wait for a new byte.
      state.IDLE:
        duration_count.d = 0;
        sequence_count.d = 0;
        if (new_rx) {   
          if(rx_data <= 3){
              laser_count.d = rx_data[1:0];  
              state.d = state.FLAG; 
          }
        }      
       
      // LISTEN: Listen to the flag.
      state.FLAG:
        if (new_rx && rx_data=="m") {                                                             
              state.d = state.MODE;
        } else if (new_rx && rx_data=="d") { 
              state.d = state.DURATION;
        } else if (new_rx && rx_data=="s") { 
              state.d = state.SEQUENCE;
        }
        
      // LISTEN: Listen to the duration.
      state.DURATION:
        if (new_rx) { // wait for a new byte
          if(duration_count.q == 0){
            duration_memory.d[laser_count.q][7:0]=rx_data;
          } else if(duration_count.q == 1){
            duration_memory.d[laser_count.q][15:8]=rx_data;
          }
          duration_count.d = duration_count.q + 1; // increment the address
 
          // if we run out of space
          if (&duration_count.q) {
            state.d = state.IDLE;
            duration_count.d = 0; // reset duration_count
          }
       }
    
      // LISTEN: Listen to the flag.
      state.MODE:
        if (new_rx) { // wait for a new byte
          mode_memory.d[laser_count.q][7:0] = rx_data;        // write the received letter to RAM
          state.d = state.IDLE;
       }
        
      // LISTEN: Listen to the sequence.
      state.SEQUENCE:
        if (new_rx) { // wait for a new byte
          if(sequence_count.q == 0){
            sequence_memory.d[laser_count.q][7:0]=rx_data;
          } else if(sequence_count.q == 1){
            sequence_memory.d[laser_count.q][15:8]=rx_data;
          }
          sequence_count.d = sequence_count.q + 1; // increment the address
 
          // if we run out of space
          if (&sequence_count.q) {
            state.d = state.IDLE;
            sequence_count.d = 0; // reset duration_count
          }
       }
    }
    
  }
}

Code: Select all

module distributor (
    input clk,  // clock
    input rst,  // reset
    input trigger,
    input sequence1[16],
    input sequence2[16],
    input sequence3[16],
    input sequence4[16],
    output flag1,
    output flag2,
    output flag3,
    output flag4,
    output ledout[8]
  ) {

  .clk(clk){ 
    .rst(rst) {
      dff ctr_s[4];   
      dff trigger_sync[2];
      dff oldTrigger;
      fsm state = {IDLE, INCREMENT};
  }}
  
  always {
    ledout[3:0] = ctr_s.q; 
    
    trigger_sync.d[0] =  trigger;
    trigger_sync.d[1] =  trigger_sync.q[0];
    oldTrigger.d = trigger_sync.q[1]; 
      
    case(state.q){
      state.IDLE:
        if(oldTrigger.q == 0 && trigger == 1)
          state.d = state.INCREMENT;
          
      state.INCREMENT:
        ctr_s.d = ctr_s.q + 1;
        state.d = state.IDLE;
    }
    
    flag1 = sequence1[ctr_s.q];
    flag2 = trigger & sequence2[ctr_s.q];
    flag3 = trigger & sequence3[ctr_s.q];
    flag4 = trigger & sequence4[ctr_s.q]; 
   }
}

Code: Select all

module triggerToPulse (
    input clk,  // clock
    input rst,  // reset
    input trigger, // trigger from camera
    output pulse,  // output pulse
    input mode[3], // mode of trigger
    input duration[16]
  ) {
  
  .clk(clk){ 
    .rst(rst) {
    dff ctr[22];    // counter for pulse
    dff trigger_sync[2];
    dff oldTrigger; // dff to detect edges
  }  }
  
  // modes of operation
  const OFF = 0;
  const ON = 1;
  const RISE = 2;
  const FALL = 3;
  const FOLLOW = 4;
   
  // number of cycles for 1us
  const NM_CYCLES = 50;
  var length;
  
  always {
    pulse = 0; // default to 0
        

    length = duration*NM_CYCLES;
    
    // save the trigger value so we can detect edges, 2 flip-flops (metastability)
    trigger_sync.d[0] =  trigger;
    trigger_sync.d[1] =  trigger_sync.q[0];
    oldTrigger.d = trigger_sync.q[1]; 
    
    if (!&ctr.q) // if not maxed out
      ctr.d = ctr.q + 1; // increment
    
    case (mode) {
      OFF:
        pulse = 0;
      ON:
        pulse = 1;
      RISE:
        // if trigger was low but is now high...
        if (oldTrigger.q == 0 && trigger == 1)
          ctr.d = 0; // reset counter
        
        // set pulse high while ctr is less than duration
        pulse = ctr.q < length;
        
      FALL:
        if (oldTrigger.q == 1 && trigger == 0)
          ctr.d = 0; // reset counter
        
        pulse = ctr.q < length;

      FOLLOW:
          pulse = trigger;
    }
  }
}

Code: Select all

module mojo_top(
    input clk,              // 50MHz clock
    input rst_n,            // reset button (active low)
    output led [8],         // 8 user controllable LEDs
    input cclk,             // configuration clock, AVR ready when high
    output spi_miso,        // AVR SPI MISO
    input spi_ss,           // AVR SPI Slave Select
    input spi_mosi,         // AVR SPI MOSI
    input spi_sck,          // AVR SPI Clock
    output spi_channel [4], // AVR general purpose pins (used by default to select ADC channel)
    input avr_tx,           // AVR TX (FPGA RX)
    output avr_rx,          // AVR RX (FPGA TX)
    input avr_rx_busy,       // AVR RX buffer full
    input camera,
    output laser1,
    output laser2,
    output laser3,
    output laser4
  ) {
 
  .clk(clk), .rst(~rst_n){
    // the avr_interface module is used to talk to the AVR for access to the USB port and analog pins
    avr_interface avr;
 
    userinput user; // instance of our user
    distributor dist;
    triggerToPulse trigger1;
    triggerToPulse trigger2;
    triggerToPulse trigger3;
    triggerToPulse trigger4;
    
  }
 
  always {
    // connect inputs of avr
    avr.cclk = cclk;
    avr.spi_ss = spi_ss;
    avr.spi_mosi = spi_mosi;
    avr.spi_sck = spi_sck;
    avr.rx = avr_tx;        
 
    // connect outputs of avr
    spi_miso = avr.spi_miso;
    spi_channel = avr.spi_channel;
    avr_rx = avr.tx;
 
    avr.channel = hf; // ADC is unused so disable
    avr.tx_block = avr_rx_busy; // block TX when AVR is busy
 
    // user input
    user.new_rx = avr.new_rx_data;
    user.rx_data = avr.rx_data;
    avr.tx_data = avr.rx_data;
    avr.new_tx_data = 0;
    
    // distributor
    dist.trigger = camera;
    dist.sequence1 = user.sequence1;
    dist.sequence2 = user.sequence2;
    dist.sequence3 = user.sequence3;
    dist.sequence4 = user.sequence4;
    
    // Laser1
    trigger1.mode = user.mode1[2:0];
    trigger1.duration = user.duration1[15:0];
    trigger1.trigger = dist.flag1;
    laser1 = trigger1.pulse;
    
    // Laser2
    trigger2.mode = user.mode2[2:0];
    trigger2.duration = user.duration2[15:0];
    trigger2.trigger = dist.flag2;
    laser2 = trigger2.pulse;
    
    // Laser3
    trigger3.mode = user.mode3[2:0];
    trigger3.duration = user.duration3[15:0];
    trigger3.trigger = dist.flag3;
    laser3 = trigger3.pulse;
    
    // Laser4
    trigger4.mode = user.mode4[2:0];
    trigger4.duration = user.duration4[15:0];
    trigger4.trigger = dist.flag4;
    laser4 = trigger4.pulse;
        
    led = dist.ledout;             // turn LEDs off
  }
}
I only monitor laser 1 in the "follow mode". I am also only passing the sequence[counter] to check its behaviour. If the laser is supposed to pulse (sequence[counter]=1), the distributor output flag1 is on from the start of a trigger to the beginning of the next one (on rising edge).

Once again I tried:
1111111111111111 (always on)
1111111100000000 (here I observed pulse of length <8 triggers, like if the counter was incremented more than by one sometimes)
1010101010101010 (erratic behaviour, pulses of every length)

these sequences are passed properly. But from the oscilloscope, it still behaves weirdly. How it looks to me is that it increments twice (which I tried to avoid by using the fsm) sometimes during one trigger. Could this be?

[EDIT]: I passed the counter (ctr_s) to the leds to monitor it, and indeed the incrementation is not working properly (if one considers that the leds are working). From the videos I made to track the evolution of the 4 bits, it seems the the ctr_s[0] stays 0 for a long time (e.g. 13 incrementations) , then it will turn to 1 and again stay for some time (e.g. 20 incrementations). I am a bit puzzled. :/



[EDIT2]: So i tried with another type of counting (not a smart one I guess):

Code: Select all

module counter (
    input clk,  // clock
    input rst,  // reset
    input trigger,
    output count[3]
  ) {

  .clk(clk){ 
    .rst(rst) {
      dff trigger_sync[2];
      dff oldTrigger;
      fsm state = {STATE0,STATE1,STATE2,STATE3,STATE4,STATE5,STATE6,STATE7};
  }}
  
  always {
    count = 0;
    
    trigger_sync.d[0] =  trigger;
    trigger_sync.d[1] =  trigger_sync.q[0];
    oldTrigger.d = trigger_sync.q[1]; 
      
    case(state.q){
      state.STATE0:
        count = 0;
        if(oldTrigger.q == 0 && trigger == 1){
          state.d = state.STATE1;
        }
      state.STATE1:
        count = 1;
        if(oldTrigger.q == 0 && trigger == 1){
          state.d = state.STATE2;
        }
      state.STATE2:
        count = 2;
        if(oldTrigger.q == 0 && trigger == 1){
          state.d = state.STATE3;
        }
      state.STATE3:
        count = 3;
        if(oldTrigger.q == 0 && trigger == 1){
          state.d = state.STATE4;
        }
      state.STATE4:
        count = 4;
        if(oldTrigger.q == 0 && trigger == 1){
          state.d = state.STATE5;
        }
      state.STATE5:
        count = 5;
        if(oldTrigger.q == 0 && trigger == 1){
          state.d = state.STATE6;
        }
      state.STATE6:
        count = 6;
        if(oldTrigger.q == 0 && trigger == 1){
          state.d = state.STATE7;
        }
      state.STATE7:
        count = 7;
        if(oldTrigger.q == 0 && trigger == 1){
          state.d = state.STATE0;
        }
    }
    
  }
}

Code: Select all

module distributor (
    input clk,  // clock
    input rst,  // reset
    input trigger,
    input sequence1[16],
    input sequence2[16],
    input sequence3[16],
    input sequence4[16],
    output flag1,
    output flag2,
    output flag3,
    output flag4,
    output ledout[8]
  ) {

  .clk(clk){ 
    .rst(rst) {
      counter count;
  }}
  
  always {
    ledout[2:0] = count.count[2:0]; //sequence1[15:8]; 
    
    count.trigger = trigger;
    
    flag1 = sequence1[count.count];
    flag2 = trigger & sequence2[count.count];
    flag3 = trigger & sequence3[count.count];
    flag4 = trigger & sequence4[count.count]; 
   }
}
And use the output "count" as the counter of the sequence. I used a trigger signal which consists of a square signal of pulse length 120ms separated by 120ms. Then I used my phone to take a video (frame rate ~30) and count the led[3:0] value. The signal does not make sense... Although in one short video (2sec) I had a repetitive pattern but with disordered numbers (4-7-2-5-0-3-6-1, an inversion of the 3 bits values does not account for this), on the long video I took I don't find patterns, values are totally disordered with repetition between 8-uplets...
So there is a huge mistake somewhere, but I am totally lost now...

[EDIT3] and same with going back to this module :

Code: Select all

module distributor (
    input clk,  // clock
    input rst,  // reset
    input trigger,
    input sequence1[16],
    input sequence2[16],
    input sequence3[16],
    input sequence4[16],
    output flag1,
    output flag2,
    output flag3,
    output flag4,
    output ledout[8]
  ) {

  .clk(clk){ 
    .rst(rst) {
      dff ctr_s[3];   
      dff trigger_sync[2];
      dff oldTrigger;
      //fsm state = {IDLE, INCREMENT};
  }}
  
  always {
    ledout[2:0] = ctr_s.q; //sequence1[15:8]; 
    
    trigger_sync.d[0] =  trigger;
    trigger_sync.d[1] =  trigger_sync.q[0];
    oldTrigger.d = trigger_sync.q[1]; 
      
    if(oldTrigger.q == 0 && trigger == 1)
        ctr_s.d = ctr_s.q + 1;
    
    flag1 = sequence1[ctr_s.q];
    flag2 = trigger & sequence2[ctr_s.q];
    flag3 = trigger & sequence3[ctr_s.q];
    flag4 = trigger & sequence4[ctr_s.q]; 
   }
}

Re: Laser trigger

Posted: January 25th, 2016, 2:42 pm
by embmicro
Can you upload your full project so it's easier to build and test out? Just delete the work directory first (don't need those extra files).