Correctly handling clocks on a older Cyclone IV - Page 1
Forum section: electronics / general

author: pieroc91
author_rank: Contributor
timestamp: May 30, 2023, 02:14:43 pm
content: Hi everyone. I'm trying to wrap my head around this but I cannot make any sense of it.I have a board based on an old EP4CE6E22, i'm using it to control a very old digital camera which returns data on a 8 bit parallel bus plus a 6 Mhz clock signal.I'm sending this data to a cache made with registers inside the FPGA in order to make slightly bigger chunk sizes and send at faster rates so i have idle time to allow for RAM refresh.The FPGA board has a built in 66 Mhz clock that i'm using for every other operation on the FPGA.The problem is when I interface the clock signal. The code increments a bit counter on the negative edge of that 6 Mhz clock and when it reaches certain amount it request the next line of the sensor.if i use:always @(negedge 6mclock)counter = counter +1;it does not work at all, sometimes doesn't even count anything, sometimes it does, but when it does, it's a complete mess and ends up hanging the counter, I got a similar behavior by floating the pin.if i use:always @(negedge copyclock)counter = counter +1;always @(posedge 66mclock)copyclock = 6mclock;Works a little jumpy and misses some chunks of clock cycles but mostly works.If i divide the 66 Mhz clock and use it instead I got a solid and stable burst of data but i'm not sure if i'm on sync with the signal.I've sent the 6 Mhz clock and my 6 Mhz divided clock to two different output pins of the FPGA for a few seconds and counted the pulses with a logic analyzer and i got the exact same number of pulses so i know the 6 Mhz clock is arriving fine to the innards of the FPGA.What am i doing wrong?

author: c64
author_rank: Frequent Contributor
timestamp: May 30, 2023, 10:56:01 pm
content: How clean is the 6M clock? If you route it through fpga and use your LA to count, does it still count correctly?Like this CAM_6M -> fpga -> LAWhat happens if you change your code to posedge and non-blocking assignments?

author: pieroc91
author_rank: Contributor
timestamp: May 31, 2023, 01:12:26 am
content: Hi @c64, thanks for your reply.Routing both the failing external 6M clock and the divided 6M i divide inside the FPGA that makes it work to two pins and make the LA to count gives me the exact amount of between both clocks, which means it's clean enough to be routed and replicated.By using posedge i get the same result. Haven't tested the non-blocking part but i'm not sure that it will change the behavior.How can you suggest to make some test-code?

author: Someone
author_rank: Super Contributor
timestamp: May 31, 2023, 07:28:14 am
content: You'll need to step back and validate exactly what the signals are that arrive at the FPGA, with a scope. Signal integrity and timing relationships/constraints.alsoDraw out all the clocks you are planning to use and what they interact with, to identify where clock crossing (magic pixie dust) methodologies are needed.

author: pieroc91
author_rank: Contributor
timestamp: May 31, 2023, 02:19:02 pm
content: Yeah, signals are fine, if i route them inside the fpga and back out again they come out again perfectly. that's ruled out.The problem is why is not counting with it, that counter is completely unrelated to any other signal, it just adds up and count the cycles from that.I know that by "buffering" the signal on a internal register tied to the faster clock can change the phase of the buffered signal a little bit with a margin of change of the size of one clock cycle of the 66mhz clock, that's minor and it's ok on this case, but the effect is dramatic enough to almost fix the problem of not counting.Why does the "buffered" signal works and the real signal doesn't?(i say "buffer" on quotes because is not a real buffer but just a copy inside the fpga)

author: asmi
author_rank: Super Contributor
timestamp: May 31, 2023, 03:13:13 pm
content: Not really sure if it's related to your issues or not, but using negedge of clock in FPGA is almost always a bad idea as all syncronous blocks inside FPGA operate on a posedge. Using BOTH edges is even worse because it effectively halves the time slack.What I typically do when encountering such issues is to open a generated netlist schematics and confirm that it synthesized what I intended/expected it to.

author: pieroc91
author_rank: Contributor
timestamp: May 31, 2023, 04:11:14 pm
content: I guess that my next step is checking if is synthesizing correctly.In this case the negedge is required by design of the camera, the ADC is on sync with the negative edge. what i've tried is to invert the clock signal while buffering it and change it to posedge but the result was exactly the same.I'm also inclined in doing a small routine at start to correct the phase of the divided clock with the external clock and use that new clock on the rest of the code

author: BrianHG
author_rank: Super Contributor
timestamp: May 31, 2023, 05:28:32 pm
content: Are you generating the 6MHz clock in the FPGA, or, is that a stable clock coming from the camera module.Aslo, a 6MHz clock is really slow if you have a 66MHz core. You can latch the data and clock all at your 66MHz core clock at a positive edge. Then, at the falling or rising edge of the external 6MHz clock input take the parallel data. This design also offers you a software programmable clock edge input delay clock skew function. Having a your core run at a double 132MHz only makes your programmable snapshot delay double refined.This way, you do not have multiple clock domains. The FPGA runs on a single core 66MHz.

author: pieroc91
author_rank: Contributor
timestamp: May 31, 2023, 05:48:53 pm
content: Quote from: BrianHG on May 31, 2023, 05:28:32 pmIs coming from the camera, the data from the camera is sync'd to that clock. For testing purposes I started with a generated clock on the FPGA and worked quite well, but upon implementing the external clock things started to fail.Quote from: BrianHG on May 31, 2023, 05:28:32 pmThis is how i'm actually handling the data, since is actually a command/data bus there are lot's of trickery to meet the timings of the camera which is based on an ancient altera EP910 and also has a lot of analog electronics on the CCD driving part. But that is working just fine with the generated clock, even the data part, I got actual pictures doing that but the generated clock is not reliable since the phase error changes on every FPGA reboot and can ruin the reading since the bus on the positive clock cycle is used for commands (i'm not sending commands at this point but the camera has no data on the port at this time).Quote from: BrianHG on May 31, 2023, 05:28:32 pmSadly the multiple clocks are needed since the camera has it's own clock and cannot be override

author: BrianHG
author_rank: Super Contributor
timestamp: May 31, 2023, 06:07:38 pm
content: Phase error?(A) use the camera clock to drive the Cyclone PLL and generate your system clocks from that input allowing for always the same phase. Though, you might want to use a proper integer multiple for the FPGA core clock like x10 for 60MHz, x12 for 72MHz, or x16 for 96MHz.Or,(B)Code:reg l_cam_clock = 0;reg cam_data_ready = 0 ;wire latch_cam_data = ~cam_clock && l_cam_clock ; // latch data on falling clock - Change this line to invert the sample clock period.always @(posedge clk_66) beginl_cam_clock <= cam_clock; // keep a record of the last camera clock statecam_data_ready <= latch_cam_data ; // internally sync 66m clean the data ready signal.if (cam_data_ready) beginlatched_data <= cam_data_in; // use the 'latched_data' reg for your computations.latched_syncs <= cam_syncs)in ; // use the 'latched_syncs' reg for your additional synchronization.//// perform all synchronous camera data inside here.//// including the optional generation of a new 6MHz clock output.endendThis should never run out of phase, though the async clock nature may be a problem if you need to feed out a 6Mhz data in perfect sync with the camera data. The you need to go with option (A) to make your life easy.

author: Scrts
author_rank: Frequent Contributor
timestamp: May 31, 2023, 08:22:35 pm
content: If the camera is generating a clock, then I'd use a small DCFIFO.Use camera clock & data for the input and FPGA clock & data for the output. Only pull the data once FIFO has enough data and feed it into the DRAM.

author: BrianHG
author_rank: Super Contributor
timestamp: May 31, 2023, 09:05:22 pm
content: Quote from: Scrts on May 31, 2023, 08:22:35 pmAnother valid method.Although, the OP may be saving blockram for something else.Otherwise, using a DCFIFO with status flags, both on the input and output if the OP has a 6MHz data output would be a means of solving his clocking delima. Though, there may be a large number of cycles/time between in and out.When it comes to video, the simplest DC fifo size I tend to use would at least 1 Horizontal line of video buffer.

author: radiolistener
author_rank: Super Contributor
timestamp: May 31, 2023, 09:29:24 pm
content: Quote from: pieroc91 on May 30, 2023, 02:14:43 pmWhere did you get that 6 MHz clock? Does it generated on PLL from 66 MHz?Note that you're needs to use the same clock for all logic, if you use different clock at some part of circuit it requires synchronization between two circuits clocked from different clock source (see synchronization between two clock domains for details). Otherwise it will leads to metastability issues and unpredictable behavior.When you're trying to access some data in a clock domain A, but the data is clocked from clock domain B, it leads to a problem. Because clock sources are async and if you latch the data on clock A edge, the data clocked from clock B can be in transition state at that moment. So the register can latch undefined transition state of the data (between 0 and 1). Seemetastabilityfor details.This is why all logic needs to be clocked from the same clock and that clock should be properly generated with 50% duty cycle and proper phase delay. And this is why you're needs to generate clock on FPGA PLL instead of use counters. When you're trying to generate clock with a counter you can't control it's duty cycle and phase delay, and since counter circuit has some phase delay its output will be out of phase with the main clock, it also can lead to metastability issues and unpredictable behavior. The worse thing is that phase delay is random and depends on synthesis, so the circuit behavior will be different when you add some change to design even if that change is not related with problematic part of circuit.

author: pieroc91
author_rank: Contributor
timestamp: June 01, 2023, 02:12:07 pm
content: Well this is going on a tangent.Thank everybody for your answers but most of the answer are for a related problem that I do not have.I need that counter to count cycles, clock isn't just for data sync, it counts horizontal pixels in order to know when to request the next line of pixels. There's another similar counter but for the cache address.A FIFO could be nice, but wouldn't work either since the FPGA is having troubles with the clock signal.My guess at the moment is that is not synthesizing the way I expect and that could be very hard to fix.@BrianHG nailed the point on the Cyclone PLL, that's something that I though too but haven't tested yet since I wanted to actually find the root of the problem but I guess this is going to be the way to go.My only concern about the PLL is how will it behave when clock is not present, does it free run? does it goes crazy? does it shut down?The clock only turns on when the analog part is on, and is not always. Also, I cannot rely on the clock from the cameras since the FPGA is missing a lot of cycles and this is the same of having the clock turned off at the "eyes" of the PLL. In those cases I need the PLL to free run at 6Mhz.I'm also liking the route of coding a simple code that detects when clock changes and resets the counter of my clock divider so it syncs the divided clock to the external clock.

author: BrianHG
author_rank: Super Contributor
timestamp: June 01, 2023, 02:29:14 pm
content: If you couldn't place a simple or multiple counters inside my (B) example, located at:// perform all synchronous camera data inside here.if you cannot add:if (latched_data/latched_syncs==reset_condition) counter<= 16'd0;else counter <= counter + 1'b1;Then I'm not sure what to tell you.Inside that 'if(cam_data_ready) begin end' condition, even though it will running on your 66MHz clock, it will only increment once after every camera clock in transition from high to low.

author: Scrts
author_rank: Frequent Contributor
timestamp: June 01, 2023, 04:38:58 pm
content: Quote from: pieroc91 on June 01, 2023, 02:12:07 pmLets confirm a couple of things first... Forget the FPGA for a moment.1) Does the clock comes out of the camera after it is powered up?2) When you say "analog part is on, but not always" - when is the analog part powered and when it's not?3) Is it constant 6MHz once it's powered up? Or it has interrupted clock, i.e. clock is active once video data is coming out and stops once frame ends?You need to figure out if you have a reliable 6MHz clock out of the sensor before looking into implementation of data capture in FPGA.

author: pieroc91
author_rank: Contributor
timestamp: June 01, 2023, 05:55:08 pm
content: Quote from: pieroc91 on May 30, 2023, 02:14:43 pmQuote from: pieroc91 on May 31, 2023, 02:19:02 pmThe clock signal is far beyond from tested, is not the problem.The problem is on the internal handling of that clock on the FPGAQuote from: Scrts on June 01, 2023, 04:38:58 pmNo, it turns on when I send the command to turn on the analog part.Quote from: Scrts on June 01, 2023, 04:38:58 pmWhenever I turn it on, it is required for the imager to work and is turned on a few uS prior to enabling the output shift register on the camera.Quote from: Scrts on June 01, 2023, 04:38:58 pmIs constant till I send the command to turn off the analog part, the actual read is only a few mS, but i've left it running for a few seconds and is rock solid even being routed from one pin to another of the FPGA.

author: Scrts
author_rank: Frequent Contributor
timestamp: June 01, 2023, 07:41:30 pm
content: Quote from: pieroc91 on June 01, 2023, 05:55:08 pmOk, very good.Can you show us how you describe the input clock in the device constrains (.sdc) file?Do you use 2FF input data sync using that input clock?Do you see signals coming in correctly using SignalTap? If so, what clock do you use for SignalTap?

author: BrianHG
author_rank: Super Contributor
timestamp: June 01, 2023, 09:58:57 pm
content: Quote from: pieroc91 on June 01, 2023, 05:55:08 pmThis should no longer be a problem with my code 'B'. It removes the need for internal handling of the 6MHz clock and puts everything on the 66MHz core and gives you a data enable every time a new valid camera word sensor comes in.It would be the same with the DCFIFO where in the core 66MHz side, you would use the 'not empty' flag as a ready enable.My code doe not require anything fancy in the timing constraints file (.sdc), just the core 66MHz PLL spec & derive PLL clocks. So long at the data coming in is valid for more than 2 clk periods of the 66MHz period, you data capture should be clean. But I will let you look at the data sheets and decide how to assign this as you may also adjust the data capture time by +/- (you decide) 66mhz clock cycles since the detection of the camera's clock transition.Using a DCFIFO gives you 2 clock domains, the 6MHz one and the 66MHz one. And depending on the situation, you will need a more sophisticated .sdc file.

author: c64
author_rank: Frequent Contributor
timestamp: June 01, 2023, 11:12:07 pm
content: What are your logic levels? EP910 is old 5v part.

author: c64
author_rank: Frequent Contributor
timestamp: June 01, 2023, 11:17:37 pm
content: Which pin is input clock connected to? Dedicated clock pin?Try to run this as top level module. Don't use any PLL.Check if clkOut is good 6M signal and check if cnt is correctCode:module test(input clk6,output clkOut,output cnt);reg [31:0] counter;assign clkOut = clk6;assign cnt = counter;always @(posedge clk6)counter <= counter + 1;endmodule

author: pieroc91
author_rank: Contributor
timestamp: June 02, 2023, 02:54:30 pm
content: This was going down to a rabbit hole and taking too much time so i did this:Quote from: pieroc91 on June 01, 2023, 02:12:07 pmI made a very small routine that buffers the state of the 6mhz clock on the negative edge of the 66mhz clock and buffers that again on another register on the positive edge and compares them, if they don't match it means the 6mhz clock changed the state and generates a pulse, also with an AND makes it only generate that pulse on the change to low, this pulse is acting as a reset on the counter for the counter-made clock that proved the working state of all the rest of the code.I tested if first with a push button and it worked flawlessly. The top signal is the 6mhz clock from the camera, the pulses on the second (not visible due to be much faster than my LA) and third is my corrected clock getting phase corrected.Here's with the clock signal, now perfectly in phase, this time the pulses are visible, probably because of the sampling aliasing with the much faster signal.Now is working perfectly... at least that part.Thanks everyone that helped.