12
12
#include <string.h>
13
13
#include <errno.h>
14
14
#include <rc/pwm.h>
15
+ #include <rc/time.h>
15
16
16
17
#define MIN_HZ 1
17
18
#define MAX_HZ 1000000000
@@ -90,6 +91,42 @@ int __export_channels(int ss)
90
91
return 0 ;
91
92
}
92
93
94
+ /**
95
+ * @brief unexports A and B pwm channels
96
+ *
97
+ * @param[in] ss subsystem, to export
98
+ *
99
+ * @return 0 on succcess, -1 on failure
100
+ */
101
+ int __unexport_channels (int ss )
102
+ {
103
+ int unexport_fd = 0 ;
104
+ char buf [MAXBUF ];
105
+ int len ;
106
+
107
+ // open export file for that subsystem
108
+ len = snprintf (buf , sizeof (buf ), BASE_DIR "%d/unexport" , ss * 2 );
109
+ unexport_fd = open (buf , O_WRONLY );
110
+ if (unlikely (unexport_fd < 0 )){
111
+ perror ("ERROR in rc_pwm_init, can't open pwm unexport file for writing" );
112
+ fprintf (stderr ,"Probably kernel or BeagleBone image is too old\n" );
113
+ return -1 ;
114
+ }
115
+ len = write (unexport_fd , "0" , 2 );
116
+ if (unlikely (len < 0 && errno != EBUSY && errno != ENODEV )){
117
+ perror ("ERROR: in rc_pwm_init, failed to write 0 to unexport file" );
118
+ return -1 ;
119
+ }
120
+ len = write (unexport_fd , "1" , 2 );
121
+ if (unlikely (len < 0 && errno != EBUSY && errno != ENODEV )){
122
+ perror ("ERROR: in rc_pwm_init, failed to write 1 to unexport file" );
123
+ return -1 ;
124
+ }
125
+ close (unexport_fd );
126
+ return 0 ;
127
+ }
128
+
129
+
93
130
int rc_pwm_init (int ss , int frequency )
94
131
{
95
132
int periodA_fd ; // pointers to frequency file descriptor
@@ -111,9 +148,17 @@ int rc_pwm_init(int ss, int frequency)
111
148
return -1 ;
112
149
}
113
150
114
- // export channels first
151
+ // unexport then export channels first
152
+ if (__unexport_channels (ss )== -1 ) return -1 ;
115
153
if (__export_channels (ss )== -1 ) return -1 ;
116
154
155
+ // wait for udev to set correct permissions
156
+
157
+ //system("ls -la /sys/class/pwm/pwmchip4/pwm-4:0/");
158
+ //system("udevadm trigger");
159
+ //rc_usleep(1000000);
160
+ //system("ls -la /sys/class/pwm/pwmchip4/pwm-4:0/");
161
+
117
162
#ifdef DEBUG
118
163
printf ("pwm ss:%d mode:%d\n" ,ss ,mode );
119
164
#endif
@@ -122,11 +167,18 @@ int rc_pwm_init(int ss, int frequency)
122
167
if (mode == 0 ) len = snprintf (buf , sizeof (buf ), BASE_DIR "%d/pwm0/duty_cycle" , ss * 2 ); // mode 0
123
168
else len = snprintf (buf , sizeof (buf ), BASE_DIR "%d/pwm-%d:0/duty_cycle" , ss * 2 , ss * 2 ); // mode 1
124
169
dutyA_fd [ss ] = open (buf ,O_WRONLY );
170
+
125
171
if (unlikely (dutyA_fd [ss ]== -1 )){
126
- perror ("ERROR in rc_pwm_init, failed to open duty_cycle channel A FD" );
127
- fprintf (stderr ,"tried accessing: %s\n" , buf );
128
- return -1 ;
172
+ // first error is probably from udev being slow, wait a bit and try again
173
+ rc_usleep (600000 );
174
+ dutyA_fd [ss ] = open (buf ,O_WRONLY );
175
+ if (unlikely (dutyA_fd [ss ]== -1 )){
176
+ perror ("ERROR in rc_pwm_init, failed to open duty_cycle channel A FD" );
177
+ fprintf (stderr ,"tried accessing: %s\n" , buf );
178
+ return -1 ;
179
+ }
129
180
}
181
+
130
182
if (mode == 0 ) len = snprintf (buf , sizeof (buf ), BASE_DIR "%d/pwm1/duty_cycle" , ss * 2 ); // mode 0
131
183
else len = snprintf (buf , sizeof (buf ), BASE_DIR "%d/pwm-%d:1/duty_cycle" , ss * 2 , ss * 2 ); // mode 1
132
184
dutyB_fd [ss ] = open (buf ,O_WRONLY );
@@ -295,6 +347,12 @@ int rc_pwm_cleanup(int ss)
295
347
// close fds
296
348
close (enableA_fd );
297
349
close (enableB_fd );
350
+ close (dutyA_fd [ss ]);
351
+ close (dutyB_fd [ss ]);
352
+
353
+ // unexport channels, not critical if this fails since everything else
354
+ // has been closed
355
+ __unexport_channels (ss );
298
356
299
357
init_flag [ss ] = 0 ;
300
358
return 0 ;
0 commit comments