Sign in to follow this  
D@n

FPGA based PWM generation

Recommended Posts

 

@Piasa,

Back to this comment

On 9/16/2017 at 9:43 AM, Piasa said:

In this application, a signed value must be mapped into "number of cycles on per 2**N cycles".  This is an unsigned value independent of if the input is signed or unsigned.  The design assumes that a 1 output maps to +V and a 0 output maps to -V.  To output 0V, the design would need to output an equal number of 0's and 1's.  In this case, the number of cycles in the period is also related to the precision of the input.  That is not required in general.  However, for this case the operation to get from signed input sample to unsigned number of on-cycles is the same as the conversion from signed to offset binary.

I don't believe that testing of the algorithm on hardware quite agrees with the above description. The description might be correct but I don't believe that the implementation does exactly what it should be doing to agree with the description. Of course I've been wrong about other aspect of this topic.

Here is my test project. I do hope that anyone interested in this conversation will look it over and try it in simulation and on hardware if they can.

 

IPTEST_R1.zip

Share this post


Link to post
Share on other sites

Can you be more specific?

For example, differences in comparisons can affect the design.  IIRC the original blog post used "<=" and "<" in two different snippets.  The difference between comparisons is either a small offset or a phase inversion or both.

Share this post


Link to post
Share on other sites

@Piasa

Yes I can. My testbed had a logic error that stalled the waveform generation under certain conditions. Here is a better version of the project. It now includes the correct testbench and the control program has minor cosmetic improvements.

The general algorithm works with signed or unsigned inputs as you indicate. On the PmodAMP2 there is considerable distortion with tones above 5 KHz but this is not unexpected as the number of samples are low and the load impedance is fixed. For low tones under 1 KHz  the results are pretty reasonable (though not particularly for an audiophile's tastes).

IPTEST_R2.zip

Edited by zygot

Share this post


Link to post
Share on other sites

It should be noted for anyone wanting to replicate this algorithm as a general purpose application that the FPGA IO are not designed to drive highly reactive loads. The 200 ohm series resistor on the Nexys Video JA pins and the first 300 ohm resistor on the PmodAMP2 limit the current into and out of the IO pin. Still there is a considerable amount of capacitive loading. When using IO, and especially when using IO with a non-standard load,  you should do the analysis of power dissipation and voltages as seen by the IO pin.

I you are replicating the project on hardware you should be aware that my version of the IP uses only unsigned values and the msb should not be flipping. It does so as a default only to replicate D@n's code behaviour.

Share this post


Link to post
Share on other sites

@zygot,

Let's pause to straighten up our language for a moment, 'cause it looks like you and I have described the same thing with two different terms and arguing about nothing as a result.  If the input to a traditional PWM is unsigned, ranging from 0-65535, what should the duty cycle be for values 0x0000, 0x4000, 0x8000, 0xc000?  Shouldn't the duty cycle result be 0%, 25%, 50%, and 75% respectively?  This would then produce at a fictional audio port the most negative bias, a halfway negative bias, a zero bias, and a halfway to positive bias respectivvely.  Now, what's wrong with creating this duty cycle, and thus the bias, by simply comparing a counter to the input value, so that if the counter is less than the given value the number should be a one, but in all other respects a zero?  At least, that's what's being done in this beginners example on fpga4fun.com (top example on the page).

Of course, this ignores the off-by-one issue which has been brought up but which I wish to treat separately only after this part of the discussion is settled.

As for any RC response from the board's manufacture, wouldn't such a response from the board simply low-pass filter the FPGA pin output on the way to the analog amplifier?  Judging by the s transform given within the discussion on wikipedia, this certainly seems so.  And, if that's the case, wouldn't that just bring this digital waveform closer to being the audio waveform that it was intended to create?  You do remember your criticism from earlier that the audio chip was expecting an audio input, rather than a digital input, right?

Dan

Share this post


Link to post
Share on other sites

@D@n

 

3 hours ago, D@n said:

Shouldn't the duty cycle result be 0%, 25%, 50%, and 75% respectively?  This would then produce at a fictional audio port the most negative bias, a halfway negative bias, a zero bias, and a halfway to positive bias respectivvely.  Now, what's wrong with creating this duty cycle, and thus the bias, by simply comparing a counter to the input value, so that if the counter is less than the given value the number should be a one, but in all other respects a zero?

As to a PWM , as long as the counter over-flow interval is the same as the input data sample period I agree with your logic. You could also use an up-down counter and center your PWM around the mid-point of the sample period.

3 hours ago, D@n said:

You do remember your criticism from earlier that the audio chip was expecting an audio input, rather than a digital input, right?

Yes, I do remember that criticism. It turns out that I hadn't properly understood the reconstruction filter characteristics. I had always expected that there would be some sort of analog representation of a waveform... just not nearly as good as it is. The SSM2237 still needs an analog input ( preferably driven differentially ). It also expects the analog common-mode input to be between 1V and Vdd-1 V ( for the PmodAMP2 this is 1V-2.3V ). The  Sigma-Delta modulator in the SSM2237 is clocked at about 6 MHz which probably helps smooth the input. As to how well this all works you can download the last version IPTEST_R2 and see for yourself. Assessing the reconstructed analog input to the SSM2237 will be hard to do without a good scope. I may try using some well known PC audio tools to see if it's reasonable to make an assessment of the amplifier output. I suggest that you try really low tones < 200 Hz and really high tones above 5 KHz to see it in action. Really low tones should be quite accurate as there are a lot of samples per sample period. Lastly, you should change the sample scale factor to see low signal levels being reconstructed.

One way to look at the application is to think of a waveform putting energy into a an RC load and removing it proportionally to the duty cycle of the digital waveform. A 50% duty waveform should have no net exchange of energy.  It's a bit more complex than that and as you saw in your reference above the time constant for putting energy into and out of a reactive load is not symmetric. But, counter to my instincts it all works better than I thought it would. That's due to the design of the reconstruction filter. It's important to understand that the analog inputs on SSM2237 on the PmodAMP2 are AC-coupled.

The only argument that I see us as having is about binary representation of values. As I understand it the method that maps input values to pulse density waveforms effectively removes the sign bit. I still have some playing around to do on that regard.

I have not yet made a plan for analyzing the SSM2237 output quality.

 

 

Edited by zygot

Share this post


Link to post
Share on other sites

Oh I forgot that I wanted to mention to the casual observers that if nothing else the project source shows how to create waveforms in Python, upload them into an  FPGA block ram memory and have a waveform generator that runs at a particular sample rate. Python lists are not ideal containers for arrays of things but it does work on Windows and Linux and supports the serial port nicely. If I were using the DPTI interface I'd use C and be a happier camper ( there are a few things about Python that I don't like but it doesn't stop me from using it extensively ). Even if you don't care about PWMs, PDM, the PmodAMP2 or binary numbers there might be something worth slogging through all the excess verbage that Piasa finds irritating. Oh, and don't forget about simulation and verification...

Edited by zygot

Share this post


Link to post
Share on other sites

The system is AC coupled, so no dc output.  You can directly use a 16b unsigned value if you consider yourself to have a 16b unsigned input.  The DC component will be removed.  If you consider yourself to have a 16b signed 2's complement input, you would need to invert the msb.  Otherwise -1 would map to ~100% duty ratio, and -32k would map to 50%.  (0 would map to 0% and +32k would map to ~50%).

Inverting the msb has the effect of converting the 16b signed value into a 16b unsigned value that is equal to x + 32*1024.  -1 maps to ~50%, -32k maps to 0%, 0 maps to 50% and 32k maps to ~100%.

This design maximizes the number of transitions.  Each transition has a cost in terms of parasitics in the circuit.  The goal of maximizing transitions is to move more energy to higher frequencies that the RCRC filter can reject more easily -- the goal being to reduce ripple within a pwm period. 

There are other options. in terms of arranging the bits.  You can also get 2x rate PWM signals or 4x rate PWM for example.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this