Forum Discussion
Altera_Forum
Honored Contributor
11 years agoThe following code implements pwm based on 15 bits phase accumulator.
You need to provide: frequency word as : round(2^14*freq/clk) duty cycle as: round(duty*2^14/100); it does not require actual LUT but is implied
library ieee;
use ieee.std_logic_1164.all;
use IEEE.numeric_std.all;
entity pwm is
port(
clk : in std_logic;
freq_word : in std_logic_vector(13 downto 0) := "00011001100110";
duty_scaled : in std_logic_vector(13 downto 0) := "10000000000000";
pwm : out std_logic
);
end entity;
architecture rtl of pwm is
signal ptr : unsigned(14 downto 0) := (others => '0');
begin
process(clk)
begin
if(rising_edge(clk)) then
ptr <= ptr + unsigned(freq_word);
pwm <= '0';
if ptr(13 downto 0) < unsigned(duty_scaled) then
pwm <= '1';
end if;
end if;
end process;
end rtl;
and here is a model in matlab
clear all; close all; clc;
clk = 100; %system clock
f = 10; %output frequency
duty = 50; %output duty cycle, 1 ~ 100
%%%%%%%%%%%%%%%%% LUT %%%%%%%%%%%%%%%%%%%
n = floor(5000/f); %test length
m = 15; %lut resolution
tw = round(2^(m-1)*f/clk); %tuning word
ptr = 0; %pointer to lut
for i = 1:n
ptr = floor(mod(ptr + tw, 2^(m-1)));
y(i) = ptr; %compute lut output
end
%%%%%%%%%%%%%%% comparator %%%%%%%%%%%%%%%
threshold = round(duty*2^(m-1)/100);
out = zeros(1,n);
for i = 1:n
if y(i) < threshold, out(i) = 2^(m-1); end
end
%%%%%%%%%%%%%% check results %%%%%%%%%%%%%
figure;plot(out,'.-');grid;
d = diff(find(diff(out))); %locate 0/1 transitions
for i = 1:2:length(d)-1
a = clk/(d(i)+d(i+1));
b = round(100*d(i+1)/(d(i)+d(i+1)));
end
achieved_freq = mean(a)
achieved_duty = mean(b)