• Content Count

  • Joined

  • Last visited

  • Days Won


Everything posted by hamster

  1. hamster

    Large Spectrum Generation

    My first guess would be... Take a pseudo-random stream of +1/-1 values, at about 1/4th your desired bandwidth. Lowpass filter that to half your desired bandwidth. Multiply that by your carrier samples Send that to DAC. Would be easy to do, but spectrum will be 'lumpy'.
  2. Phew... not putting a space for "the perfect frequency" clock isn't a worry anymore, as 12MHz * 64 / 31.25 = 25.576MHz, the required for 48kHz sample rate and this is just within the range of the MMCM block. Most likely has less-than-ideal jitter and noise specs for hi-fi buffs, but should be perfectly adequate for my needs.
  3. I've got a few project ideas around a digital crossover for bi-amped speakers... I had the DACs left over from building a few stereo I2S boards with PMOD interfaces, but found using many of them at once was getting impractical - if I had to tidy my desk I would waste a lot of time connecting things up again when I got back to playing with them. The other reason for these chips is they are really, really dumb and simple to use. No preamp or signal routing to configure, no I2C management needed - just send the correct clocks and they send back the correct data. Dumb parts are also cheap parts - the DACs were $0.50, the ADCs are ~$1.00, the sockets are $0.40, making this around a $20 project... I've just had that pang of "I've sent the board away too early". On thing I should have done is added a few extra pads to allow for strapping resistors on the ADCs to configure them, but is is unclear to me how they will interact with the FPGA's pin's default state while the FPGA is being configured. I should have also have added a 24.576 MHz Oscillator too,... so I could run at 48kHz, not the 46.875KHz I'll be running at from the on-board 12MHz clock. Oh, and then... ... maybe I should have added a version number on the PCB too!
  4. I've just sent a PCB away from manufacture - it will have four stereo ADCs and four stereo DACs for the CMOD A7. Once I have one built I'll have to find a use for it!
  5. Maybe remove the 'reg' from the Verilog port definition?
  6. I've done it before without issue, and all I can suggest is that you look carefully at your component/module names and especially uppercase / lowercase. Maybe add some code snippets to the thread?
  7. The Vivado virtual logic analyser is very easy to set up and use, and will give you the most accurate result for minimal effort
  8. This little project might give you some ideas - it controls the speed of the dev board's fan based on the XADC reading. It also uses no IP blocks so everything is exposed. http://hamsterworks.co.nz/mediawiki/index.php/XADC_Fan_PWM
  9. As a gross oversimplification, FPGAs only have clocked flipflops that can store state information. You can use variables to store state rather than signals, but they have to be used in such a way that they can be mapped down to flipflops. Without using a clock edge in the HDL code this can't happen, and all sorts of weird stuff happens.
  10. Hi again, Changed the XDC file, and to run it on a board - it didn't work for me either. There are a few synthesis issues that need to be addressed (both of which were pointed out as warning in the logs, BTW): 1. input needs to be added on this process's sensitivity list: process(present_state,data,clk,rst,start, input) 2. The major problem - you are updating count and index_reg inside the async process: count:=count+1; and index:=index+1; You can't do this, as conceptually the process is "run" each time any of the input signals change state. If you want to work with the similar structure you need to assign count_next and index_next inside the async process, then assign them to count and index in the clocked one. Oh, and another tiny issue - if you want to do something every 10400 cycles, you need to count from 0 to 10399.
  11. Looking at the reference manual, if you intend to use the onboard USB to serial Bridge then your output pin should be A18 https://reference.digilentinc.com/basys3/refmanual
  12. I wrote a quick test bench. I couldn''t get it out of 'idle' state because of this code: if start='1' and rst='0' then count:=count+1; if count=clk_max then next_state<=start_state; count:=0; end if; end if; I asserted 'start' for only one cycle, and nothing happened. I see now that I need to assert it for up to 10,400 cycles before it will send data. Will let you know how testing progresses. Also, the async reset is a slightly unusual design pattern for FPGA designs. Synchronous resets (with a properly synchronised reset signal) work better. Here is the test bench so far. library IEEE; use IEEE.STD_LOGIC_1164.ALL; entity tb is end tb; architecture Behavioral of tb is component rs232_omo is generic(clk_max:integer:=10400); --for baudrate port( clk : in std_logic; rst : in std_logic; start : in std_logic; input : in std_logic_vector(7 downto 0); done : out std_logic; output : out std_logic; showstates : out std_logic_vector(3 downto 0) ); end component ; signal clk : std_logic; signal rst : std_logic := '0'; signal start : std_logic := '0'; signal input : std_logic_vector(7 downto 0) := x"55"; signal done : std_logic; signal output : std_logic; signal showstates : std_logic_vector(3 downto 0); begin process begin clk <= '0'; wait for 5ns; clk <= '1'; wait for 5ns; end process; process begin wait for 100ns; rst <= '1'; wait for 20ns; rst <= '0'; wait for 100ns; start <= '1'; wait for 10ns; start <= '0'; wait; end process; uut: rs232_omo generic map (clk_max => 10400) port map( clk => clk, rst => rst, start => start, input => input, done => done, output => output, showstates => showstates ); end Behavioral;
  13. I haven't looks at the code too much, but I did notice that you don't appear to have synchronizers on your external connections that control the state machine (start and reset). Although this is most likely not your problem it will cause inconsistent behaviour. Are you also sure you haven't got the Tx/Rx pins back to front, as naming depends on the designer perspective and whims on the day
  14. The error is because the magnitude as to be one bit longer than the inputs, (as the magnitude of (0xFFFFFF, 0xFFFFFF) is 0x16A09E4, which will overflow if you put it into a 25-bit signed value. It will however fit nicely into a 25-bit unsigned value, and as it is a magnitude it will be positive. So maybe snip off the top bit in the assignment, but remember it is unsigned!
  15. Using a tool for what it is meant to do is easy. Using a tool for something where it isn't suited, that is where the learning begins! (I now goes back to doing dental surgery with a steamroller, or maybe digging a tunnel with a teaspoon).
  16. Oh, a quick hack of a CORDIC magnitude library IEEE; use IEEE.STD_LOGIC_1164.ALL; use IEEE.NUMERIC_STD.ALL; entity magnitude is Port ( clk : in std_logic; x_in : in std_logic_vector; y_in : in std_logic_vector; x_out : out std_logic_vector := (others => '0'); y_out : out std_logic_vector := (others => '0'); magnitude_out : out std_logic_vector := (others => '0') -- Accurate to 5 bits or so ); end magnitude; architecture Behavioral of magnitude is type a_x is array(0 to 5) of signed(x_in'high+1 downto 0); type a_y is array(0 to 5) of signed(y_in'high+1 downto 0); type a_x_delay is array(0 to 5) of std_logic_vector(x_in'high downto 0); type a_y_delay is array(0 to 5) of std_logic_vector(y_in'high downto 0); signal x : a_x := (others => (others => '0')); signal y : a_y := (others => (others => '0')); signal x_delay : a_x_delay := (others => (others => '0')); signal y_delay : a_y_delay := (others => (others => '0')); begin magnitude_out <= std_logic_vector(y(5)); x_out <= x_delay(x_delay'high); y_out <= y_delay(y_delay'high); process(clk) begin if rising_edge(clk) then if x(4) >= 0 then -- x(5) is not needed y(5) <= y(4) + x(4)(x(4)'high downto 4); else -- x(5) is not needed y(5) <= y(4) - x(4)(x(4)'high downto 4); end if; if x(3) >= 0 then x(4) <= x(3) - y(3)(y(3)'high downto 3); y(4) <= y(3) + x(3)(x(3)'high downto 3); else x(4) <= x(3) + y(3)(y(3)'high downto 3); y(4) <= y(3) - x(3)(x(3)'high downto 3); end if; if x(2) >= 0 then x(3) <= x(2) - y(2)(y(2)'high downto 2); y(3) <= y(2) + x(2)(x(2)'high downto 2); else x(3) <= x(2) + y(2)(y(2)'high downto 2); y(3) <= y(2) - x(2)(x(2)'high downto 2); end if; if x(1) >= 0 then x(2) <= x(1) - y(1)(y(1)'high downto 1); y(2) <= y(1) + x(1)(x(1)'high downto 1); else x(2) <= x(1) + y(1)(y(1)'high downto 1); y(2) <= y(1) - x(1)(x(1)'high downto 1); end if; if x(0) >= 0 then x(1) <= x(0) - y(0)(y(0)'high downto 0); y(1) <= y(0) + x(0)(x(0)'high downto 0); else x(1) <= x(0) + y(0)(y(0)'high downto 0); y(1) <= y(0) - x(0)(x(0)'high downto 0); end if; if y_in(y_in'high) = '1' then x(0) <= signed(x_in(x_in'high) & x_in); y(0) <= signed(to_signed(0,y_in'length+1)-signed(y_in)); else x(0) <= signed(x_in(x_in'high) & x_in); y(0) <= signed(y_in(y_in'high) & y_in); end if; -- Delay to output the inputs, so they are aligned with the magnitudes x_delay(1 to 5) <= x_delay(0 to 4); y_delay(1 to 5) <= y_delay(0 to 4); x_delay(0) <= x_in; y_delay(0) <= y_in; end if; end process; end Behavioral; Chaining the two together, and it seems to work. Top trace is the input, second trace is the delayed input, Third is the delayed output of the Hilbert filter, and the last is the scaled magnitude of the complex x+iy signal. NOTE: I know for sure that these are buggy, as they have range overflows), but they should give the idea of how @Ahmed Alfadhel could be implement it. magnitude.vhd hilbert_transformer.vhd tb_hilbert_transformer.vhd
  17. Going to Incorporate it into my (MCU based) guitar tuner... but it is a nice tool to have in the kit.
  18. I was intrigued enough by the Hilbert Transform to actually learn, experiment and implement it in VHDL. The math behind it is pretty nifty. Here's the very naively implemented example, using a short FIR filter. You can find this, a test bench and simulation output at http://hamsterworks.co.nz/mediawiki/index.php/Hilbert_Transform library IEEE; use IEEE.STD_LOGIC_1164.ALL; use IEEE.NUMERIC_STD.ALL; entity hilbert_transformer is Port ( clk : in STD_LOGIC; real_in : in STD_LOGIC_VECTOR (9 downto 0); real_out : out STD_LOGIC_VECTOR (10 downto 0) := (others => '0'); imag_out : out STD_LOGIC_VECTOR (10 downto 0) := (others => '0')); end hilbert_transformer; architecture Behavioral of hilbert_transformer is -- Constants are 2/(n * pi) * 512, for n of -7,-5,-3,-1,1,3,5,7 constant kernel0 : signed(real_in'length-1 downto 0) := to_signed( -47, real_in'length); constant kernel2 : signed(real_in'length-1 downto 0) := to_signed( -66, real_in'length); constant kernel4 : signed(real_in'length-1 downto 0) := to_signed(-109, real_in'length); constant kernel6 : signed(real_in'length-1 downto 0) := to_signed(-326, real_in'length); constant kernel8 : signed(real_in'length-1 downto 0) := to_signed( 326, real_in'length); constant kernel10 : signed(real_in'length-1 downto 0) := to_signed( 109, real_in'length); constant kernel12 : signed(real_in'length-1 downto 0) := to_signed( 66, real_in'length); constant kernel14 : signed(real_in'length-1 downto 0) := to_signed( 47, real_in'length); type a_delay is array (0 to 14) of signed(real_in'high downto 0); signal delay : a_delay := (others => (others => '0')); signal tap0 : signed(real_in'length+kernel0'length-1 downto 0) := (others => '0'); signal tap2 : signed(real_in'length+kernel2'length-1 downto 0) := (others => '0'); signal tap4 : signed(real_in'length+kernel4'length-1 downto 0) := (others => '0'); signal tap6 : signed(real_in'length+kernel6'length-1 downto 0) := (others => '0'); signal tap8 : signed(real_in'length+kernel8'length-1 downto 0) := (others => '0'); signal tap10 : signed(real_in'length+kernel10'length-1 downto 0) := (others => '0'); signal tap12 : signed(real_in'length+kernel12'length-1 downto 0) := (others => '0'); signal tap14 : signed(real_in'length+kernel14'length-1 downto 0) := (others => '0'); begin process(clk) variable imag_tmp : signed(real_in'length*2-1 downto 0); begin if rising_edge(clk) then real_out <= std_logic_vector(resize(delay(8),real_out'length)); -- deliberatly advanced by one due to latency imag_tmp := tap0 + tap2 + tap4 + tap6 + tap8 + tap10 + tap12 + tap14; imag_out <= std_logic_vector(imag_tmp(imag_tmp'high downto imag_tmp'high-imag_out'high)); tap0 <= delay(0) * kernel0; tap2 <= delay(2) * kernel2; tap4 <= delay(4) * kernel4; tap6 <= delay(6) * kernel6; tap8 <= delay(8) * kernel8; tap10 <= delay(10) * kernel10; tap12 <= delay(12) * kernel12; tap14 <= delay(14) * kernel14; -- Update the delay line delay(1 to 14) <= delay(0 to 13) ; delay(0) <= signed(real_in); end if; end process; end Behavioral;
  19. Oh, for what it's worth I've been toying with the Hilbert Transform. Here is a example of it; #include <math.h> #include <stdio.h> #define SAMPLES 1000 #define HALF_WIDTH 11 /* e.g. 11 filters from -11 to 11 */ float x[SAMPLES]; int main(int argc, char *argv[]) { int i; /* Build some test data */ for(i = 0; i < SAMPLES; i++) { x[i] = cos(2*M_PI*i/10.3); } /* Now apply the Hilbert Transform and see what we get */ /* It should be close to sin(2*M_PI*i/10.3) */ for(i = HALF_WIDTH; i < SAMPLES-HALF_WIDTH-1; i++) { double h = 0; int j; /* Apply the kernel */ for(j = 1; j <= HALF_WIDTH; j+=2) h += (x[i-j]-x[i+j]) * 2.0/(j*M_PI); /* Print result */ printf("%8.5f, %8.5f\n", x[i], h); } }
  20. Oh having a look at the full signal chain, it looks like you just need to apply a low-pass filter on the absolute value of the signal. It might be just as simple as: if sample < 0 then filter := filter - filter/64 - sample; else filter := filter - filter/64 + sample; end if; With the value of "64" change depending on your sample rates and desired cutoff frequency. Or if your needs get very complex you might need to use a FIR low pass filter. Run some sample data through it in Matlab or Excel (or heavens forbid, some C code) and see what happens.
  21. Hi @Ahmed Alfadhel I had the C code handy because I have been working on an atan2(y,x) implementation for FPGAs, and had been testing ideas. I left it in C because I don't really know your requirements, but I wanted to give you a working algorithm, complete with proof that it does work, and so you can tinker with it, see how it works, and make use of it. Oh, and I must admit that it was also because I am also lazy 😀 But seriously: - I don't know if you use VHDL or Verilog, or some HLS tool - I don't know if your inputs are 4 bits or 40 bits long, - I don''t know if you need the answer to be within 10% or 0.0001% - I don't know if it has to run at 40Mhz or 400Mhz - I don't know if you have 1000s of cycles to process each sample, or just one. - I don't even know if you need the algorithm at all! But it has been written to be trivially converted to any HDL as it only uses bit shifts and addition/subtraction. But maybe more importantly you can then use it during any subsequent debugging to verify that you correctly implemented it. For an example of how trivial it is to convert to HDL: if(x > 0) { x += -ty/8; y += tx/8;} else { x += ty/8; y += -tx/8;} could be implemented as IF x(x'high) = '0' THEN x := x - resize(y(y'high downto 3), y'length); y := y + resize(x(x'high downto 3), x'length); ELSE x := x + resize(y(y'high downto 3), y'length); y := y - resize(x(x'high downto 3), x'length); END IF My suggestion is that should you choose to use it, compile the C program, making the main() function a sort of test bench, and then work out exactly what you need to implement in your HDL., You will then spend very little time writing, debugging and improving the HDL because you will have a very clear idea of what you are implementing.
  22. Um, are you sure that you are asking the right question? if the signal is BFSK, it should have pretty much a constant envelope, as only the frequency is changed?
  23. Hi, Sorry to barge in, but if anybody can point me to the Hibbert Transformer info I would be very grateful. However, here is an FPGA friendly way to calculate mag = sqrt(x*x+y*y), with about a 99% accuracy. You can easily see the pattern to get whatever accuracy you need. #include <math.h> #include <stdio.h> #define M_SCALE (16) /* Scaling for the magnitude calc */ void cordic_mag(int x,int y, int *mag) { int tx, ty; x *= M_SCALE; y *= M_SCALE; /* This step makes the CORDIC gain about 2 */ if(y < 0) { x = -(x+x/4-x/32-x/256); y = -(y+y/4-y/32-y/256); } else { x = (x+x/4-x/32-x/256); y = (y+y/4-y/32-y/256); } tx = x; ty = y; if(x > 0) { x += -ty/1; y += tx/1;} else { x += ty/1; y += -tx/1;} tx = x; ty = y; if(x > 0) { x += -ty/2; y += tx/2;} else { x += ty/2; y += -tx/2;} tx = x; ty = y; if(x > 0) { x += -ty/4; y += tx/4;} else { x += ty/4; y += -tx/4;} tx = x; ty = y; if(x > 0) { x += -ty/8; y += tx/8;} else { x += ty/8; y += -tx/8;} tx = x; ty = y; if(x > 0) { x += -ty/16; y += tx/16;} else { x += ty/16; y += -tx/16;} *mag = ty/M_SCALE/2; /* the 2 is to remove the CORDIC gain */ } int main(int argc, char *argv[]) { int i; int cases = 300; printf("Irput Calculated CORDIC Error\n"); for(i = 0; i < cases; i++) { float angle = 2*M_PI*i/cases; int x = sin(angle)*20000; int y = cos(angle)*20000; int mag, a_mag = (int)sqrt(x*x+y*y); cordic_mag(x,y, &mag); printf("%6i %6i = %6i vs %6i %4i\n", x, y, a_mag, mag, mag-a_mag); } } Oh, here is the output with a couple more iterations added. Irput Calculated CORDIC Error 0 20000 = 20000 vs 19999 -1 418 19995 = 19999 vs 19995 -4 837 19982 = 19999 vs 20001 2 1255 19960 = 19999 vs 19998 -1 1673 19929 = 19999 vs 19995 -4 2090 19890 = 19999 vs 20001 2 2506 19842 = 19999 vs 19998 -1 2921 19785 = 19999 vs 19996 -3 3335 19719 = 19999 vs 20001 2 3747 19645 = 19999 vs 19998 -1 4158 19562 = 19999 vs 19996 -3 4567 19471 = 19999 vs 20001 2 4973 19371 = 19999 vs 19997 -2 5378 19263 = 19999 vs 19996 -3 5780 19146 = 19999 vs 20001 2 6180 19021 = 19999 vs 19998 -1 6577 18887 = 19999 vs 19999 0 6971 18745 = 19999 vs 20001 2 7362 18595 = 19999 vs 19993 -6
  24. Dan seems on to something. Are you sure you have a low-pass filter, not a high pass one?
  25. hamster

    DAC spartan3e

    Have you done any debugging yourself? If so, what have you tried? I am not familiar with the FPGA board you are using... is it a Digilent one? Do you have any documentation for iit? Do you know what the part code is for the DAC? Are you sure you are using the correct pin locations? What would the correct signal look like (e.g. it is a sine wave at 1234Hz, with 2V peak-to-peak)? Are you sure you included the correct right code? The header says: -- Copyright (c) 2007 Frank Buss (fb@frank-buss.de) -- See license.txt for license If it is the right code, have you tried to get hold of Frank Buss?