基于NIOS II的PWM实现

  • 首先先说明一下我这个AVALON SLAVE PWM 组件的寄存器,一个有5个寄存器

1.AVALON_SLAVE_PWM_CLOCK_DIVIDE_REG : PWM时钟分频寄存器.(32位)

2.AVALON_SLAVE_PWM_DUTY_CYCYLE_REG : PWM占空比寄存器.(32位)

3.AVALON_SLAVE_PWM_ENABLE_REG          : PWM使能寄存器.(1位)

4.AVALON_SLAVE_PWM_IRQ_ENABLE_REG    : PWM中断使能寄存器.(1位)

5.AVALON_SLAVE_PWM_CLR_IRQ_FLAG_REG : PWM中断标志清零寄存器.(1位)

 

  • AVALON SLAVE PWM的VHDL实现(一共分为三个文件:avalon_slave_pwm.vhd , pwm_register_file.vhd , pwm_task_logic.vhd)

1. avalon_slave_pwm.vhd 为顶层文件,描述了PWM内部组件的连结关系以及内部组件与外部AVALON总线的连接关系

LIBRARY ieee;
USE ieee.std_logic_1164.all;

LIBRARY work;

ENTITY avalon_slave_pwm IS
 port
 (
  csi_pwm_clock :  IN  STD_LOGIC;
  avs_pwm_reset_n :  IN  STD_LOGIC;
  avs_pwm_chipselect :  IN  STD_LOGIC;
  avs_pwm_write :  IN  STD_LOGIC;
  avs_pwm_read :  IN  STD_LOGIC;
  avs_pwm_address :  IN  STD_LOGIC_VECTOR(2 downto 0);
  avs_pwm_writedata :  IN  STD_LOGIC_VECTOR(31 downto 0);
  ins_pwm_irq :  OUT  STD_LOGIC;
  pwm_out :  OUT  STD_LOGIC;
  avs_pwm_readdata :  OUT  STD_LOGIC_VECTOR(31 downto 0)
 );
END avalon_slave_pwm;

ARCHITECTURE bdf_type OF avalon_slave_pwm IS

component pwm_task_logic
 PORT(clock : IN STD_LOGIC;
   reset_n : IN STD_LOGIC;
   clr_irqflag : IN STD_LOGIC;
   pwm_enable : IN STD_LOGIC;
   clock_divide : IN STD_LOGIC_VECTOR(31 downto 0);
   duty_cycle : IN STD_LOGIC_VECTOR(31 downto 0);
   irq_flagset : OUT STD_LOGIC;
   pwm_out : OUT STD_LOGIC
 );
end component;

component pwm_register_file
 PORT(csi_pwm_clock : IN STD_LOGIC;
   avs_pwm_reset_n : IN STD_LOGIC;
   avs_pwm_chipselect : IN STD_LOGIC;
   avs_pwm_write : IN STD_LOGIC;
   avs_pwm_read : IN STD_LOGIC;
   irq_flag : IN STD_LOGIC;
   avs_pwm_address : IN STD_LOGIC_VECTOR(2 downto 0);
   avs_pwm_writedata : IN STD_LOGIC_VECTOR(31 downto 0);
   ins_pwm_irq : OUT STD_LOGIC;
   clr_irq : OUT STD_LOGIC;
   pwm_enable : OUT STD_LOGIC;
   avs_pwm_readdata : OUT STD_LOGIC_VECTOR(31 downto 0);
   pwm_clock_divide : OUT STD_LOGIC_VECTOR(31 downto 0);
   pwm_duty_cycle : OUT STD_LOGIC_VECTOR(31 downto 0)
 );
end component;

signal SYNTHESIZED_WIRE_0 :  STD_LOGIC;
signal SYNTHESIZED_WIRE_1 :  STD_LOGIC;
signal SYNTHESIZED_WIRE_2 :  STD_LOGIC_VECTOR(31 downto 0);
signal SYNTHESIZED_WIRE_3 :  STD_LOGIC_VECTOR(31 downto 0);
signal SYNTHESIZED_WIRE_4 :  STD_LOGIC;

BEGIN

b2v_inst : pwm_task_logic
PORT MAP(clock => csi_pwm_clock,
   reset_n => avs_pwm_reset_n,
   clr_irqflag => SYNTHESIZED_WIRE_0,
   pwm_enable => SYNTHESIZED_WIRE_1,
   clock_divide => SYNTHESIZED_WIRE_2,
   duty_cycle => SYNTHESIZED_WIRE_3,
   irq_flagset => SYNTHESIZED_WIRE_4,
   pwm_out => pwm_out);

b2v_inst1 : pwm_register_file
PORT MAP(csi_pwm_clock => csi_pwm_clock,
   avs_pwm_reset_n => avs_pwm_reset_n,
   avs_pwm_chipselect => avs_pwm_chipselect,
   avs_pwm_write => avs_pwm_write,
   avs_pwm_read => avs_pwm_read,
   irq_flag => SYNTHESIZED_WIRE_4,
   avs_pwm_address => avs_pwm_address,
   avs_pwm_writedata => avs_pwm_writedata,
   ins_pwm_irq => ins_pwm_irq,
   clr_irq => SYNTHESIZED_WIRE_0,
   pwm_enable => SYNTHESIZED_WIRE_1,
   avs_pwm_readdata => avs_pwm_readdata,
   pwm_clock_divide => SYNTHESIZED_WIRE_2,
   pwm_duty_cycle => SYNTHESIZED_WIRE_3);

END;

2.pwm_register_file.vhd描述了PWM内部寄存器的读写操作

LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.ALL;
USE IEEE.STD_LOGIC_ARITH.ALL;
USE IEEE.STD_LOGIC_UNSIGNED.ALL;

ENTITY pwm_register_file IS
PORT
(
 -- INPUT
    csi_pwm_clock        : IN   STD_LOGIC;
    avs_pwm_reset_n      : IN   STD_LOGIC;
    avs_pwm_chipselect   : IN   STD_LOGIC;
    avs_pwm_address      : IN   STD_LOGIC_VECTOR(2 DOWNTO 0);
    avs_pwm_write        : IN   STD_LOGIC;
    avs_pwm_writedata    : IN   STD_LOGIC_VECTOR(31 DOWNTO 0);
    avs_pwm_read         : IN   STD_LOGIC;
    irq_flag             : IN   STD_LOGIC;
 -- OUTPUT
   avs_pwm_readdata     : OUT  STD_LOGIC_VECTOR(31 DOWNTO 0);
   pwm_clock_divide     : OUT  STD_LOGIC_VECTOR(31 DOWNTO 0);
   pwm_duty_cycle       : OUT  STD_LOGIC_VECTOR(31 DOWNTO 0);
   ins_pwm_irq          : OUT  STD_LOGIC;
   clr_irq              : OUT  STD_LOGIC;
   pwm_enable           : OUT  STD_LOGIC
);
END ENTITY;

ARCHITECTURE behave OF pwm_register_file IS 

CONSTANT CLOCK_DIVIDE_REG_INIT : STD_LOGIC_VECTOR(31 DOWNTO 0) := (OTHERS => '0');
CONSTANT DUTY_CYCLE_REG_INIT   : STD_LOGIC_VECTOR(31 DOWNTO 0) := (OTHERS => '0');
CONSTANT ZERO                  : STD_LOGIC_VECTOR(30 DOWNTO 0) := (OTHERS => '0');
CONSTANT CLOCK_DIVIDE          : STD_LOGIC_VECTOR(2  DOWNTO 0) := "000";
CONSTANT DUTY_CYCLE            : STD_LOGIC_VECTOR(2  DOWNTO 0) := "001";
CONSTANT ENABLE_PWM            : STD_LOGIC_VECTOR(2  DOWNTO 0) := "010";
CONSTANT ENABLE_IRQ            : STD_LOGIC_VECTOR(2  DOWNTO 0) := "011";
CONSTANT CLR_IRQ_FLAG          : STD_LOGIC_VECTOR(2  DOWNTO 0) := "100";

SIGNAL clock_divide_r : STD_LOGIC_VECTOR(31 DOWNTO 0);
SIGNAL duty_cycle_r   : STD_LOGIC_VECTOR(31 DOWNTO 0);
SIGNAL enable_pwm_r   : STD_LOGIC;
SIGNAL enable_irq_r   : STD_LOGIC;
SIGNAL clr_irq_flag_r : STD_LOGIC;
SIGNAL readdata_r     : STD_LOGIC_VECTOR(31 DOWNTO 0);
SIGNAL write_act      : STD_LOGIC;
SIGNAL read_act       : STD_LOGIC;

BEGIN
write_act <= avs_pwm_chipselect AND avs_pwm_write;
read_act  <= avs_pwm_chipselect AND avs_pwm_read;

-- Register Write
Register_Write:PROCESS(csi_pwm_clock,avs_pwm_reset_n)
                    BEGIN
                      IF avs_pwm_reset_n = '0' THEN
                         clock_divide_r <= CLOCK_DIVIDE_REG_INIT;
                         duty_cycle_r   <= DUTY_CYCLE_REG_INIT;
                         enable_pwm_r   <= '0';
                         enable_irq_r   <= '0';
                    ELSIF RISING_EDGE(csi_pwm_clock) THEN
                         IF write_act = '1' THEN
                             CASE avs_pwm_address IS
                             WHEN CLOCK_DIVIDE => clock_divide_r <= avs_pwm_writedata;
                             WHEN DUTY_CYCLE   => duty_cycle_r   <= avs_pwm_writedata;
                             WHEN ENABLE_PWM   => enable_pwm_r   <= avs_pwm_writedata(0);
                             WHEN ENABLE_IRQ   => enable_irq_r   <= avs_pwm_writedata(0);
                             WHEN OTHERS => NULL;
                             END CASE;
                       END IF;
                    END IF;
                 END PROCESS Register_Write;
ClrIrqFlag_Reg_Write:PROCESS(csi_pwm_clock,avs_pwm_reset_n)
                             BEGIN
                             IF avs_pwm_reset_n = '0' THEN
                                 clr_irq_flag_r <= '0';
                             ELSIF RISING_EDGE(csi_pwm_clock) THEN
                                  IF irq_flag = '1' THEN
                                       IF write_act = '1' THEN
                                            IF avs_pwm_address = CLR_IRQ_FLAG THEN
                                                    clr_irq_flag_r <= '1';
                                            ELSE
                                                    NULL;
                                            END IF;
                                       END IF;
                                  ELSE
                                      clr_irq_flag_r <= '0';
                                 END IF;
                           END IF;
                           END PROCESS ClrIrqFlag_Reg_Write;
IrqFlag_Clr:PROCESS(csi_pwm_clock)
                BEGIN
                IF FALLING_EDGE(csi_pwm_clock) THEN
                     IF clr_irq_flag_r = '1' THEN
                             clr_irq <= '1';
                     ELSE
                         clr_irq <= '0';
                    END IF;
                ELSE
                   NULL;
               END IF;
               END PROCESS IrqFlag_Clr;


--  Register Read 
Register_Read:PROCESS(read_act,avs_pwm_address,clock_divide_r,duty_cycle_r,enable_pwm_r)
              BEGIN
                  IF read_act = '1' THEN
                       CASE avs_pwm_address IS
                       WHEN CLOCK_DIVIDE => readdata_r <= clock_divide_r;
                       WHEN DUTY_CYCLE   => readdata_r <= duty_cycle_r;
                       WHEN ENABLE_PWM   => readdata_r <= ZERO & enable_pwm_r;
                       WHEN ENABLE_IRQ   => readdata_r <= ZERO & enable_irq_r;
                       WHEN CLR_IRQ_FLAG => readdata_r <= ZERO & clr_irq_flag_r;
                       WHEN OTHERS       => readdata_r <= (OTHERS => '0'); 
                 END CASE;
               END IF;
              END PROCESS Register_Read;
avs_pwm_readdata  <= readdata_r;
pwm_clock_divide  <= clock_divide_r;
pwm_duty_cycle    <= duty_cycle_r;
pwm_enable        <= enable_pwm_r;
ins_pwm_irq       <= enable_irq_r AND irq_flag;
END behave;

 3.pwm_task_logic.vhd 描述了PWM的功能

LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.ALL;
USE IEEE.STD_LOGIC_ARITH.ALL;
USE IEEE.STD_LOGIC_UNSIGNED.ALL;
ENTITY pwm_task_logic IS
PORT
(
  -- INPUT
  clock        : IN STD_LOGIC;
  reset_n      : IN STD_LOGIC;
  clr_irqflag  : IN STD_LOGIC;
  pwm_enable   : IN STD_LOGIC;
  clock_divide : IN STD_LOGIC_VECTOR(31 DOWNTO 0);
  duty_cycle   : IN STD_LOGIC_VECTOR(31 DOWNTO 0);
  -- OUTPUT
  irq_flagset  : OUT STD_LOGIC;
  pwm_out      : OUT STD_LOGIC
);
END pwm_task_logic;
ARCHITECTURE behave OF pwm_task_logic IS
SIGNAL counter   : STD_LOGIC_VECTOR(31 DOWNTO 0);
BEGIN
PWM_Counter:PROCESS(clock,reset_n)
                   BEGIN
                     IF reset_n = '0' THEN
                         counter <= (OTHERS => '0');
                     ELSIF(RISING_EDGE(clock)) THEN
                         IF pwm_enable = '1' THEN
                            IF (counter >= clock_divide) THEN
                                counter <= (OTHERS => '0');
                            ELSE
                               counter <= counter + '1';
                            END IF;
                         END IF;
                     END IF;
                   END PROCESS PWM_Counter;
PWM_Comparitor:PROCESS(clock,reset_n)
                        BEGIN
                           IF reset_n = '0' THEN
                                  pwm_out <= '0';
                           ELSIF(RISING_EDGE(clock)) THEN
                                   IF (pwm_enable = '1' AND counter <= duty_cycle) THEN
                                         pwm_out <= '1';
                                  ELSE
                                        pwm_out <= '0';
                                  END IF;
                             END IF;
                        END PROCESS PWM_Comparitor;
PWM_SetIrqFlag:PROCESS(clock,reset_n,clr_irqflag)
                        BEGIN
                        IF reset_n = '0' THEN
                             irq_flagset <= '0';
                        ELSIF clr_irqflag = '1' THEN
                             irq_flagset <= '0';
                        ELSIF counter >= clock_divide THEN
                             irq_flagset <= '1';
                        ELSE
                             NULL;
                        END IF;
                        END PROCESS PWM_SetIrqFlag;
END behave;

你可能感兴趣的:(基于NIOS II的PWM实现)