Jump to content
  • 0

Signal voltage modulation problem with Basys3 VHDL


iratidance

Question

Dear All,

 

I am planning to program a PID controller on the Basys3. For this purpose,

 

  1. I first tried to get a signal from a function generator into the ADC (pmodAD1) and output it through the DAC (pmodDA2). This works fine.
  2. I wanna take the digital output of the ADC, multiply or divide it by a real factor and output the result through the DAC. There might be better ways of doing this but in order to specify the re number, I have created two integer numbers and apply a division between them. This would allow me to get any "real" number that I want.

 

    constant mul_number :          integer := 5;
    constant div_number :           integer := 4;
    signal mul_number_unsigned :  unsigned(11 downto 0);
    signal div_number_unsigned :   unsigned(11 downto 0);
 
    mul_number_unsigned <= to_unsigned(mul_number,12);
    div_number_unsigned <= to_unsigned(div_number,12);
 
  • when mul_number_unsigned/div_number_unsigned = integer : the voltage height increases according to the set value. 
  • when mul_number_unsigned/div_number_unsigned > 1 and real : nothing happens to the signal and the same input signal is output again.
  • when mul_number_unsigned/div_number_unsigned < 1 , positive and real : the is no output signal.

I do not know how to solve the problem since the compiling does not give me any warning or error...Any help or suggestion would be really appreciated.

 

Thanks a lot!

 

PS: sorry for the code file format but the system did not allow me to upload a .vhd file.

 

 

acd_func_dac.txt

Link to comment
Share on other sites

2 answers to this question

Recommended Posts

Hi iratidance,

 

The problem is here:

                    data_unsigned_func <= resize(data_unsigned * (mul_number_unsigned/div_number_unsigned), data_unsigned_func'length);
 
Unsigned numbers are like integers, and if mul_number_unsigned is less than div_number_unsigned it will end up being zero. as (mul_number_unsigned/div_number_unsigned) will be zero.
 
This will give you different results.

                    data_unsigned_func <= resize((data_unsigned * mul_number_unsigned)/div_number_unsigned), data_unsigned_func'length);
 
One other thing you might want to do is check the limits of inputs to outputs, and make sure that you get sensible results.
 
You might also want to be careful about your zero offsets. If you have a 10 bit input and a scale factor of 1/2, then the range of 0 to 1023 will output 0 to 511. You might be expecting 256 to 767 (i.e. centered on half of the range).
 
You may also want to saturate rather than wrap, as a number wrapping around might make strange things happen, or make sure you have enough dynamic range that you can't overflow.
 
Division is very expensive in FPGAs, and best avoided if you can. You might be better off using fixed point binary. Here's how I would do it in C::
    scale_factor = mul_number_unsigned * 256 / div_number_unsigned; /* these are all compile time constants */
    temp = data_unsigned_func * scale_factor; 
    data_unsigned_func = temp / 256; /* Dividing by 256 is easy in binary - just drop the lowest 8 bits */
 
But whatever you do, run through the calculations on paper for max and min values, and check that the length of the signals are sufficient to hold the full range.
Link to comment
Share on other sites

Thank you very much Hamster!

 

I have changed the parenthesis position and it works fine. The problem is that the accuracy of the output signal is not quite great....

 

Input 700mV, multiplied by 1/3 gives 300mV signal...

 

I thought about using real numbers in order to avoid the division part but I did not find a nice solution to typecast real numbers into unsigned ones...I'll look into the fixed point solution :)

Link to comment
Share on other sites

Archived

This topic is now archived and is closed to further replies.

×
×
  • Create New...