├── Driver ├── main.c └── PWM_Generator.h ├── HDL ├── pwm_gen.v ├── PWM_Generator_v1_0.v └── PWM_Generator_v1_0_S_AXI.v └── README.md /Driver/main.c: -------------------------------------------------------------------------------- 1 | /* 2 | * main.c 3 | * 4 | * Created on: May 18, 2014 5 | * Author: Devon 6 | */ 7 | 8 | #include "xparameters.h" 9 | #include "xil_types.h" 10 | #include "PWM_Generator.h" 11 | 12 | int main(void) 13 | { 14 | // Set period to 20ms and compare to 5% duty cycle 15 | PWM_GENERATOR_mDisableOutput(XPAR_PWM_GENERATOR_0_S_AXI_BASEADDR); 16 | PWM_GENERATOR_mSetLoad(XPAR_PWM_GENERATOR_0_S_AXI_BASEADDR, 2000000); 17 | PWM_GENERATOR_mSetCompare(XPAR_PWM_GENERATOR_0_S_AXI_BASEADDR, 200000); 18 | PWM_GENERATOR_mEnableOutput(XPAR_PWM_GENERATOR_0_S_AXI_BASEADDR); 19 | 20 | while(1) 21 | { 22 | 23 | } 24 | 25 | return 0; 26 | } 27 | -------------------------------------------------------------------------------- /HDL/pwm_gen.v: -------------------------------------------------------------------------------- 1 | `timescale 1ns / 1ps 2 | ////////////////////////////////////////////////////////////////////////////////// 3 | // Engineer: Devon Andrade 4 | // 5 | // Create Date: 05/18/2014 02:43:10 PM 6 | // Design Name: PWM Generator 7 | // Module Name: pwm_gen 8 | // Project Name: PWM Generator 9 | // Target Devices: xc7z010clg400-1 10 | // Tool Versions: Vivado 2014.1 11 | // 12 | // Parameters: 13 | // WIDTH - How many bits the counter, load, and compare values are 14 | // 15 | // Inputs: 16 | // load - The value at which the counter will reset to zero and set the output 17 | // compare - The value at which the counter will clear the output 18 | // control - Register bit map: 19 | // Bit 0: PWM Enable - Output is enabled if this bit is high, disabled otherwise 20 | // 21 | // Outputs: 22 | // pwm_out - The pulse width modulated signal, or ground if disabled 23 | ////////////////////////////////////////////////////////////////////////////////// 24 | 25 | 26 | module pwm_gen 27 | #(parameter WIDTH=32) ( 28 | input wire clk, rst, 29 | input wire [WIDTH-1:0] load, compare, control, 30 | output wire pwm_out 31 | ); 32 | 33 | reg [WIDTH-1:0] count; 34 | reg pwm_out_r; 35 | 36 | // Make sure output is low if PWM is disabled 37 | assign pwm_out = control[0] & pwm_out_r; 38 | 39 | initial begin 40 | pwm_out_r = 1'b0; 41 | count = {WIDTH{1'b0}}; 42 | end 43 | 44 | // The counter 45 | always @(posedge clk) begin 46 | if(!rst) 47 | count = {WIDTH{1'b0}}; 48 | else if (count < load && control[0]) 49 | count = count + 1; 50 | else 51 | count = 0; 52 | end 53 | 54 | always @(negedge clk) begin 55 | if(!rst) 56 | pwm_out_r = 1'b0; 57 | else begin 58 | case(count) 59 | 0 : pwm_out_r = 1'b1; 60 | compare : pwm_out_r = 1'b0; 61 | default : pwm_out_r = pwm_out_r; 62 | endcase 63 | end 64 | end 65 | 66 | endmodule 67 | -------------------------------------------------------------------------------- /HDL/PWM_Generator_v1_0.v: -------------------------------------------------------------------------------- 1 | 2 | `timescale 1 ps / 1 ps 3 | 4 | module PWM_Generator_v1_0 # 5 | ( 6 | // Users to add parameters here 7 | 8 | // User parameters ends 9 | // Do not modify the parameters beyond this line 10 | 11 | 12 | // Parameters of Axi Slave Bus Interface S_AXI 13 | parameter integer C_S_AXI_DATA_WIDTH = 32, 14 | parameter integer C_S_AXI_ADDR_WIDTH = 4 15 | ) 16 | ( 17 | // Users to add ports here 18 | output wire pwm_out, 19 | // User ports ends 20 | // Do not modify the ports beyond this line 21 | 22 | 23 | // Ports of Axi Slave Bus Interface S_AXI 24 | input wire s_axi_aclk, 25 | input wire s_axi_aresetn, 26 | input wire [C_S_AXI_ADDR_WIDTH-1 : 0] s_axi_awaddr, 27 | input wire [2 : 0] s_axi_awprot, 28 | input wire s_axi_awvalid, 29 | output wire s_axi_awready, 30 | input wire [C_S_AXI_DATA_WIDTH-1 : 0] s_axi_wdata, 31 | input wire [(C_S_AXI_DATA_WIDTH/8)-1 : 0] s_axi_wstrb, 32 | input wire s_axi_wvalid, 33 | output wire s_axi_wready, 34 | output wire [1 : 0] s_axi_bresp, 35 | output wire s_axi_bvalid, 36 | input wire s_axi_bready, 37 | input wire [C_S_AXI_ADDR_WIDTH-1 : 0] s_axi_araddr, 38 | input wire [2 : 0] s_axi_arprot, 39 | input wire s_axi_arvalid, 40 | output wire s_axi_arready, 41 | output wire [C_S_AXI_DATA_WIDTH-1 : 0] s_axi_rdata, 42 | output wire [1 : 0] s_axi_rresp, 43 | output wire s_axi_rvalid, 44 | input wire s_axi_rready 45 | ); 46 | // Instantiation of Axi Bus Interface S_AXI 47 | PWM_Generator_v1_0_S_AXI # ( 48 | .C_S_AXI_DATA_WIDTH(C_S_AXI_DATA_WIDTH), 49 | .C_S_AXI_ADDR_WIDTH(C_S_AXI_ADDR_WIDTH) 50 | ) PWM_Generator_v1_0_S_AXI_inst ( 51 | .pwm_out(pwm_out), 52 | .S_AXI_ACLK(s_axi_aclk), 53 | .S_AXI_ARESETN(s_axi_aresetn), 54 | .S_AXI_AWADDR(s_axi_awaddr), 55 | .S_AXI_AWPROT(s_axi_awprot), 56 | .S_AXI_AWVALID(s_axi_awvalid), 57 | .S_AXI_AWREADY(s_axi_awready), 58 | .S_AXI_WDATA(s_axi_wdata), 59 | .S_AXI_WSTRB(s_axi_wstrb), 60 | .S_AXI_WVALID(s_axi_wvalid), 61 | .S_AXI_WREADY(s_axi_wready), 62 | .S_AXI_BRESP(s_axi_bresp), 63 | .S_AXI_BVALID(s_axi_bvalid), 64 | .S_AXI_BREADY(s_axi_bready), 65 | .S_AXI_ARADDR(s_axi_araddr), 66 | .S_AXI_ARPROT(s_axi_arprot), 67 | .S_AXI_ARVALID(s_axi_arvalid), 68 | .S_AXI_ARREADY(s_axi_arready), 69 | .S_AXI_RDATA(s_axi_rdata), 70 | .S_AXI_RRESP(s_axi_rresp), 71 | .S_AXI_RVALID(s_axi_rvalid), 72 | .S_AXI_RREADY(s_axi_rready) 73 | ); 74 | 75 | // Add user logic here 76 | 77 | // User logic ends 78 | 79 | endmodule 80 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Pulse Width Modulation IP 2 | ========================= 3 | 4 | A PWM Module IP core written in Verilog, along with a firmware driver (developed for the Zynq-7000 Programmable SoC). 5 | 6 | This repository doesn't contain the Xilinx Vivado project files needed to utilize it as an IP, but instead cuts out the cruft and shows you the bare logic and how to utilize from within a software project. 7 | 8 |

HDL

9 | In the HDL folder you'll find three files: 10 | 15 | 16 | There are three registers that control the operation of the PWM module: 17 | 22 | 23 | The PWM module will continuously count up to the "load" value and once it reaches the load value, will loop back to zero. When the counter is at zero, the output is set high. When the PWM module reaches the "compare" value, it clears the output. So the "high" width of the output signal is exactly "compare" clock ticks long (the clock is whatever clock you connect to the IP in your block design, but it will most likely be generated by the Zynq Processing System). The "low" width of the output signal is exactly "load" - "compare" clock ticks long. If you disable the PWM module (by setting bit zero of the control register to zero) then the output will always be low. 24 | 25 | In other words, the "load" register determines your period, while the "compare" register determines your duty cycle. 26 | 27 |

Driver

28 | The "PWM_Generator.h" header file contains helpful macros for manipulating the PWM registers while "main.c" gives an example of using those macros. This code would be used in a Xilinx SDK project created for a Zynq design that utilizes the PWM IP. -------------------------------------------------------------------------------- /Driver/PWM_Generator.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef PWM_GENERATOR_H 3 | #define PWM_GENERATOR_H 4 | 5 | 6 | /****************** Include Files ********************/ 7 | #include "xil_types.h" 8 | #include "xstatus.h" 9 | #include "xil_io.h" 10 | 11 | #define PWM_GENERATOR_S_AXI_LOAD_REG_OFFSET 0 12 | #define PWM_GENERATOR_S_AXI_COMPARE_REG_OFFSET 4 13 | #define PWM_GENERATOR_S_AXI_CONTROL_REG_OFFSET 8 14 | #define PWM_GENERATOR_S_AXI_UNUSED_REG_OFFSET 12 15 | 16 | /**************************** Type Definitions *****************************/ 17 | /** 18 | * 19 | * Write a value to a PWM_GENERATOR register. A 32 bit write is performed. 20 | * If the component is implemented in a smaller width, only the least 21 | * significant data is written. 22 | * 23 | * @param BaseAddress is the base address of the PWM_GENERATORdevice. 24 | * @param RegOffset is the register offset from the base to write to. 25 | * @param Data is the data written to the register. 26 | * 27 | * @return None. 28 | * 29 | * @note 30 | * C-style signature: 31 | * void PWM_GENERATOR_mWriteReg(u32 BaseAddress, unsigned RegOffset, u32 Data) 32 | * 33 | */ 34 | #define PWM_GENERATOR_mWriteReg(BaseAddress, RegOffset, Data) \ 35 | Xil_Out32((BaseAddress) + (RegOffset), (u32)(Data)) 36 | 37 | /** 38 | * 39 | * Read a value from a PWM_GENERATOR register. A 32 bit read is performed. 40 | * If the component is implemented in a smaller width, only the least 41 | * significant data is read from the register. The most significant data 42 | * will be read as 0. 43 | * 44 | * @param BaseAddress is the base address of the PWM_GENERATOR device. 45 | * @param RegOffset is the register offset from the base to write to. 46 | * 47 | * @return Data is the data from the register. 48 | * 49 | * @note 50 | * C-style signature: 51 | * u32 PWM_GENERATOR_mReadReg(u32 BaseAddress, unsigned RegOffset) 52 | * 53 | */ 54 | #define PWM_GENERATOR_mReadReg(BaseAddress, RegOffset) \ 55 | Xil_In32((BaseAddress) + (RegOffset)) 56 | 57 | // Enables PWM Output by setting bit 0 of the control register 58 | #define PWM_GENERATOR_mEnableOutput(BaseAddress) \ 59 | PWM_GENERATOR_mWriteReg(BaseAddress, PWM_GENERATOR_S_AXI_CONTROL_REG_OFFSET, 1) 60 | 61 | // Disables PWM Output by clearing bit 0 of the control register 62 | #define PWM_GENERATOR_mDisableOutput(BaseAddress) \ 63 | PWM_GENERATOR_mWriteReg(BaseAddress, PWM_GENERATOR_S_AXI_CONTROL_REG_OFFSET, 0) 64 | 65 | // Sets the PWM Generator's load value 66 | #define PWM_GENERATOR_mSetLoad(BaseAddress, Load) \ 67 | PWM_GENERATOR_mWriteReg(BaseAddress, PWM_GENERATOR_S_AXI_LOAD_REG_OFFSET, Load) 68 | 69 | // Sets the PWM Generator's compare value 70 | #define PWM_GENERATOR_mSetCompare(BaseAddress, Compare) \ 71 | PWM_GENERATOR_mWriteReg(BaseAddress, PWM_GENERATOR_S_AXI_COMPARE_REG_OFFSET, Compare) 72 | 73 | /************************** Function Prototypes ****************************/ 74 | /** 75 | * 76 | * Run a self-test on the driver/device. Note this may be a destructive test if 77 | * resets of the device are performed. 78 | * 79 | * If the hardware system is not built correctly, this function may never 80 | * return to the caller. 81 | * 82 | * @param baseaddr_p is the base address of the PWM_GENERATOR instance to be worked on. 83 | * 84 | * @return 85 | * 86 | * - XST_SUCCESS if all self-test code passed 87 | * - XST_FAILURE if any self-test code failed 88 | * 89 | * @note Caching must be turned off for this function to work. 90 | * @note Self test may fail if data memory and device are not on the same bus. 91 | * 92 | */ 93 | XStatus PWM_GENERATOR_Reg_SelfTest(void * baseaddr_p); 94 | 95 | #endif // PWM_GENERATOR_H 96 | -------------------------------------------------------------------------------- /HDL/PWM_Generator_v1_0_S_AXI.v: -------------------------------------------------------------------------------- 1 | 2 | `timescale 1 ps / 1 ps 3 | 4 | module PWM_Generator_v1_0_S_AXI # 5 | ( 6 | // Users to add parameters here 7 | 8 | // User parameters ends 9 | // Do not modify the parameters beyond this line 10 | 11 | // Width of S_AXI data bus 12 | parameter integer C_S_AXI_DATA_WIDTH = 32, 13 | // Width of S_AXI address bus 14 | parameter integer C_S_AXI_ADDR_WIDTH = 4 15 | ) 16 | ( 17 | // Users to add ports here 18 | output wire pwm_out, 19 | // User ports ends 20 | // Do not modify the ports beyond this line 21 | 22 | // Global Clock Signal 23 | input wire S_AXI_ACLK, 24 | // Global Reset Signal. This Signal is Active LOW 25 | input wire S_AXI_ARESETN, 26 | // Write address (issued by master, acceped by Slave) 27 | input wire [C_S_AXI_ADDR_WIDTH-1 : 0] S_AXI_AWADDR, 28 | // Write channel Protection type. This signal indicates the 29 | // privilege and security level of the transaction, and whether 30 | // the transaction is a data access or an instruction access. 31 | input wire [2 : 0] S_AXI_AWPROT, 32 | // Write address valid. This signal indicates that the master signaling 33 | // valid write address and control information. 34 | input wire S_AXI_AWVALID, 35 | // Write address ready. This signal indicates that the slave is ready 36 | // to accept an address and associated control signals. 37 | output wire S_AXI_AWREADY, 38 | // Write data (issued by master, acceped by Slave) 39 | input wire [C_S_AXI_DATA_WIDTH-1 : 0] S_AXI_WDATA, 40 | // Write strobes. This signal indicates which byte lanes hold 41 | // valid data. There is one write strobe bit for each eight 42 | // bits of the write data bus. 43 | input wire [(C_S_AXI_DATA_WIDTH/8)-1 : 0] S_AXI_WSTRB, 44 | // Write valid. This signal indicates that valid write 45 | // data and strobes are available. 46 | input wire S_AXI_WVALID, 47 | // Write ready. This signal indicates that the slave 48 | // can accept the write data. 49 | output wire S_AXI_WREADY, 50 | // Write response. This signal indicates the status 51 | // of the write transaction. 52 | output wire [1 : 0] S_AXI_BRESP, 53 | // Write response valid. This signal indicates that the channel 54 | // is signaling a valid write response. 55 | output wire S_AXI_BVALID, 56 | // Response ready. This signal indicates that the master 57 | // can accept a write response. 58 | input wire S_AXI_BREADY, 59 | // Read address (issued by master, acceped by Slave) 60 | input wire [C_S_AXI_ADDR_WIDTH-1 : 0] S_AXI_ARADDR, 61 | // Protection type. This signal indicates the privilege 62 | // and security level of the transaction, and whether the 63 | // transaction is a data access or an instruction access. 64 | input wire [2 : 0] S_AXI_ARPROT, 65 | // Read address valid. This signal indicates that the channel 66 | // is signaling valid read address and control information. 67 | input wire S_AXI_ARVALID, 68 | // Read address ready. This signal indicates that the slave is 69 | // ready to accept an address and associated control signals. 70 | output wire S_AXI_ARREADY, 71 | // Read data (issued by slave) 72 | output wire [C_S_AXI_DATA_WIDTH-1 : 0] S_AXI_RDATA, 73 | // Read response. This signal indicates the status of the 74 | // read transfer. 75 | output wire [1 : 0] S_AXI_RRESP, 76 | // Read valid. This signal indicates that the channel is 77 | // signaling the required read data. 78 | output wire S_AXI_RVALID, 79 | // Read ready. This signal indicates that the master can 80 | // accept the read data and response information. 81 | input wire S_AXI_RREADY 82 | ); 83 | 84 | // AXI4LITE signals 85 | reg [C_S_AXI_ADDR_WIDTH-1 : 0] axi_awaddr; 86 | reg axi_awready; 87 | reg axi_wready; 88 | reg [1 : 0] axi_bresp; 89 | reg axi_bvalid; 90 | reg [C_S_AXI_ADDR_WIDTH-1 : 0] axi_araddr; 91 | reg axi_arready; 92 | reg [C_S_AXI_DATA_WIDTH-1 : 0] axi_rdata; 93 | reg [1 : 0] axi_rresp; 94 | reg axi_rvalid; 95 | 96 | // Example-specific design signals 97 | // local parameter for addressing 32 bit / 64 bit C_S_AXI_DATA_WIDTH 98 | // ADDR_LSB is used for addressing 32/64 bit registers/memories 99 | // ADDR_LSB = 2 for 32 bits (n downto 2) 100 | // ADDR_LSB = 3 for 64 bits (n downto 3) 101 | localparam integer ADDR_LSB = (C_S_AXI_DATA_WIDTH/32) + 1; 102 | localparam integer OPT_MEM_ADDR_BITS = 1; 103 | //---------------------------------------------- 104 | //-- Signals for user logic register space example 105 | //------------------------------------------------ 106 | //-- Number of Slave Registers 4 107 | reg [C_S_AXI_DATA_WIDTH-1:0] load_reg; 108 | reg [C_S_AXI_DATA_WIDTH-1:0] compare_reg; 109 | reg [C_S_AXI_DATA_WIDTH-1:0] control_reg; 110 | reg [C_S_AXI_DATA_WIDTH-1:0] unused_reg; 111 | wire slv_reg_rden; 112 | wire slv_reg_wren; 113 | reg [C_S_AXI_DATA_WIDTH-1:0] reg_data_out; 114 | integer byte_index; 115 | 116 | // I/O Connections assignments 117 | 118 | assign S_AXI_AWREADY = axi_awready; 119 | assign S_AXI_WREADY = axi_wready; 120 | assign S_AXI_BRESP = axi_bresp; 121 | assign S_AXI_BVALID = axi_bvalid; 122 | assign S_AXI_ARREADY = axi_arready; 123 | assign S_AXI_RDATA = axi_rdata; 124 | assign S_AXI_RRESP = axi_rresp; 125 | assign S_AXI_RVALID = axi_rvalid; 126 | // Implement axi_awready generation 127 | // axi_awready is asserted for one S_AXI_ACLK clock cycle when both 128 | // S_AXI_AWVALID and S_AXI_WVALID are asserted. axi_awready is 129 | // de-asserted when reset is low. 130 | 131 | always @( posedge S_AXI_ACLK ) 132 | begin 133 | if ( S_AXI_ARESETN == 1'b0 ) 134 | begin 135 | axi_awready <= 1'b0; 136 | end 137 | else 138 | begin 139 | if (~axi_awready && S_AXI_AWVALID && S_AXI_WVALID) 140 | begin 141 | // slave is ready to accept write address when 142 | // there is a valid write address and write data 143 | // on the write address and data bus. This design 144 | // expects no outstanding transactions. 145 | axi_awready <= 1'b1; 146 | end 147 | else 148 | begin 149 | axi_awready <= 1'b0; 150 | end 151 | end 152 | end 153 | 154 | // Implement axi_awaddr latching 155 | // This process is used to latch the address when both 156 | // S_AXI_AWVALID and S_AXI_WVALID are valid. 157 | 158 | always @( posedge S_AXI_ACLK ) 159 | begin 160 | if ( S_AXI_ARESETN == 1'b0 ) 161 | begin 162 | axi_awaddr <= 0; 163 | end 164 | else 165 | begin 166 | if (~axi_awready && S_AXI_AWVALID && S_AXI_WVALID) 167 | begin 168 | // Write Address latching 169 | axi_awaddr <= S_AXI_AWADDR; 170 | end 171 | end 172 | end 173 | 174 | // Implement axi_wready generation 175 | // axi_wready is asserted for one S_AXI_ACLK clock cycle when both 176 | // S_AXI_AWVALID and S_AXI_WVALID are asserted. axi_wready is 177 | // de-asserted when reset is low. 178 | 179 | always @( posedge S_AXI_ACLK ) 180 | begin 181 | if ( S_AXI_ARESETN == 1'b0 ) 182 | begin 183 | axi_wready <= 1'b0; 184 | end 185 | else 186 | begin 187 | if (~axi_wready && S_AXI_WVALID && S_AXI_AWVALID) 188 | begin 189 | // slave is ready to accept write data when 190 | // there is a valid write address and write data 191 | // on the write address and data bus. This design 192 | // expects no outstanding transactions. 193 | axi_wready <= 1'b1; 194 | end 195 | else 196 | begin 197 | axi_wready <= 1'b0; 198 | end 199 | end 200 | end 201 | 202 | // Implement memory mapped register select and write logic generation 203 | // The write data is accepted and written to memory mapped registers when 204 | // axi_awready, S_AXI_WVALID, axi_wready and S_AXI_WVALID are asserted. Write strobes are used to 205 | // select byte enables of slave registers while writing. 206 | // These registers are cleared when reset (active low) is applied. 207 | // Slave register write enable is asserted when valid address and data are available 208 | // and the slave is ready to accept the write address and write data. 209 | assign slv_reg_wren = axi_wready && S_AXI_WVALID && axi_awready && S_AXI_AWVALID; 210 | 211 | always @( posedge S_AXI_ACLK ) 212 | begin 213 | if ( S_AXI_ARESETN == 1'b0 ) 214 | begin 215 | load_reg <= 0; 216 | compare_reg <= 0; 217 | control_reg <= 0; 218 | unused_reg <= 0; 219 | end 220 | else begin 221 | if (slv_reg_wren) 222 | begin 223 | case ( axi_awaddr[ADDR_LSB+OPT_MEM_ADDR_BITS:ADDR_LSB] ) 224 | 2'h0: 225 | for ( byte_index = 0; byte_index <= (C_S_AXI_DATA_WIDTH/8)-1; byte_index = byte_index+1 ) 226 | if ( S_AXI_WSTRB[byte_index] == 1 ) begin 227 | // Respective byte enables are asserted as per write strobes 228 | // Slave register 0 229 | load_reg[(byte_index*8) +: 8] <= S_AXI_WDATA[(byte_index*8) +: 8]; 230 | end 231 | 2'h1: 232 | for ( byte_index = 0; byte_index <= (C_S_AXI_DATA_WIDTH/8)-1; byte_index = byte_index+1 ) 233 | if ( S_AXI_WSTRB[byte_index] == 1 ) begin 234 | // Respective byte enables are asserted as per write strobes 235 | // Slave register 1 236 | compare_reg[(byte_index*8) +: 8] <= S_AXI_WDATA[(byte_index*8) +: 8]; 237 | end 238 | 2'h2: 239 | for ( byte_index = 0; byte_index <= (C_S_AXI_DATA_WIDTH/8)-1; byte_index = byte_index+1 ) 240 | if ( S_AXI_WSTRB[byte_index] == 1 ) begin 241 | // Respective byte enables are asserted as per write strobes 242 | // Slave register 2 243 | control_reg[(byte_index*8) +: 8] <= S_AXI_WDATA[(byte_index*8) +: 8]; 244 | end 245 | 2'h3: 246 | for ( byte_index = 0; byte_index <= (C_S_AXI_DATA_WIDTH/8)-1; byte_index = byte_index+1 ) 247 | if ( S_AXI_WSTRB[byte_index] == 1 ) begin 248 | // Respective byte enables are asserted as per write strobes 249 | // Slave register 3 250 | unused_reg[(byte_index*8) +: 8] <= S_AXI_WDATA[(byte_index*8) +: 8]; 251 | end 252 | default : begin 253 | load_reg <= load_reg; 254 | compare_reg <= compare_reg; 255 | control_reg <= control_reg; 256 | unused_reg <= unused_reg; 257 | end 258 | endcase 259 | end 260 | end 261 | end 262 | 263 | // Implement write response logic generation 264 | // The write response and response valid signals are asserted by the slave 265 | // when axi_wready, S_AXI_WVALID, axi_wready and S_AXI_WVALID are asserted. 266 | // This marks the acceptance of address and indicates the status of 267 | // write transaction. 268 | 269 | always @( posedge S_AXI_ACLK ) 270 | begin 271 | if ( S_AXI_ARESETN == 1'b0 ) 272 | begin 273 | axi_bvalid <= 0; 274 | axi_bresp <= 2'b0; 275 | end 276 | else 277 | begin 278 | if (axi_awready && S_AXI_AWVALID && ~axi_bvalid && axi_wready && S_AXI_WVALID) 279 | begin 280 | // indicates a valid write response is available 281 | axi_bvalid <= 1'b1; 282 | axi_bresp <= 2'b0; // 'OKAY' response 283 | end // work error responses in future 284 | else 285 | begin 286 | if (S_AXI_BREADY && axi_bvalid) 287 | //check if bready is asserted while bvalid is high) 288 | //(there is a possibility that bready is always asserted high) 289 | begin 290 | axi_bvalid <= 1'b0; 291 | end 292 | end 293 | end 294 | end 295 | 296 | // Implement axi_arready generation 297 | // axi_arready is asserted for one S_AXI_ACLK clock cycle when 298 | // S_AXI_ARVALID is asserted. axi_awready is 299 | // de-asserted when reset (active low) is asserted. 300 | // The read address is also latched when S_AXI_ARVALID is 301 | // asserted. axi_araddr is reset to zero on reset assertion. 302 | 303 | always @( posedge S_AXI_ACLK ) 304 | begin 305 | if ( S_AXI_ARESETN == 1'b0 ) 306 | begin 307 | axi_arready <= 1'b0; 308 | axi_araddr <= 32'b0; 309 | end 310 | else 311 | begin 312 | if (~axi_arready && S_AXI_ARVALID) 313 | begin 314 | // indicates that the slave has acceped the valid read address 315 | axi_arready <= 1'b1; 316 | // Read address latching 317 | axi_araddr <= S_AXI_ARADDR; 318 | end 319 | else 320 | begin 321 | axi_arready <= 1'b0; 322 | end 323 | end 324 | end 325 | 326 | // Implement axi_arvalid generation 327 | // axi_rvalid is asserted for one S_AXI_ACLK clock cycle when both 328 | // S_AXI_ARVALID and axi_arready are asserted. The slave registers 329 | // data are available on the axi_rdata bus at this instance. The 330 | // assertion of axi_rvalid marks the validity of read data on the 331 | // bus and axi_rresp indicates the status of read transaction.axi_rvalid 332 | // is deasserted on reset (active low). axi_rresp and axi_rdata are 333 | // cleared to zero on reset (active low). 334 | always @( posedge S_AXI_ACLK ) 335 | begin 336 | if ( S_AXI_ARESETN == 1'b0 ) 337 | begin 338 | axi_rvalid <= 0; 339 | axi_rresp <= 0; 340 | end 341 | else 342 | begin 343 | if (axi_arready && S_AXI_ARVALID && ~axi_rvalid) 344 | begin 345 | // Valid read data is available at the read data bus 346 | axi_rvalid <= 1'b1; 347 | axi_rresp <= 2'b0; // 'OKAY' response 348 | end 349 | else if (axi_rvalid && S_AXI_RREADY) 350 | begin 351 | // Read data is accepted by the master 352 | axi_rvalid <= 1'b0; 353 | end 354 | end 355 | end 356 | 357 | // Implement memory mapped register select and read logic generation 358 | // Slave register read enable is asserted when valid address is available 359 | // and the slave is ready to accept the read address. 360 | assign slv_reg_rden = axi_arready & S_AXI_ARVALID & ~axi_rvalid; 361 | always @(*) 362 | begin 363 | if ( S_AXI_ARESETN == 1'b0 ) 364 | begin 365 | reg_data_out <= 0; 366 | end 367 | else 368 | begin 369 | // Address decoding for reading registers 370 | case ( axi_araddr[ADDR_LSB+OPT_MEM_ADDR_BITS:ADDR_LSB] ) 371 | 2'h0 : reg_data_out <= load_reg; 372 | 2'h1 : reg_data_out <= compare_reg; 373 | 2'h2 : reg_data_out <= control_reg; 374 | 2'h3 : reg_data_out <= unused_reg; 375 | default : reg_data_out <= 0; 376 | endcase 377 | end 378 | end 379 | 380 | // Output register or memory read data 381 | always @( posedge S_AXI_ACLK ) 382 | begin 383 | if ( S_AXI_ARESETN == 1'b0 ) 384 | begin 385 | axi_rdata <= 0; 386 | end 387 | else 388 | begin 389 | // When there is a valid read address (S_AXI_ARVALID) with 390 | // acceptance of read address by the slave (axi_arready), 391 | // output the read dada 392 | if (slv_reg_rden) 393 | begin 394 | axi_rdata <= reg_data_out; // register read data 395 | end 396 | end 397 | end 398 | 399 | // Add user logic here 400 | pwm_gen #(.WIDTH(C_S_AXI_DATA_WIDTH)) pwm ( 401 | .clk(S_AXI_ACLK), 402 | .rst(S_AXI_ARESETN), 403 | .load(load_reg), 404 | .compare(compare_reg), 405 | .control(control_reg), 406 | .pwm_out(pwm_out) 407 | ); 408 | // User logic ends 409 | 410 | endmodule 411 | --------------------------------------------------------------------------------