Last modified on 11 March 2018, at 07:29

PWM

Pulse Width Modulation, is a DAC (Digital Analog Convertor) using only numerical components (outputting only 0v or 5v values)
Using an entry clock, you output several signals 0v or 5v in order to result an average fix value between 0v and 5v, for sample 2.3v. Changing like it the speed of a small electric motor (speeding it up or slowing it down) as you want but using at its inputs only two values : 0v or 5v.
Using a quicker clock, you can generate analog signal, like sound music.

pwm.vhd

library IEEE;
use IEEE.STD_LOGIC_1164.all;
use IEEE.STD_LOGIC_UNSIGNED.ALL;

-- http://www.fpga4fun.com/PWM_DAC.html

entity PWM is
  port (
   clk : in std_logic; -- 1MHz : same one as sound chip clk
   PWM_in : in std_logic_vector (7 downto 0) := "00000000";
   PWM_out : out std_logic
  );
end PWM;

architecture PWM_arch of PWM is
  signal  PWM_Accumulator : std_logic_vector(8 downto 0):=(others=>'0'); -- sim XXXXXXXXX
begin
  process
  begin
    wait until rising_edge(clk);
			PWM_Accumulator  <=  ("0" & PWM_Accumulator(7 downto 0)) + ("0" & PWM_in);
  end process;
  PWM_out <= PWM_Accumulator(8);
end PWM_arch;

Ok, let's go further, let's target 2.5v using only 0v and 5v, with a stupid slow clock, you result in a sequence like this : 05050505050505v. It has a bad border effect : it's a noise ! 2.5v normaly doesn't produce sound by here, but using this simple PWM it does.
This problem is solved here : this is an original homemade PWM component enabling Arkanoid not producing noises instead of silents, don't ask me how I solved it two years ago but it does :

pwm.vhd - currently used in FPGAmstrad project

--    {@{@{@{@{@{@
--  {@{@{@{@{@{@{@{@  This code is covered by CoreAmstrad synthesis r004
--  {@    {@{@    {@  A core of Amstrad CPC 6128 running on MiST-board platform
--  {@{@{@{@{@{@{@{@
--  {@  {@{@{@{@  {@  CoreAmstrad is implementation of FPGAmstrad on MiST-board
--  {@{@        {@{@   Contact : renaudhelias@gmail.com
--  {@{@{@{@{@{@{@{@   @see http://github.com/mist-devel/mist-board/wiki
--    {@{@{@{@{@{@     @see FPGAmstrad at CPCWiki
--
--
--------------------------------------------------------------------------------
-- FPGAmstrad_amstrad_motherboard.PWM patched for luxurious output quality
-- clk : a big clock, upper than dog sound frequency, here 17MHz
-- clk_ref : clock matching with PWM_in data, here YM2149.CLK (Yamaha chip clock)
--------------------------------------------------------------------------------
library IEEE;
use IEEE.STD_LOGIC_1164.all;
use IEEE.STD_LOGIC_UNSIGNED.ALL;

-- http://www.fpga4fun.com/PWM_DAC.html

entity PWM is
  port (
   clk : in std_logic; -- 50MHz : higher than dog and cat frequency, a multiple of clk_ref
   clk_ref : in std_logic; -- 1MHz : same one as sound chip clk
   PWM_in : in std_logic_vector (7 downto 0) := "00000000";
   PWM_out : out std_logic
  );
end PWM;

architecture PWM_arch of PWM is
  signal  PWM_Accumulator : std_logic_vector(8 downto 0):=(others=>'0'); -- sim XXXXXXXXX
  signal PWM_iRef:std_logic_vector(7 downto 0);
  signal PWM_i:std_logic_vector(7 downto 0);
begin

  process(clk_ref)
	variable PWM_mem : std_logic_vector(7 downto 0):=x"00";
  begin
		if rising_edge(clk_ref) then
			PWM_mem:=PWM_in;
			PWM_iRef<=PWM_mem;
		end if;
  end process;

  process(clk)
	variable PWM_mem : std_logic_vector(7 downto 0):=x"00";
  begin
		if rising_edge(clk) then
			PWM_mem:=PWM_iRef;
			PWM_i<=PWM_mem;
		end if;
  end process;


  process(clk)
  begin
		if rising_edge(clk) then
			PWM_Accumulator  <=  ("0" & PWM_Accumulator(7 downto 0)) + ("0" & PWM_i);
		end if;
  end process;

  PWM_out <= PWM_Accumulator(8);
end PWM_arch;