]> rtime.felk.cvut.cz Git - fpga/zynq/canbench-sw.git/commitdiff
microzed_apo: Single channel PWM audio implemented as simple PWM generator.
authorPavel Pisa <pisa@cmp.felk.cvut.cz>
Tue, 14 Feb 2017 17:00:58 +0000 (18:00 +0100)
committerPavel Pisa <pisa@cmp.felk.cvut.cz>
Tue, 14 Feb 2017 17:00:58 +0000 (18:00 +0100)
Signed-off-by: Pavel Pisa <pisa@cmp.felk.cvut.cz>
system/ip/audio_single_pwm_1.0/component.xml
system/ip/audio_single_pwm_1.0/hdl/audio_single_pwm_v1_0.vhd
system/ip/audio_single_pwm_1.0/hdl/audio_single_pwm_v1_0_S00_AXI.vhd
system/ip/audio_single_pwm_1.0/hdl/cnt_div.vhdl [new file with mode: 0644]
system/ip/audio_single_pwm_1.0/hdl/pulse_gen.vhdl [new file with mode: 0644]

index 6537e1d9fc3aaee5835ffc9e137aa5ac5f708408..7fc6455db64dea5cc3e391dda4d7ca62660be7e2 100644 (file)
         <spirit:parameters>
           <spirit:parameter>
             <spirit:name>viewChecksum</spirit:name>
-            <spirit:value>0e326a61</spirit:value>
+            <spirit:value>d51b8d9c</spirit:value>
           </spirit:parameter>
         </spirit:parameters>
       </spirit:view>
         <spirit:parameters>
           <spirit:parameter>
             <spirit:name>viewChecksum</spirit:name>
-            <spirit:value>0e326a61</spirit:value>
+            <spirit:value>d51b8d9c</spirit:value>
           </spirit:parameter>
         </spirit:parameters>
       </spirit:view>
         <spirit:parameters>
           <spirit:parameter>
             <spirit:name>viewChecksum</spirit:name>
-            <spirit:value>48257339</spirit:value>
+            <spirit:value>b09a532b</spirit:value>
           </spirit:parameter>
         </spirit:parameters>
       </spirit:view>
         <spirit:parameters>
           <spirit:parameter>
             <spirit:name>viewChecksum</spirit:name>
-            <spirit:value>45a2f450</spirit:value>
+            <spirit:value>eb6528c9</spirit:value>
           </spirit:parameter>
         </spirit:parameters>
       </spirit:view>
   <spirit:fileSets>
     <spirit:fileSet>
       <spirit:name>xilinx_vhdlsynthesis_view_fileset</spirit:name>
+      <spirit:file>
+        <spirit:name>hdl/pulse_gen.vhdl</spirit:name>
+        <spirit:fileType>vhdlSource</spirit:fileType>
+      </spirit:file>
+      <spirit:file>
+        <spirit:name>hdl/cnt_div.vhdl</spirit:name>
+        <spirit:fileType>vhdlSource</spirit:fileType>
+      </spirit:file>
       <spirit:file>
         <spirit:name>hdl/audio_single_pwm_v1_0_S00_AXI.vhd</spirit:name>
         <spirit:fileType>vhdlSource</spirit:fileType>
       <spirit:file>
         <spirit:name>hdl/audio_single_pwm_v1_0.vhd</spirit:name>
         <spirit:fileType>vhdlSource</spirit:fileType>
-        <spirit:userFileType>CHECKSUM_1ede7192</spirit:userFileType>
+        <spirit:userFileType>CHECKSUM_bb805960</spirit:userFileType>
       </spirit:file>
     </spirit:fileSet>
     <spirit:fileSet>
       <spirit:name>xilinx_vhdlbehavioralsimulation_view_fileset</spirit:name>
+      <spirit:file>
+        <spirit:name>hdl/pulse_gen.vhdl</spirit:name>
+        <spirit:fileType>vhdlSource</spirit:fileType>
+      </spirit:file>
+      <spirit:file>
+        <spirit:name>hdl/cnt_div.vhdl</spirit:name>
+        <spirit:fileType>vhdlSource</spirit:fileType>
+      </spirit:file>
       <spirit:file>
         <spirit:name>hdl/audio_single_pwm_v1_0_S00_AXI.vhd</spirit:name>
         <spirit:fileType>vhdlSource</spirit:fileType>
         <xilinx:taxonomy>AXI_Peripheral</xilinx:taxonomy>
       </xilinx:taxonomies>
       <xilinx:displayName>audio_single_pwm_v1.0</xilinx:displayName>
-      <xilinx:coreRevision>4</xilinx:coreRevision>
-      <xilinx:coreCreationDateTime>2017-02-09T08:42:05Z</xilinx:coreCreationDateTime>
+      <xilinx:coreRevision>5</xilinx:coreRevision>
+      <xilinx:coreCreationDateTime>2017-02-14T16:58:34Z</xilinx:coreCreationDateTime>
       <xilinx:tags>
         <xilinx:tag xilinx:name="user.org:user:audio_single_pwm:1.0_ARCHIVE_LOCATION">/home/pi/fpga/zynq/canbech-sw/system/ip/audio_single_pwm_1.0</xilinx:tag>
       </xilinx:tags>
       <xilinx:checksum xilinx:scope="busInterfaces" xilinx:value="4150380b"/>
       <xilinx:checksum xilinx:scope="addressSpaces" xilinx:value="64346dae"/>
       <xilinx:checksum xilinx:scope="memoryMaps" xilinx:value="493665f4"/>
-      <xilinx:checksum xilinx:scope="fileGroups" xilinx:value="b412d8a3"/>
-      <xilinx:checksum xilinx:scope="ports" xilinx:value="c6e93652"/>
+      <xilinx:checksum xilinx:scope="fileGroups" xilinx:value="aec9cff9"/>
+      <xilinx:checksum xilinx:scope="ports" xilinx:value="92f3f6c6"/>
       <xilinx:checksum xilinx:scope="hdlParameters" xilinx:value="07a22c67"/>
       <xilinx:checksum xilinx:scope="parameters" xilinx:value="7e56a690"/>
     </xilinx:packagingInfo>
index 35ada4c9df941930f8c57b0901c5db3774f56796..87dec816268a21c00a1151df0626a2be1f8b889e 100644 (file)
@@ -83,9 +83,13 @@ architecture arch_imp of audio_single_pwm_v1_0 is
        component audio_single_pwm_v1_0_S00_AXI is
                generic (
                C_S_AXI_DATA_WIDTH      : integer       := 32;
-               C_S_AXI_ADDR_WIDTH      : integer       := 6
+               C_S_AXI_ADDR_WIDTH      : integer       := 6;
+               audio_pwm_width         : integer       := 24
                );
                port (
+               audio_pwm_period: out std_logic_vector(audio_pwm_width-1 downto 0);
+               audio_pwm_duty: out std_logic_vector(audio_pwm_width-1 downto 0);
+
                S_AXI_ACLK      : in std_logic;
                S_AXI_ARESETN   : in std_logic;
                S_AXI_AWADDR    : in std_logic_vector(C_S_AXI_ADDR_WIDTH-1 downto 0);
@@ -146,6 +150,44 @@ architecture arch_imp of audio_single_pwm_v1_0 is
                );
        end component audio_single_pwm_v1_0_M00_AXI;
 
+       component cnt_div is
+               generic (
+               cnt_width_g : natural := 4
+               );
+               port
+               (
+               clk_i     : in std_logic;                               --clk to divide
+               en_i      : in std_logic;                               --enable bit?
+               reset_i   : in std_logic;                               --asynch. reset
+               ratio_i   : in std_logic_vector(cnt_width_g-1 downto 0);--initial value
+               q_out_o   : out std_logic                               --generates puls when counter underflows
+               );
+       end component;
+
+       component pulse_gen is
+               generic (
+               duration_width_g : natural := 4
+               );
+               port (
+               clk_i      : in std_logic;                              --clk to divide
+               en_i       : in std_logic;                              --enable bit?
+               reset_i    : in std_logic;                              --asynch. reset
+               trigger_i  : in std_logic;                              --start to generate pulse
+               duration_i : in std_logic_vector(duration_width_g-1 downto 0);--duration/interval of the pulse
+               q_out_o    : out std_logic                              --generates pulse for given duration
+               );
+       end component;
+
+       constant audio_pwm_width : integer := 24;
+
+       signal audio_pwm_period: std_logic_vector(audio_pwm_width-1 downto 0);
+       signal audio_pwm_duty: std_logic_vector(audio_pwm_width-1 downto 0);
+
+       signal fsm_clk : std_logic;
+       signal fsm_rst : std_logic;
+
+       signal pwm_cycle_start : std_logic;
+
        signal m00_axi_init_axi_txn     : std_logic;
        signal m00_axi_error    : std_logic;
        signal m00_axi_txn_done : std_logic;
@@ -156,9 +198,14 @@ begin
 audio_single_pwm_v1_0_S00_AXI_inst : audio_single_pwm_v1_0_S00_AXI
        generic map (
                C_S_AXI_DATA_WIDTH      => C_S00_AXI_DATA_WIDTH,
-               C_S_AXI_ADDR_WIDTH      => C_S00_AXI_ADDR_WIDTH
+               C_S_AXI_ADDR_WIDTH      => C_S00_AXI_ADDR_WIDTH,
+
+               audio_pwm_width => audio_pwm_width
        )
        port map (
+               audio_pwm_period => audio_pwm_period,
+               audio_pwm_duty  => audio_pwm_duty,
+
                S_AXI_ACLK      => s00_axi_aclk,
                S_AXI_ARESETN   => s00_axi_aresetn,
                S_AXI_AWADDR    => s00_axi_awaddr,
@@ -220,9 +267,36 @@ audio_single_pwm_v1_0_M00_AXI_inst : audio_single_pwm_v1_0_M00_AXI
 
        -- Add user logic here
 
-    speaker_pwm_out <= '0';
-    irq_rq_out <= '0';
-    m00_axi_init_axi_txn <= '0';
+cnt_div_inst: cnt_div
+       generic map (
+               cnt_width_g => audio_pwm_width
+       )
+       port map (
+               clk_i => fsm_clk,
+               en_i => '1',
+               reset_i => fsm_rst,
+               ratio_i => audio_pwm_period,
+               q_out_o => pwm_cycle_start
+       );
+
+audio_pwm_inst: pulse_gen
+       generic map (
+               duration_width_g => audio_pwm_width
+       )
+       port map (
+               clk_i => fsm_clk,
+               en_i => '1',
+               reset_i => fsm_rst,
+               trigger_i => pwm_cycle_start,
+               duration_i => audio_pwm_duty,
+               q_out_o => speaker_pwm_out
+       );
+
+       irq_rq_out <= '0';
+       m00_axi_init_axi_txn <= '0';
+
+       fsm_clk <= s00_axi_aclk;
+       fsm_rst <= not s00_axi_aresetn;
        -- User logic ends
 
 end arch_imp;
index 23edd9bfb08b7eb8d139cdafb877fff67ab05955..ee8166acfbf8fcdabe983c0d63a07fae5adca6b5 100644 (file)
@@ -5,7 +5,7 @@ use ieee.numeric_std.all;
 entity audio_single_pwm_v1_0_S00_AXI is
        generic (
                -- Users to add parameters here
-
+               audio_pwm_width         : integer       := 24;
                -- User parameters ends
                -- Do not modify the parameters beyond this line
 
@@ -16,7 +16,8 @@ entity audio_single_pwm_v1_0_S00_AXI is
        );
        port (
                -- Users to add ports here
-
+               audio_pwm_period: out std_logic_vector(audio_pwm_width-1 downto 0);
+               audio_pwm_duty: out std_logic_vector(audio_pwm_width-1 downto 0);
                -- User ports ends
                -- Do not modify the ports beyond this line
 
@@ -535,7 +536,8 @@ begin
 
 
        -- Add user logic here
-
+       audio_pwm_period <= slv_reg2(audio_pwm_width-1 downto 0);
+       audio_pwm_duty <= slv_reg3(audio_pwm_width-1 downto 0);
        -- User logic ends
 
 end arch_imp;
diff --git a/system/ip/audio_single_pwm_1.0/hdl/cnt_div.vhdl b/system/ip/audio_single_pwm_1.0/hdl/cnt_div.vhdl
new file mode 100644 (file)
index 0000000..e65e562
--- /dev/null
@@ -0,0 +1,62 @@
+--
+-- * Counter - divider *
+--
+-- part of LXPWR motion control board (c) PiKRON Ltd
+-- idea by Pavel Pisa PiKRON Ltd <ppisa@pikron.com>
+--
+-- license: BSD
+--
+-- This file is used in "RPI PMS motor control" as frequency divider - divides by 6
+
+library ieee;
+use ieee.std_logic_1164.all;
+use ieee.numeric_std.all;
+
+entity cnt_div is
+       generic (
+               cnt_width_g : natural := 4
+       );
+       port
+       (
+               clk_i     : in std_logic;                               --clk to divide
+               en_i      : in std_logic;                               --enable bit?
+               reset_i   : in std_logic;                               --asynch. reset
+               ratio_i   : in std_logic_vector(cnt_width_g-1 downto 0);--initial value
+               q_out_o   : out std_logic                               --generates puls when counter underflows
+       );
+end cnt_div;
+
+architecture behavioral of cnt_div is
+       signal cnt_val_s : natural range 0 to (2**cnt_width_g - 1);     --counter value before DFF
+       signal cnt_val_r : natural range 0 to (2**cnt_width_g - 1);     --counter value after DFF
+begin
+
+comb: process (reset_i, en_i, ratio_i, cnt_val_r)
+       begin
+               if reset_i = '1' then --reset detection
+                       cnt_val_s <= to_integer(unsigned(ratio_i));     --set initial value
+                       q_out_o   <= '0';                               --reset output  
+               else
+                       if en_i = '0' then                              --stop-state
+                               cnt_val_s <= cnt_val_r;                 --hold the value
+                               q_out_o   <= '0';                       --reset output
+                       else
+                               if cnt_val_r <= 1 then                  --counter underflows
+                                       cnt_val_s <= to_integer(unsigned(ratio_i)); --set initial value
+                                       q_out_o   <= '1';               --set output
+                               else
+                                       cnt_val_s <= cnt_val_r - 1;     --decrement counter
+                                       q_out_o   <= '0';               --reset output
+                               end if;
+                       end if;
+               end if;
+       end process;
+
+seq: process
+       begin
+               wait until clk_i'event and clk_i = '1';
+               cnt_val_r <= cnt_val_s;
+       end process;
+
+end behavioral;
+
diff --git a/system/ip/audio_single_pwm_1.0/hdl/pulse_gen.vhdl b/system/ip/audio_single_pwm_1.0/hdl/pulse_gen.vhdl
new file mode 100644 (file)
index 0000000..e682b45
--- /dev/null
@@ -0,0 +1,68 @@
+--
+-- * pulse generator *
+--
+-- based on code from LXPWR motion control board (c) PiKRON Ltd
+-- idea by Pavel Pisa PiKRON Ltd <ppisa@pikron.com>
+--
+-- license: BSD
+--
+
+library ieee;
+use ieee.std_logic_1164.all;
+use ieee.numeric_std.all;
+
+entity pulse_gen is
+       generic (
+               duration_width_g : natural := 4
+       );
+       port
+       (
+               clk_i      : in std_logic;                              --clk to divide
+               en_i       : in std_logic;                              --enable bit?
+               reset_i    : in std_logic;                              --asynch. reset
+               trigger_i  : in std_logic;                              --start to generate pulse
+               duration_i : in std_logic_vector(duration_width_g-1 downto 0);--duration/interval of the pulse
+               q_out_o    : out std_logic                              --generates pulse for given duration
+       );
+end pulse_gen;
+
+architecture behavioral of pulse_gen is
+       signal cnt_val_s : natural range 0 to (2**duration_width_g - 1);        --counter value before DFF
+       signal cnt_val_r : natural range 0 to (2**duration_width_g - 1);        --counter value after DFF
+begin
+
+comb: process (reset_i, en_i, duration_i, trigger_i, cnt_val_r)
+       begin
+               if reset_i = '1' then --reset detection
+                       cnt_val_s <= 0;         --set defined value
+                       q_out_o   <= '0';                               --reset output
+               else
+                       if en_i = '0' then                              --stop-state
+                               cnt_val_s <= cnt_val_r;                 --hold the value
+                       else
+                               if trigger_i = '1' then                 --trigger pulse generator
+                                       if to_integer(unsigned(duration_i)) = 0 then
+                                               q_out_o   <= '0';
+                                       else
+                                               q_out_o   <= '1';
+                                       end if;
+                                       cnt_val_s <= to_integer(unsigned(duration_i)); --set initial value
+                               elsif cnt_val_r = 0 then                        --pulse finished
+                                       cnt_val_s <= cnt_val_r;
+                                       q_out_o   <= '0';               --set output
+                               else
+                                       cnt_val_s <= cnt_val_r - 1;     --decrement counter
+                                       q_out_o   <= '1';               --reset output
+                               end if;
+                       end if;
+               end if;
+       end process;
+
+seq: process
+       begin
+               wait until clk_i'event and clk_i = '1';
+               cnt_val_r <= cnt_val_s;
+       end process;
+
+end behavioral;
+