-- Title : Cordic -- Function : Cordic Implementation -- Author : Pascal Schiks (C) 2020 GNU/GPL, Meaning anyone can copy use and modify this code for selfeducation and leasure. -- Board : RZ_EasyFPGA -- FPGA : EP4CE6E22C8 -- ConfigDev : EPS4N BS03X -- Notes -- The purpose of this experiment is to generate a Sine/Cosine wave using an aproximation algorithm -- such not using an sinewave table. -- The 3 PwmOut pins are to be connected to a RC LowPass Filter, where R=2k2 and C=4nF, -- Asci art impression of this: FPGApin ---===---+---||-----Gnd -- 2k2 47nF -- Where the scope should be hooked op at the + sign -- Scope settings for all channels 1V/Div, timebase 2ms/Dev (the output is aprox 90Hz) -- Chan 1 and 2 show Sine and Cosine, while Chan 3 optional is to show the linearity (or more nonelinearity) of the DAC -- Also Sync is not realy required as the scope realy tiggers well on the signal -- Setting the scope in X/Y mode should show a perfect circle which it doesn't, after all it's an aproximation. library ieee; use ieee.std_logic_1164.all; use ieee.std_logic_unsigned.all; use ieee.std_logic_arith.all; use ieee.numeric_std.all; entity Cordic is port ( PwmOut : Out std_logic_vector(3 DownTo 1) := "000"; SyncOut : Out std_logic := '0'; CLK50MHz : IN std_logic ); End entity Cordic; Architecture cordic_demo of Cordic is -- ClockSignals signal ClkDiv : std_logic_vector(31 downto 0); signal WaveClk : std_logic; signal PwmClk : std_logic; -- PWM Signals signal PwmCnt : Integer Range 0 to 300 := 0; type PwmType is array(1 to 3) of Integer Range 0 To 255; signal PwmVal : PwmType := (others=>0); -- CORDIC signals signal Alpha : Integer Range 0 to 520 := 0; constant TwoPi : Integer := 512; constant Pi : Integer := 256; constant HalfPi : Integer := 128; constant Gain : Integer := 129; constant Offset : Integer := 128; -- Pin assignment straight into the source attribute chip_pin: string; attribute chip_pin of PwmOut : signal is "86,98,84"; attribute chip_pin of syncOut : signal is "103"; attribute chip_pin of Clk50MHz : signal is "23"; -- Aproximation of Sinewave Function Sine(X : Integer Range 0 to 1024) return Integer Is Variable Xmod2Pi : Integer Range 0 to 512; Begin XMod2Pi := X Mod TwoPi; If Xmod2Pi > Pi Then return (((Xmod2Pi - Pi) * (Xmod2Pi - TwoPi)) / Gain) - Offset; Else return Offset - (((Xmod2Pi - 0) * (Xmod2Pi - Pi)) / Gain); End If; End Function Sine; -- -- Main program -- Begin -- Generate reqiured clock signals ClockDivider : Process (Clk50MHz) Begin if Clk50MHz'Event and Clk50MHz='1' then ClkDiv <= ClkDiv + '1'; end if; PwmClk <= ClkDiv(0); WaveClk <= ClkDiv(9); end process; -- Single pin PWM based DAC Then requires only a simple RC LowPassFilter PwmGenerator : Process (PwmClk) Begin If PwmClk'Event and PwmClk='1' Then -- Counter If PwmCnt < 255 Then PwmCnt <= PwmCnt+1; Else PwmCnt <= 0; End If; -- PWM-DAC 1- 3 For ch in 1 to 3 loop If PwmVal(ch) > PwmCnt Then PwmOut(ch) <= '1'; Else PwmOut(ch) <= '0'; End If; End Loop; End If; End Process PwmGenerator; -- The SineWave aproximation CordicWaveGenerator : Process (WaveClk) Begin If WaveClk'Event And waveClk='1' Then -- Phase progression ranging from 0 to 2*Pi If Alpha < TwoPi Then Alpha <= Alpha + 1; Else Alpha <= 0; End If; -- Sync If Alpha < HalfPi Then SyncOut <= '1'; Else SyncOut <= '0'; End If; PwmVal(1) <= Sine(Alpha); PwmVal(2) <= Sine(Alpha+HalfPi); PwmVal(3) <= Alpha / 2; End If; End Process CordicWaveGenerator; End cordic_demo;