For an Assignment for university my class had to write a verilog program to produce a PWM output derived from the ASCII Value of our initials which can drive a servo.
We were provided a sample verilog source from fpgas for fun, which was clear as mud, but did produce the required output. All examples a could find online where for a simpler PWM output, ie with a period the same size as the largest value of the pulse. Which is more suited for constructing a analog output.
So I have gone through the source provided and found what i considered an acceptable explanation, from which I taught a several of my classmates who where struggling. I though I would put it up here for everyone to see, I hope it is of some use to someone. And apologies for poorly drawn graphs.
For producing a Servo signal we need pulses between 1ms and 2ms with a frequency of between 50Hz - 100Hz
As we want to module to accept a 8-bit number to determine the pulse width, in the case of my assignment an ASCII Character, we need to divide the variation by the number of steps you can have in a 8-bit value.
1ms/256 steps = 3.9us per step
Therefore we need to generate a clock with period 3.9us from which we will work from to produce the outputs.
For this we take the frequency of the input clock, in this case 50MHz, multiply it by the time variation and divide by the number of steps in that variation.
(50e^(6) x 1e^(-3))/256 ~= 195
This is the value we will use to generate a saw tooth wave which will allow us to generate the clock of period 3.9us
A counter will be incremented on each 50MHZ clock edge, when this counter reaches 195; we generate a pulse on clkTick and reset the counter. This looping is what will generate the 3.9us clock
To generate the period between the pulses we will use a second saw tooth counter which will use the 3.9us clock to increment it.
To calculate the size of this counter we need to use the desired period of the output
log2(output period/clock period) = log2(16ms/3.9us) = log2(4109) ~= 12-bits
16ms was used as it gives a value closest to a whole bit. This counter will be incremented every 3.9us clock pulse so we have approximately 16ms between pulses, and will be allowed to roll over to zero when it maximum value is reached.
To generate the output pulse into we first need to take the input 8-bit and add a 4-bit binary 1 onto the front, this is done using condensation operator (can't remember actual name)
using;
{4'b0001, Input}
this produces a 12-bit output with a minimum value of 256 and max of 511, which when multiplied by 3.9us give us 1ms and 2ms respectively. To do this in the code, we set the output high when this number is less than the current value of the 12-bit counter.
So by giving the input a value between 0 and 255 we can produce servo pulses between 1ms and 2ms with and variation of 3.9us.
I have included below my verilog source for my assignment, which includes some extra case statements for changing between upper and lower case, and for counting the output pulse to change the value after two. I will also add the original source from fpga for fun, and you will see what i mean by mud, no disrespect to the author.
I hope someone find this useful, or just interesting, please let me know your thought in the comments
Top Comments