@@ -21,13 +21,15 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
2121SOFTWARE.
2222*/
2323
24+ #include <errno.h>
2425#include <stdio.h>
2526#include <stdlib.h>
2627#include <sys/stat.h>
2728#include <sys/types.h>
2829#include <string.h>
2930#include <fcntl.h>
3031#include <unistd.h>
32+
3133#include "c_pwm.h"
3234#include "common.h"
3335
@@ -46,7 +48,9 @@ struct pwm_exp
4648 int period_fd ;
4749 int duty_fd ;
4850 int polarity_fd ;
49- unsigned long duty ;
51+ int enable_fd ;
52+ float duty ;
53+ unsigned long duty_ns ;
5054 unsigned long period_ns ;
5155 struct pwm_exp * next ;
5256};
@@ -87,11 +91,11 @@ void export_pwm(struct pwm_exp *new_pwm)
8791
8892BBIO_err initialize_pwm (void )
8993{
90- BBIO_err err ;
9194#ifdef BBBVERSION41 // don't load overlay in 4.1+
9295 if (!pwm_initialized ) {
9396 strncpy (ocp_dir , "/sys/devices/platform/ocp" , sizeof (ocp_dir ));
9497#else
98+ BBIO_err err ;
9599 if (!pwm_initialized && load_device_tree ("am33xx_pwm" )) {
96100 err = build_path ("/sys/devices" , "ocp" , ocp_dir , sizeof (ocp_dir ));
97101 if (err != BBIO_OK )
@@ -126,16 +130,29 @@ BBIO_err pwm_set_frequency(const char *key, float freq) {
126130 if (period_ns != pwm -> period_ns ) {
127131 pwm -> period_ns = period_ns ;
128132
133+ // Update period ns
129134 len = snprintf (buffer , sizeof (buffer ), "%lu" , period_ns );
130- write (pwm -> period_fd , buffer , len );
135+ lseek (pwm -> period_fd , 0 , SEEK_SET ); // Seek to beginning of file
136+ if (write (pwm -> period_fd , buffer , len ) < 0 ) {
137+ return BBIO_SYSFS ;
138+ }
139+
140+ // Update duty ns
141+ pwm -> duty_ns = (unsigned long )(pwm -> period_ns * (pwm -> duty / 100.0 ));
142+ len = snprintf (buffer , sizeof (buffer ), "%lu" , pwm -> duty_ns );
143+ lseek (pwm -> duty_fd , 0 , SEEK_SET ); // Seek to beginning of file
144+ if (write (pwm -> duty_fd , buffer , len ) < 0 ) {
145+ return BBIO_SYSFS ;
146+ }
131147 }
132148
133149 return BBIO_OK ;
134150}
135151
152+ // Only works before chip is enabled
136153BBIO_err pwm_set_polarity (const char * key , int polarity ) {
137154 int len ;
138- char buffer [7 ]; /* allow room for trailing NUL byte */
155+ char buffer [9 ]; /* allow room for trailing NUL byte */
139156 struct pwm_exp * pwm ;
140157
141158 pwm = lookup_exported_pwm (key );
@@ -144,8 +161,45 @@ BBIO_err pwm_set_polarity(const char *key, int polarity) {
144161 return BBIO_GEN ;
145162 }
146163
164+ // polarity can't be changed with enabled.
165+ #ifdef BBBVERSION41
166+ // Read the current enabled status
167+ len = 1 ;
168+ memset (buffer , 0 , 9 ); // Initialize buffer
169+ lseek (pwm -> enable_fd , 0 , SEEK_SET );
170+ if (read (pwm -> enable_fd , buffer , len ) < 0 ) {
171+ return BBIO_SYSFS ;
172+ }
173+
174+ // If the PWM is enabled, disable it
175+ // Can't set the polarity with device enabled
176+ // It will be reenabled after the parameters are set
177+ if (buffer [0 ] == '1' ) {
178+ lseek (pwm -> enable_fd , 0 , SEEK_SET );
179+ len = snprintf (buffer , sizeof (buffer ), "0" );
180+ if (write (pwm -> enable_fd , buffer , len ) < 0 ) {
181+ return BBIO_SYSFS ;
182+ }
183+ }
184+
185+ // Treating 0 as normal, 1 as inversed
186+ // See documentation of sysfs interface at
187+ // https://www.kernel.org/doc/Documentation/pwm.txt
188+ if (polarity == 0 ) {
189+ len = snprintf (buffer , sizeof (buffer ), "normal" );
190+ } else if (polarity == 1 ) {
191+ len = snprintf (buffer , sizeof (buffer ), "inversed" );
192+ } else {
193+ return BBIO_INVARG ;
194+ }
195+ #else
147196 len = snprintf (buffer , sizeof (buffer ), "%d" , polarity );
148- write (pwm -> polarity_fd , buffer , len );
197+ #endif
198+
199+ lseek (pwm -> polarity_fd , 0 , SEEK_SET ); // Seek to beginning of file
200+ if (write (pwm -> polarity_fd , buffer , len ) < 0 ) {
201+ return BBIO_SYSFS ;
202+ }
149203
150204 return BBIO_OK ;
151205}
@@ -164,17 +218,22 @@ BBIO_err pwm_set_duty_cycle(const char *key, float duty) {
164218 return BBIO_GEN ;
165219 }
166220
167- pwm -> duty = (unsigned long )(pwm -> period_ns * (duty / 100.0 ));
221+ pwm -> duty = duty ;
222+ pwm -> duty_ns = (unsigned long )(pwm -> period_ns * (duty / 100.0 ));
168223
169- len = snprintf (buffer , sizeof (buffer ), "%lu" , pwm -> duty );
170- write (pwm -> duty_fd , buffer , len );
224+ len = snprintf (buffer , sizeof (buffer ), "%lu" , pwm -> duty_ns );
225+ lseek (pwm -> duty_fd , 0 , SEEK_SET ); // Seek to beginning of file
226+ if (write (pwm -> duty_fd , buffer , len ) < 0 ) {
227+ return BBIO_SYSFS ;
228+ }
171229
172230 return BBIO_OK ;
173231}
174232
175- BBIO_err pwm_start (const char * key , float duty , float freq , int polarity )
233+ BBIO_err pwm_setup (const char * key , float duty , float freq , int polarity )
176234{
177- int err ;
235+ int e ;
236+ BBIO_err err ;
178237
179238#ifdef BBBVERSION41
180239 char pwm_dev_path [45 ]; // "/sys/devices/platform/ocp/48300000.epwmss"
@@ -187,14 +246,14 @@ BBIO_err pwm_start(const char *key, float duty, float freq, int polarity)
187246 char polarity_path [90 ];
188247 char enable_path [90 ];
189248
190- int period_fd , duty_fd , polarity_fd ;
191- struct pwm_exp * new_pwm , * pwm ;
249+ int period_fd , duty_fd , polarity_fd , enable_fd ;
250+ struct pwm_exp * new_pwm ;
192251 struct stat s ;
193252 FILE * f = NULL ;
194253 pwm_t * p ;
195254
196255 if (!pwm_initialized ) {
197- err = initialize_pwm ()
256+ err = initialize_pwm ();
198257 if (err != BBIO_OK ) {
199258 return err ;
200259 }
@@ -225,22 +284,25 @@ BBIO_err pwm_start(const char *key, float duty, float freq, int polarity)
225284 }
226285
227286 err = build_path (ocp_dir , p -> chip , pwm_dev_path , sizeof (pwm_dev_path ));
228- if (err != BBIO_OK )
287+ if (err != BBIO_OK ) {
229288 return err ;
289+ }
230290
231291 err = build_path (pwm_dev_path , p -> addr , pwm_addr_path , sizeof (pwm_addr_path ));
232- if (err != BBIO_OK )
292+ if (err != BBIO_OK ) {
233293 return err ;
294+ }
234295
235296 err = build_path (pwm_addr_path , "pwm/pwmchip" , pwm_chip_path , sizeof (pwm_chip_path ));
236- if (err != BBIO_OK )
297+ if (err != BBIO_OK ) {
237298 return err ;
299+ }
238300
239301 snprintf (pwm_path , sizeof (pwm_path ), "%s/pwm%d" , pwm_chip_path , p -> index );
240302
241303 // Export PWM if hasn't already been
242- err = stat (pwm_path , & s );
243- if (-1 == err ) {
304+ e = stat (pwm_path , & s );
305+ if (-1 == e ) {
244306 if (ENOENT == errno ) { // directory does not exist
245307 snprintf (pwm_export_path , sizeof (pwm_export_path ), "%s/export" , pwm_chip_path );
246308 f = fopen (pwm_export_path , "w" );
@@ -252,30 +314,31 @@ BBIO_err pwm_start(const char *key, float duty, float freq, int polarity)
252314 } else {
253315 perror ("stat" );
254316 return BBIO_GEN ;
317+ }
318+ } else {
319+ if (S_ISDIR (s .st_mode )) {
320+ /* It is a directory. Already exported */
255321 } else {
256- if (S_ISDIR (s .st_mode )) {
257- /* It is a directory. Already exported */
258- } else {
259- /* It's a file. Shouldn't ever happen */
260- return BBIO_GEN ;
261- }
322+ /* It's a file. Shouldn't ever happen */
323+ return BBIO_GEN ;
262324 }
263325 }
264326
265- err = stat (pwm_path , & s );
266- if (-1 == err ) {
327+ e = stat (pwm_path , & s );
328+ if (-1 == e ) {
267329 if (ENOENT == errno ) {
268330 // Directory still doesn't exist, exit with error
269331 return BBIO_GEN ;
270332 }
271333 }
272334
273335 snprintf (duty_path , sizeof (duty_path ), "%s/duty_cycle" , pwm_path );
336+ snprintf (enable_path , sizeof (enable_path ), "%s/enable" , pwm_path );
274337#else
275338 char fragment [18 ];
276339 char pwm_fragment [20 ];
277340 char pwm_path [45 ];
278- char duty_path [56 ]
341+ char duty_path [56 ];
279342 char period_path [50 ];
280343 char polarity_path [55 ];
281344 int period_fd , duty_fd , polarity_fd ;
@@ -317,10 +380,10 @@ BBIO_err pwm_start(const char *key, float duty, float freq, int polarity)
317380 if ((period_fd = open (period_path , O_RDWR )) < 0 )
318381 return BBIO_SYSFS ;
319382
320-
321383 if ((duty_fd = open (duty_path , O_RDWR )) < 0 ) {
322384 //error, close already opened period_fd.
323385 close (period_fd );
386+
324387 return BBIO_SYSFS ;
325388 }
326389
@@ -329,11 +392,24 @@ BBIO_err pwm_start(const char *key, float duty, float freq, int polarity)
329392 close (period_fd );
330393 close (duty_fd );
331394 return BBIO_SYSFS ;
332- }
395+ }
396+
397+ #ifdef BBBVERSION41
398+ if ((enable_fd = open (enable_path , O_RDWR )) < 0 ) {
399+ // error, close already opened files
400+ close (period_fd );
401+ close (duty_fd );
402+ close (polarity_fd );
403+ return BBIO_SYSFS ;
404+ }
405+ #endif
333406
334407 // add to list
335408 new_pwm = malloc (sizeof (struct pwm_exp ));
336- if (new_pwm == 0 ) {
409+ if (new_pwm == NULL ) {
410+ close (period_fd );
411+ close (duty_fd );
412+ close (polarity_fd );
337413 return BBIO_MEM ; // out of memory
338414 }
339415
@@ -342,32 +418,67 @@ BBIO_err pwm_start(const char *key, float duty, float freq, int polarity)
342418 new_pwm -> period_fd = period_fd ;
343419 new_pwm -> duty_fd = duty_fd ;
344420 new_pwm -> polarity_fd = polarity_fd ;
421+ new_pwm -> enable_fd = enable_fd ;
345422 new_pwm -> next = NULL ;
346423
347424 export_pwm (new_pwm );
348425
349- pwm_set_frequency (key , freq );
350- pwm_set_polarity (key , polarity );
351- pwm_set_duty_cycle (key , duty );
426+ return BBIO_OK ;
427+ }
428+
429+ BBIO_err pwm_start (const char * key , float duty , float freq , int polarity )
430+ {
431+ BBIO_err err ;
432+ char buffer [20 ];
433+ size_t len ;
434+
435+ struct pwm_exp * pwm = lookup_exported_pwm (key );
436+ if (pwm == NULL ) {
437+ err = pwm_setup (key , duty , freq , polarity );
438+ if (err != BBIO_OK ) {
439+ return err ;
440+ }
352441
353- #ifdef BBBVERSION41 // Enable the PWM
354- f = fopen (enable_path );
355- if (f == NULL )
442+ pwm = lookup_exported_pwm (key );
443+ }
444+
445+ err = pwm_set_polarity (key , polarity );
446+ if (err != BBIO_OK ) {
447+ return err ;
448+ }
449+
450+ err = pwm_set_frequency (key , freq );
451+ if (err != BBIO_OK ) {
452+ return err ;
453+ }
454+
455+ err = pwm_set_duty_cycle (key , duty );
456+ if (err != BBIO_OK ) {
457+ return err ;
458+ }
459+
460+ #ifdef BBBVERSION41 // Enable the PWM (don't think it's necessary before 4.1+)
461+ if (pwm == NULL ) {
462+ return BBIO_GEN ;
463+ }
464+ len = snprintf (buffer , sizeof (buffer ), "1" );
465+ lseek (pwm -> enable_fd , 0 , SEEK_SET );
466+ if (write (pwm -> enable_fd , buffer , len ) < 0 ) {
356467 return BBIO_SYSFS ;
357- fprintf (f , "1" );
358- fclose (f );
468+ }
359469#endif
360470
361471 return BBIO_OK ;
362472}
363473
474+
364475BBIO_err pwm_disable (const char * key )
365476{
366477 struct pwm_exp * pwm , * temp , * prev_pwm = NULL ;
367- char fragment [18 ];
368- int err ;
369478
370479#ifndef BBBVERSION41
480+ BBIO_err err ;
481+ char fragment [18 ];
371482 snprintf (fragment , sizeof (fragment ), "bone_pwm_%s" , key );
372483 err = unload_device_tree (fragment );
373484 if (err != BBIO_OK )
0 commit comments