blob: 2b18da74cecec8ee951f904931e4f8604cd61065 [file] [log] [blame]
// /******************************************************************************
// The MIT License (MIT)
// Copyright (c) 2019 Alchitry
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
// *****************************************************************************
// PWM: This module can be used to produce a PWM
// (pulse width modulated) output. That means it
// will output a continuous chain of pulses whose
// duty cycle (percent of time high) is
// proportional to the input value.
// When you want to set the PWM value, pull update
// high. The input value will then be saved and
// applied on the next pulse. This way you will
// not get glitches due to updates in the middle
// of a cycle. This is important when working
// with servos since they will see these glitches
// and twitch.
// You can set WIDTH to the resolution you need.
// If you need a specific period (i.e. for servos),
// you can use DIV to divide the clock in powers
// of 2 and TOP to set the max value.
// If TOP is 0, 2^WIDTH is used for TOP.
// Note that if WIDTH isn't big enough to store the
// TOP value, TOP will never be reached and 2^WIDTH
// will be used instead.
// The duty cycle is: TOP / value
// The period is: TOP / (CLK_FREQ / 2^DIV)
// For a servo, you typically want a frequency of
// 50Hz, or a period of 0.02 seconds. With a
// clock frequency of 50MHz, you should use
// TOP = 244, DIV = 12, and WIDTH = 8. If you
// want more resolution you can use
// TOP = 62500, DIV = 4, and WIDTH = 16.
// */
// module pwm (
// input clk, // clock
// input rst, // reset
// input value[WIDTH], // duty cycle value
// input update, // new value flag
// output pulse // PWM output
// ){
// .clk(clk) {
// .rst(rst) {
// counter ctr(#SIZE(WIDTH), #DIV(DIV), #TOP(TOP));
// dff curValue[WIDTH];
// dff needUpdate;
// }
// // nextValue doesn't need reset
// dff nextValue[WIDTH];
// }
// always {
// // if ctr.value is 0 and we need to update
// if (!|ctr.value && needUpdate.q) {
// curValue.d = nextValue.q; // set our new value
// needUpdate.d = 0; // don't need update now
// }
// // if value is valid
// if (update) {
// nextValue.d = value; // save it
// needUpdate.d = 1; // flag for update
// }
// // if the counter is less than the set
// // value output 1, otherwise output 0
// pulse = ctr.value < curValue.q;
// }
// }
module pwm #(
parameter WIDTH = 8, // resolution of PWM counter
parameter DIV = 16, // clock pre-scaler
parameter TOP = 0 // max value of counter
)(
input clk,
input rst,
input [WIDTH-1:0] compareValue,
output pwm
);
wire [WIDTH-1:0] counterValue;
counter #(.WIDTH(WIDTH), .DIV(DIV), .TOP(TOP)) ctr(.clk(clk), .rst(rst), .halt(1'b0), .value(counterValue));
reg [WIDTH-1:0] currentCompareValue;
assign pwm = counterValue < currentCompareValue;
always @(posedge clk) begin
if (counterValue == 0) currentCompareValue = compareValue;
end
endmodule