Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support for PWM in 4.1+ #108

Merged
merged 27 commits into from
Aug 18, 2016
Merged

Support for PWM in 4.1+ #108

merged 27 commits into from
Aug 18, 2016

Conversation

MatthewWest
Copy link
Contributor

@MatthewWest MatthewWest commented Aug 8, 2016

This patch does several things. Principally, it:

  • Adds support for the changed PWM sysfs interface in Linux 4.1+
  • Updates tests to reflect changes in Linux 4.1+
  • Changes return conventions, from nonzero as success to the more conventional nonzero as failure. Also switch to using an enum error type specific to the library.
  • Use the new, preferred method of using the capemanager - using the beaglebone-universal-io library.
  • Replace home-rolled build_path implementation with a call to glob, the system library.
  • Include guards in all header files to handle double-includes

Numerous parts of the code were modified, as it was necessary in order to implement the different error handling convention.

One known limitation of the change is that the disable section does not unexport PWMs, it merely disables them. That means that the hardware is still powered (and probably clocked), it simply isn't putting out an output.

Tests are all passing on both Python 2 and Python 3 on Linux kernel 4.1.15-bone11. I haven't been able to test on 3.8 yet (working on it).

@MatthewWest
Copy link
Contributor Author

Addresses #103

@pdp7
Copy link
Collaborator

pdp7 commented Aug 9, 2016

@MatthewWest: awesome! I'll try it out with set of Debian images that I test with and post my results here.

@pdp7
Copy link
Collaborator

pdp7 commented Aug 10, 2016

@MatthewWest I installed Adafruit_BBIO from your repo:
https://github.com/MatthewWest/adafruit-beaglebone-io-python/

onto the Debian Jessie 8.5 image with Linux 4.4:

root@beaglebone:~/pr-matthew-west/adafruit-beaglebone-io-python# cat /etc/debian_version 
8.5
root@beaglebone:~/pr-matthew-west/adafruit-beaglebone-io-python# uname -a
Linux beaglebone 4.4.11-ti-r29 #1 SMP Fri May 27 22:58:36 UTC 2016 armv7l GNU/Linux
root@beaglebone:~/pr-matthew-west/adafruit-beaglebone-io-python# cat /etc/dogtag 
BeagleBoard.org Debian Image 2016-06-05

test/test_pwm_setup.py encounters several AssertionErrors:

E       assert <function exists at 0xb6cf7d30>('/sys/devices/platform/ocp/48302000.epwmss/48302200.ehrpwm/pwm/pwmchip2/pwm0')
E       assert <function exists at 0xb6cf7d30>('/sys/devices/platform/ocp/48302000.epwmss/48302200.ehrpwm/pwm/pwmchip2/pwm0')
E       assert <function exists at 0xb6cf7d30>('/sys/devices/platform/ocp/48302000.epwmss/48302200.ehrpwm/pwm/pwmchip2/pwm0')
E       assert <function exists at 0xb6cf7d30>('/sys/devices/platform/ocp/48302000.epwmss/48302200.ehrpwm/pwm/pwmchip2/pwm0')
E       assert <function exists at 0xb6cf7d30>('/sys/devices/platform/ocp/48302000.epwmss/48302200.ehrpwm/pwm/pwmchip2/pwm0')

Full test results with full error messages:
https://gist.github.com/pdp7/86919d099afb3c5394945f060fabb959

The issue seems to be that this dir exists:

# ls /sys/devices/platform/ocp/48302000.epwmss/
48302180.eqep  48302200.pwm  driver  driver_override  modalias  of_node  power  subsystem  uevent

but the desired subdir does not:

# ls /sys/devices/platform/ocp/48302000.epwmss/48302200.ehrpwm
ls: cannot access /sys/devices/platform/ocp/48302000.epwmss/48302200.ehrpwm: No such file or directory

@pdp7
Copy link
Collaborator

pdp7 commented Aug 10, 2016

For Debian 7.11 with Linux 3.8.13:

debian@beaglebone:~/adafruit-beaglebone-io-python$ uname -a
Linux beaglebone 3.8.13-bone80 #1 SMP Wed Jun 15 17:03:55 UTC 2016 armv7l GNU/Linux
debian@beaglebone:~/adafruit-beaglebone-io-python$ cat /etc/debian_version 
7.11
debian@beaglebone:~/adafruit-beaglebone-io-python$ cat /etc/dogtag 
BeagleBoard.org Debian Image 2016-06-15

Errors from py.test:

>       ADC.setup()
E       RuntimeError: Unable to setup ADC system. Possible causes are: 
E         - A cape with a conflicting pin mapping is loaded 
E         - A device tree object is loaded that uses the same name for a fragment: helper
>       ADC.setup()
E       RuntimeError: Unable to setup ADC system. Possible causes are: 
E         - A cape with a conflicting pin mapping is loaded 
E         - A device tree object is loaded that uses the same name for a fragment: helper
>       ADC.setup()
E       RuntimeError: Unable to setup ADC system. Possible causes are: 
E         - A cape with a conflicting pin mapping is loaded 
E         - A device tree object is loaded that uses the same name for a fragment: helper
>       ADC.setup()
E       RuntimeError: Unable to setup ADC system. Possible causes are: 
E         - A cape with a conflicting pin mapping is loaded 
E         - A device tree object is loaded that uses the same name for a fragment: helper
>       PWM.start("P9_14", 0)
E       RuntimeError: Unknown error
>       PWM.start("P9_14", 0, 2000, 1)
E       RuntimeError: Unknown error
>       PWM.start("P9_14", 0, 2000)
E       RuntimeError: Unknown error
>       PWM.start("P9_14", 0, 2000, 0)
E       RuntimeError: Unknown error
>       PWM.start("P9_14", 0)
E       RuntimeError: Unknown error
>       PWM.start("P9_14", 100)
E       RuntimeError: Unknown error
>       PWM.start("P9_14", 0)
E       RuntimeError: Unknown error
>       PWM.start("P9_14", 0)
E       RuntimeError: Unknown error
>       PWM.start("P9_14", 0)
E       RuntimeError: Unknown error
>       PWM.start("P9_14", 0)
E       RuntimeError: Unknown error
>       PWM.start("P9_14", 0)
E       RuntimeError: Unknown error
>       PWM.start("P9_14", 0)
E       RuntimeError: Unknown error
>       SPI(1,1)
E       IOError: [Errno 2] No such file or directory
>           UART.setup("UART1")
E           RuntimeError: Unable to export UART channel.
>           UART.setup("UART1")
E           RuntimeError: Unable to export UART channel.

Full listing of errors:
https://gist.github.com/pdp7/c5344c1a71f33b6b7f793b9723dd3223

@pdp7
Copy link
Collaborator

pdp7 commented Aug 10, 2016

I installed the linux-image-4.1.29-bone22 package on the Debian 7.11 image:

debian@beaglebone:~$ uname -a
Linux beaglebone 4.1.29-bone22 #1 Fri Aug 5 15:16:03 UTC 2016 armv7l GNU/Linux
debian@beaglebone:~$ cat /etc/dogtag 
BeagleBoard.org Debian Image 2016-06-15
debian@beaglebone:~$ cat /etc/debian_version 
7.11

Errors from py.test:
https://gist.github.com/pdp7/c5344c1a71f33b6b7f793b9723dd3223#gistcomment-1846060

@pdp7
Copy link
Collaborator

pdp7 commented Aug 10, 2016

For Debian 8.3 image with 4.1 kernel:

debian@beaglebone:~/adafruit-beaglebone-io-python$ cat /etc/dogtag 
BeagleBoard.org Debian Image 2016-01-24
debian@beaglebone:~/adafruit-beaglebone-io-python$ uname -a
Linux beaglebone 4.1.15-ti-rt-r43 #1 SMP PREEMPT RT Thu Jan 21 20:13:58 UTC 2016 armv7l GNU/Linux
debian@beaglebone:~/adafruit-beaglebone-io-python$ cat /etc/debian_version 
8.3

py.test errors messages for pwm:
https://gist.github.com/pdp7/aad85478890f37ac7a19538e9702f69c

@MatthewWest
Copy link
Contributor Author

@pdp7 Just submitted a pull request to fix the error with Debian 8.5, kernel 4.4. It was a simple case where the exact path can vary in the ocp directory between .ehrpwm and .pwm. As far as the other errors, could you run them again with strace?

sudo strace -o trace.txt py.test

I've found that's the best (only?) way to debug the code, seeing what files it attempts to open. If you can't / don't have time to do that, let me know - I might be able to make images for all the different versions and test them that way.

@MatthewWest
Copy link
Contributor Author

Should we include any necessary device trees in this library and install them? The 4.1+ code requires that the user have one of the universal device trees loaded:

    // Make sure that one of the universal capes is loaded
    if (!( device_tree_loaded("cape-univ-audio") // from cdsteinkuehler/beaglebone-universal-io
        || device_tree_loaded("cape-univ-emmc")  // ""
        || device_tree_loaded("cape-univ-hdmi")  // ""
        || device_tree_loaded("cape-universal")  // ""
        || device_tree_loaded("cape-universala") // ""
        || device_tree_loaded("cape-universaln") // ""
        || device_tree_loaded("univ-all")        // from latest BeagleBone Debian 8 images
        || device_tree_loaded("univ-bbgw")       // ""
        || device_tree_loaded("univ-emmc")       // ""
        || device_tree_loaded("univ-hdmi")       // ""
        || device_tree_loaded("univ-nhdmi")))    // ""
    {
        return BBIO_CAPE;
    }

These images, from the beaglebone-universal-io project, are included on new BeagleBone images (from here), but on older images which have been upgraded to include the new kernel, they might be missing. This would also require us to switch tacks and use these overlays for the other functionality as well.

From the beaglebone-universal-io project:

This project is a series of four overlay files, designed to work with
the BeagleBone Black:

  • cape-universal Exports all pins not used by HDMIN and eMMC (including audio)
  • cape-universaln Exports all pins not used by HDMI and eMMC (no audio pins are exported)
  • cape-univ-emmc Exports pins used by eMMC, load if eMMC is disabled
  • cape-univ-hdmi Exports pins used by HDMI video, load if HDMI is disabled
  • cape-univ-audio Exports pins used by HDMI audio

So the universal capes are not compatible with the approach used by the UART, SPI, and GPIO sections of this library.

@MatthewWest
Copy link
Contributor Author

I've been doing a bit of looking into how other people are handling the differences between kernels 3.8 and 4.1, and it looks like we'll probably have to support both - if the universal cape is present, use it. If not (and possibly other capes are present which would conflict with which the universal cape conflicts), use a custom overlay strategy. That's at least the conclusion that the folks over at PyBBIO came to.

@pdp7
Copy link
Collaborator

pdp7 commented Aug 10, 2016

@MatthewWest Thanks for updating the test.

I've updated the results for Debian 8.3 image with Linux 4.1.15-ti-rt-r43:
https://gist.github.com/pdp7/aad85478890f37ac7a19538e9702f69c

I included strace log for file operations on /sys/devices. Relevant listing of directories:

debian@beaglebone:~/adafruit-beaglebone-io-python$ ls /sys/devices/platform/ocp/48302000.epwmss/48302200.ehrpwm/pwm/pwmchip2/pwm0
ls: cannot access /sys/devices/platform/ocp/48302000.epwmss/48302200.ehrpwm/pwm/pwmchip2/pwm0: No such file or directory
debian@beaglebone:~/adafruit-beaglebone-io-python$ ls /sys/devices/platform/ocp/48302000.epwmss/48302200.ehrpwm/
\driver  driver_override  modalias  of_node  power  pwm  subsystem  uevent
debian@beaglebone:~/adafruit-beaglebone-io-python$ ls /sys/devices/platform/ocp/48302000.epwmss/48302200.ehrpwm/pwm/
pwmchip4
debian@beaglebone:~/adafruit-beaglebone-io-python$ ls /sys/devices/platform/ocp/48302000.epwmss/48302200.ehrpwm/pwm/pwmchip4/
device  export  npwm  power  pwm0  subsystem  uevent  unexport
debian@beaglebone:~/adafruit-beaglebone-io-python$ ls /sys/devices/platform/ocp/48302000.epwmss/48302200.ehrpwm/pwm/pwmchip4/pwm0/
duty_cycle  enable  period  polarity  power  uevent

I should be able to swap in the different SD cards later and run the updated test on Debian 7.11 with Linux 3.8.13 and Debian 8.5 with Linux 4.4.

@ladyada ladyada merged commit 165301f into adafruit:master Aug 18, 2016
@pdp7
Copy link
Collaborator

pdp7 commented Aug 20, 2016

Thanks @ladyada for merging. And thanks very much to @MatthewWest!!

@Dark-Guan
Copy link

I use Linux kamikaze 4.1.6-bone15 #1 Tue Aug 18 12:45:47 UTC 2015 armv7l GNU/Linux

File "testHardPwm.py", line 6, in
PWM.start("P9_14", 50 , 2000, 1)
RuntimeError: Problem with a sysfs file

When I run testing demo, the error I get above.
It's nice that if some body can tell me the problem,thanks!

@MatthewWest
Copy link
Contributor Author

@Dark-Guan My guess is that the beaglebone-universal-io capes are not present. Can you list results of the following commands:

  • cat /sys/devices/platform/bone_capemgr/slots
  • ls /sys/devices/platform/ocp/
  • ls /lib/firmware

Try those first. We may have to resort to strace if they don't work, but that's a bit more tedious. Try those, and hopefully we can figure out what's happening

@Dark-Guan
Copy link

@MatthewWest Thanks for your reponse.

root@kamikaze:# cat /sys/devices/platform/bone_capemgr/slots
0: PF---- -1
1: PF---- -1
2: PF---- -1
3: PF---- -1
4: P-O-L- 0 Override Board Name,00A0,Override Manuf,cape-universal
root@kamikaze:
# ls /sys/devices/platform/ocp/
40300000.ocmcram 4804c000.gpio 48310000.rng ocp:P8_15_pinmux ocp:P9_24_pinmux
44d00000.wkup_m3 48060000.mmc 49000000.edma ocp:P8_16_pinmux ocp:P9_26_pinmux
44e07000.gpio 480c8000.mailbox 4a100000.ethernet ocp:P8_17_pinmux ocp:P9_27_pinmux
44e09000.serial 480ca000.spinlock 4a300000.pruss ocp:P8_18_pinmux ocp:P9_30_pinmux
44e0b000.i2c 4819c000.i2c 53100000.sham ocp:P8_19_pinmux ocp:P9_41_pinmux
44e35000.wdt 481a0000.spi 53500000.aes ocp:P8_26_pinmux ocp:P9_42_pinmux
44e3e000.rtc 481a8000.serial 56000000.sgx ocp:P9_11_pinmux ocp:P9_91_pinmux
47400000.usb 481ac000.gpio driver_override ocp:P9_12_pinmux ocp:P9_92_pinmux
48022000.serial 481ae000.gpio modalias ocp:P9_13_pinmux ocp:cape-universal
48024000.serial 481cc000.can ocp:P8_07_pinmux ocp:P9_14_pinmux ocp:l4_wkup@44c00000
4802a000.i2c 481d0000.can ocp:P8_08_pinmux ocp:P9_15_pinmux of_node
48030000.spi 481d8000.mmc ocp:P8_09_pinmux ocp:P9_16_pinmux power
48042000.timer 48200000.interrupt-controller ocp:P8_10_pinmux ocp:P9_17_pinmux subsystem
48044000.timer 48300000.epwmss ocp:P8_11_pinmux ocp:P9_18_pinmux uevent
48046000.timer 48302000.epwmss ocp:P8_12_pinmux ocp:P9_21_pinmux
48048000.timer 48304000.epwmss ocp:P8_13_pinmux ocp:P9_22_pinmux
4804a000.timer 4830e000.lcdc ocp:P8_14_pinmux ocp:P9_23_pinmux
root@kamikaze:~# ls /lib/firmware
ADAFRUIT-SPI0-00A0.dtbo BB-BONE-SERL-03-00A1.dtbo GHI-LCD-00A0.dtbo carl9170-1.fw
ADAFRUIT-SPI1-00A0.dtbo BB-BONE-WL1837-00A0.dtbo LICENCE.atheros_firmware dev-USB-PWR-CTL-00A1.dtbo
ADAFRUIT-UART1-00A0.dtbo BB-BONE-WTHR-01-00B0.dtbo LICENCE.broadcom_bcm43xx dra7-ipu2-fw.xem4
ADAFRUIT-UART2-00A0.dtbo BB-CAN1-00A0.dtbo LICENCE.rtlwifi_firmware.txt dra7xx-m4-ipu2.xem4
ADAFRUIT-UART4-00A0.dtbo BB-CAPE-DISP-CT4-00A0.dtbo LICENCE.ti-connectivity htc_7010.fw
ADAFRUIT-UART5-00A0.dtbo BB-I2C1-00A0.dtbo NL-AB-BBBC-00D0.dtbo htc_9271.fw
BB-ADC-00A0.dtbo BB-I2C1-PCA9685-00A0.dtbo RTL8192E mt7601u.bin
BB-BBBMINI-00A0.dtbo BB-I2C2-0A00.dtbo am33xx_pwm-00A0.dtbo rt2561.bin
BB-BONE-AUDI-02-00A0.dtbo BB-PWM0-00A0.dtbo ar3k rt2561s.bin
BB-BONE-BACONE-00A0.dtbo BB-PWM1-00A0.dtbo ar5523.bin rt2661.bin
BB-BONE-BBH-00A1.dtbo BB-PWM2-00A0.dtbo ar7010.fw rt2860.bin
BB-BONE-BBH-00A2.dtbo BB-RELAY-4PORT-00A0.dtbo ar7010_1_1.fw rt2870.bin
BB-BONE-CRAMPS-00B4.dtbo BB-RTC-01-00A0.dtbo ar9271.fw rt3070.bin
BB-BONE-CRAMPS-00B5.dtbo BB-SPI0-MCP3008-00A0.dtbo ath10k rt3071.bin
BB-BONE-CRYPTO-00A0.dtbo BB-SPIDEV0-00A0.dtbo ath3k-1.fw rt3090.bin
BB-BONE-DVID-01-00A3.dtbo BB-SPIDEV1-00A0.dtbo ath6k rt3290.bin
BB-BONE-LCD3-01-00A2.dtbo BB-SPIDEV1A1-00A0.dtbo ath9k_htc rt73.bin
BB-BONE-LCD4-01-00A1.dtbo BB-UART1-00A0.dtbo bone_eqep0-00A0.dtbo rtl_bt
BB-BONE-LCD5-01-00A1.dtbo BB-UART2-00A0.dtbo bone_eqep1-00A0.dtbo rtl_nic
BB-BONE-LCD7-01-00A1.dtbo BB-UART2-RTSCTS-00A0.dtbo bone_eqep2-00A0.dtbo rtlwifi
BB-BONE-LCD7-01-00A2.dtbo BB-UART3-00A0.dtbo bone_eqep2b-00A0.dtbo ti-connectivity
BB-BONE-LCD7-01-00A3.dtbo BB-UART4-00A0.dtbo brcm uio_pruss_enable-00A0.dtbo
BB-BONE-REACH-00A0.dtbo BB-UART4-RS485-00A0.dtbo cape-CBB-Serial-r01.dtbo univ-all-00A0.dtbo
BB-BONE-REPLICAP-00A4.dtbo BB-UART5-00A0.dtbo cape-bone-ibb-00A0.dtbo univ-bbgw-00A0.dtbo
BB-BONE-REPLICAP-00B1.dtbo BB-VIEW-LCD4-01-00A0.dtbo cape-univ-audio-00A0.dtbo univ-emmc-00A0.dtbo
BB-BONE-REPLICAP-00B2.dtbo BB-VIEW-LCD7-01-00A0.dtbo cape-univ-emmc-00A0.dtbo univ-hdmi-00A0.dtbo
BB-BONE-REPLICAP-00B3.dtbo BB-W1-P9.12-00A0.dtbo cape-univ-hdmi-00A0.dtbo univ-nhdmi-00A0.dtbo
BB-BONE-REPLICAP-00B4.dtbo CAP-BONE-IIO-00A0.dtbo cape-universal-00A0.dtbo zd1211
BB-BONE-REPLICAP-0A4A.dtbo DVK530-LCD4-01-00A0.dtbo cape-universaln-00A0.dtbo

There is the result.
I use cape-universaln-00A0.dtbo.
It seems 48300000.epwmss is wired ,there is some different with the file directory.

@MatthewWest
Copy link
Contributor Author

MatthewWest commented Aug 26, 2016

@Dark-Guan Alright, I don't see an easy answer based on what you've provided so far. Can you please run the following commands, and paste the output (trace.txt) into a gist for us to look at?

# Install strace somehow (not sure what the package management situation is on kamikaze)
# on Debian it'd be
sudo apt-get install strace
sudo strace -o trace.txt python3  # Or python
from Adafruit_BBIO import PWM
PWM.start("P9_14", 50 , 2000, 1)
# press Ctrl-D

Then upload the contents of trace.txt into a gist here.

If you're not familiar with it, strace is a fantastic tool for seeing what system commands a program makes (file opening, writing, etc.). Hopefully this will let us see what errors it is hitting.

@Dark-Guan
Copy link

Ok,Thanks @MatthewWest I will test it soon! Trace is very a nice tool !

@Dark-Guan
Copy link

@MatthewWest https://github.com/Dark-Guan/No-Used-Things/blob/master/trace.txt
I've uploaded "trace.txt" there . Thanks very much

@MatthewWest
Copy link
Contributor Author

I figured it out. Here's the critical part:

open("/sys/devices/platform/ocp/48302000.epwmss/48302200.ehrpwm/pwm/pwmchip2/pwm0/period", O_RDWR) = 3
open("/sys/devices/platform/ocp/48302000.epwmss/48302200.ehrpwm/pwm/pwmchip2/pwm0/duty_cycle", O_RDWR) = 4
open("/sys/devices/platform/ocp/48302000.epwmss/48302200.ehrpwm/pwm/pwmchip2/pwm0/polarity", O_RDWR) = 5
open("/sys/devices/platform/ocp/48302000.epwmss/48302200.ehrpwm/pwm/pwmchip2/pwm0/enable", O_RDWR) = 6
lseek(6, 0, SEEK_SET)                   = 0
read(6, "0", 1)                         = 1
lseek(5, 0, SEEK_SET)                   = 0
write(5, "inversed", 8)                 = 8
lseek(6, 0, SEEK_SET)                   = 0
write(6, "1", 1)                        = 1
lseek(4, 0, SEEK_SET)                   = 0
write(4, "250000", 6)                   = -1 EINVAL (Invalid argument)

The invalid argument when setting the duty cycle happens when the duty cycle is set to longer than the period of the pwm. This was happening because we weren't reading the current duty_ns and period_ns from the files. I've written a short patch which reads the current duty_ns and pwm_ns from the files before setting the default values, in order to set the duty and period in the correct order.

That said, I've written the changes but don't have access to a BeagleBone for the next 2 weeks. So I haven't tested my changes at all, even to see if it will compile. You're welcome to try the code in the develop branch of my repository. I won't submit a pull request until I've had a chance to test it.

@Dark-Guan
Copy link

@MatthewWest OK, Nice work ! I will spend some time to test yours develop version. Thanks very much !

@pdp7
Copy link
Collaborator

pdp7 commented Sep 1, 2016

All tests I've run are OK for @MatthewWest's develop branch:

  • Debian 8.5 (2016-08-14):
    • Linux beaglebone 4.1.15-bone18
    • Linux beaglebone 4.1.14-bone17
    • Linux beaglebone 4.1.6-bone15
  • Debian 8.5 (2016-06-05):
    • Linux beaglebone 4.4.11-ti-r29
  • Debian 8.2 (2015-12-07):
    • Linux beaglebone 4.1.13-ti-r35 GNU/Linux
    • Linux beaglebone 4.4.19-bone13
  • Debian 7.5 (2014-05-14):
    • Linux beaglebone 3.8.13-bone50

@pdp7
Copy link
Collaborator

pdp7 commented Sep 1, 2016

@MatthewWest If you can create a pull request with the fix from your develop branch, then I will test again and merge if no issues.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants