@@ -23,17 +23,19 @@ SOFTWARE.
2323
2424#include <stdio.h>
2525#include <stdlib.h>
26+ #include <sys/stat.h>
2627#include <sys/types.h>
2728#include <string.h>
2829#include <fcntl.h>
2930#include <unistd.h>
3031#include "c_pwm.h"
3132#include "common.h"
3233
33- #define KEYLEN 7
34+ #ifdef BBBVERSION41
35+ #include "c_pinmux.h"
36+ #endif
3437
35- #define PERIOD 0
36- #define DUTY 1
38+ #define KEYLEN 7
3739
3840int pwm_initialized = 0 ;
3941
@@ -85,13 +87,20 @@ void export_pwm(struct pwm_exp *new_pwm)
8587
8688int initialize_pwm (void )
8789{
90+ #ifdef BBBVERSION41 // don't load overlay in 4.1+
91+ if (!pwm_initialized ) {
92+ #else
8893 if (!pwm_initialized && load_device_tree ("am33xx_pwm" )) {
89- build_path ("/sys/devices" , "ocp" , ocp_dir , sizeof (ocp_dir ));
94+ #endif
95+ if (!build_path ("/sys/devices" , "ocp" , ocp_dir , sizeof (ocp_dir )))
96+ {
97+ return -1 ;
98+ }
9099 pwm_initialized = 1 ;
91100 return 1 ;
92101 }
93102
94- return 0 ;
103+ return 0 ;
95104}
96105
97106int pwm_set_frequency (const char * key , float freq ) {
@@ -162,37 +171,128 @@ int pwm_set_duty_cycle(const char *key, float duty) {
162171
163172int pwm_start (const char * key , float duty , float freq , int polarity )
164173{
174+ #ifdef BBBVERSION41
175+ char pwm_dev_path [45 ]; // "/sys/devices/platform/ocp/48300000.epwmss"
176+ char pwm_addr_path [60 ]; // "/sys/devices/platform/ocp/48300000.epwmss/48300200.ehrpwm"
177+ char pwm_chip_path [75 ]; // "/sys/devices/platform/ocp/48300000.epwmss/48300200.ehrpwm/pwm/pwmchip0"
178+ char pwm_export_path [80 ]; // "/sys/devices/platform/ocp/48300000.epwmss/48300200.ehrpwm/pwm/pwmchip0/export"
179+ char pwm_path [80 ]; // "/sys/devices/platform/ocp/48300000.epwmss/48300200.ehrpwm/pwm/pwmchip0/pwm1"
180+ char duty_path [90 ]; // "/sys/devices/platform/ocp/48300000.epwmss/48300200.ehrpwm/pwm/pwmchip0/pwm1/duty_cycle"
181+ char period_path [90 ];
182+ char polarity_path [90 ];
183+ char enable_path [90 ];
184+
185+ int period_fd , duty_fd , polarity_fd ;
186+ struct pwm_exp * new_pwm , * pwm ;
187+ struct stat s ;
188+ int err ;
189+ FILE * f = NULL ;
190+ pwm_t * p ;
191+
192+ if (!pwm_initialized ) {
193+ if (initialize_pwm () < 0 ) {
194+ return -1 ;
195+ }
196+ }
197+
198+ // Make sure that one of the universal capes is loaded
199+ if (!( device_tree_loaded ("cape-univ-audio" ) // from cdsteinkuehler/beaglebone-universal-io
200+ || device_tree_loaded ("cape-univ-emmc" ) // ""
201+ || device_tree_loaded ("cape-univ-hdmi" ) // ""
202+ || device_tree_loaded ("cape-universal" ) // ""
203+ || device_tree_loaded ("cape-universala" ) // ""
204+ || device_tree_loaded ("cape-universaln" ) // ""
205+ || device_tree_loaded ("univ-all" ) // from latest BeagleBone Debian 8 images
206+ || device_tree_loaded ("univ-bbgw" ) // ""
207+ || device_tree_loaded ("univ-emmc" ) // ""
208+ || device_tree_loaded ("univ-hdmi" ) // ""
209+ || device_tree_loaded ("univ-nhdmi" ))) // ""
210+ {
211+ return -1 ;
212+ }
213+ // Do pinmuxing
214+ set_pin_mode (key , "pwm" );
215+
216+ // Get info for pwm
217+ if (!get_pwm_by_key (key , & p )) {
218+ return -1 ;
219+ }
220+
221+ build_path (ocp_dir , p -> chip , pwm_dev_path , sizeof (pwm_dev_path ));
222+ build_path (pwm_dev_path , p -> addr , pwm_addr_path , sizeof (pwm_addr_path ));
223+ build_path (pwm_addr_path , "pwm/pwmchip" , pwm_chip_path , sizeof (pwm_chip_path ));
224+
225+ snprintf (pwm_path , sizeof (pwm_path ), "%s/pwm%d" , pwm_chip_path , p -> index );
226+
227+ // Export PWM if hasn't already been
228+ err = stat (pwm_path , & s );
229+ if (-1 == err ) {
230+ if (ENOENT == errno ) { // directory does not exist
231+ snprintf (pwm_export_path , sizeof (pwm_export_path ), "%s/export" , pwm_chip_path );
232+ f = fopen (pwm_export_path , "w" );
233+ if (f == NULL ) { // Can't open the export file
234+ return -1 ;
235+ }
236+ fprintf (f , "%d" , p -> index );
237+ fclose (f );
238+ } else {
239+ perror ("stat" );
240+ return -1 ;
241+ } else {
242+ if (S_ISDIR (s .st_mode )) {
243+ /* It is a directory. Already exported */
244+ } else {
245+ /* It's a file. Shouldn't ever happen */
246+ return -1 ;
247+ }
248+ }
249+ }
250+
251+ err = stat (pwm_path , & s );
252+ if (-1 == err ) {
253+ if (ENOENT == errno ) {
254+ // Directory still doesn't exist, exit with error
255+ return -1 ;
256+ }
257+ }
258+
259+ snprintf (duty_path , sizeof (duty_path ), "%s/duty_cycle" , pwm_path );
260+ #else
165261 char fragment [18 ];
166- char pwm_test_fragment [20 ];
167- char pwm_test_path [45 ];
262+ char pwm_fragment [20 ];
263+ char pwm_path [45 ];
264+ char duty_path [56 ]
168265 char period_path [50 ];
169- char duty_path [50 ];
170266 char polarity_path [55 ];
171267 int period_fd , duty_fd , polarity_fd ;
172- struct pwm_exp * new_pwm , * pwm ;
268+ struct pwm_exp * new_pwm ;
173269
174270 if (!pwm_initialized ) {
175- initialize_pwm ();
271+ if (initialize_pwm () < 0 ) {
272+ return -1 ;
273+ }
176274 }
177275
276+ // load tree
178277 snprintf (fragment , sizeof (fragment ), "bone_pwm_%s" , key );
179-
180-
181278 if (!load_device_tree (fragment )) {
182279 //error enabling pin for pwm
183280 return -1 ;
184281 }
185282
186283 //creates the fragment in order to build the pwm_test_filename, such as "pwm_test_P9_13"
187- snprintf (pwm_test_fragment , sizeof (pwm_test_fragment ), "pwm_test_%s" , key );
284+ snprintf (pwm_fragment , sizeof (pwm_fragment ), "pwm_test_%s" , key );
285+
286+ //finds and builds the pwm_path, as it can be variable...
287+ build_path (ocp_dir , pwm_fragment , pwm_path , sizeof (pwm_path ));
188288
189- //finds and builds the pwm_test_path, as it can be variable...
190- build_path (ocp_dir , pwm_test_fragment , pwm_test_path , sizeof (pwm_test_path ));
289+ //create the path for duty
290+ snprintf (duty_path , sizeof (duty_path ), "%s/duty" , pwm_path );
291+ #endif
191292
192- //create the path for the period and duty
193- snprintf (period_path , sizeof (period_path ), "%s/period" , pwm_test_path );
194- snprintf (duty_path , sizeof (duty_path ), "%s/duty" , pwm_test_path );
195- snprintf (polarity_path , sizeof (polarity_path ), "%s/polarity" , pwm_test_path );
293+ // create the path for period and polarity
294+ snprintf (period_path , sizeof (period_path ), "%s/period" , pwm_path );
295+ snprintf (polarity_path , sizeof (polarity_path ), "%s/polarity" , pwm_path );
196296
197297 //add period and duty fd to pwm list
198298 if ((period_fd = open (period_path , O_RDWR )) < 0 )
@@ -231,6 +331,14 @@ int pwm_start(const char *key, float duty, float freq, int polarity)
231331 pwm_set_polarity (key , polarity );
232332 pwm_set_duty_cycle (key , duty );
233333
334+ #ifdef BBBVERSION41 // Enable the PWM
335+ f = fopen (enable_path );
336+ if (f == NULL )
337+ return -1 ;
338+ fprintf (f , "1" );
339+ fclose (f );
340+ #endif
341+
234342 return 1 ;
235343}
236344
0 commit comments