« Close

Datasheets and User Guides

App Notes

Software & Driver

 

13.1.2 PWM Out

Capable DIO: DIO0, DIO2, DIO3, DIO4, DIO5 (aka FIO0, FIO2, FIO3, FIO4, FIO5)

Requires Clock Source: Yes

Index: 0


PWM Out will generate a pulse width modulated wave form.


Operation:
PWM output will set the DIO high and low relative to the clock source's count. When the count is zero the DIO line will be set high. When the count matches Config A the line will be set low. Therefore Config A is used to control the duty cycle and the resolution is equal to the roll value.

Clock#Frequency = CoreFrequency / DIO_EF_CLOCK#_DIVISOR   // typically 80M/Divisor
PWMFrequency = Clock#Frequency / DIO_EF_CLOCK#_ROLL_VALUE
DutyCycle% = 100 * DIO#_EF_CONFIG_A / DIO_EF_CLOCK#_ROLL_VALUE

For the common case of CoreFrequency = 80 MHz we can rewrite output frequency as:

PWMFrequency = 80M / (DIO_EF_CLOCK#_DIVISOR * DIO_EF_CLOCK#_ROLL_VALUE)
 

... and for 50% duty-cycle (square wave) simply set:

DIO#_EF_CONFIG_A = DIO_EF_CLOCK#_ROLL_VALUE / 2


CoreFrequency is always 80 MHz at this time, but in the future some low-power operational modes might result in different core frequencies.  The valid values for DIO_EF_CLOCK#_DIVISOR are 1, 2, 4, 8, 16, 32, 64, or 256, and a value of 0 (default) equates to a divisor of 1.  For more details about Clock#Frequency and DIO_EF_CLOCK#_DIVISOR, see the DIO-EF Clock Source section.

PWM Out is capable of glitch-free updates in most situations. A glitch-free update means that the PWM will finish the current period consisting of the high time then the low time before loading the new value. The next period will then have the new duty cycle. This is true for all cases except zero. When setting the duty cycle to zero the line will be set low regardless of the current position. This means that a single high pulse with duration between zero and the previous high time can be output before the line goes low.


Configure:
DIO#_EF_ENABLE: 0 = Disable, 1 = Enable
DIO#_EF_INDEX: 0
DIO#_EF_OPTIONS: Bits 0-2 specify which clock source to use ... 000 for Clock0, 001 for Clock1, and 010 for Clock2. All other bits reserved and should be set to 0.
DIO#_EF_CONFIG_A: When the specified clocks source's count matches this value the line will transition from high to low.
DIO#_EF_CONFIG_B: Not used.
DIO#_EF_CONFIG_C: Not used.
DIO#_EF_CONFIG_D: Not used.


Update:
The duty cycle can be updated at any time. To update, write the new value to DIO#_EF_CONFIG_A. The new value will not be used until the clock source rolls to zero. This means that at the end of the current period the new value will be loaded resulting in a glitch-free transition.


Read:
No information is returned by PWM Out


Reset:
Reset has no affect on this feature.


Example:
Generate a 10 kHz PWM starting at 25% DC.
First configure the clock source.  The higher the roll value the greater the duty cycle resolution will be. For the highest resolution, we want to maximize the roll value, so use the smallest clock divisor that will not result in a roll value greater than the clock source's maximum (32-bits or 16-bits). With a divisor of 1 the roll value will be 8000: 80 MHz / (1 * 8000) = 10 kHz. Now set the registers accordingly:

DIO_EF_CLOCK0_ENABLE = 0
DIO_EF_CLOCK0_DIVISOR = 1
DIO_EF_CLOCK0_ROLL_VALUE = 8000
DIO_EF_CLOCK0_ENABLE = 1

Once the clock source is configured we can use the roll value to calculate Config_A: DC = 25% = 100 * Config_A / 8000. So Config_A = 2000. Now the PWM can be turned on by writing the proper registers:

DIO0_EF_ENABLE = 0
DIO0_EF_INDEX = 0
DIO0_EF_CONFIG_A = 2000
DIO0_EF_ENABLE = 1

T7 PWM Output Config

Configure settings to generate LJM pseudocode

Desired FIO Channel:
Desired Frequency (Hz):
Desired Duty Cycle (%):
Select Clock Source:
Select Clock Divisor:

Pseudocode:

        // Compiling Code, if code doesn't appear please enable JavaScript or
        // try using an up to date version of Google Chrome/Mozilla Firefox.
        // Ideally an example of how to configure the T7's PWM functionality
        // will appear here.
        
Information regarding the functions used in this example are available on LJM's function reference page.

Support - General Psuedocode Compiler

Support - T7 PWM Output Config Script

11 comments

Can you please clarify this line: "DIO#_EF_OPTIONS: Bits 0-2 specify which clock source to use. All other bits reserved (write 0)."

You imply that it is possible to use a bitmask to specify which clock to use, but then you instruct to write 0. This is confusing and contradictive. 

For example, I want to set a PWM on FIO0 to use Clock1, how would I do that?

I added information above that I believe makes this clearer.  For FIO0 to use Clock1, you write DIO#_EF_OPTIONS = 1.

I am having some issues with using PWM outputs. I am using them to drive an LED (through a BJT circuit). When I write 0 to the Config_A register, instead of the line going low for the duration of the period, it goes high. So I am unable to fully turn off my LED because I cannot output a PWM signal with a duty cycle of zero. Any help or advice would be appreciated. 

We will take a closer look, but it might not be possible to change that behavior.  In the meantime, you can do something like:

DIO0_EF_ENABLE = 0  //Disable EF on the line.
DIO0 = 0  //Set line to output-low.

The following test works for me:

 

Set a source clock to 1 kHz and 10000 counts:

DIO_EF_CLOCK#_ENABLE = 0

DIO_EF_CLOCK#_DIVISOR = 8

DIO_EF_CLOCK#_ROLL_VALUE = 10000

DIO_EF_CLOCK#_ENABLE = 1

 

Set to 50%:

DIO#_EF_ENABLE = 0

DIO#_EF_TYPE = 0

DIO#_EF_VALUE_A = 5000

DIO#_EF_ENABLE = 1

 

Set to 100%:

DIO#_EF_VALUE_A = 10000

 

Set to 0%:

DIO#_EF_VALUE_A = 0

 

Make sure your firmware version is up to date: http://labjack.com/support/firmware/t7

I implemented your sample test code and experimented some more. I have figured out that when I set the initial value to zero, before enabling port:

DIO#_EF_ENABLE = 0

DIO#_EF_TYPE = 0

DIO#_EF_VALUE_A = 0

DIO#_EF_ENABLE = 1

and then set VALUE_A to dim my LED on and off, any time I set VALUE_A to zero again, the line will go high. 

However, if the initial value that I set is non zero:

DIO#_EF_ENABLE = 0

DIO#_EF_TYPE = 0

DIO#_EF_VALUE_A = 5000

DIO#_EF_ENABLE = 1

Then I can later write VALUE_A = 0 and the line will go low as expected. 

Thank you for finding the specific case that causes a problem. I submitted a bug report so this should be looked at soon.

alexmead's picture

I'm trying to setup a PWM to control a basic analog servo motor. I desire a signal with 50 Hz (20 ms wave length), and duty cycles between 5% (1 ms High, 19 ms low) and 10% (2 ms High, 18 ms Low).

I am able to configure and set up my T7-Pro over ethernet using a Python script with the appropriately modified code for python from the above sections "// Configure Clock Registers:" and "// Configure EF Channel Registers:" and move the servo to the initial setting. Thus, I know I'm getting the setup going at least somewhat correctly. 

However, when I go to change the duty cycle to another number by updating "DIO0_EF_CONFIG_A" (  Python code: ljm.eWriteName(handle, "DIO0_EF_CONFIG_A", 120000)  )  I can only get about 1 or 2 updates to DIO0_EF_CONFIG_A before I get a  "LJM library error code 1269 LJME_INVALID_LENGTH"  

The behavior is nondeterministic, as in sometimes I can update DIO0_EF_CONFIG_A once,  sometimes twice, but I can't seem to do it more than that. I've updated the firmware to the latest,  1.0199, with no improvement if this has any meaning.

Any help would be appreciated. Thanks.

alexmead's picture

By the way, I'm using a MacBook Pro, running Mac OS X, 10.11 (El Capitan) operating system.  I know this information can be helpful sometimes.

LabJack Support's picture

LJM 1.1301 (available for download in the beta installer as of this writing) may fix the LJME_INVALID_LENGTH issue you're experiencing. We were unable to reproduce the issue, however, so please do let us know if the issue is not fixed - you can email your code to [email protected] if that's easy for you.

LabJack Support's picture

LJME_INVALID_LENGTH may indicate that a length parameter is incorrect. Alternately, there may be a bug in LJM. While we haven't been able to reproduce this yet, we'll continue to investigate. In the meantime, make sure your LJM and your LJM Python versions are up to date.