Showing results for 
Show  only  | Search instead for 
Did you mean: 
Registered: ‎08-26-2014

Does anyone know why this HLS code hangs when implemented in the Zynq?



I am having problems with the function below when using HLS 2017.2. The C and RTL co-simulation on HLS works nicely, but after the IP generation and implementation in Vivado, it hangs after a few calls. The number of calls vary randomly. I am running the function with a 100MHz clock and it needs 50 clock cycles to perform the calculations. In Vivado, I have a counter which calls the function every 5us, but after a while, the DONE signal does not go high.


waveform problem.png


It happened to me other times, but I could get around writing a very simple code. However, I cannot get it working this time.


Does anyone know where could be the problem? I had experienced similar problems in this post, but no one answered.


Many thanks,




void mmc_HIL(data_t2 Vin, ap_uint<6> PWM, bool mode, data_t2* is_out, data_t2* id_out,
		data_t2* Ecs0_out, data_t2* Ecs1_out, data_t2* Ecs2_out,
		data_t2* Ecd0_out, data_t2* Ecd1_out, data_t2* Ecd2_out, data_t2* Vout)
#pragma HLS INTERFACE ap_none register depth=1 port=Vin
#pragma HLS INTERFACE ap_none register depth=1 port=PWM
#pragma HLS INTERFACE ap_none register depth=1 port=mode
#pragma HLS INTERFACE ap_vld register depth=1 port=is_out
#pragma HLS INTERFACE ap_vld register depth=1 port=id_out
#pragma HLS INTERFACE ap_vld register depth=1 port=Ecs0_out
#pragma HLS INTERFACE ap_vld register depth=1 port=Ecs1_out
#pragma HLS INTERFACE ap_vld register depth=1 port=Ecs2_out
#pragma HLS INTERFACE ap_vld register depth=1 port=Ecd0_out
#pragma HLS INTERFACE ap_vld register depth=1 port=Ecd1_out
#pragma HLS INTERFACE ap_vld register depth=1 port=Ecd2_out
#pragma HLS INTERFACE ap_vld register depth=1 port=Vout
	const data_t2 C = 470e-6;
	const data_t2 delta_C = 5e-6/(C);
	const data_t2 Ts = 5e-6;
	const data_t2 L2 = 5e-3;
	const data_t2 R1 = 0.01;
	const data_t2 Ron = 0.033;
	data_t2 isdelta_C, iddelta_C, Es_eq = 0.0, Ed_eq = 0.0, is_der = 0.0, id_der = 0.0;
	static data_t2 i_s = 0.0, i_d = 0.0, Ecs0 = 0.0, Ecs1 = 0.0, Ecs2 = 0.0,
			Ecd0 = 0.0, Ecd1 = 0.0, Ecd2 = 0.0;
	const data_t2
	// PARAMETERS FOR Rload = 1Mohm (Charging mode)
	A0[2][2] = {{4.9994550296999357e-01,  4.9994550296999352e-01},
	{4.9994550296999352e-01,   4.9994550296999346e-01}},

	B0[2][3] = {{5.0022275097634289e-04,  -5.0022275097634300e-04,  -4.9972275100360725e-04},
	{4.9972275100359294e-04,   -4.9972275100359294e-04,  -5.0022275097635720e-04}},

	C0[2] = {1.0000000000000000e+06,  -1.0000000000000000e+06},

	// PARAMETERS FOR Rload = 44ohm (normal operation)
	A1[2][2] = {{9.5777603508396336e-01,  4.2114970856320780e-02},
	{4.2114970856320787e-02,   9.5777603508396358e-01}},

	B1[2][3] = {{9.7857843129716131e-04,  -9.7857843129716131e-04,  -2.1367070682951673e-05},
	{2.1367070682951673e-05,   -2.1367070682951673e-05,  -9.7857843129716131e-04}},

	C1[2] = {4.4000000000000000e+01,  -4.4000000000000000e+01};

	// Vcaps update

	isdelta_C = (i_s)*delta_C;
	iddelta_C = (i_d)*delta_C;

	// Series arm
	if(PWM & (0x01<<0))
			Ecs0 = Ecs0 + (float)isdelta_C;
	if(PWM & (0x01<<1))
			Ecs1 = Ecs1 + (float)isdelta_C;
	if(PWM & (0x01<<2))
			Ecs2 = Ecs2 + (float)isdelta_C;

	// Derivation arm
	if(PWM & (0x01<<3))
		Ecd0 = Ecd0 + (float)iddelta_C;
	if(PWM & (0x01<<4))
		Ecd1 = Ecd1 + (float)iddelta_C;
	if(PWM & (0x01<<5))
		Ecd2 = Ecd2 + (float)iddelta_C;

	if(Ecs0 < 0) Ecs0 = 0.0;
	if(Ecs1 < 0) Ecs1 = 0.0;
	if(Ecs2 < 0) Ecs2 = 0.0;

	if(Ecd0 < 0) Ecd0 = 0.0;
	if(Ecd1 < 0) Ecd1 = 0.0;
	if(Ecd2 < 0) Ecd2 = 0.0;

	// Equivalent arm voltage update

	if(PWM & (0x01<<0))
		Es_eq = Ecs0;
	if(PWM & (0x01<<1))
		Es_eq = Es_eq + Ecs1;
	if(PWM & (0x01<<2))
		Es_eq = Es_eq + Ecs2;

	if(PWM & (0x01<<3))
		Ed_eq = Ecd0;
	if(PWM & (0x01<<4))
		Ed_eq = Ed_eq + Ecd1;
	if(PWM & (0x01<<5))
		Ed_eq = Ed_eq + Ecd2;

	// Full State Space equations

		is_der = A0[0][0] * i_s + A0[0][1] * i_d + B0[0][0] * Vin + B0[0][1] * Es_eq + B0[0][2] * Ed_eq;
		id_der = A0[1][0] * i_s + A0[1][1] * i_d + B0[1][0] * Vin + B0[1][1] * Es_eq + B0[1][2] * Ed_eq;
		*Vout = C0[0] * (is_der - id_der);
		is_der = A1[0][0] * i_s + A1[0][1] * i_d + B1[0][0] * Vin + B1[0][1] * Es_eq + B1[0][2] * Ed_eq;
		id_der = A1[1][0] * i_s + A1[1][1] * i_d + B1[1][0] * Vin + B1[1][1] * Es_eq + B1[1][2] * Ed_eq;
		*Vout = C1[0] * (is_der - id_der);

	i_s = is_der;
	i_d = id_der;

	// Outputs update

	*is_out = i_s;
	*id_out = i_d;
	*Ecs0_out = Ecs0;
	*Ecs1_out = Ecs1;
	*Ecs2_out = Ecs2;
	*Ecd0_out = Ecd0;
	*Ecd1_out = Ecd1;
	*Ecd2_out = Ecd2;


0 Kudos
3 Replies
Registered: ‎03-13-2017

Hi Daniel,

in the following you will find just a guess....

The failure could be due not to the.module itself (as it works in co-simulation) but due to the way you integrate it in Vivado.
i mean, are you sure you call it correctly?
From the ILA plot it is not clear to me the timing sequence of the input signals vs. the block-level interface protocol (ref. my previous reply to this post).
As example for your investigation, when is changed the input Vin signal ?
I would change it far from the start signal, e.g. around the counter_5us assertion...


Try also some small change that could help to spot the problem, e.g. 

the signals PWM and mode looks like slow/static control signals; try to change their if from ap_none to ap_stable. I don't expect this solve but you could gain some more useful info.


Registered: ‎08-26-2014

Thanks @baltam for your answer.


The IP performed well in other versions of the code, so it is unlikely that the problem is in the block design used in Vivado to test it.


Vin is changed first using an AXI_GPIO, then ap_start is asserted using as well an AXI_GPIO. It lasts several clock cycles, so it is sure the IP sees the ap_start signal.


And regarding the PWMs and the mode signals, they are constant at the begining of the simulation, but not later.


I upgraded to Vivado 2017.4 but the problem persists.


I just found what might be causing the hanging, or what can make the hanging not to happen I would say. In the previous code, if I use these lines the IP hangs:


isdelta_C = is*delta_C;
iddelta_C = id*delta_C;


However, if I perform the multiplication and division explicitly instead of using a multiplication by a constant, the IP runs OK:


isdelta_C = is*5e-6/C;
iddelta_C = id*5e-6/C;


Can someone from @Xilinx explain this behavior, please? It happened to me in another version of the IP where I changed a division by a multiplication by a constant as well. So it is something that can be reproduced.

0 Kudos
Registered: ‎08-26-2014

I am testing the working version of the IP (using isdelta_C = is*5e-6/C;), and it does funny things. The ap_done and ap_idle go high right after the ap_start. According to HLS, the IP needs 75 clock cycles to output a valid result. The green squares show how it should behave. Red squares show when it has weird behavior.


Do you think this is a normal behavior? I think not...


IP strange behavior.png





0 Kudos