PWM Frequency Upper Limitation with Jetson.GPIO

Hi all,

I am trying to blink/control an LED strip (WS281x series) with Jetson.GPIO library. What I have been done so far is:

1. I have enabled pwm0 (pin-32) and pwm2 (pin-33) using a command:

sudo /opt/nvidia/jetson-io/jetson-io.py

2. After executing a python script, I could see that PWM is working.

python nano-whitish.py

import RPi.GPIO as GPIO
import time
output_pins = {
    'JETSON_XAVIER': 18,
    'JETSON_NANO': 33,
    'JETSON_NX': 33,
}

output_pin = output_pins.get(GPIO.model, None)
if output_pin is None:
    raise Exception('PWM not supported on this board')

def main():
    GPIO.setmode(GPIO.BOARD)
    GPIO.setup(output_pin, GPIO.OUT, initial=GPIO.HIGH)
    p = GPIO.PWM(output_pin, FREQUENCY) # set (Hz) frequency
    p.start(90) #set (%) duty-cycle

    print("PWM running. Press CTRL+C to exit.")
    try:
        while True:
            pass
    finally:
        p.stop()
        GPIO.cleanup()

if __name__ == '__main__':
    main()

If I would set FREQUENCY = 100000 (=100kHz), the period should be 10000 nano-seconds (=1/100000 seconds) (and it works-!).

sudo cat /sys/kernel/debug/pwm

platform/70110000.pwm, 1 PWM device
    pwm-0   (pwm-regulator       ): requested enabled period: 2500 ns duty: 0 ns polarity: normal

platform/7000a000.pwm, 4 PWM devices
    pwm-0   ((null)              ): period: 0 ns duty: 0 ns polarity: normal
    pwm-1   (pwm-regulator       ): requested period: 8000 ns duty: 1440 ns polarity: normal
    pwm-2   (sysfs               ): requested enabled period: 10000 ns duty: 9000 ns polarity: normal
    pwm-3   (pwm-fan             ): requested enabled period: 45334 ns duty: 0 ns polarity: normal

3. Our goal is to change a PWM Frequency (on pin-33 of J41) to 800kHz by using a method GPIO.PWM(output_pin, FREQUENCY).

If I would set FREQUENCY = 200000 (=200kHz) (and more than this value), I am facing some errors like this:

Traceback (most recent call last):
    File "nano_whitish.py", line 37, in <module>
        main()
    File "nano_whitish.py", line 25, in main
        p = GPIO.PWM(output_pin, 200000) # frequency
    File "/usr/lib/python2.7/dist-packages/Jetson/GPIO/gpio.py", line 616, in __init__
        self._reconfigure(frequency_hz, 0.0)
    File "/usr/lib/python2.7/dist-packages/Jetson/GPIO/gpio.py", line 654, in _reconfigure
        _set_pwm_period(self._ch_info, self._period_ns)
    File "/usr/lib/python2.7/dist-packages/Jetson/GPIO/gpio.py", line 247, in _set_pwm_period
        f.write(str(period_ns))
IOError: [Errno 22] Invalid argument

After some tests, I would think that there are some upper frequency limitation around 188000 Hz (=188kHz). More technically, if we put a bigger value than this, something prohibit my Jetson Nano to write a duty_cycle and period - as of like this process:

<open file ‘/sys/devices/7000a000.pwm/pwm/pwmchip0/pwm2/duty_cycle’, mode ‘w’ at 0x7f7a711030>

<open file ‘/sys/devices/7000a000.pwm/pwm/pwmchip0/pwm2/period’, mode ‘w’ at 0x7f7a711030>

Question1. Are there any technical report (for a Jetson Nano) regarding the PWM Frequency Range of Operation?

For a Jetson TX2, thanks to @enrique.ramirez, I could find an interesting table from:

Tegra X2 (Parker Series SoC) Technical Reference Manual” (Chapter 40)

For a Jetson Nano, I could not find any information from:

Tegra X1 SoC Technical Reference Manual
at the link → https://developer.nvidia.com/embedded/downloads

Hi,

You can only access pwmchip0 (@7000a000).
pwmchip4(@70110000) is not expected to be used by user.

“The Pulse Width Modulator controller is a four channel frequency divider whose pulse width varies. Each channel has a programmable frequency divider and a programmable pulse width generator”

As per the above statement, individual 4 channels of pwm@pwmchip0 can be used (based on availability) by exporting them.
i.e. echo <0/1/2/3> > /sys/class/pwm/pwmchip0/export

Please try with above and let us know what problem do you face on your configuration.

Thanks & Regards,
Sandipan

Hi @spatra,

Thank you for the explanations. Then, I would need to focus on pwmchip4(@70110000). :-)

For this trial, what I have been done is:

1. Rebooted the Jetson Nano.

sudo reboot

2. Checked the PWM status.

sudo cat /sys/kernel/debug/pwm

platform/7000a000.pwm, 4 PWM devices
    pwm-0   ((null)              ): period: 0 ns duty: 0 ns polarity: normal
    pwm-1   (pwm-regulator       ): requested period: 8000 ns duty: 1440 ns polarity: normal
    pwm-2   ((null)              ): period: 0 ns duty: 0 ns polarity: normal
    pwm-3   (pwm-fan             ): requested enabled period: 45334 ns duty: 0 ns polarity: normal

3. Execute the command.

echo 0 > /sys/class/pwm/pwmchip0/export

    (No messages)

echo 1 > /sys/class/pwm/pwmchip0/export

-bash: echo: write error: Device or resource busy

echo 2 > /sys/class/pwm/pwmchip0/export

    (No messages)

echo 3 > /sys/class/pwm/pwmchip0/export

-bash: echo: write error: Device or resource busy

4. Checked the PWM status.

sudo cat /sys/kernel/debug/pwm

platform/7000a000.pwm, 4 PWM devices
    pwm-0   (sysfs               ): requested period: 0 ns duty: 0 ns polarity: normal
    pwm-1   (pwm-regulator       ): requested period: 8000 ns duty: 1440 ns polarity: normal
    pwm-2   (sysfs               ): requested period: 0 ns duty: 0 ns polarity: normal
    pwm-3   (pwm-fan             ): requested enabled period: 45334 ns duty: 0 ns polarity: normal

Analysis

I could see some changes on the PWM status of pwm-0 and pwm-2.

Before the command, both were:

((null)              ): period: 0 ns duty: 0 ns polarity: normal

Now we could see that:

(sysfs               ): requested period: 0 ns duty: 0 ns polarity: normal

Thanks for the update.
Yes, that right with your observation.
Ideally while doing
echo <channel_no> > /sys/class/pwm/pwmchip0/export
No message means the channel is acquired successfully.

once the channel is acquired you can configure the period and duty width manually:
echo <period_val> > /sys/class/pwm/pwmchip0/pwmN/period
echo <duty_width> > /sys/class/pwm/pwmchip0/pwmN/duty_cycle

Where:
pwmN => pwm0 or pwm1 based on which channel was acquired
period_val=> perid in nano second
duty_width=> duty width in nano second

Also please make sure, there is an upper and lower limit value supported based on controller’s clock source and the frequency and pulse divisor values.

Hope this helps.

Thanks & Regards,
Sandipan

1 Like

Hi @spatra,

Thank you for the detailed descriptions. Now I am pretty sure that there is an upper limitation on the pwm-2 (pin-33). :-)

Before moving to the conclusion, I would love to share the minimal-test-procedures (for some other fellows) who want to investigate this issue.

Step0. Reboot a Jetson Nano.

sudo reboot

Step1. Enable pwm0 (pin-32) and pwm2 (pin-33) using a command:

sudo /opt/nvidia/jetson-io/jetson-io.py

image

Step2. Check the PWM status.

sudo cat /sys/kernel/debug/pwm

It will probably look like as follows:

platform/7000a000.pwm, 4 PWM devices
    pwm-0   ((null)              ): period: 0 ns duty: 0 ns polarity: normal
...
    pwm-2   ((null)              ): period: 0 ns duty: 0 ns polarity: normal
...

Step3. Export pwm-0 (pin-32) and pwm-2 (pin-33) using a command:

echo 0 > /sys/class/pwm/pwmchip0/export

echo 2 > /sys/class/pwm/pwmchip0/export

Step4. Check the PWM status.

sudo cat /sys/kernel/debug/pwm

For this time, it will probably look like as follows:

platform/7000a000.pwm, 4 PWM devices
    pwm-0   (sysfs               ): requested period: 0 ns duty: 0 ns polarity: normal
...
    pwm-2   (sysfs               ): requested period: 0 ns duty: 0 ns polarity: normal
...

Step5. Freely change the period and duty_cycle and apply it on the pin.

For example, if you want to set:
*Target: pwm-2 (pin-33 of J41)
*Frequency : 100 kHz
*Duty cycle: 20 %

Please note that the unit of period and duty_cycle is nano-seconds, you just need to type:

frequency 100 kHz (=100000 Hz)
period: 1/100000 seconds (=10000 nano-seconds)
duty_cycle: 2000 nano-seconds (20% of 10000 nano-seconds)

echo 10000 > /sys/class/pwm/pwmchip0/pwm2/period

echo 2000 > /sys/class/pwm/pwmchip0/pwm2/duty_cycle

echo 1 > /sys/class/pwm/pwmchip0/pwm2/enable

Step6. Investigate the PWM Frequency Upper Limitation.

Firstly, we would need to set the duty_cycle as 0 %.

echo 0 > /sys/class/pwm/pwmchip0/pwm2/duty_cycle

Secondly, we would need to decrease the period. For me, I could see an -bash: echo: write error: Invalid argument error between 5333 and 5334 nano-seconds of a period value.

period: 5334 nano-seconds
→ period: 5.334e-6 seconds
→ frequency: 187 kHz (=1/5.334e-6 Hz)

echo 5334 > /sys/class/pwm/pwmchip0/pwm2/period

    (No messages)

echo 5333 > /sys/class/pwm/pwmchip0/pwm2/period

-bash: echo: write error: Invalid argument error

Analysis

I would think that the PWM Frequency Upper Limit (on Jetson Nano) is around 187 kHz.

Yes, you are right. There is an upper limit rate and a lower limit rate that can be set as output frequency on the PWM controller.
The primary factors behind the limits are source clock rate and the divisor values of the controller.

Thanks & Regards,
Sandipan

1 Like

Hi @spatra,

Thank you for the swift supports. I will also make sure to investigate the source clock and the divisor values of the controller. :-)

Best regards,
Dongsin