hamster

Members
  • Content Count

    545
  • Joined

  • Last visited

  • Days Won

    84

Reputation Activity

  1. Like
    hamster got a reaction from CPerez10 in Simple UART message repeater (not working)   
    I think of std_logic_vector the same way I would think of digits in a number...  the rightmost digit is digit zero. It most likely isn't the best way set things up for this example, but it avoids the need to swap the bit ordering in the ASCII characters.
    Oh, for the button synchronization...  signals take time to get across the chip (speed of light, capacitance and so on), so different parts of the design can see different values for the same signal as it change unless. As you can't control when the user might press the button you have to sample the value of the input signal on the clock edge,  holding that in a register. That registered value is then used drive the rest of your logic.
    There is a slight complication - If the signal from the button changes state *exactly* on the clock edge, the flipflop might not be able to correctly register as a 1 or a 0, but could be in some weird "metastable" state that takes a short while to become either a 1 or a 0. To stop this causing bugs in the operation of the logic deeper in the deign, the output of that fliplfop is then sampled a second time to get a "known good, either 1 or 0" signal, that can get to where it needs to within a clock cycle.
    Hence the design pattern... btn  gets sampled into btn_metastable (which is a bit dodgy if you use it), and then btn_metastable gets sampled into btn_synchronized, which is then used by the rest of the logic.
  2. Like
    hamster got a reaction from CPerez10 in Simple UART message repeater (not working)   
    Had a hack at it... tested working on BASYS3
     
    library IEEE; use IEEE.STD_LOGIC_1164.ALL; use IEEE.NUMERIC_STD.ALL; entity msg_repeater is Port ( clk : in STD_LOGIC; btn : in STD_LOGIC; tx : out STD_LOGIC; led : out STD_LOGIC_VECTOR (3 DOWNTO 0)); end msg_repeater; architecture Behavioral of msg_repeater is constant char_t : std_logic_vector (7 downto 0) := "01010100"; constant char_e : std_logic_vector (7 downto 0) := "01000101"; constant char_s : std_logic_vector (7 downto 0) := "01010011"; constant char_space : std_logic_vector (7 downto 0) := "00100000"; -- Note message is sent from bit 0 to the highest signal msg : std_logic_vector (49 downto 0) := char_space & "0" & -- Character 4, with start bit "1" & char_t & "0" & -- Character 3, wrapped in start and stop bit "1" & char_s & "0" & -- Character 2, wrapped in start and stop bit "1" & char_e & "0" & -- Character 1, wrapped in start and stop bit "1" & char_t & "0" & -- Character 0, wrapped in start and stop bit "1"; -- Idle symbol and stop bit of the last character signal msg_index : unsigned( 7 downto 0) := (others =>'0'); -- Should we send a message? signal triggered : std_logic := '0'; -- for generating the baud tick rate constant clock_rate : natural := 100000000; constant baud_rate : natural := 9600; signal baud_counter : unsigned(27 downto 0) := (others => '0'); signal baud_tick : std_logic := '0'; -- For the button synchonizer signal btn_synchronized : std_logic := '0'; signal btn_metastable : std_logic := '0'; begin process(clk) begin if rising_edge(clk) then -- Set the serial output bit tx <= msg(to_integer(msg_index)); led <= "0001"; -- Controlling the message index if baud_tick = '1' then if msg_index = 0 then -- We are waiting to be triggered if triggered = '1' then msg_index <= msg_index + 1; end if; elsif msg_index = msg'high then -- We have finished the message msg_index <= (others => '0'); triggered <= '0'; else -- We are sending bits msg_index <= msg_index + 1; end if; end if; -- Generating the baud tick if baud_counter < baud_rate then baud_tick <= '1'; baud_counter <= baud_counter - baud_rate + clock_rate; else baud_tick <= '0'; baud_counter <= baud_counter - baud_rate; end if; -- Seeing if we are triggered if btn_synchronized = '1' then triggered <= '1'; end if; -- Synchronize the button with the clock domain btn_metastable <= btn; btn_synchronized <= btn_metastable; end if; end process; end Behavioral;  
  3. Like
    hamster got a reaction from JColvin in CMOD A7 Audio board...   
    The last of the parts came in and the new board is up and running.
    Here's the old and new boards side by side, and spectrum of a 10kHz test tone going from the ADC, through the FPGA and then DAC (top = new board, middle = old board, bottom = no board in the loop.
    The additional work I did on grounding on the PCB has paid off, with a very good noise floor - better than I can measure with the tools I have to hand.
     


  4. Like
    hamster got a reaction from xc6lx45 in RISC-V RV32I CPU/controller   
    I just had a look at the J1b source, and saw something of interest (well, at least to weird old me):
    4'b1001: _st0 = st1 >> st0[3:0]; .... 4'b1101: _st0 = st1 << st0[3:0]; A 32-bit shifter takes two and a half levels of 4-input, -2 select MUXs per input bit PER DIRECTION (left or right) and the final selection between the two takes another half a LUT, so about 160 LUTs in total (which agrees with the numbers above)
    However, if you optionally reverse the order of bits going in, and then also reverse them going out of the shifter, then the same shifter logic can do both left and right shifts.
    This needs only three and a half levels of LUT6s, and no output MUX is needed. That is somewhere between 96 and 128 LUTs, saving maybe up to 64 LUTs.
    It's a few more lines of quite ugly code, but might save ~10% of logic and may not hit performance (unless the shifter becomes the critical path...).
  5. Like
    hamster got a reaction from xc6lx45 in RISC-V RV32I CPU/controller   
    I've just posted my holiday project to Github - Rudi-RV32I - https://github.com/hamsternz/Rudi-RV32I
    It is a 32-bit CPU, memory and peripherals for a simple RISC-V microcontroller-sized system for use in an FPGA.
    A very compact implementation and can use under 750 LUTs and as little as two block RAMs -  < 10% of an Artix-7 15T.
    All instructions can run in a single cycle, at around 50MHz to 75MHz. Actual performance currently depends on the complexity of system bus.
    It has full support for the RISC-V RV32I instructions, and has supporting files that allow you to use the RISC-V GNU toolchain (i.e. standard GCC C compiler) to compile programs and run them on your FPGA board. 
    Here is an example of the sort of code I'm running on it - a simple echo test:, that counts characters on the GPIO port that I have connected to the LEDs.
    // These match the address of the peripherals on the system bus. volatile char *serial_tx = (char *)0xE0000000; volatile char *serial_tx_full = (char *)0xE0000004; volatile char *serial_rx = (char *)0xE0000008; volatile char *serial_rx_empty = (char *)0xE000000C; volatile int *gpio_value = (int *)0xE0000010; volatile int *gpio_direction = (int *)0xE0000014; int getchar(void) { // Wait until status is zero while(*serial_rx_empty) { } // Output character return *serial_rx; } int putchar(int c) { // Wait until status is zero while(*serial_tx_full) { } // Output character *serial_tx = c; return c; } int puts(char *s) { int n = 0; while(*s) { putchar(*s); s++; n++; } return n; } int test_program(void) { puts("System restart\r\n"); /* Run a serial port echo */ *gpio_direction = 0xFFFF; while(1) { putchar(getchar()); *gpio_value = *gpio_value + 1; } return 0; } As it doesn't have interrupts it isn't really a general purpose CPU, but somebody might find it useful for command and control of a larger FPGA project (converting button presses or serial data into control signals). It is released under the MIT license, so you can do pretty much whatever you want with it.
    Oh, all resources are inferred, so it is easily ported to different vendor FPGAs (unlike vendor IP controllers)
  6. Like
    hamster got a reaction from JColvin in RISC-V RV32I CPU/controller   
    I've just posted my holiday project to Github - Rudi-RV32I - https://github.com/hamsternz/Rudi-RV32I
    It is a 32-bit CPU, memory and peripherals for a simple RISC-V microcontroller-sized system for use in an FPGA.
    A very compact implementation and can use under 750 LUTs and as little as two block RAMs -  < 10% of an Artix-7 15T.
    All instructions can run in a single cycle, at around 50MHz to 75MHz. Actual performance currently depends on the complexity of system bus.
    It has full support for the RISC-V RV32I instructions, and has supporting files that allow you to use the RISC-V GNU toolchain (i.e. standard GCC C compiler) to compile programs and run them on your FPGA board. 
    Here is an example of the sort of code I'm running on it - a simple echo test:, that counts characters on the GPIO port that I have connected to the LEDs.
    // These match the address of the peripherals on the system bus. volatile char *serial_tx = (char *)0xE0000000; volatile char *serial_tx_full = (char *)0xE0000004; volatile char *serial_rx = (char *)0xE0000008; volatile char *serial_rx_empty = (char *)0xE000000C; volatile int *gpio_value = (int *)0xE0000010; volatile int *gpio_direction = (int *)0xE0000014; int getchar(void) { // Wait until status is zero while(*serial_rx_empty) { } // Output character return *serial_rx; } int putchar(int c) { // Wait until status is zero while(*serial_tx_full) { } // Output character *serial_tx = c; return c; } int puts(char *s) { int n = 0; while(*s) { putchar(*s); s++; n++; } return n; } int test_program(void) { puts("System restart\r\n"); /* Run a serial port echo */ *gpio_direction = 0xFFFF; while(1) { putchar(getchar()); *gpio_value = *gpio_value + 1; } return 0; } As it doesn't have interrupts it isn't really a general purpose CPU, but somebody might find it useful for command and control of a larger FPGA project (converting button presses or serial data into control signals). It is released under the MIT license, so you can do pretty much whatever you want with it.
    Oh, all resources are inferred, so it is easily ported to different vendor FPGAs (unlike vendor IP controllers)
  7. Like
    hamster got a reaction from Andrew Touma in Bitstream problem with Basys 3   
    Seen the problem. You need to define both o1[0] and o1[1] in your constraints, as o1 is a vector of two signals. 
    At the moment you are trying to attach both signals to the same pin, hence the error. 
    Ditto for o2,  o3 and o4. 
  8. Like
    hamster got a reaction from Bryan_S in how to Parse a ASCII character as an identifier to received UART data?   
    I receive and process serial data in this hack:  http://hamsterworks.co.nz/mediawiki/index.php/PmodMAXSONAR
    It looks for an R character, then takes numeric ('0' to '9' ) that appear after that.
     
     
  9. Like
    hamster got a reaction from FloMai in Analog Discovery 2 vs Raspberry Pi 3   
    Hi. I've replaced my Cubieboard with a Raspberry Pi 3, and it runs the ARM version of Waveforms really well. With an Electronics Explorer everything works sweet.
    With the AD2, it complains about supply and/or AUX voltage, even with a 5V 3A power pack attached (The power supply panel indicates that the AUX supply is present so I know it is working well). The USB voltage usually shows as 4.92V at a few 10s of mAs
    I've tried with 2.5A USB PSU => Pi3 => Powered Hub => AD2, as well as 2.5A USB PSU => Pi3 => AD2. I also get a "unsufficent power". I've tried a few different USB cables too.
    The USB 2.0 spec, according to Wikipedia is 5V +/- 0.25V, so anything above 4.75V should be possible. Is there any hints?
    If I wanted to make a USB dummy load and test the voltage drop, what specs should I be checking for?
     
  10. Like
    hamster got a reaction from jpeyron in Setting the 8 bits of addr_in in order to monitor Temperature on XADC   
    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
  11. Like
    hamster got a reaction from Ahmed Alfadhel in Enevlope Detection using FPGA board   
    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!
  12. Like
    hamster got a reaction from Ahmed Alfadhel in Enevlope Detection using FPGA board   
    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).
  13. Like
    hamster got a reaction from Ahmed Alfadhel in Enevlope Detection using FPGA board   
    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
  14. Like
    hamster got a reaction from Ahmed Alfadhel in Enevlope Detection using FPGA board   
    Going to Incorporate it into my (MCU based) guitar tuner... but it is a nice tool to have in the kit.
  15. Like
    hamster got a reaction from Ahmed Alfadhel in Enevlope Detection using FPGA board   
    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;  
  16. Like
    hamster got a reaction from Ahmed Alfadhel in Enevlope Detection using FPGA board   
    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); } }  
  17. Like
    hamster got a reaction from Ahmed Alfadhel in Enevlope Detection using FPGA board   
    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.
  18. Like
    hamster got a reaction from Ahmed Alfadhel in Enevlope Detection using FPGA board   
    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.
  19. Like
    hamster got a reaction from Ahmed Alfadhel in Enevlope Detection using FPGA board   
    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
  20. Like
    hamster got a reaction from jpeyron in Enevlope Detection using FPGA board   
    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
  21. Like
    hamster got a reaction from [email protected] in 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 ([email protected]) -- See license.txt for license If it is the right code, have you tried to get hold of Frank Buss?
     
  22. Like
    hamster got a reaction from Ahmed Alfadhel in FIR compiler 7.2 stopband   
    That's a Verilog thing.. A 16-bit hex value, equivalent to 32767 decimal. 
    The VHDL equivalent would be x"7FFF"
  23. Like
    hamster got a reaction from That_Guy in MMCM dynamic clocking   
    Hey, something else I just saw when reading the clocking guide was:
    MMCM Counter Cascading The CLKOUT6 divider (counter) can be cascaded with the CLKOUT4 divider. This provides a capability to have an output divider that is larger than 128. CLKOUT6 feeds the input of the CLKOUT4 divider. There is a static phase offset between the output of the cascaded divider and all other output dividers.
    And:
    CLKOUT4_CASCADE : Cascades the output divider (counter) CLKOUT6 into the input of the CLKOUT4 divider for an output clock divider that is greater than 128, effectively providing a total divide value of 16,384.
    So that can divide a 600 MHz VCO down to 36.6 kHz.
  24. Like
    hamster got a reaction from That_Guy in MMCM dynamic clocking   
    I feel a bit bad about posting a minor novel here, but here is an example of going from "5 cycles on, 5 off" (i.e. divide by 10) to "10 on, 10 off" (device by 20).
    The VCO is initially to 800 MHz with CLK0 being VCO divide by 8.... so after config you get 100MHz.
    Push the button and you get 800/20 = 40MHz, release the button and you get 80MHz.
    It is all really hairy in practice!
    EDIT: Through experimentation I just found that you don't need to reset the MMCM if you are not changing the VCO frequency. So the 'rst' signal in the code below isn't needed (and LOCKED will stay asserted).
    -------------------------------------------------------------------------------------------------------- -- Playing with the MMCM DRP ports. -- see https://www.xilinx.com/support/documentation/application_notes/xapp888_7Series_DynamicRecon.pdf -- for the Dynamic Reconviguration Port addresses -------------------------------------------------------------------------------------------------------- library IEEE; use IEEE.STD_LOGIC_1164.ALL; use IEEE.NUMERIC_STD.ALL; library UNISIM; use UNISIM.VComponents.all; entity mmcm_reset is Port ( clk_100 : in STD_LOGIC; btn_raw : in STD_LOGIC; led : out STD_LOGIC_VECTOR (15 downto 0)); end mmcm_reset; architecture Behavioral of mmcm_reset is signal btn_meta : std_logic := '0'; signal btn : std_logic := '0'; signal speed_select : std_logic := '0'; signal counter : unsigned(26 downto 0) := (others => '0'); signal debounce : unsigned(15 downto 0) := (others => '0'); signal clk_switched : std_logic := '0'; signal clk_fb : std_logic := '0'; type t_state is (state_idle_fast, state_go_slow_1, state_go_slow_2, state_go_slow_3, state_idle_slow, state_go_fast_1, state_go_fast_2, state_go_fast_3); signal state : t_state := state_idle_fast; ----------------------------------------------------------------------------- --- This is the CLKOUT0 ClkReg1 address - the only register to be played with ----------------------------------------------------------------------------- signal daddr : std_logic_vector(6 downto 0) := "0001000"; signal do : std_logic_vector(15 downto 0) := (others => '0'); signal drdy : std_logic := '0'; signal den : std_logic := '0'; signal di : std_logic_vector(15 downto 0) := (others => '0'); signal dwe : std_logic := '0'; signal rst : std_logic := '0'; begin MMCME2_ADV_inst : MMCME2_ADV generic map ( BANDWIDTH => "OPTIMIZED", -- Jitter programming (OPTIMIZED, HIGH, LOW) CLKFBOUT_MULT_F => 8.0, -- Multiply value for all CLKOUT (2.000-64.000). CLKFBOUT_PHASE => 0.0, -- Phase offset in degrees of CLKFB (-360.000-360.000). -- CLKIN_PERIOD: Input clock period in ns to ps resolution (i.e. 33.333 is 30 MHz). CLKIN1_PERIOD => 10.0, CLKIN2_PERIOD => 0.0, -- CLKOUT0_DIVIDE - CLKOUT6_DIVIDE: Divide amount for CLKOUT (1-128) CLKOUT1_DIVIDE => 1, CLKOUT2_DIVIDE => 1, CLKOUT3_DIVIDE => 1, CLKOUT4_DIVIDE => 1, CLKOUT5_DIVIDE => 1, CLKOUT6_DIVIDE => 1, CLKOUT0_DIVIDE_F => 8.0, -- Divide amount for CLKOUT0 (1.000-128.000). -- CLKOUT0_DUTY_CYCLE - CLKOUT6_DUTY_CYCLE: Duty cycle for CLKOUT outputs (0.01-0.99). CLKOUT0_DUTY_CYCLE => 0.5, CLKOUT1_DUTY_CYCLE => 0.5, CLKOUT2_DUTY_CYCLE => 0.5, CLKOUT3_DUTY_CYCLE => 0.5, CLKOUT4_DUTY_CYCLE => 0.5, CLKOUT5_DUTY_CYCLE => 0.5, CLKOUT6_DUTY_CYCLE => 0.5, -- CLKOUT0_PHASE - CLKOUT6_PHASE: Phase offset for CLKOUT outputs (-360.000-360.000). CLKOUT0_PHASE => 0.0, CLKOUT1_PHASE => 0.0, CLKOUT2_PHASE => 0.0, CLKOUT3_PHASE => 0.0, CLKOUT4_PHASE => 0.0, CLKOUT5_PHASE => 0.0, CLKOUT6_PHASE => 0.0, CLKOUT4_CASCADE => FALSE, -- Cascade CLKOUT4 counter with CLKOUT6 (FALSE, TRUE) COMPENSATION => "ZHOLD", -- ZHOLD, BUF_IN, EXTERNAL, INTERNAL DIVCLK_DIVIDE => 1, -- Master division value (1-106) -- REF_JITTER: Reference input jitter in UI (0.000-0.999). REF_JITTER1 => 0.0, REF_JITTER2 => 0.0, STARTUP_WAIT => FALSE, -- Delays DONE until MMCM is locked (FALSE, TRUE) -- Spread Spectrum: Spread Spectrum Attributes SS_EN => "FALSE", -- Enables spread spectrum (FALSE, TRUE) SS_MODE => "CENTER_HIGH", -- CENTER_HIGH, CENTER_LOW, DOWN_HIGH, DOWN_LOW SS_MOD_PERIOD => 10000, -- Spread spectrum modulation period (ns) (VALUES) -- USE_FINE_PS: Fine phase shift enable (TRUE/FALSE) CLKFBOUT_USE_FINE_PS => FALSE, CLKOUT0_USE_FINE_PS => FALSE, CLKOUT1_USE_FINE_PS => FALSE, CLKOUT2_USE_FINE_PS => FALSE, CLKOUT3_USE_FINE_PS => FALSE, CLKOUT4_USE_FINE_PS => FALSE, CLKOUT5_USE_FINE_PS => FALSE, CLKOUT6_USE_FINE_PS => FALSE ) port map ( -- Clock Outputs: 1-bit (each) output: User configurable clock outputs CLKOUT0 => clk_switched, CLKOUT0B => open, CLKOUT1 => open, CLKOUT1B => open, CLKOUT2 => open, CLKOUT2B => open, CLKOUT3 => open, CLKOUT3B => open, CLKOUT4 => open, CLKOUT5 => open, CLKOUT6 => open, -- Dynamic Phase Shift Ports: 1-bit (each) output: Ports used for dynamic phase shifting of the outputs PSDONE => open, -- Feedback Clocks: 1-bit (each) output: Clock feedback ports CLKFBOUT => clk_fb, CLKFBOUTB => open, -- Status Ports: 1-bit (each) output: MMCM status ports CLKFBSTOPPED => open, CLKINSTOPPED => open, LOCKED => open, -- Clock Inputs: 1-bit (each) input: Clock inputs CLKIN1 => clk_100, CLKIN2 => '0', -- Control Ports: 1-bit (each) input: MMCM control ports CLKINSEL => '1', PWRDWN => '0', -- 1-bit input: Power-down RST => rst, -- 1-bit input: Reset -- DRP Ports: 16-bit (each) output: Dynamic reconfiguration ports DCLK => clk_100, -- 1-bit input: DRP clock DO => DO, -- 16-bit output: DRP data DRDY => DRDY, -- 1-bit output: DRP ready -- DRP Ports: 7-bit (each) input: Dynamic reconfiguration ports DADDR => DADDR, -- 7-bit input: DRP address DEN => DEN, -- 1-bit input: DRP enable DI => DI, -- 16-bit input: DRP data DWE => DWE, -- 1-bit input: DRP write enable -- Dynamic Phase Shift Ports: 1-bit (each) input: Ports used for dynamic phase shifting of the outputs PSCLK => '0', PSEN => '0', PSINCDEC => '0', -- Feedback Clocks: 1-bit (each) input: Clock feedback ports CLKFBIN => clk_fb ); speed_change_fsm: process(clk_100) begin if rising_edge(clk_100) then di <= (others => '0'); dwe <= '0'; den <= '0'; case state is when state_idle_fast => if speed_select = '1'then state <= state_go_slow_1; -- High 10 Low 10 di <= "0001" & "001010" & "001010"; dwe <= '1'; den <= '1'; end if; when state_go_slow_1 => if drdy = '1' then state <= state_go_slow_2; end if; when state_go_slow_2 => rst <= '1'; state <= state_go_slow_3; when state_go_slow_3 => rst <= '0'; state <= state_idle_slow; when state_idle_slow => di <= (others => '0'); if speed_select = '0' and drdy = '0' then state <= state_go_fast_1; -- High 5 Low 5 di <= "0001" & "000101" & "000101"; dwe <= '1'; den <= '1'; end if; when state_go_fast_1 => if drdy = '1' then state <= state_go_fast_2; end if; when state_go_fast_2 => rst <= '1'; state <= state_go_fast_3; when state_go_fast_3 => rst <= '0'; state <= state_idle_fast; end case; end if; end process; dbounce_proc: process(clk_100) begin if rising_edge(clk_100) then if speed_select = btn then debounce <= (others => '0'); elsif debounce(debounce'high) = '1' then speed_select <= not speed_select; else debounce <= debounce + 1; end if; -- Syncronise the button btn <= btn_meta; btn_meta <= btn_raw; end if; end process; show_speed_proc: process(clk_switched) begin if rising_edge(clk_switched) then counter <= counter + 1; led(7 downto 0) <= std_logic_vector(counter(counter'high downto counter'high-7)); end if; end process; led(15) <= speed_select; end Behavioral;
  25. Like
    hamster got a reaction from amkichu in MMCM dynamic clocking   
    Hey, something else I just saw when reading the clocking guide was:
    MMCM Counter Cascading The CLKOUT6 divider (counter) can be cascaded with the CLKOUT4 divider. This provides a capability to have an output divider that is larger than 128. CLKOUT6 feeds the input of the CLKOUT4 divider. There is a static phase offset between the output of the cascaded divider and all other output dividers.
    And:
    CLKOUT4_CASCADE : Cascades the output divider (counter) CLKOUT6 into the input of the CLKOUT4 divider for an output clock divider that is greater than 128, effectively providing a total divide value of 16,384.
    So that can divide a 600 MHz VCO down to 36.6 kHz.