Author Topic: FPGA output not consistent with ModelSim  (Read 8227 times)

0 Members and 1 Guest are viewing this topic.

Online BrianHG

  • Super Contributor
  • ***
  • Posts: 8076
  • Country: ca
Re: FPGA output not consistent with ModelSim
« Reply #50 on: March 24, 2022, 11:02:29 am »
One last thing about lines:

96 - function_pos <= 1 ; // Go to position 1.
104 - if ( sync_trigger_on ) function_pos <= 2 ; // Goto function 2 when the sync_trigger goes from high to low
117 - function_pos <= 4;  // Goto next case

In these cases, where you are actually only incrementing the function_pos instead of jumping to a complete random point, it would take less logic and fpga resources to write:

function_pos <= function_pos + 1'b1 ;

Since the add 1 happens so many times elsewhere or even if you add additional position steps, the compiler will simplify that duplicate logic and determine it is an 'add 1 enable' when needed, while each discrete custom jump you create are be considered additional exclusion cases increasing logic gates & potentially impacting FMAX.
 

Offline kpow8050Topic starter

  • Regular Contributor
  • *
  • Posts: 57
  • Country: au
Re: FPGA output not consistent with ModelSim
« Reply #51 on: March 24, 2022, 11:09:21 am »
Once done and simulated, we will take a look at making your external control interface work.

Ok, I've got those working. And updated the function_pos to have the more efficient jumping. Code posted below:

Code: [Select]
module LaserControl_v2 (
input data_in,
input comms_clk,
input execute,
input clk_in,
input in_a,
input in_b,
output reg ld_out,
output wire [7:0] debug_reg,
output reg debug_output);

// Control constants
//localparam laser_ctrl_mode = 7;
//localparam set_pixel_offset_mode = 1;
//localparam set_pixel_clock_divider_mode = 5;
//localparam set_pixel_scan_line_limit_mode = 6;
parameter  bit  USE_NEG_EDGE  = 1 ;

reg       reset             = 1 ; // since you do not have a reset, we are artificially making preset to on.
reg       enable_laser      = 0 ; // A reg to block the laser from coming on.
reg       laser_out         = 0 ; // A reg to block the laser from coming on.
reg [4:0] function_pos      = 0 ; // Create a program position pointer which can serve 32 states.


reg        reg_data_in       = 0 ; // Register inputs
reg        reg_comms_clk     = 0 ;
reg        reg_execute       = 0 ;
reg        reg_in_a          = 0 ;
reg        reg_in_b          = 0 ;
reg        sync_in           = 0 ;

  // Internal registers for keeping track of state
reg [15:0] max_pixel_count   = 20;
reg [15:0] pixel_offset      = 100;   // how many pixels to delay the output laser pulses
reg [15:0] pixel_count       = 0 ;
reg [15:0] pixel_period      = 16 ;      // Period of the pixel clock (1 = period of main clock, 2 = 1/2 of main clock, etc..
reg [15:0] pixel_period_timer_reg = 0;
reg        sync_in_dly       = 0 ;


wire sync_pos_trigger = sync_in && !sync_in_dly ;
wire sync_neg_trigger = !sync_in && sync_in_dly ;
wire sync_trigger_on  = USE_NEG_EDGE ? sync_neg_trigger  : sync_pos_trigger ; // Use a parameter or reg to select the trigger edge.
 

// **************************************************
// Everything should run from the 25MHz clock.
// **************************************************
always @(posedge clk_in) begin

// Cleanly register FPGA inputs.
reg_data_in    <= data_in   ;
reg_comms_clk  <= comms_clk ;
reg_execute    <= execute   ;
reg_in_a       <= in_a      ;
reg_in_b       <= in_b      ;

// **************************************************
// During the reset condition, do these things.
// **************************************************
if (reset) begin

    reset        <= 0 ; // dispixel_period_timer_regable the reset.
    enable_laser <= 0 ; // Force laser off.
    ld_out       <= 0 ; // Force laser off.
    function_pos <= 0 ; // Clear the function position so that position 0 runs once the reset is released.

  end else begin
// **************************************************
// Once the reset condition has cleared, do these things.
// **************************************************

ld_out <= !(enable_laser && laser_out) ; // For now, always drive the laser output pin when these are high and !reset.
                                      // We will change this to a memory lookup when we create the 2048 pixel line memory


// **************************************************
// Schmitt trigger
// **************************************************
        if (reg_in_a && reg_in_b) sync_in <= 1'b1; // Both high, so set.
  else if (!(reg_in_a || reg_in_b)) sync_in <= 1'b0; // Both low, so clear, otherwise, hold the last value.
 
  sync_in_dly <= sync_in;

// **************************************************
// Begin Sequencer driving for the laser output
// **************************************************
     case (function_pos)

        default : function_pos <= 0 ; // If an undefined position has been reached, goto position 0.

       0 : begin // This state begins after the reset has been released

            enable_laser <= 0 ; // Force laser off
            function_pos <= function_pos + 1'b1 ; // Go to next function (1).
       
           end

       1 : begin
         
            SET_laser_clock ( pixel_period, pixel_offset ); // setup the laser clock for a delay (pixel offset delay)

            if ( sync_trigger_on ) function_pos <= function_pos + 1'b1 ; // Goto next function when the sync_trigger goes from high to low
           
           end

       2 : begin
         
              RUN_laser_clock ( pixel_period );   // counting pixel offset delay

           end
           
       3 : begin
             
              enable_laser <= 1 ; // Force laser on
              SET_laser_clock ( pixel_period, max_pixel_count ); // Set the number of pixels to display in the scan line
              function_pos <= function_pos + 1'b1;  // Goto next function
               
          end
               
       4 : begin
         
              RUN_laser_clock ( pixel_period );   // counting laser output pixel clock
             
              laser_out <= pixel_count[0];  // Laser is toggled based on the LSB of pixel counter
             
           end
           
      5 : begin
           
            // Turn laser on
            laser_out <= 1'b0;
            function_pos <= 1;    // Reset function counter
         
          end

      endcase
// **************************************************
// End Sequencer for driving the laser output
// **************************************************


// **************************************************
// External commands input registering
// **************************************************
// External commands input registering
// **************************************************


  end // !reset
end // always @25 MHz clock.


// **************************************************
// TASKS - set laser pixel clock and address pointer.
// **************************************************
task SET_laser_clock(bit [15:0] period,bit [15:0] length);
  begin
    pixel_count <= length;
    pixel_period_timer_reg <= period;
  end
endtask

// **************************************************
// TASKS - run laser pixel timer and address pointer.
// **************************************************
task RUN_laser_clock(bit [15:0] period);
  begin
   
    if ( pixel_period_timer_reg != 0 ) pixel_period_timer_reg <= pixel_period_timer_reg - 1'b1 ; // decrement the pixel period count
    else begin
     
      pixel_period_timer_reg <= period;   // reset the period counter
   
      if (pixel_count !=0) pixel_count   <= pixel_count  - 1'b1  ; // Count down until 0
      else                 function_pos  <= function_pos + 1'b1  ; // Once 0, auto-increment the function_pos for the case statement.
    end
  end
endtask


endmodule




And here is an image of the output waveform with significantly larger period than the main clock

« Last Edit: March 24, 2022, 11:13:36 am by kpow8050 »
 

Online BrianHG

  • Super Contributor
  • ***
  • Posts: 8076
  • Country: ca
Re: FPGA output not consistent with ModelSim
« Reply #52 on: March 24, 2022, 11:20:43 am »
Ok, nice sim.
Note that without adding some choice net from your DUU, like I had in my sim 2 posts back, it would make debugging in the future easier.

Decide to test on the FPGA.

The, tell me about your control interface.
Is it parallel, serial, normal UART, I2c?
How fast does it need to be?
Will you need to fill your 2000 pixel memory through this interface?
 
The following users thanked this post: kpow8050

Offline kpow8050Topic starter

  • Regular Contributor
  • *
  • Posts: 57
  • Country: au
Re: FPGA output not consistent with ModelSim
« Reply #53 on: March 24, 2022, 11:31:31 am »
I won't get a chance to simulate on the actual device until after work tomorrow - about to head to bed. Once I do I'll let you know the results hopefully sometime tomorrow.

So my control interface is non-standard serial interface. Essentially I just send data to a shift register on the FPGA and its clocked externally from an arduino for each bit I send across. It is formated so that the 3 least significant bits contain the operation code (8 functions possible) to indicate what exactly the FPGA should do with the data stored in the remaining bits of the shift register. The execute signal is then sent from the Arduino to let the FPGA know that the data is shifted into the register and its time for the command to be executed. The list of commands it will support are:

Opcode - Command
_______________
0 - Store pixel array
1 - Set pixel offset
2 - Increment memory address for pixel array (increments in size of the data width (eg 16 bits etc)
3 - Load new scan line (load the contents of the buffer register into the active scan line register - ie the live pixels that are being scanned)
4 - NA
5 - Set pixel clock divider/period
6 - Set pixel scan length
7 - Force control of laser state (0 = off, 1 = on, 2 = controlled by FPGA)


I don't need to send this data super fast, as long as it can be sent into the FPGA before the next line needs to be scanned (dependent on the photoresist I use). I would be aiming for something like 100k- 500k baud, whatever is error free.

Also another thing is that the FPGA needs to be outputting pixels while the arduino sends in the next line without pausing. So I would assume we need 1 pixel buffer (to store the new pixels the arduino is putting in and another pixel register for the active scan line so that no matter how slow the Arduino is, its not going to pause the output of the scan line

 

Online BrianHG

  • Super Contributor
  • ***
  • Posts: 8076
  • Country: ca
Re: FPGA output not consistent with ModelSim
« Reply #54 on: March 24, 2022, 11:46:53 am »
So my control interface is non-standard serial interface. Essentially I just send data to a shift register on the FPGA and its clocked externally from an arduino for each bit I send across.
If the arduino has a uart, this may be advantageous when coding as the old fashioned bit-bang approach can run  really slow written in C code.  See what the arduino's uart baud rate can run at.  Having a normal uart means that you can also use an FTDI USB-> TTL RS232 dongle or IC and have PC connectivity as well.  921600 baud should work on both devices and it is above your speed requirements.  Also, it is a 2 wire interface which gives your both directions.  Error free isn't a problem.
Quote
Also another thing is that the FPGA needs to be outputting pixels while the arduino sends in the next line without pausing. So I would assume we need 1 pixel buffer (to store the new pixels the arduino is putting in and another pixel register for the active scan line so that no matter how slow the Arduino is, its not going to pause the output of the scan line
Not a problem.
With the numbered  function_pos I sent you, you can add and remove steps at different points.  Check buffer status, what has been filled, what's next.  You can even store something like a 32 line back buffer with a small Cyclone II as we will be storing the pixels of each line in blockram.  Just look up on how many bits of blockram is available in your Cyclone II.  Figure 1 line buffer will eat 2048bits of mem.
« Last Edit: March 24, 2022, 11:52:30 am by BrianHG »
 

Offline kpow8050Topic starter

  • Regular Contributor
  • *
  • Posts: 57
  • Country: au
Re: FPGA output not consistent with ModelSim
« Reply #55 on: March 24, 2022, 11:54:02 am »
I'm using the only UART on the MCU (AT328P) I believe, and it is connected to an FTDI USB for PC connectivity. The MCU is required for controlling other parts of the device such as polygon mirror speed, steppers and such. Also the wires are soldered in, so for now I prefer not to deviate from the current bit banging method. If it proves to be too slow for my application I may have to change it.

The Cyclone II has 1 Mbit of RAM (https://engineering.purdue.edu/ece477/Archive/2007/Fall/F07-Grp02/nb/Notes/Cyclone-II_Memory_Blocks.pdf) so that should be way more than I'll ever need
 

Online BrianHG

  • Super Contributor
  • ***
  • Posts: 8076
  • Country: ca
Re: FPGA output not consistent with ModelSim
« Reply #56 on: March 24, 2022, 11:59:19 am »
Ok, you will only need 3 wires for 1 bit data, 1 clock and 1 data ready, or, better yet, 2-3 control wires and 1 8bit wide bus to get the cpu cycles down to only a few per command.
 

Offline kpow8050Topic starter

  • Regular Contributor
  • *
  • Posts: 57
  • Country: au
Re: FPGA output not consistent with ModelSim
« Reply #57 on: March 24, 2022, 12:03:49 pm »
Ok, you will only need 3 wires for 1 bit data, 1 clock and 1 data ready, or, better yet, 2-3 control wires and 1 8bit wide bus to get the cpu cycles down to only a few per command.

Sounds good. We'll have to stick with 1 data wire, since I've also used all the general purpose pins on the AT328P
 

Online BrianHG

  • Super Contributor
  • ***
  • Posts: 8076
  • Country: ca
Re: FPGA output not consistent with ModelSim
« Reply #58 on: March 24, 2022, 12:19:28 pm »
So, we are speaking like:

   input data_in,
   input comms_clk,
   input execute,

...

reg_data_in    <= data_in   ;
reg_comms_clk  <= comms_clk ;
reg_execute    <= execute   ;

dly_comms_clk  <= reg_comms_clk ;

// load a bit into the 20bit register every time the comms clock goes low to high, or goes from high to low.
// bi-directional sensitivity on the comm clock means 1 less write to the MCU port for every bit.
shift_bit_in <= reg_comms_clk  != dly_comms_clk;
if ( shift_bit_in ) command_packet[19:0] <= { command_packet[18:0] , reg_data_in } ;

// store results in the 16 bit setting register bank 4 word array
if (reg_execute) reg_bank[command_packet[19:16]] <= command_packet[15:0] ;

This should get you started with 16 available 16 bit setting registers.
You should be able to bit-blast up to ~8 megabaud with your 25MHz source clock.

 

Online BrianHG

  • Super Contributor
  • ***
  • Posts: 8076
  • Country: ca
Re: FPGA output not consistent with ModelSim
« Reply #59 on: March 24, 2022, 12:23:56 pm »
You can shrink the 20 bit reg into a 16 bit one and have 12bit data, 4 bit address.

This way in your MCU, you use only 2 bytes per command, storing the destination address in the upper 4 bits of the 16 bit word.

This means the pixel clock period and pixel length will now only be 12 bits, or 0-4095.
 

Online BrianHG

  • Super Contributor
  • ***
  • Posts: 8076
  • Country: ca
Re: FPGA output not consistent with ModelSim
« Reply #60 on: March 24, 2022, 12:53:36 pm »
You can also change the bit clock sensitivity to:
shift_bit_in <= reg_comms_clk  && !dly_comms_clk;
If you want to trigger exclusively on the rising edge.

It depends on your bitbang routing.

I know I would do bare metal in assembly to send 2 bytes by writing 35 lines of code like:

clrf port (mircochip style)
bittestsc byte1,bit0
set port,databit
set port,clk
clr port,databit
bittestsc byte1,bit1
set port,databit
clr port,clk
.....
At 20 mips on the MCU, this would transmit at 4 megabaud.
 

Online pcprogrammer

  • Super Contributor
  • ***
  • Posts: 4295
  • Country: nl
Re: FPGA output not consistent with ModelSim
« Reply #61 on: March 24, 2022, 03:20:54 pm »
I'm using the only UART on the MCU (AT328P) I believe, and it is connected to an FTDI USB for PC connectivity. The MCU is required for controlling other parts of the device such as polygon mirror speed, steppers and such. Also the wires are soldered in, so for now I prefer not to deviate from the current bit banging method. If it proves to be too slow for my application I may have to change it.

The AT328P does also have SPI and TWI. The TWI is only 400KHz i2c, but will be faster than bit blasting. The SPI needs three wires for bidirectional communication but is a lot faster.

So maybe an option. I'm sure BrianHG has some module for this lying around. :)


Offline kpow8050Topic starter

  • Regular Contributor
  • *
  • Posts: 57
  • Country: au
Re: FPGA output not consistent with ModelSim
« Reply #62 on: March 25, 2022, 05:38:37 am »
I'm using the only UART on the MCU (AT328P) I believe, and it is connected to an FTDI USB for PC connectivity. The MCU is required for controlling other parts of the device such as polygon mirror speed, steppers and such. Also the wires are soldered in, so for now I prefer not to deviate from the current bit banging method. If it proves to be too slow for my application I may have to change it.

The AT328P does also have SPI and TWI. The TWI is only 400KHz i2c, but will be faster than bit blasting. The SPI needs three wires for bidirectional communication but is a lot faster.

So maybe an option. I'm sure BrianHG has some module for this lying around. :)

Good point! Is it possible to use any pins for SPI? Or are there dedicated pins for that function. I prefer not to have to de-solder anything at this stage
 

Online pcprogrammer

  • Super Contributor
  • ***
  • Posts: 4295
  • Country: nl
Re: FPGA output not consistent with ModelSim
« Reply #63 on: March 25, 2022, 06:04:13 am »
Unfortunately these pins are only available on fixed locations. See section 14.3 in the ATmega48A/PA/88A/PA/168A/PA/328/P datasheet.
https://ww1.microchip.com/downloads/en/DeviceDoc/ATmega48A-PA-88A-PA-168A-PA-328-P-DS-DS40002061A.pdf

For SPI the pins are:

PB5 => SCK
PB4 => MISO
PB3 => MOSI
PB2 => SS (Slave select, which is not needed in a single slave device on the bus setup)

Attached the assembler instruction manual. These 8 bit AVR devices are fairly simple to program in assembler if better performance is needed over output from C.

Offline kpow8050Topic starter

  • Regular Contributor
  • *
  • Posts: 57
  • Country: au
Re: FPGA output not consistent with ModelSim
« Reply #64 on: March 25, 2022, 10:23:46 am »
Decide to test on the FPGA.

I've tested the new code on the real hardware and its working great - as expected. I've attached a photo of the laser output below which clearly shows it working. So I guess the next step is to implement the communication interface and get it working with commands
 
The following users thanked this post: BrianHG

Online BrianHG

  • Super Contributor
  • ***
  • Posts: 8076
  • Country: ca
Re: FPGA output not consistent with ModelSim
« Reply #65 on: March 25, 2022, 10:24:46 am »
I'm using the only UART on the MCU (AT328P) I believe, and it is connected to an FTDI USB for PC connectivity. The MCU is required for controlling other parts of the device such as polygon mirror speed, steppers and such. Also the wires are soldered in, so for now I prefer not to deviate from the current bit banging method. If it proves to be too slow for my application I may have to change it.

The AT328P does also have SPI and TWI. The TWI is only 400KHz i2c, but will be faster than bit blasting. The SPI needs three wires for bidirectional communication but is a lot faster.

So maybe an option. I'm sure BrianHG has some module for this lying around. :)
:'(  And after everything I taught you 2 over the past week, including triggering on different edge events and serial / parallel stacking clocked data input registers.  You should be able to make your own SPI or I2C slave within a few lines of code and make it synchronous to you system clock compared to many of existing online examples which use their own clock domain and then transfer that data to your system clock with those possible headaches.  But, there is always www.Opencores.org.  This is an opportunity to further develop some HDL skills.
« Last Edit: March 25, 2022, 10:31:04 am by BrianHG »
 
The following users thanked this post: kpow8050

Offline kpow8050Topic starter

  • Regular Contributor
  • *
  • Posts: 57
  • Country: au
Re: FPGA output not consistent with ModelSim
« Reply #66 on: March 25, 2022, 10:34:36 am »
No worries. I think you've taught me enough that I can now proceed on my own with this project. I appreciate your guidance and helping me learn HDL basics  :). If I need more help hopefully you'll be here to answer in the future
 

Online pcprogrammer

  • Super Contributor
  • ***
  • Posts: 4295
  • Country: nl
Re: FPGA output not consistent with ModelSim
« Reply #67 on: March 25, 2022, 11:49:47 am »
I'm using the only UART on the MCU (AT328P) I believe, and it is connected to an FTDI USB for PC connectivity. The MCU is required for controlling other parts of the device such as polygon mirror speed, steppers and such. Also the wires are soldered in, so for now I prefer not to deviate from the current bit banging method. If it proves to be too slow for my application I may have to change it.

The AT328P does also have SPI and TWI. The TWI is only 400KHz i2c, but will be faster than bit blasting. The SPI needs three wires for bidirectional communication but is a lot faster.

So maybe an option. I'm sure BrianHG has some module for this lying around. :)
:'(  And after everything I taught you 2 over the past week, including triggering on different edge events and serial / parallel stacking clocked data input registers.  You should be able to make your own SPI or I2C slave within a few lines of code and make it synchronous to you system clock compared to many of existing online examples which use their own clock domain and then transfer that data to your system clock with those possible headaches.  But, there is always www.Opencores.org.  This is an opportunity to further develop some HDL skills.

I'm sure I will be able to make such an interface on my own now. And you are right there is lots of information online. I just needed the jump start :-+

And one more thanks to you BrianHG,

Peter


Share me

Digg  Facebook  SlashDot  Delicious  Technorati  Twitter  Google  Yahoo
Smf