├── README.md ├── driver ├── Makefile ├── pwm_test.c └── pwm_test.ko ├── firmware ├── compiled │ ├── sc_pwm_P8_13-00A0.dtbo │ ├── sc_pwm_P8_19-00A0.dtbo │ ├── sc_pwm_P8_34-00A0.dtbo │ ├── sc_pwm_P8_36-00A0.dtbo │ ├── sc_pwm_P8_45-00A0.dtbo │ ├── sc_pwm_P8_46-00A0.dtbo │ ├── sc_pwm_P9_14-00A0.dtbo │ ├── sc_pwm_P9_16-00A0.dtbo │ ├── sc_pwm_P9_21-00A0.dtbo │ ├── sc_pwm_P9_22-00A0.dtbo │ ├── sc_pwm_P9_28-00A0.dtbo │ ├── sc_pwm_P9_29-00A0.dtbo │ ├── sc_pwm_P9_31-00A0.dtbo │ └── sc_pwm_P9_42-00A0.dtbo ├── sc_pwm_P8_13-00A0.dts ├── sc_pwm_P8_19-00A0.dts ├── sc_pwm_P8_34-00A0.dts ├── sc_pwm_P8_36-00A0.dts ├── sc_pwm_P8_45-00A0.dts ├── sc_pwm_P8_46-00A0.dts ├── sc_pwm_P9_14-00A0.dts ├── sc_pwm_P9_16-00A0.dts ├── sc_pwm_P9_21-00A0.dts ├── sc_pwm_P9_22-00A0.dts ├── sc_pwm_P9_28-00A0.dts ├── sc_pwm_P9_29-00A0.dts ├── sc_pwm_P9_31-00A0.dts └── sc_pwm_P9_42-00A0.dts └── library ├── Makefile ├── Motor.h ├── PWM.cpp ├── PWM.h └── examples ├── BasicPWMExample.cpp ├── MotorExample.cpp └── ServoExample.cpp /README.md: -------------------------------------------------------------------------------- 1 | Introduction 2 | ======================== 3 | I found that while trying to get PWM control for my motors/servos on the BBB 4 | many of the old tutorials were no longer working. Using what I found at 5 | http://www.phys-x.org/rbots/index.php?option=com_content&view=article&id=106:lesson-3-beaglebone-black-pwm&catid=46:beaglebone-black&Itemid=81 6 | and https://groups.google.com/d/msg/beagleboard/wjbOVE6ItNg/Dym4H4HuI8gJ 7 | I modified the driver and firmware and implemented a library on top of it. 8 | 9 | Features 10 | ======================== 11 | * Allows changing the period of EHRPWM modules at run time 12 | * Allows for servo and motor esc control 13 | * Basic examples to show LED brightness fading 14 | 15 | Installation 16 | ======================== 17 | 18 | NOTE: My kernel building knowledge is limited and these are the stops I followed to make it work. 19 | If someone has better/more correct steps please submit them! 20 | 21 | Firmware and update driver 22 | 23 | Compiling the driver on the BeagleBone 24 | ------------------------------- 25 | 1) Download & install build prereqs (Angstrom) 26 | ````sh 27 | opkg update 28 | opkg upgrade 29 | opkg install kernel-dev 30 | opkg install kernel-headers 31 | opkg install task-native-sdk 32 | opkg git 33 | ```` 34 | 35 | 2) Set up build environment and make the module 36 | ````sh 37 | cd /usr/src/kernel 38 | make scripts 39 | ln -s /usr/src/kernel /lib/modules/$(uname -r)/build 40 | cd ~ 41 | git clone git://SaadAhmad/beaglebone-black-cpp-PWM.git 42 | cd beaglebone-black-cpp-PWM/driver 43 | make 44 | ```` 45 | 46 | Compiling the driver and module (Optional) 47 | ------------------------------- 48 | 1) Follow the instructions at http://beagleboard.org/linux or http://wiki.beyondlogic.org/index.php/BeagleBoneBlack_Building_Kernel 49 | to setup your kernel build files. 50 | 51 | 2) Copy/paste pwm_test.c into /kernel/drivers/pwm 52 | ````sh 53 | cp /driver/pwm_test.c /kernel/drivers/pwm/ 54 | ```` 55 | 56 | 3) For the firmware files, copy them over to /kernel/firmware/capes/ 57 | ````sh 58 | cp /firmware/*dts /kernel/firmware/capes/ 59 | ```` 60 | 61 | 4) Open up /kernel/firmware/Makefile and after the bone_pwm_P9_42-00A0.dtbo \ (line 179) add in the following 62 | ````sh 63 | sc_pwm_P8_13-00A0.dtbo \ 64 | sc_pwm_P8_19-00A0.dtbo \ 65 | sc_pwm_P8_34-00A0.dtbo \ 66 | sc_pwm_P8_36-00A0.dtbo \ 67 | sc_pwm_P8_45-00A0.dtbo \ 68 | sc_pwm_P8_46-00A0.dtbo \ 69 | sc_pwm_P9_14-00A0.dtbo \ 70 | sc_pwm_P9_16-00A0.dtbo \ 71 | sc_pwm_P9_21-00A0.dtbo \ 72 | sc_pwm_P9_22-00A0.dtbo \ 73 | sc_pwm_P9_28-00A0.dtbo \ 74 | sc_pwm_P9_29-00A0.dtbo \ 75 | sc_pwm_P9_31-00A0.dtbo \ 76 | sc_pwm_P9_42-00A0.dtbo \ 77 | ```` 78 | 79 | 5) Once you have those changes, compile the kernel again so it builds the updated firmware/driver 80 | 81 | Using the compiled files 82 | ------------------------ 83 | Note you can use the compiled kernel driver file however I'm not sure how easily it will work with different kernel versions. 84 | At the time I compiled it for v3.8.13 and it seems to work for that. If the provided file doesn't work then you might want to try rebuilding it. 85 | 86 | 1) First make sure that your beaglebone isn't running any any of the overlays from the current bone_pwm and that the pwm_test module isnt loaded 87 | A reboot should fix this however if you dont want to reboot you can do the following steps to unload the driver 88 | ````sh 89 | cat /sys/devices/bone_capemgr./slots 90 | # Find the slot for any pwm modules 91 | echo - > /sys/devices/bone_capemgr./slots 92 | # Repeat for all modules 93 | 94 | #Once done 95 | modprobe -r pwm_test.ko 96 | ```` 97 | 98 | 2) Backup the old pwm_test.ko file 99 | ````sh 100 | cd /lib/modules//kernel/drivers/pwm/ 101 | cp pwm_test.ko pwm_test.ko.orig 102 | ```` 103 | 104 | 3) Find the built pwm_test.ko file and copy it over to /lib/modules//kernel/drivers/pwm/ 105 | 106 | 4) Copy over the built dtbo (sc_pwm_P*.dtbo) files to /lib/firmware 107 | 108 | 5) Youre done setting up the files! Do a reboot and you should be set 109 | 110 | Userspace Usage 111 | ------------------------ 112 | 1) Load in the am33xx_pwm module and load in which even PWM pins (the names of the dtb files you copied over) you want loaded. 113 | 114 | ````sh 115 | echo am33xx_pwm > /sys/devices/bone_capemgr./slots 116 | #Example pin firmware would be sc_pwm_P8_13 117 | echo sc_pwm_P > /sys/devices/bone_capemgr./slots 118 | ```` 119 | 120 | 2) Locate the driver interface. It is in /sys/devices/ocp./pwm_test_ 121 | 122 | 3) Set the periods to to whatever value you want (Make sure that the period on both channels of each EHRPWM is same) by doing 123 | ````sh 124 | echo > /sys/devices/ocp./pwm_test_/period 125 | ```` 126 | 127 | 4) Set the duty to to whatever value you want (Make sure that the period on both channels of each EHRPWM is same) by doing 128 | ````sh 129 | echo > /sys/devices/ocp./pwm_test_/duty 130 | ```` 131 | 132 | Note: As was pointed out by Kurt (https://groups.google.com/d/msg/beagleboard/qma8bMph0yM/nOtE1R-gQpAJ) the polarity by default is inverted. 133 | The duty by default repersents the time low instead of the time high. 134 | Fix the polarity so that the duty specifies the high time by doing 135 | ````sh 136 | echo 0 > /sys/devices/ocp./pwm_test_/polarity 137 | ```` 138 | Where 0 is for active high and 1 is for active low (default) 139 | 140 | 5) Once configured, enable the pwm by doing 141 | ````sh 142 | echo 1 > /sys/devices/ocp./pwm_test_/run 143 | ```` 144 | 145 | 6) If you want to reset the period for an EHRPWM where both channels are active, you need to unload the entire PWM module and restart from step 1. (You can skip loading in am33xx_pwm). 146 | This is similar to what you did in the Using compiled files in step 1. 147 | 148 | Library Usage 149 | ------------------------ 150 | The libary provided wraps most of these functions so that they can be be used in your C++ application. Note this isn't compatible with C 151 | however it would be great if people were willing to help out and make it happen! 152 | 153 | I have provided a BasicPWMExample.cpp which shows 154 | you how to get an LED to fade in and out (NOTE dont actually connect the LED directly to your PWM output otherwise you may damage it). 155 | It also includes a MotorExample.cpp and ServoExample.cpp which show you how to use a motor and servo, respectively. Just type "make" in the 156 | the library directory and it will compile the examples. 157 | 158 | Just copy over the CPP/Header files into your application and you are good to go! 159 | 160 | I have described a bit about the problem I found with the PWM and how the fix works at http://saadahmad.ca/using-pwm-on-the-beaglebone-black/ 161 | 162 | 163 | Enjoy 164 | ------------------------ 165 | On a smaller note, if anyone knows how to make and submit this as a patch into the BBB kernel I would greatly appreciate some help! 166 | 167 | 168 | 169 | 170 | -------------------------------------------------------------------------------- /driver/Makefile: -------------------------------------------------------------------------------- 1 | obj-m += pwm_test.o 2 | 3 | all: 4 | make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules 5 | 6 | clean: 7 | make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean 8 | 9 | -------------------------------------------------------------------------------- /driver/pwm_test.c: -------------------------------------------------------------------------------- 1 | /* 2 | * PWM Test driver 3 | * 4 | * Copyright (C) 2012 Texas Instruments. 5 | * 6 | * This program is free software; you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation; either version 2 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program; if not, write to the Free Software 18 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 19 | */ 20 | 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | 31 | struct pwm_test { 32 | struct pwm_device *pwm; 33 | struct class *pwm_test_class; 34 | int period; 35 | int duty; 36 | enum pwm_polarity polarity; 37 | int run; 38 | }; 39 | 40 | static ssize_t pwm_test_show_duty(struct device *dev, 41 | struct device_attribute *attr, char *buf) 42 | { 43 | struct pwm_test *pwm_test = dev_get_drvdata(dev); 44 | 45 | return sprintf(buf, "%d\n", pwm_test->duty); 46 | } 47 | 48 | static ssize_t pwm_test_store_duty(struct device *dev, 49 | struct device_attribute *attr, const char *buf, size_t count) 50 | { 51 | int rc; 52 | struct pwm_test *pwm_test = dev_get_drvdata(dev); 53 | int duty; 54 | 55 | rc = kstrtoint(buf, 0, &duty); 56 | if (rc) 57 | return rc; 58 | 59 | if (duty < 0) 60 | return -EINVAL; 61 | 62 | rc = pwm_config(pwm_test->pwm, duty, pwm_test->period); 63 | if (rc) { 64 | dev_err(dev, "pwm_config() failed setting duty\n"); 65 | return rc; 66 | } 67 | 68 | pwm_test->duty = duty; 69 | 70 | return count; 71 | } 72 | 73 | static ssize_t pwm_test_show_period(struct device *dev, 74 | struct device_attribute *attr, char *buf) 75 | { 76 | struct pwm_test *pwm_test = dev_get_drvdata(dev); 77 | 78 | return sprintf(buf, "%d\n", pwm_test->period); 79 | } 80 | 81 | static ssize_t pwm_test_store_period(struct device *dev, 82 | struct device_attribute *attr, const char *buf, size_t count) 83 | { 84 | int rc; 85 | struct pwm_test *pwm_test = dev_get_drvdata(dev); 86 | int period; 87 | 88 | rc = kstrtoint(buf, 0, &period); 89 | if (rc) 90 | return rc; 91 | 92 | if (period < 0) 93 | return -EINVAL; 94 | 95 | /* same period? just return */ 96 | if (pwm_test->period == period) 97 | return count; 98 | 99 | rc = pwm_config(pwm_test->pwm, pwm_test->duty, period); 100 | if (rc) { 101 | dev_err(dev, "pwm_config() failed setting period\n"); 102 | return rc; 103 | } 104 | 105 | pwm_test->period = period; 106 | 107 | return count; 108 | } 109 | 110 | static ssize_t pwm_test_show_run(struct device *dev, 111 | struct device_attribute *attr, char *buf) 112 | { 113 | struct pwm_test *pwm_test = dev_get_drvdata(dev); 114 | 115 | return sprintf(buf, "%d\n", pwm_test->run); 116 | } 117 | 118 | static ssize_t pwm_test_store_run(struct device *dev, 119 | struct device_attribute *attr, const char *buf, size_t count) 120 | { 121 | int rc; 122 | struct pwm_test *pwm_test = dev_get_drvdata(dev); 123 | int run; 124 | 125 | rc = kstrtoint(buf, 0, &run); 126 | if (rc) 127 | return rc; 128 | 129 | /* only 0 & 1 allowed */ 130 | if (run != 0 && run != 1) 131 | return -EINVAL; 132 | 133 | /* same state, don't bother */ 134 | if (run == pwm_test->run) 135 | return count; 136 | 137 | if (run) { 138 | rc = pwm_enable(pwm_test->pwm); 139 | if (rc != 0) { 140 | dev_err(dev, "pwm_enable failed trying to set run\n"); 141 | return rc; 142 | } 143 | } else 144 | pwm_disable(pwm_test->pwm); 145 | 146 | pwm_test->run = run; 147 | 148 | return count; 149 | } 150 | 151 | static ssize_t pwm_test_show_polarity(struct device *dev, 152 | struct device_attribute *attr, char *buf) 153 | { 154 | struct pwm_test *pwm_test = dev_get_drvdata(dev); 155 | 156 | return sprintf(buf, "%u\n", pwm_test->polarity); 157 | } 158 | 159 | static ssize_t pwm_test_store_polarity(struct device *dev, 160 | struct device_attribute *attr, const char *buf, size_t count) 161 | { 162 | int rc; 163 | struct pwm_test *pwm_test = dev_get_drvdata(dev); 164 | int val; 165 | enum pwm_polarity polarity; 166 | 167 | rc = kstrtoint(buf, 0, &val); 168 | if (rc) 169 | return rc; 170 | 171 | /* only zero and one allowed */ 172 | if (val != 0 && val != 1) 173 | return -EINVAL; 174 | 175 | polarity = val ? PWM_POLARITY_INVERSED : PWM_POLARITY_NORMAL; 176 | 177 | /* same? don't do anything */ 178 | if (polarity == pwm_test->polarity) 179 | return count; 180 | 181 | /* polarity can only change when we stop the pwm */ 182 | if (pwm_test->run) 183 | pwm_disable(pwm_test->pwm); 184 | 185 | rc = pwm_set_polarity(pwm_test->pwm, polarity); 186 | if (rc) { 187 | dev_err(dev, "pwm_set_polarity failed\n"); 188 | if (pwm_test->run) 189 | pwm_enable(pwm_test->pwm); 190 | return rc; 191 | } 192 | 193 | if (pwm_test->run) 194 | pwm_enable(pwm_test->pwm); 195 | 196 | pwm_test->polarity = polarity; 197 | 198 | return count; 199 | } 200 | 201 | static DEVICE_ATTR(duty, S_IRUSR | S_IWUSR, pwm_test_show_duty, pwm_test_store_duty); 202 | static DEVICE_ATTR(period, S_IRUSR | S_IWUSR, pwm_test_show_period, pwm_test_store_period); 203 | static DEVICE_ATTR(polarity, S_IRUSR | S_IWUSR, pwm_test_show_polarity, 204 | pwm_test_store_polarity); 205 | static DEVICE_ATTR(run, S_IRUSR | S_IWUSR , pwm_test_show_run, pwm_test_store_run); 206 | 207 | static const struct attribute *pwm_attrs[] = { 208 | &dev_attr_duty.attr, 209 | &dev_attr_period.attr, 210 | &dev_attr_run.attr, 211 | &dev_attr_polarity.attr, 212 | NULL, 213 | }; 214 | 215 | static const struct attribute_group pwm_device_attr_group = { 216 | .attrs = (struct attribute **) pwm_attrs, 217 | }; 218 | 219 | static int pwm_test_probe(struct platform_device *pdev) 220 | { 221 | struct device *dev = &pdev->dev; 222 | struct device_node *node = dev->of_node; 223 | struct pwm_test *pwm_test; 224 | struct of_phandle_args args; 225 | struct pinctrl *pinctrl; 226 | u32 val; 227 | int rc; 228 | 229 | if (node == NULL) { 230 | dev_err(dev, "Non DT platforms not supported\n"); 231 | return -EINVAL; 232 | } 233 | 234 | pinctrl = devm_pinctrl_get_select_default(&pdev->dev); 235 | if (IS_ERR(pinctrl)) 236 | dev_warn(&pdev->dev, "Unable to select pin group\n"); 237 | 238 | pwm_test = devm_kzalloc(&pdev->dev, sizeof(*pwm_test), GFP_KERNEL); 239 | if (!pwm_test) { 240 | dev_err(&pdev->dev, "memory error\n"); 241 | return -ENOMEM; 242 | } 243 | platform_set_drvdata(pdev, pwm_test); 244 | 245 | /* now do the probe time config */ 246 | pwm_test->pwm = devm_pwm_get(&pdev->dev, NULL); 247 | if (IS_ERR(pwm_test->pwm)) { 248 | dev_err(dev, "unable to request PWM\n"); 249 | return PTR_ERR(pwm_test->pwm); 250 | } 251 | 252 | rc = of_parse_phandle_with_args(node, "pwms", "#pwm-cells", 0, &args); 253 | if (rc != 0) { 254 | dev_err(dev, "of_parse_phandle_with_args() failed\n"); 255 | return rc; 256 | } 257 | 258 | /* read the period */ 259 | pwm_test->period = args.args[1]; 260 | 261 | /* should be at least 2, but 3 is possible to store polarity */ 262 | pwm_test->polarity = PWM_POLARITY_NORMAL; 263 | /* PWM_SPEC_POLARITY is (1 << 0) */ 264 | if (args.args_count >= 3 && (args.args[2] & (1 << 0)) != 0) 265 | pwm_test->polarity = PWM_POLARITY_INVERSED; 266 | 267 | /* Determine the duty from the device tree */ 268 | rc = of_property_read_u32(node, "duty", &val); 269 | if (rc != 0) 270 | val = 0; /* default is 0 */ 271 | pwm_test->duty = val; 272 | 273 | /* Only set the config if the period is > 0. Otherwise the period will be set later dynamically */ 274 | if ( pwm_test->period > 0 ) 275 | { 276 | /* polarity is already set */ 277 | rc = pwm_config(pwm_test->pwm, pwm_test->duty, pwm_test->period); 278 | if (rc) { 279 | dev_err(dev, "pwm_config() failed\n"); 280 | return rc; 281 | } 282 | } else { 283 | pwm_test->period = 0; 284 | } 285 | 286 | /* Determine running or not from the device tree */ 287 | rc = of_property_read_u32(node, "enabled", &val); 288 | if (rc < 0) 289 | val = 0; /* default is disabled */ 290 | 291 | /* single bit */ 292 | pwm_test->run = !!val; 293 | 294 | if (pwm_test->run) { 295 | rc = pwm_enable(pwm_test->pwm); 296 | if (rc < 0) { 297 | dev_err(dev, "pwm_enable failed\n"); 298 | return rc; 299 | } 300 | } 301 | 302 | rc = sysfs_create_group(&dev->kobj, &pwm_device_attr_group); 303 | if (rc != 0) { 304 | dev_err(dev, "Unable to create sysfs entries\n"); 305 | return rc; 306 | } 307 | 308 | return 0; 309 | } 310 | 311 | static int pwm_test_remove(struct platform_device *pdev) 312 | { 313 | struct pwm_test *pwm_test = platform_get_drvdata(pdev); 314 | 315 | sysfs_remove_group(&pdev->dev.kobj, &pwm_device_attr_group); 316 | 317 | if (pwm_test->run) { 318 | pwm_config(pwm_test->pwm, 0, 0x1000); 319 | pwm_disable(pwm_test->pwm); 320 | } 321 | 322 | devm_pwm_put(&pdev->dev, pwm_test->pwm); 323 | return 0; 324 | } 325 | 326 | static struct of_device_id pwm_test_of_match[] = { 327 | { .compatible = "pwm_test" }, 328 | { } 329 | }; 330 | 331 | MODULE_DEVICE_TABLE(of, pwm_test_of_match); 332 | 333 | static struct platform_driver pwm_test_driver = { 334 | .driver = { 335 | .name = "pwm_test", 336 | .owner = THIS_MODULE, 337 | .of_match_table = of_match_ptr(pwm_test_of_match), 338 | }, 339 | .probe = pwm_test_probe, 340 | .remove = pwm_test_remove, 341 | }; 342 | 343 | module_platform_driver(pwm_test_driver); 344 | 345 | MODULE_DESCRIPTION("pwm_test Driver"); 346 | MODULE_LICENSE("GPL"); 347 | MODULE_ALIAS("platform:pwm_test"); 348 | -------------------------------------------------------------------------------- /driver/pwm_test.ko: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SaadAhmad/beaglebone-black-cpp-PWM/dfdf942492c559cfbfe27de47e97c3f1008e903d/driver/pwm_test.ko -------------------------------------------------------------------------------- /firmware/compiled/sc_pwm_P8_13-00A0.dtbo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SaadAhmad/beaglebone-black-cpp-PWM/dfdf942492c559cfbfe27de47e97c3f1008e903d/firmware/compiled/sc_pwm_P8_13-00A0.dtbo -------------------------------------------------------------------------------- /firmware/compiled/sc_pwm_P8_19-00A0.dtbo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SaadAhmad/beaglebone-black-cpp-PWM/dfdf942492c559cfbfe27de47e97c3f1008e903d/firmware/compiled/sc_pwm_P8_19-00A0.dtbo -------------------------------------------------------------------------------- /firmware/compiled/sc_pwm_P8_34-00A0.dtbo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SaadAhmad/beaglebone-black-cpp-PWM/dfdf942492c559cfbfe27de47e97c3f1008e903d/firmware/compiled/sc_pwm_P8_34-00A0.dtbo -------------------------------------------------------------------------------- /firmware/compiled/sc_pwm_P8_36-00A0.dtbo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SaadAhmad/beaglebone-black-cpp-PWM/dfdf942492c559cfbfe27de47e97c3f1008e903d/firmware/compiled/sc_pwm_P8_36-00A0.dtbo -------------------------------------------------------------------------------- /firmware/compiled/sc_pwm_P8_45-00A0.dtbo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SaadAhmad/beaglebone-black-cpp-PWM/dfdf942492c559cfbfe27de47e97c3f1008e903d/firmware/compiled/sc_pwm_P8_45-00A0.dtbo -------------------------------------------------------------------------------- /firmware/compiled/sc_pwm_P8_46-00A0.dtbo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SaadAhmad/beaglebone-black-cpp-PWM/dfdf942492c559cfbfe27de47e97c3f1008e903d/firmware/compiled/sc_pwm_P8_46-00A0.dtbo -------------------------------------------------------------------------------- /firmware/compiled/sc_pwm_P9_14-00A0.dtbo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SaadAhmad/beaglebone-black-cpp-PWM/dfdf942492c559cfbfe27de47e97c3f1008e903d/firmware/compiled/sc_pwm_P9_14-00A0.dtbo -------------------------------------------------------------------------------- /firmware/compiled/sc_pwm_P9_16-00A0.dtbo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SaadAhmad/beaglebone-black-cpp-PWM/dfdf942492c559cfbfe27de47e97c3f1008e903d/firmware/compiled/sc_pwm_P9_16-00A0.dtbo -------------------------------------------------------------------------------- /firmware/compiled/sc_pwm_P9_21-00A0.dtbo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SaadAhmad/beaglebone-black-cpp-PWM/dfdf942492c559cfbfe27de47e97c3f1008e903d/firmware/compiled/sc_pwm_P9_21-00A0.dtbo -------------------------------------------------------------------------------- /firmware/compiled/sc_pwm_P9_22-00A0.dtbo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SaadAhmad/beaglebone-black-cpp-PWM/dfdf942492c559cfbfe27de47e97c3f1008e903d/firmware/compiled/sc_pwm_P9_22-00A0.dtbo -------------------------------------------------------------------------------- /firmware/compiled/sc_pwm_P9_28-00A0.dtbo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SaadAhmad/beaglebone-black-cpp-PWM/dfdf942492c559cfbfe27de47e97c3f1008e903d/firmware/compiled/sc_pwm_P9_28-00A0.dtbo -------------------------------------------------------------------------------- /firmware/compiled/sc_pwm_P9_29-00A0.dtbo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SaadAhmad/beaglebone-black-cpp-PWM/dfdf942492c559cfbfe27de47e97c3f1008e903d/firmware/compiled/sc_pwm_P9_29-00A0.dtbo -------------------------------------------------------------------------------- /firmware/compiled/sc_pwm_P9_31-00A0.dtbo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SaadAhmad/beaglebone-black-cpp-PWM/dfdf942492c559cfbfe27de47e97c3f1008e903d/firmware/compiled/sc_pwm_P9_31-00A0.dtbo -------------------------------------------------------------------------------- /firmware/compiled/sc_pwm_P9_42-00A0.dtbo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SaadAhmad/beaglebone-black-cpp-PWM/dfdf942492c559cfbfe27de47e97c3f1008e903d/firmware/compiled/sc_pwm_P9_42-00A0.dtbo -------------------------------------------------------------------------------- /firmware/sc_pwm_P8_13-00A0.dts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2013 CircuitCo 3 | * Copyright (C) 2013 Texas Instruments 4 | * 5 | * This program is free software; you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License version 2 as 7 | * published by the Free Software Foundation. 8 | */ 9 | /dts-v1/; 10 | /plugin/; 11 | 12 | / { 13 | compatible = "ti,beaglebone", "ti,beaglebone-black"; 14 | 15 | /* identification */ 16 | part-number = "sc_pwm_P8_13"; 17 | version = "00A0"; 18 | 19 | /* state the resources this cape uses */ 20 | exclusive-use = 21 | /* the pin header uses */ 22 | "P8.13", /* pwm: ehrpwm2B */ 23 | /* the hardware IP uses */ 24 | "ehrpwm2B"; 25 | 26 | fragment@0 { 27 | target = <&am33xx_pinmux>; 28 | __overlay__ { 29 | pwm_P8_13: pinmux_pwm_P8_13_pins { 30 | pinctrl-single,pins = <0x024 0x4>; /* P8_13 (ZCZ ball T10) | MODE 4 */ 31 | }; 32 | }; 33 | }; 34 | 35 | fragment@1 { 36 | target = <&ocp>; 37 | __overlay__ { 38 | pwm_test_P8_13 { 39 | compatible = "pwm_test"; 40 | pwms = <&ehrpwm2 1 0 1>; 41 | pwm-names = "PWM_P8_13"; 42 | 43 | pinctrl-names = "default"; 44 | pinctrl-0 = <&pwm_P8_13>; 45 | 46 | enabled = <0>; 47 | duty = <0>; 48 | status = "okay"; 49 | }; 50 | }; 51 | }; 52 | }; 53 | -------------------------------------------------------------------------------- /firmware/sc_pwm_P8_19-00A0.dts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2013 CircuitCo 3 | * Copyright (C) 2013 Texas Instruments 4 | * 5 | * This program is free software; you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License version 2 as 7 | * published by the Free Software Foundation. 8 | */ 9 | /dts-v1/; 10 | /plugin/; 11 | 12 | / { 13 | compatible = "ti,beaglebone", "ti,beaglebone-black"; 14 | 15 | /* identification */ 16 | part-number = "sc_pwm_P8_19"; 17 | version = "00A0"; 18 | 19 | /* state the resources this cape uses */ 20 | exclusive-use = 21 | /* the pin header uses */ 22 | "P8.19", /* pwm: ehrpwm2A */ 23 | /* the hardware IP uses */ 24 | "ehrpwm2A"; 25 | 26 | fragment@0 { 27 | target = <&am33xx_pinmux>; 28 | __overlay__ { 29 | pwm_P8_19: pinmux_pwm_P8_19_pins { 30 | pinctrl-single,pins = <0x020 0x4>; /* P8_19 (ZCZ ball U10) | MODE 4 */ 31 | }; 32 | }; 33 | }; 34 | 35 | fragment@1 { 36 | target = <&ocp>; 37 | __overlay__ { 38 | pwm_test_P8_19 { 39 | compatible = "pwm_test"; 40 | pwms = <&ehrpwm2 0 0 1>; 41 | pwm-names = "PWM_P8_19"; 42 | 43 | pinctrl-names = "default"; 44 | pinctrl-0 = <&pwm_P8_19>; 45 | 46 | enabled = <0>; 47 | duty = <0>; 48 | status = "okay"; 49 | }; 50 | }; 51 | }; 52 | }; 53 | -------------------------------------------------------------------------------- /firmware/sc_pwm_P8_34-00A0.dts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2013 CircuitCo 3 | * Copyright (C) 2013 Texas Instruments 4 | * 5 | * This program is free software; you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License version 2 as 7 | * published by the Free Software Foundation. 8 | */ 9 | /dts-v1/; 10 | /plugin/; 11 | 12 | / { 13 | compatible = "ti,beaglebone", "ti,beaglebone-black"; 14 | 15 | /* identification */ 16 | part-number = "sc_pwm_P8_34"; 17 | version = "00A0"; 18 | 19 | /* state the resources this cape uses */ 20 | exclusive-use = 21 | /* the pin header uses */ 22 | "P8.34", /* pwm: ehrpwm1B */ 23 | /* the hardware IP uses */ 24 | "ehrpwm1B"; 25 | 26 | fragment@0 { 27 | target = <&am33xx_pinmux>; 28 | __overlay__ { 29 | pwm_P8_34: pinmux_pwm_P8_34_pins { 30 | pinctrl-single,pins = <0x0cc 0x2>; /* P8_34 (ZCZ ball U4) | MODE 2 */ 31 | }; 32 | }; 33 | }; 34 | 35 | fragment@1 { 36 | target = <&ocp>; 37 | __overlay__ { 38 | pwm_test_P8_34 { 39 | compatible = "pwm_test"; 40 | pwms = <&ehrpwm1 1 0 1>; 41 | pwm-names = "PWM_P8_34"; 42 | pinctrl-names = "default"; 43 | pinctrl-0 = <&pwm_P8_34>; 44 | enabled = <0>; 45 | duty = <0>; 46 | status = "okay"; 47 | }; 48 | }; 49 | }; 50 | }; 51 | -------------------------------------------------------------------------------- /firmware/sc_pwm_P8_36-00A0.dts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2013 CircuitCo 3 | * Copyright (C) 2013 Texas Instruments 4 | * 5 | * This program is free software; you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License version 2 as 7 | * published by the Free Software Foundation. 8 | */ 9 | /dts-v1/; 10 | /plugin/; 11 | 12 | / { 13 | compatible = "ti,beaglebone", "ti,beaglebone-black"; 14 | 15 | /* identification */ 16 | part-number = "sc_pwm_P8_36"; 17 | version = "00A0"; 18 | 19 | /* state the resources this cape uses */ 20 | exclusive-use = 21 | /* the pin header uses */ 22 | "P8.36", /* pwm: ehrpwm1A */ 23 | /* the hardware IP uses */ 24 | "ehrpwm1A"; 25 | 26 | fragment@0 { 27 | target = <&am33xx_pinmux>; 28 | __overlay__ { 29 | pwm_P8_36: pinmux_pwm_P8_36_pins { 30 | pinctrl-single,pins = <0x0c8 0x2>; /* P8_36 (ZCZ ball U3) | MODE 2 */ 31 | }; 32 | }; 33 | }; 34 | 35 | fragment@1 { 36 | target = <&ocp>; 37 | __overlay__ { 38 | pwm_test_P8_36 { 39 | compatible = "pwm_test"; 40 | pwms = <&ehrpwm1 0 0 1>; 41 | pwm-names = "PWM_P8_36"; 42 | pinctrl-names = "default"; 43 | pinctrl-0 = <&pwm_P8_36>; 44 | enabled = <0>; 45 | duty = <0>; 46 | status = "okay"; 47 | }; 48 | }; 49 | }; 50 | }; 51 | -------------------------------------------------------------------------------- /firmware/sc_pwm_P8_45-00A0.dts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2013 CircuitCo 3 | * Copyright (C) 2013 Texas Instruments 4 | * 5 | * This program is free software; you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License version 2 as 7 | * published by the Free Software Foundation. 8 | */ 9 | /dts-v1/; 10 | /plugin/; 11 | 12 | / { 13 | compatible = "ti,beaglebone", "ti,beaglebone-black"; 14 | 15 | /* identification */ 16 | part-number = "sc_pwm_P8_45"; 17 | version = "00A0"; 18 | 19 | /* state the resources this cape uses */ 20 | exclusive-use = 21 | /* the pin header uses */ 22 | "P8.45", /* pwm: ehrpwm2A */ 23 | /* the hardware IP uses */ 24 | "ehrpwm2A"; 25 | 26 | fragment@0 { 27 | target = <&am33xx_pinmux>; 28 | __overlay__ { 29 | pwm_P8_45: pinmux_pwm_P8_45_pins { 30 | pinctrl-single,pins = <0x0a0 0x3>; /* P8_45 (ZCZ ball R1) | MODE 3 */ 31 | }; 32 | }; 33 | }; 34 | 35 | fragment@1 { 36 | target = <&ocp>; 37 | __overlay__ { 38 | pwm_test_P8_45 { 39 | compatible = "pwm_test"; 40 | pwms = <&ehrpwm2 0 0 1>; 41 | pwm-names = "PWM_P8_45"; 42 | pinctrl-names = "default"; 43 | pinctrl-0 = <&pwm_P8_45>; 44 | enabled = <0>; 45 | duty = <0>; 46 | status = "okay"; 47 | }; 48 | }; 49 | }; 50 | }; 51 | -------------------------------------------------------------------------------- /firmware/sc_pwm_P8_46-00A0.dts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2013 CircuitCo 3 | * Copyright (C) 2013 Texas Instruments 4 | * 5 | * This program is free software; you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License version 2 as 7 | * published by the Free Software Foundation. 8 | */ 9 | /dts-v1/; 10 | /plugin/; 11 | 12 | / { 13 | compatible = "ti,beaglebone", "ti,beaglebone-black"; 14 | 15 | /* identification */ 16 | part-number = "sc_pwm_P8_46"; 17 | version = "00A0"; 18 | 19 | /* state the resources this cape uses */ 20 | exclusive-use = 21 | /* the pin header uses */ 22 | "P8.46", /* pwm: ehrpwm2B */ 23 | /* the hardware IP uses */ 24 | "ehrpwm2B"; 25 | 26 | fragment@0 { 27 | target = <&am33xx_pinmux>; 28 | __overlay__ { 29 | pwm_P8_46: pinmux_pwm_P8_46_pins { 30 | pinctrl-single,pins = <0x0a4 0x3>; /* P8_46 (ZCZ ball R2) | MODE 3 */ 31 | }; 32 | }; 33 | }; 34 | 35 | fragment@1 { 36 | target = <&ocp>; 37 | __overlay__ { 38 | pwm_test_P8_46 { 39 | compatible = "pwm_test"; 40 | pwms = <&ehrpwm2 1 0 1>; 41 | pwm-names = "PWM_P8_46"; 42 | pinctrl-names = "default"; 43 | pinctrl-0 = <&pwm_P8_46>; 44 | enabled = <0>; 45 | duty = <0>; 46 | status = "okay"; 47 | }; 48 | }; 49 | }; 50 | }; 51 | -------------------------------------------------------------------------------- /firmware/sc_pwm_P9_14-00A0.dts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2013 CircuitCo 3 | * Copyright (C) 2013 Texas Instruments 4 | * 5 | * This program is free software; you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License version 2 as 7 | * published by the Free Software Foundation. 8 | */ 9 | /dts-v1/; 10 | /plugin/; 11 | 12 | / { 13 | compatible = "ti,beaglebone", "ti,beaglebone-black"; 14 | 15 | /* identification */ 16 | part-number = "sc_pwm_P9_14"; 17 | version = "00A0"; 18 | 19 | /* state the resources this cape uses */ 20 | exclusive-use = 21 | /* the pin header uses */ 22 | "P9.14", /* pwm: ehrpwm1A */ 23 | /* the hardware IP uses */ 24 | "ehrpwm1A"; 25 | 26 | fragment@0 { 27 | target = <&am33xx_pinmux>; 28 | __overlay__ { 29 | pwm_P9_14: pinmux_pwm_P9_14_pins { 30 | pinctrl-single,pins = <0x048 0x6>; /* P9_14 (ZCZ ball U14) | MODE 6 */ 31 | }; 32 | }; 33 | }; 34 | 35 | fragment@1 { 36 | target = <&ocp>; 37 | __overlay__ { 38 | pwm_test_P9_14 { 39 | compatible = "pwm_test"; 40 | pwms = <&ehrpwm1 0 0 1>; 41 | pwm-names = "PWM_P9_14"; 42 | pinctrl-names = "default"; 43 | pinctrl-0 = <&pwm_P9_14>; 44 | enabled = <0>; 45 | duty = <0>; 46 | status = "okay"; 47 | }; 48 | }; 49 | }; 50 | }; 51 | -------------------------------------------------------------------------------- /firmware/sc_pwm_P9_16-00A0.dts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2013 CircuitCo 3 | * Copyright (C) 2013 Texas Instruments 4 | * 5 | * This program is free software; you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License version 2 as 7 | * published by the Free Software Foundation. 8 | */ 9 | /dts-v1/; 10 | /plugin/; 11 | 12 | / { 13 | compatible = "ti,beaglebone", "ti,beaglebone-black"; 14 | 15 | /* identification */ 16 | part-number = "sc_pwm_P9_16"; 17 | version = "00A0"; 18 | 19 | /* state the resources this cape uses */ 20 | exclusive-use = 21 | /* the pin header uses */ 22 | "P9.16", /* pwm: ehrpwm1B */ 23 | /* the hardware IP uses */ 24 | "ehrpwm1B"; 25 | 26 | fragment@0 { 27 | target = <&am33xx_pinmux>; 28 | __overlay__ { 29 | pwm_P9_16: pinmux_pwm_P9_16_pins { 30 | pinctrl-single,pins = <0x04c 0x6>; /* P9_16 (ZCZ ball T14) | MODE 6 */ 31 | }; 32 | }; 33 | }; 34 | 35 | fragment@1 { 36 | target = <&ocp>; 37 | __overlay__ { 38 | pwm_test_P9_16 { 39 | compatible = "pwm_test"; 40 | pwms = <&ehrpwm1 1 0 1>; 41 | pwm-names = "PWM_P9_16"; 42 | pinctrl-names = "default"; 43 | pinctrl-0 = <&pwm_P9_16>; 44 | enabled = <0>; 45 | duty = <0>; 46 | status = "okay"; 47 | }; 48 | }; 49 | }; 50 | }; 51 | -------------------------------------------------------------------------------- /firmware/sc_pwm_P9_21-00A0.dts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2013 CircuitCo 3 | * Copyright (C) 2013 Texas Instruments 4 | * 5 | * This program is free software; you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License version 2 as 7 | * published by the Free Software Foundation. 8 | */ 9 | /dts-v1/; 10 | /plugin/; 11 | 12 | / { 13 | compatible = "ti,beaglebone", "ti,beaglebone-black"; 14 | 15 | /* identification */ 16 | part-number = "sc_pwm_P9_21"; 17 | version = "00A0"; 18 | 19 | /* state the resources this cape uses */ 20 | exclusive-use = 21 | /* the pin header uses */ 22 | "P9.21", /* pwm: ehrpwm0B */ 23 | /* the hardware IP uses */ 24 | "ehrpwm0B"; 25 | 26 | fragment@0 { 27 | target = <&am33xx_pinmux>; 28 | __overlay__ { 29 | pwm_P9_21: pinmux_pwm_P9_21_pins { 30 | pinctrl-single,pins = <0x154 0x3>; /* P9_21 (ZCZ ball B17) | MODE 3 */ 31 | }; 32 | }; 33 | }; 34 | 35 | fragment@1 { 36 | target = <&ocp>; 37 | __overlay__ { 38 | pwm_test_P9_21 { 39 | compatible = "pwm_test"; 40 | pwms = <&ehrpwm0 1 0 1>; 41 | pwm-names = "PWM_P9_21"; 42 | pinctrl-names = "default"; 43 | pinctrl-0 = <&pwm_P9_21>; 44 | enabled = <0>; 45 | duty = <0>; 46 | status = "okay"; 47 | }; 48 | }; 49 | }; 50 | }; 51 | -------------------------------------------------------------------------------- /firmware/sc_pwm_P9_22-00A0.dts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2013 CircuitCo 3 | * Copyright (C) 2013 Texas Instruments 4 | * 5 | * This program is free software; you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License version 2 as 7 | * published by the Free Software Foundation. 8 | */ 9 | /dts-v1/; 10 | /plugin/; 11 | 12 | / { 13 | compatible = "ti,beaglebone", "ti,beaglebone-black"; 14 | 15 | /* identification */ 16 | part-number = "sc_pwm_P9_22"; 17 | version = "00A0"; 18 | 19 | /* state the resources this cape uses */ 20 | exclusive-use = 21 | /* the pin header uses */ 22 | "P9.22", /* pwm: ehrpwm0A */ 23 | /* the hardware IP uses */ 24 | "ehrpwm0A"; 25 | 26 | fragment@0 { 27 | target = <&am33xx_pinmux>; 28 | __overlay__ { 29 | pwm_P9_22: pinmux_pwm_P9_22_pins { 30 | pinctrl-single,pins = <0x150 0x3>; /* P9_22 (ZCZ ball A17) | MODE 3 */ 31 | }; 32 | }; 33 | }; 34 | 35 | fragment@1 { 36 | target = <&ocp>; 37 | __overlay__ { 38 | pwm_test_P9_22 { 39 | compatible = "pwm_test"; 40 | pwms = <&ehrpwm0 0 0 1>; 41 | pwm-names = "PWM_P9_22"; 42 | pinctrl-names = "default"; 43 | pinctrl-0 = <&pwm_P9_22>; 44 | enabled = <0>; 45 | duty = <0>; 46 | status = "okay"; 47 | }; 48 | }; 49 | }; 50 | }; 51 | -------------------------------------------------------------------------------- /firmware/sc_pwm_P9_28-00A0.dts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2013 CircuitCo 3 | * Copyright (C) 2013 Texas Instruments 4 | * 5 | * This program is free software; you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License version 2 as 7 | * published by the Free Software Foundation. 8 | */ 9 | /dts-v1/; 10 | /plugin/; 11 | 12 | / { 13 | compatible = "ti,beaglebone", "ti,beaglebone-black"; 14 | 15 | /* identification */ 16 | part-number = "sc_pwm_P9_28"; 17 | version = "00A0"; 18 | 19 | /* state the resources this cape uses */ 20 | exclusive-use = 21 | /* the pin header uses */ 22 | "P9.28", /* pwm: eCAP2_in_PWM2_out */ 23 | /* the hardware IP uses */ 24 | "eCAP2_in_PWM2_out"; 25 | 26 | fragment@0 { 27 | target = <&am33xx_pinmux>; 28 | __overlay__ { 29 | pwm_P9_28: pinmux_pwm_P9_28_pins { 30 | pinctrl-single,pins = <0x19c 0x4>; /* P9_28 (ZCZ ball C12) | MODE 4 */ 31 | }; 32 | }; 33 | }; 34 | 35 | fragment@1 { 36 | target = <&ocp>; 37 | __overlay__ { 38 | pwm_test_P9_28 { 39 | compatible = "pwm_test"; 40 | pwms = <&ecap2 0 0 1>; 41 | pwm-names = "PWM_P9_28"; 42 | pinctrl-names = "default"; 43 | pinctrl-0 = <&pwm_P9_28>; 44 | enabled = <0>; 45 | duty = <0>; 46 | status = "okay"; 47 | }; 48 | }; 49 | }; 50 | }; 51 | -------------------------------------------------------------------------------- /firmware/sc_pwm_P9_29-00A0.dts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2013 CircuitCo 3 | * Copyright (C) 2013 Texas Instruments 4 | * 5 | * This program is free software; you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License version 2 as 7 | * published by the Free Software Foundation. 8 | */ 9 | /dts-v1/; 10 | /plugin/; 11 | 12 | / { 13 | compatible = "ti,beaglebone", "ti,beaglebone-black"; 14 | 15 | /* identification */ 16 | part-number = "sc_pwm_P9_29"; 17 | version = "00A0"; 18 | 19 | /* state the resources this cape uses */ 20 | exclusive-use = 21 | /* the pin header uses */ 22 | "P9.29", /* pwm: ehrpwm0B */ 23 | /* the hardware IP uses */ 24 | "ehrpwm0B"; 25 | 26 | fragment@0 { 27 | target = <&am33xx_pinmux>; 28 | __overlay__ { 29 | pwm_P9_29: pinmux_pwm_P9_29_pins { 30 | pinctrl-single,pins = <0x194 0x1>; /* P9_29 (ZCZ ball B13) | MODE 1 */ 31 | }; 32 | }; 33 | }; 34 | 35 | fragment@1 { 36 | target = <&ocp>; 37 | __overlay__ { 38 | pwm_test_P9_29 { 39 | compatible = "pwm_test"; 40 | pwms = <&ehrpwm0 1 0 1>; 41 | pwm-names = "PWM_P9_29"; 42 | pinctrl-names = "default"; 43 | pinctrl-0 = <&pwm_P9_29>; 44 | enabled = <0>; 45 | duty = <0>; 46 | status = "okay"; 47 | }; 48 | }; 49 | }; 50 | }; 51 | -------------------------------------------------------------------------------- /firmware/sc_pwm_P9_31-00A0.dts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2013 CircuitCo 3 | * Copyright (C) 2013 Texas Instruments 4 | * 5 | * This program is free software; you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License version 2 as 7 | * published by the Free Software Foundation. 8 | */ 9 | /dts-v1/; 10 | /plugin/; 11 | 12 | / { 13 | compatible = "ti,beaglebone", "ti,beaglebone-black"; 14 | 15 | /* identification */ 16 | part-number = "sc_pwm_P9_31"; 17 | version = "00A0"; 18 | 19 | /* state the resources this cape uses */ 20 | exclusive-use = 21 | /* the pin header uses */ 22 | "P9.31", /* pwm: ehrpwm0A */ 23 | /* the hardware IP uses */ 24 | "ehrpwm0A"; 25 | 26 | fragment@0 { 27 | target = <&am33xx_pinmux>; 28 | __overlay__ { 29 | pwm_P9_31: pinmux_pwm_P9_31_pins { 30 | pinctrl-single,pins = <0x190 0x1>; /* P9_31 (ZCZ ball A13) | MODE 1 */ 31 | }; 32 | }; 33 | }; 34 | 35 | fragment@1 { 36 | target = <&ocp>; 37 | __overlay__ { 38 | pwm_test_P9_31 { 39 | compatible = "pwm_test"; 40 | pwms = <&ehrpwm0 0 0 1>; 41 | pwm-names = "PWM_P9_31"; 42 | pinctrl-names = "default"; 43 | pinctrl-0 = <&pwm_P9_31>; 44 | enabled = <0>; 45 | duty = <0>; 46 | status = "okay"; 47 | }; 48 | }; 49 | }; 50 | }; 51 | -------------------------------------------------------------------------------- /firmware/sc_pwm_P9_42-00A0.dts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2013 CircuitCo 3 | * Copyright (C) 2013 Texas Instruments 4 | * 5 | * This program is free software; you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License version 2 as 7 | * published by the Free Software Foundation. 8 | */ 9 | /dts-v1/; 10 | /plugin/; 11 | 12 | / { 13 | compatible = "ti,beaglebone", "ti,beaglebone-black"; 14 | 15 | /* identification */ 16 | part-number = "sc_pwm_P9_42"; 17 | version = "00A0"; 18 | 19 | /* state the resources this cape uses */ 20 | exclusive-use = 21 | /* the pin header uses */ 22 | "P9.42", /* pwm: eCAP0_in_PWM0_out */ 23 | /* the hardware IP uses */ 24 | "eCAP0_in_PWM0_out"; 25 | 26 | fragment@0 { 27 | target = <&am33xx_pinmux>; 28 | __overlay__ { 29 | pwm_P9_42: pinmux_pwm_P9_42_pins { 30 | pinctrl-single,pins = <0x164 0x0>; /* P9_42 (ZCZ ball C18) | MODE 0 */ 31 | }; 32 | }; 33 | }; 34 | 35 | fragment@1 { 36 | target = <&ocp>; 37 | __overlay__ { 38 | pwm_test_P9_42 { 39 | compatible = "pwm_test"; 40 | pwms = <&ecap0 0 0 1>; 41 | pwm-names = "PWM_P9_42"; 42 | pinctrl-names = "default"; 43 | pinctrl-0 = <&pwm_P9_42>; 44 | enabled = <0>; 45 | duty = <0>; 46 | status = "okay"; 47 | }; 48 | }; 49 | }; 50 | }; 51 | -------------------------------------------------------------------------------- /library/Makefile: -------------------------------------------------------------------------------- 1 | all: MotorExample BasicPWMExample ServoExample 2 | 3 | MotorExample: MotorExample.o PWM.o 4 | g++ MotorExample.o PWM.o -o MotorExample 5 | 6 | BasicPWMExample: BasicPWMExample.o PWM.o 7 | g++ BasicPWMExample.o PWM.o -o BasicPWMExample 8 | 9 | ServoExample: ServoExample.o PWM.o 10 | g++ ServoExample.o PWM.o -o ServoExample 11 | 12 | MotorExample.o: examples/MotorExample.cpp 13 | g++ -c examples/MotorExample.cpp 14 | 15 | BasicPWMExample.o: examples/BasicPWMExample.cpp 16 | g++ -c examples/BasicPWMExample.cpp 17 | 18 | ServoExample.o: examples/ServoExample.cpp 19 | g++ -c examples/ServoExample.cpp 20 | 21 | PWM.o: PWM.cpp 22 | g++ -c PWM.cpp 23 | 24 | clean: 25 | rm -rf *o MotorExample BasicPWMExample ServoExample 26 | 27 | -------------------------------------------------------------------------------- /library/Motor.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Motor.h 3 | * Some helper libraries to use 4 | * 5 | * Created on: May 27, 2013 6 | * Author: Saad Ahmad ( http://www.saadahmad.ca ) 7 | */ 8 | 9 | #ifndef MOTOR_H_ 10 | #define MOTOR_H_ 11 | 12 | // #include "Globals.h" 13 | #include 14 | #include "PWM.h" 15 | 16 | // This is so that we get smooth transitions between different PWM levels. 17 | // Useful for motors as a sudden voltage change can cause kick back and producing undesirable results 18 | const int SPEED_STEP_VALUE = 100; 19 | 20 | // A motor esc controller library 21 | class MotorControl 22 | { 23 | PWM::Pin m_pin; 24 | int m_minPWM; 25 | int m_maxPWM; 26 | int m_currentPWM; 27 | int m_targetPWM; 28 | float m_minValue; 29 | float m_maxValue; 30 | public: 31 | PWM::Pin &ModifyPWMPin() 32 | { 33 | return m_pin; 34 | } 35 | const int &GetMinPWM() const 36 | { 37 | return m_minPWM; 38 | } 39 | void SetMinPWM(const int & minPWM) 40 | { 41 | m_minPWM = minPWM; 42 | } 43 | const int &GetMaxPWM() const 44 | { 45 | return m_maxPWM; 46 | } 47 | void SetMaxPWM(const int & maxPWM) 48 | { 49 | m_maxPWM = maxPWM; 50 | } 51 | const int &GetTargetPWM() const 52 | { 53 | return m_targetPWM; 54 | } 55 | void SetTargetPWM(const int & targetPWM) 56 | { 57 | m_targetPWM = targetPWM; 58 | } 59 | const int &GetCurrentPWM() const 60 | { 61 | return m_currentPWM; 62 | } 63 | void SetCurrentPWM(const int & currentPWM) 64 | { 65 | m_currentPWM = currentPWM; 66 | } 67 | const float &GetMinValue() const 68 | { 69 | return m_minValue; 70 | } 71 | void SetMinValue(const float & minValue) 72 | { 73 | m_minValue = minValue; 74 | } 75 | const float &GetMaxValue() const 76 | { 77 | return m_maxValue; 78 | } 79 | void SetMaxValue(const float & maxValue) 80 | { 81 | m_maxValue = maxValue; 82 | } 83 | 84 | MotorControl(const std::string & pinName, const float & currentValue, const float & minValue, const float & maxValue, const int & minPWM = 1000, const int & maxPWM = 2000) : 85 | m_pin(pinName, 20 * MILLISECONDS_TO_NANOSECONDS, 1 * MILLISECONDS_TO_NANOSECONDS) 86 | { 87 | SetMinPWM(minPWM); 88 | SetMaxPWM(maxPWM); 89 | SetMinValue(minValue); 90 | SetMaxValue(maxValue); 91 | SetOutputValue(currentValue); 92 | SetCurrentPWM(GetTargetPWM()); 93 | } 94 | virtual ~MotorControl() { } 95 | void SetOutputPercent(const float & percent) 96 | { 97 | int newPWM = int(GetMinPWM() + percent * (GetMaxPWM() - GetMinPWM())); 98 | #if 0 99 | SetTargetPWM(Clamp(newPWM, GetMinPWM(), GetMaxPWM())); 100 | #else 101 | SetTargetPWM(newPWM); 102 | #endif 103 | } 104 | virtual void SetOutputValue(const float & value) 105 | { 106 | SetOutputPercent((value - GetMinValue()) / (GetMaxValue() - GetMinValue())); 107 | } 108 | void UpdatePWMSignal() 109 | { 110 | UpdatePWMOutput(); 111 | // Write out to PWM 112 | ModifyPWMPin().SetDutyUS(GetCurrentPWM()); 113 | } 114 | void Enable() 115 | { 116 | ModifyPWMPin().Enable(); 117 | } 118 | private: 119 | void UpdatePWMOutput() 120 | { 121 | if (m_currentPWM < m_targetPWM && (m_targetPWM - m_currentPWM) >= SPEED_STEP_VALUE) 122 | { 123 | m_currentPWM += SPEED_STEP_VALUE; 124 | } 125 | else if (m_currentPWM > m_targetPWM && (m_currentPWM - m_targetPWM) >= SPEED_STEP_VALUE) 126 | { 127 | m_currentPWM -= SPEED_STEP_VALUE; 128 | } 129 | else 130 | { 131 | m_currentPWM = m_targetPWM; 132 | } 133 | } 134 | }; 135 | 136 | // A servo controller library 137 | class ServoControl: public MotorControl 138 | { 139 | float m_centerValue; 140 | public: 141 | const float &GetCenterValue() const 142 | { 143 | return m_centerValue; 144 | } 145 | void SetCenterValue(const float & centerValue) 146 | { 147 | m_centerValue = centerValue; 148 | } 149 | 150 | ServoControl(const std::string & pinName, const float & centerValue, const float & minValue, const float & maxValue, const int & minPWM = 1000, const int & maxPWM = 2000) : 151 | MotorControl(pinName, centerValue, minValue, maxValue, minPWM, maxPWM) 152 | { 153 | SetCenterValue(centerValue); 154 | } 155 | void SetAngleRelativeToCenter(const float & offset) 156 | { 157 | SetOutputValue(GetCenterValue() + offset); 158 | } 159 | void SetAngle(const float & angle) 160 | { 161 | SetOutputValue(angle); 162 | } 163 | }; 164 | 165 | #endif /* MOTOR_H_ */ 166 | -------------------------------------------------------------------------------- /library/PWM.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * PWM.cpp 3 | * 4 | * Created on: May 30, 2013 5 | * Author: Saad Ahmad ( http://www.saadahmad.ca ) 6 | */ 7 | #include "PWM.h" 8 | #include 9 | 10 | namespace PWM 11 | { 12 | // A bunch of helper functions to get us locations in the file system. 13 | // They are used so that we can manipulate the pwm driver through the /sys interface 14 | std::string GetFullNameOfFileInDirectory(const std::string & dirName, const std::string & fileNameToFind) 15 | { 16 | DIR *pDir; 17 | 18 | dirent *pFile; 19 | if ((pDir = opendir(dirName.c_str())) == NULL) 20 | { 21 | std::cout << "Directory name: " << dirName << " doesnt exist!" << std::endl; 22 | throw std::bad_exception(); 23 | } 24 | while ((pFile = readdir(pDir)) != NULL) 25 | { 26 | std::string currentFileName = (pFile->d_name); 27 | if (currentFileName.find(fileNameToFind) != std::string::npos) 28 | { 29 | return currentFileName; 30 | } 31 | } 32 | return std::string(""); 33 | } 34 | 35 | std::string GetCapeManagerSlotsPath() 36 | { 37 | static std::string g_capeManagerSlotsPath; 38 | if (g_capeManagerSlotsPath.length() <= 0) 39 | { 40 | #if DEBUG_VERBOSE_OUTPUT 41 | std::cout << "Setting up cape manager path" << std::endl; 42 | #endif 43 | std::string capeBasePath("/sys/devices/"); 44 | std::string fileName = GetFullNameOfFileInDirectory(capeBasePath, std::string("bone_capemgr.")); 45 | g_capeManagerSlotsPath = capeBasePath + fileName + "/slots"; 46 | } 47 | return g_capeManagerSlotsPath; 48 | } 49 | 50 | std::string GetOCPPath() 51 | { 52 | static std::string g_ocpPath; 53 | if (g_ocpPath.length() == 0) 54 | { 55 | std::string ocpBasePath("/sys/devices/"); 56 | std::string ocpName = GetFullNameOfFileInDirectory(ocpBasePath, std::string("ocp.")); 57 | g_ocpPath = ocpBasePath + ocpName + '/'; 58 | } 59 | return g_ocpPath; 60 | } 61 | 62 | int GetCapeManagerSlot(const std::string & moduleName) 63 | { 64 | #if DEBUG_VERBOSE_OUTPUT 65 | std::cout << "Trying to find slot for module: " << moduleName << std::endl; 66 | #endif 67 | std::ifstream in(GetCapeManagerSlotsPath().c_str()); 68 | in.exceptions(std::ios::badbit); 69 | int slot = -1; 70 | while (in >> slot) 71 | { 72 | std::string restOfLine; 73 | std::getline(in, restOfLine); 74 | if (restOfLine.find(moduleName) != std::string::npos) 75 | { 76 | #if DEBUG_VERBOSE_OUTPUT 77 | std::cout << "Found Module: " << moduleName << " at slot: " << slot << std::endl; 78 | #endif 79 | return slot; 80 | } 81 | } 82 | #if DEBUG_VERBOSE_OUTPUT 83 | std::cout << "Module: " << moduleName << " not found in cape manager!" << std::endl; 84 | #endif 85 | return -1; 86 | } 87 | void LoadDeviceTreeModule(const std::string & name) 88 | { 89 | int slot = GetCapeManagerSlot(name); 90 | if (slot == -1) 91 | { 92 | #if DEBUG_VERBOSE_OUTPUT 93 | std::cout << "Adding Module: " << name << std::endl; 94 | std::cout << "Its going in: " << GetCapeManagerSlotsPath() << std::endl; 95 | #endif 96 | WriteToFile(GetCapeManagerSlotsPath(), name); 97 | 98 | usleep(MODULE_DELAY_TIME_US); 99 | } 100 | else 101 | { 102 | #if DEBUG_VERBOSE_OUTPUT 103 | std::cout << "Module " << name << " is already in here!" << std::endl; 104 | #endif 105 | } 106 | } 107 | void UnloadDeviceTreeModule(const std::string name) 108 | { 109 | int currentSlot = GetCapeManagerSlot(name); 110 | if (currentSlot == -1) 111 | { 112 | std::cout << "Why is the module " << name << " being unloaded when its not in use?" << std::endl; 113 | throw std::bad_exception(); 114 | } 115 | #if DEBUG_VERBOSE_OUTPUT 116 | std::cout << "Unloading module: " << name << std::endl; 117 | #endif 118 | WriteToFile(GetCapeManagerSlotsPath(), std::string("-") + ToString(currentSlot)); 119 | 120 | usleep(MODULE_DELAY_TIME_US); 121 | } 122 | } 123 | -------------------------------------------------------------------------------- /library/PWM.h: -------------------------------------------------------------------------------- 1 | /* 2 | * PWM.h 3 | * A C++ wrapper for the EHRPWM interface 4 | * 5 | * Created on: May 27, 2013 6 | * Author: Saad Ahmad ( http://www.saadahmad.ca ) 7 | */ 8 | 9 | #ifndef PWM_H_ 10 | #define PWM_H_ 11 | 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | 18 | const int MICRSECONDS_TO_NANOSECONDS = 1000; 19 | const int MILLISECONDS_TO_MICROSECONDS = 1000; 20 | const int MILLISECONDS_TO_NANOSECONDS = MILLISECONDS_TO_MICROSECONDS * MICRSECONDS_TO_NANOSECONDS; 21 | const long MODULE_DELAY_TIME_US = 100 * MILLISECONDS_TO_MICROSECONDS; // Time to wait for module to be loaded and the sysfs interface setup 22 | 23 | #define DEBUG_VERBOSE_OUTPUT 0 24 | 25 | namespace PWM 26 | { 27 | template inline std::string ToString(const T & value) 28 | { 29 | std::stringstream ss; 30 | ss << value; 31 | return ss.str(); 32 | } 33 | 34 | inline void WriteToFile(const std::string & filePath, const std::string & value) 35 | { 36 | #if DEBUG_VERBOSE_OUTPUT 37 | std::cout << "Writing: " << value << " to: " << filePath << std::endl; 38 | #endif 39 | std::ofstream out; 40 | out.open(filePath.c_str()); 41 | out.exceptions(std::ios::badbit); 42 | out << value << std::endl; 43 | out.close(); 44 | } 45 | 46 | 47 | // A bunch of helper functions to get us locations in the file system. 48 | // They are used so that we can manipulate the pwm driver through the /sys interface 49 | std::string GetFullNameOfFileInDirectory(const std::string & dirName, const std::string & fileNameToFind); 50 | std::string GetCapeManagerSlotsPath(); 51 | std::string GetOCPPath(); 52 | int GetCapeManagerSlot(const std::string & moduleName); 53 | void LoadDeviceTreeModule(const std::string & name); 54 | void UnloadDeviceTreeModule(const std::string name); 55 | 56 | class Pin 57 | { 58 | public: 59 | enum RunStatus 60 | { 61 | Free = -2, WaitingForSetp, Disabled, Enabled, 62 | }; 63 | enum Polarity 64 | { 65 | PolaritryHigh = 0, PolarityLow, 66 | }; 67 | 68 | private: 69 | std::string m_dutyFilePath; 70 | std::string m_periodFilePath; 71 | std::string m_polarityFilePath; 72 | std::string m_runFilePath; 73 | std::string m_pinName; 74 | 75 | long m_periodNS; 76 | long m_dutyNS; 77 | Polarity m_polarity; 78 | RunStatus m_runStatus; 79 | 80 | public: 81 | const std::string &GetDutyFilePath() const 82 | { 83 | return m_dutyFilePath; 84 | } 85 | const std::string &GetPeriodFilePath() const 86 | { 87 | return m_periodFilePath; 88 | } 89 | const std::string &GetPolarityFilePath() const 90 | { 91 | return m_polarityFilePath; 92 | } 93 | const std::string &GetPinName() const 94 | { 95 | return m_pinName; 96 | } 97 | const std::string &GetRunFilePath() const 98 | { 99 | return m_runFilePath; 100 | } 101 | 102 | const RunStatus &GetRunStatus() const 103 | { 104 | return m_runStatus; 105 | } 106 | 107 | const long &GetPeriodNS() const 108 | { 109 | return m_periodNS; 110 | } 111 | const Polarity &GetPolarity() const 112 | { 113 | return m_polarity; 114 | } 115 | const long &GetDutyNS() const 116 | { 117 | return m_dutyNS; 118 | } 119 | 120 | private: 121 | void WriteDutyNSToFile() 122 | { 123 | WriteToFile(GetDutyFilePath(), ToString(GetDutyNS())); 124 | } 125 | void WritePeriodNSToFile() 126 | { 127 | WriteToFile(GetPeriodFilePath(), ToString(GetPeriodNS())); 128 | } 129 | void WritePolarityToFile() 130 | { 131 | WriteToFile(GetPolarityFilePath(), GetPolarity() == PolaritryHigh ? std::string("0") : std::string("1")); 132 | } 133 | 134 | public: 135 | void SetDutyNS(const long & dutyNS) 136 | { 137 | m_dutyNS = std::min(dutyNS, GetPeriodNS()); 138 | if (GetRunStatus() == Enabled) 139 | WriteDutyNSToFile(); 140 | } 141 | void SetDutyUS(const int &dutyUS) 142 | { 143 | SetDutyNS((long) dutyUS * MICRSECONDS_TO_NANOSECONDS); 144 | } 145 | void SetDutyMS(const int &dutyMS) 146 | { 147 | SetDutyNS((long) dutyMS * MILLISECONDS_TO_NANOSECONDS); 148 | } 149 | void SetDutyPercent(const float &percent) 150 | { 151 | SetDutyNS(long(GetPeriodNS() * percent)); 152 | } 153 | 154 | void SetPeriodNS(const long & periodNS) 155 | { 156 | if (GetRunStatus() == Enabled || GetRunStatus() == Disabled) 157 | { 158 | std::cout << "Trying to set the period but we need to release the PWM module first!" << std::endl; 159 | throw std::bad_exception(); 160 | return; 161 | } 162 | m_periodNS = periodNS; 163 | if (GetRunStatus() == Enabled) 164 | WritePeriodNSToFile(); 165 | } 166 | void SetPeriodUS(const int &periodUS) 167 | { 168 | SetPeriodNS((long) periodUS * MICRSECONDS_TO_NANOSECONDS); 169 | } 170 | void SetPeriodMS(const int &periodMS) 171 | { 172 | SetPeriodNS((long) periodMS * MILLISECONDS_TO_NANOSECONDS); 173 | } 174 | 175 | void SetPolarity(const Polarity & polarity) 176 | { 177 | m_polarity = polarity; 178 | if (GetRunStatus() == Enabled) 179 | WritePolarityToFile(); 180 | } 181 | 182 | private: 183 | void SetRunStatus(const RunStatus & newRunStatus) 184 | { 185 | if (newRunStatus != GetRunStatus()) 186 | { 187 | if (newRunStatus == Disabled) 188 | { 189 | WriteToFile(GetRunFilePath(), std::string("0")); 190 | } 191 | else if (newRunStatus == Enabled) 192 | { 193 | if (GetRunStatus() == Free) 194 | { 195 | InitPinFS(); 196 | } 197 | // Force write the file values out 198 | WritePeriodNSToFile(); 199 | WriteDutyNSToFile(); 200 | WritePolarityToFile(); 201 | 202 | WriteToFile(GetRunFilePath(), std::string("1")); 203 | } 204 | else if (newRunStatus == Free) 205 | { 206 | if (GetRunStatus() != Disabled) 207 | { 208 | SetRunStatus(Disabled); 209 | } 210 | UnloadDeviceTreeModule(GetPinName()); 211 | } 212 | } 213 | m_runStatus = newRunStatus; 214 | } 215 | public: 216 | void Enable() 217 | { 218 | SetRunStatus(Enabled); 219 | } 220 | void Disable() 221 | { 222 | SetRunStatus(Disabled); 223 | } 224 | void Release() 225 | { 226 | SetRunStatus(Free); 227 | } 228 | 229 | public: 230 | ~Pin() 231 | { 232 | Release(); 233 | } 234 | Pin(const std::string & pinName, const long & periodNS = 20 * MILLISECONDS_TO_NANOSECONDS, const long & dutyNS = 1 * MILLISECONDS_TO_NANOSECONDS) : 235 | m_pinName(pinName) 236 | { 237 | // If the pin is already in use then we need to free it! 238 | if (GetCapeManagerSlot(GetPinName()) != -1) 239 | UnloadDeviceTreeModule(GetPinName()); 240 | 241 | m_runStatus = WaitingForSetp; 242 | 243 | SetPeriodNS(periodNS); 244 | SetDutyNS(dutyNS); 245 | SetPolarity(PolaritryHigh); 246 | 247 | InitPinFS(); 248 | } 249 | 250 | void InitPinFS() 251 | { 252 | LoadDeviceTreeModule(std::string("am33xx_pwm")); 253 | std::string pinModule = std::string("sc_pwm_") + GetPinName(); 254 | LoadDeviceTreeModule(pinModule); 255 | std::string pinInterfacePath = GetOCPPath() + GetFullNameOfFileInDirectory(GetOCPPath(), GetPinName()) + "/"; 256 | m_dutyFilePath = pinInterfacePath + "duty"; 257 | m_periodFilePath = pinInterfacePath + "period"; 258 | m_polarityFilePath = pinInterfacePath + "polarity"; 259 | m_runFilePath = pinInterfacePath + "run"; 260 | 261 | 262 | #if DEBUG_VERBOSE_OUTPUT 263 | std::cout << GetDutyFilePath() << std::endl; 264 | std::cout << GetPeriodFilePath() << std::endl; 265 | std::cout << GetPolarityFilePath() << std::endl; 266 | std::cout << GetRunFilePath() << std::endl; 267 | #endif 268 | } 269 | }; 270 | } 271 | 272 | #endif /* PWM_H_ */ 273 | -------------------------------------------------------------------------------- /library/examples/BasicPWMExample.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * BasicPWM.cpp 3 | * 4 | * Example of basic PWM usage and fading an LED. Also shows how periods should be changed 5 | * 6 | * Created on: May 29, 2013 7 | * Author: Saad Ahmad ( http://www.saadahmad.ca ) 8 | */ 9 | 10 | #include "../PWM.h" 11 | #include 12 | #include 13 | 14 | int main() 15 | { 16 | const int delayMS = 50; 17 | const long periodNS = 2 * MILLISECONDS_TO_NANOSECONDS; 18 | PWM::Pin pinA("P8_13", periodNS); // Since both pins share the same channel, they're periods must be the same 19 | PWM::Pin pinB("P8_19", periodNS); 20 | 21 | std::cout << PWM::GetCapeManagerSlot("P8_13") << std::endl; 22 | 23 | // Enable both only after we have set the periods properly. 24 | // Otherwise we will have conflicts since each pin will try to set its own period and conflict with the others 25 | pinA.Enable(); 26 | pinB.Enable(); 27 | 28 | std::cout << "Pins Setup and ready to go!" << std::endl; 29 | 30 | for (int i = 0; i < 100; i++) 31 | { 32 | std::clock_t startTime = std::clock(); 33 | while (((clock() - startTime) * 1000.0 / CLOCKS_PER_SEC) < delayMS) 34 | { 35 | pinA.SetDutyPercent(float(i) / 100); 36 | pinB.SetDutyPercent(1 - float(i) / 100); 37 | } 38 | 39 | } 40 | 41 | // Release the pins so they are disabled and so that we can also reset their periods 42 | // Note if you just call Disable() then you cant change the period as both channels will be treated as in use 43 | pinA.Release(); 44 | pinB.Release(); 45 | 46 | std::cout << "Setting new periods " << std::endl; 47 | 48 | pinA.SetPeriodNS(periodNS * 2); 49 | std::cout << "New period for Pin A set" << std::endl; 50 | 51 | pinB.SetPeriodNS(periodNS * 2); 52 | std::cout << "New period for Pin B set" << std::endl; 53 | 54 | // Once the periods have been set we can start again 55 | pinA.Enable(); 56 | std::cout << "Enabled pin A" << std::endl; 57 | 58 | pinB.Enable(); 59 | std::cout << "Enabled pin B" << std::endl; 60 | 61 | for (int i = 0; i < 100; i++) 62 | { 63 | std::clock_t startTime = std::clock(); 64 | while (((clock() - startTime) * 1000.0 / CLOCKS_PER_SEC) < delayMS) 65 | { 66 | pinA.SetDutyPercent(float(i) / 100); 67 | pinB.SetDutyPercent(1 - float(i) / 100); 68 | } 69 | } 70 | 71 | std::cout << "Done everything. Quiting now!" << std::endl; 72 | } 73 | 74 | -------------------------------------------------------------------------------- /library/examples/MotorExample.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * MotorExample.cpp 3 | * 4 | * Example of PWM used to control motors via an esc 5 | * 6 | * Created on: May 29, 2013 7 | * Author: Saad Ahmad ( http://www.saadahmad.ca ) 8 | */ 9 | 10 | #include 11 | #include "../PWM.h" 12 | #include "../Motor.h" 13 | #include 14 | #include 15 | 16 | const float MIN_SPEED = 0; 17 | const float MAX_SPEED = 100; 18 | const int MIN_MOTOR_PULSE_TIME = 1000; 19 | const int MAX_MOTOR_PULSE_TIME = 2000; 20 | const std::string PIN_MOTOR_YAW("P8_13"); 21 | const std::string PIN_MOTOR_RIGHT("P8_19"); 22 | const std::string PIN_MOTOR_LEFT("P9_14"); 23 | 24 | MotorControl motorControls[] = { MotorControl(PIN_MOTOR_LEFT, MIN_SPEED, MIN_SPEED, MAX_SPEED), MotorControl(PIN_MOTOR_RIGHT, MIN_SPEED, MIN_SPEED, MAX_SPEED), MotorControl(PIN_MOTOR_YAW, MIN_SPEED, MIN_SPEED, MAX_SPEED), }; 25 | 26 | 27 | #include 28 | 29 | // Stop all the motors when we interrupt the program so they don't keep going 30 | void sig_handler(int signum) 31 | { 32 | for (unsigned int iMotor = 0; iMotor < 3; iMotor++) 33 | { 34 | MotorControl & motor = motorControls[iMotor]; 35 | motor.SetOutputValue(0); 36 | motor.UpdatePWMSignal(); 37 | } 38 | 39 | exit(signum); 40 | } 41 | 42 | int main() 43 | { 44 | signal(SIGINT, sig_handler); 45 | signal(SIGSEGV, sig_handler); 46 | signal(SIGQUIT, sig_handler); 47 | signal(SIGHUP, sig_handler); 48 | signal(SIGABRT, sig_handler); 49 | 50 | for (int iMotor = 0; iMotor < 3; iMotor++) 51 | { 52 | motorControls[iMotor].Enable(); 53 | } 54 | 55 | while (true) 56 | { 57 | // Increase by 10% each time and view the output PPM signal 58 | for (int i = 0; i < 100; i += 10) 59 | { 60 | std::clock_t startTime = std::clock(); 61 | while ( ((clock() - startTime) * 1000.0 / CLOCKS_PER_SEC) < 500 ) 62 | { 63 | for (int iMotor = 0; iMotor < 3; iMotor++) 64 | { 65 | MotorControl & motor = motorControls[iMotor]; 66 | motor.SetOutputValue((i + iMotor * 20) % 100); // Offset the motors a bit 67 | motor.UpdatePWMSignal(); 68 | } 69 | } 70 | } 71 | } 72 | } 73 | 74 | -------------------------------------------------------------------------------- /library/examples/ServoExample.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * ServoExample.cpp 3 | * 4 | * Example of PWM used to control servos via an esc 5 | * 6 | * Created on: May 29, 2013 7 | * Author: Saad Ahmad ( http://www.saadahmad.ca ) 8 | * Modified: Mike Lewis ( http://alphalem.com ) 9 | */ 10 | 11 | #include 12 | #include "../PWM.h" 13 | #include "../Motor.h" 14 | #include 15 | #include 16 | 17 | const float MIN_SPEED = 0; 18 | const float CTR_SPEED = 90; 19 | const float MAX_SPEED = 180; 20 | const int MIN_SERVO_PULSE_TIME = 750; 21 | const int MAX_SERVO_PULSE_TIME = 2250; 22 | const std::string PIN_SERVO_RIGHT("P8_13"); 23 | const std::string PIN_SERVO_LEFT("P9_14"); 24 | 25 | ServoControl servoControls[] = { 26 | ServoControl(PIN_SERVO_LEFT, CTR_SPEED, MIN_SPEED, MAX_SPEED), 27 | ServoControl(PIN_SERVO_RIGHT, CTR_SPEED, MIN_SPEED, MAX_SPEED) 28 | }; 29 | 30 | 31 | #include 32 | 33 | // Stop all the motors when we interrupt the program so they don't keep going 34 | void sig_handler(int signum) { 35 | for (unsigned int i = 0; i < 2; i++) { 36 | ServoControl& servo = servoControls[i]; 37 | servo.SetAngle(90); 38 | servo.UpdatePWMSignal(); 39 | } 40 | 41 | exit(signum); 42 | } 43 | 44 | void servo_test(int angle) 45 | { 46 | std::clock_t startTime = std::clock(); 47 | while (((clock() - startTime) * 1000.0 / CLOCKS_PER_SEC) < 500) { 48 | for (int iServo = 0; iServo < 2; iServo++) { 49 | ServoControl& servo = servoControls[iServo]; 50 | // Offset the motors a bit 51 | servo.SetAngle(angle); 52 | servo.UpdatePWMSignal(); 53 | } 54 | } 55 | } 56 | 57 | int main() { 58 | signal(SIGINT, sig_handler); 59 | signal(SIGSEGV, sig_handler); 60 | signal(SIGQUIT, sig_handler); 61 | signal(SIGHUP, sig_handler); 62 | signal(SIGABRT, sig_handler); 63 | 64 | for (int i = 0; i < 2; i++) { 65 | servoControls[i].Enable(); 66 | } 67 | 68 | while (true) { 69 | // Increase by 10 degrees (CW) each time 70 | for (int i = 90; i < 180; i += 5) { 71 | servo_test(i); 72 | } 73 | 74 | // Decrease by 10 degrees (CCW) each time 75 | for (int i = 180; i > 90; i -= 5) { 76 | servo_test(i); 77 | } 78 | 79 | // Decrease by 10 degrees (CCW) each time 80 | for (int i = 90; i > 0; i -= 5) { 81 | servo_test(i); 82 | } 83 | 84 | // Increase by 10 degrees (CW) each time 85 | for (int i = 0; i < 90; i += 5) { 86 | servo_test(i); 87 | } 88 | } 89 | } 90 | 91 | --------------------------------------------------------------------------------