1 | #include <stdio.h> |
---|
2 | #include <stdlib.h> |
---|
3 | #include <sys/mman.h> |
---|
4 | #include <sys/stat.h> |
---|
5 | #include <fcntl.h> |
---|
6 | #include <errno.h> |
---|
7 | #include <time.h> |
---|
8 | #include "BBBiolib.h" |
---|
9 | /*-----------------------------------------------------------------------------------------------*/ |
---|
10 | /* |
---|
11 | * PWMSS Registers |
---|
12 | * |
---|
13 | * @Source : AM335x Technical Reference Manual ,page 1991 |
---|
14 | * Table 15-5. PWMSS REGISTERS |
---|
15 | * |
---|
16 | */ |
---|
17 | |
---|
18 | #define PWMSS0_MMAP_ADDR 0x48300000 |
---|
19 | #define PWMSS1_MMAP_ADDR 0x48302000 |
---|
20 | #define PWMSS2_MMAP_ADDR 0x48304000 |
---|
21 | #define PWMSS_MMAP_LEN 0x1000 |
---|
22 | |
---|
23 | #define PWMSS_IDVER 0x0 |
---|
24 | #define PWMSS_SYSCONFIG 0x4 |
---|
25 | #define PWMSS_CLKCONFIG 0x8 |
---|
26 | #define PWMSS_CLKSTATUS 0xC |
---|
27 | |
---|
28 | /* EPWM Registers |
---|
29 | * |
---|
30 | * @Source : AM335x Technical Reference Manual ,page 2084 |
---|
31 | * Table 15-58. EPWM REGISTERS |
---|
32 | * |
---|
33 | */ |
---|
34 | #define EPWM_TBCTL 0x0 |
---|
35 | #define EPWM_TBSTS 0x2 |
---|
36 | #define EPWM_TBPHSHR 0x4 |
---|
37 | #define EPWM_TBPHS 0x6 |
---|
38 | #define EPWM_TBCNT 0x8 |
---|
39 | #define EPWM_TBPRD 0xA |
---|
40 | #define EPWM_CMPCTL 0xE |
---|
41 | #define EPWM_CMPAHR 0x10 |
---|
42 | #define EPWM_CMPA 0x12 |
---|
43 | #define EPWM_CMPB 0x14 |
---|
44 | #define EPWM_AQCTLA 0x16 |
---|
45 | #define EPWM_AQCTLB 0x18 |
---|
46 | #define EPWM_AQSFRC 0x1A |
---|
47 | #define EPWM_AQCSFRC 0x1C |
---|
48 | #define EPWM_DBCTL 0x1E |
---|
49 | #define EPWM_DBRED 0x20 |
---|
50 | #define EPWM_DBFED 0x22 |
---|
51 | /*-----------------------------------------------------------------------------------------------*/ |
---|
52 | extern int memh; |
---|
53 | extern volatile unsigned int *CM_ptr; /*c ontrol module */ |
---|
54 | volatile unsigned int *cm_per_addr; |
---|
55 | |
---|
56 | |
---|
57 | const unsigned int PWMSS_AddressOffset[]={PWMSS0_MMAP_ADDR, |
---|
58 | PWMSS1_MMAP_ADDR, |
---|
59 | PWMSS2_MMAP_ADDR}; |
---|
60 | volatile unsigned int *pwmss_ptr[3] ={NULL, NULL, NULL} ; |
---|
61 | volatile unsigned int *epwm_ptr[3] ={NULL, NULL, NULL} ; |
---|
62 | volatile unsigned int *ecap_ptr[3] ={NULL, NULL, NULL} ; |
---|
63 | volatile unsigned int *eqep_ptr[3] ={NULL, NULL, NULL} ; |
---|
64 | |
---|
65 | #define TBCTL_CTRMODE_UP 0x0 |
---|
66 | #define TBCTL_CTRMODE_DOWN 0x1 |
---|
67 | #define TBCTL_CTRMODE_UPDOWN 0x2 |
---|
68 | #define TBCTL_CTRMODE_FREEZE 0x3 |
---|
69 | /* ----------------------------------------------------------------------------------------------- */ |
---|
70 | /* PWMSS Timebase clock check |
---|
71 | * check the timenase clock enable or not |
---|
72 | * |
---|
73 | * @param PWMSS_ID : PWM sumsystem ID (BBBIO_PWMSS0 ,BBBIO_PWMSS1, BBBIO_PWMSS2) |
---|
74 | * |
---|
75 | * @return : 0 for disable timebase clock , 1 for enable for timebase clock |
---|
76 | */ |
---|
77 | static int PWMSS_TB_clock_check(unsigned int PWMSS_ID) |
---|
78 | { |
---|
79 | volatile unsigned int* reg; |
---|
80 | unsigned int reg_value ; |
---|
81 | |
---|
82 | /* Control module check */ |
---|
83 | reg =(void *)CM_ptr + BBBIO_PWMSS_CTRL; |
---|
84 | reg_value = *reg ; |
---|
85 | |
---|
86 | return (reg_value & (1 << PWMSS_ID)) ; |
---|
87 | } |
---|
88 | |
---|
89 | /* ----------------------------------------------------------------------------------------------- */ |
---|
90 | /* PWM subsystem system control |
---|
91 | * enable or disable module clock |
---|
92 | * |
---|
93 | * @param PWMSS_ID : PWM sumsystem ID (BBBIO_PWMSS0 ,BBBIO_PWMSS1, BBBIO_PWMSS2). |
---|
94 | * @param enable : 0 for disable , else for enable . |
---|
95 | * |
---|
96 | * @return : 1 for success , 0 for error |
---|
97 | */ |
---|
98 | static int PWMSS_module_ctrl(unsigned int PWMSS_ID, int enable) |
---|
99 | { |
---|
100 | volatile unsigned int *reg = NULL; |
---|
101 | unsigned int module_set[] = {BBBIO_PWMSS0, BBBIO_PWMSS1, BBBIO_PWMSS2}; |
---|
102 | unsigned int module_clk_set[] = {BBBIO_CM_PER_EPWMSS0_CLKCTRL, BBBIO_CM_PER_EPWMSS1_CLKCTRL, BBBIO_CM_PER_EPWMSS2_CLKCTRL}; |
---|
103 | int ret = 1; |
---|
104 | |
---|
105 | reg = (void*)cm_per_addr + module_clk_set[PWMSS_ID]; |
---|
106 | if(enable) { |
---|
107 | if(PWMSS_TB_clock_check(module_set[PWMSS_ID])) { |
---|
108 | /* Enable module clock */ |
---|
109 | *reg = 0x2; /* Module enable and fully functional */ |
---|
110 | return ret; |
---|
111 | } |
---|
112 | #ifdef BBBIO_LIB_DBG |
---|
113 | else { |
---|
114 | printf("PWMSS_module_ctrl : PWMSS-%d timebase clock disable in Control Module\n", PWMSS_ID); |
---|
115 | } |
---|
116 | #endif |
---|
117 | ret = 0 ; |
---|
118 | } |
---|
119 | *reg = 0x3 << 16; /* Module is disabled and cannot be accessed */ |
---|
120 | return ret; |
---|
121 | } |
---|
122 | |
---|
123 | /* ----------------------------------------------------------------------------------------------- */ |
---|
124 | /* PWM init |
---|
125 | * iolib_init will run this function automatically |
---|
126 | * |
---|
127 | * @return : 1 for success , 0 for failed |
---|
128 | */ |
---|
129 | |
---|
130 | int BBBIO_PWM_Init() |
---|
131 | { |
---|
132 | int i = 0; |
---|
133 | |
---|
134 | if (memh == 0) { |
---|
135 | #ifdef BBBIO_LIB_DBG |
---|
136 | printf("BBBIO_PWM_Init: memory not mapped?\n"); |
---|
137 | #endif |
---|
138 | return 0; |
---|
139 | } |
---|
140 | |
---|
141 | /* Create Memory map */ |
---|
142 | for (i = 0 ; i < 3 ; i ++) { |
---|
143 | pwmss_ptr[i] = mmap(0, PWMSS_MMAP_LEN, PROT_READ | PROT_WRITE, MAP_SHARED, memh, PWMSS_AddressOffset[i]); |
---|
144 | if(pwmss_ptr[i] == MAP_FAILED) { |
---|
145 | #ifdef BBBIO_LIB_DBG |
---|
146 | printf("BBBIO_PWM_Init: PWMSS %d mmap failure!\n", i); |
---|
147 | #endif |
---|
148 | goto INIT_ERROR ; |
---|
149 | } |
---|
150 | ecap_ptr[i] = (void *)pwmss_ptr[i] + 0x100 ; |
---|
151 | eqep_ptr[i] = (void *)pwmss_ptr[i] + 0x180 ; |
---|
152 | epwm_ptr[i] = (void *)pwmss_ptr[i] + 0x200 ; |
---|
153 | |
---|
154 | if(!PWMSS_module_ctrl(i, 1)) { |
---|
155 | #ifdef BBBIO_LIB_DBG |
---|
156 | printf("BBBIO_PWM_Init: PWMSS %d clock failure!\n", i); |
---|
157 | #endif |
---|
158 | goto INIT_ERROR ; |
---|
159 | } |
---|
160 | } |
---|
161 | return 1; |
---|
162 | |
---|
163 | INIT_ERROR : |
---|
164 | BBBIO_PWM_Release(); |
---|
165 | return 0; |
---|
166 | } |
---|
167 | |
---|
168 | /* ----------------------------------------------------------------------------------------------- */ |
---|
169 | void BBBIO_PWM_Release() |
---|
170 | { |
---|
171 | int i = 0; |
---|
172 | for(i = 0 ; i < 3 ; i ++) { |
---|
173 | if(pwmss_ptr[i] != NULL) { |
---|
174 | munmap((void *)pwmss_ptr[i], PWMSS_MMAP_LEN); |
---|
175 | pwmss_ptr[i] = NULL; |
---|
176 | ecap_ptr[i] = NULL; |
---|
177 | eqep_ptr[i] = NULL; |
---|
178 | epwm_ptr[i] = NULL; |
---|
179 | } |
---|
180 | } |
---|
181 | } |
---|
182 | |
---|
183 | /* ----------------------------------------------------------------------------------------------- */ |
---|
184 | /* PWMSS status (no effect now) |
---|
185 | * set pluse rgument of epwm module |
---|
186 | * |
---|
187 | * @param PWMID : EPWMSS number , 0~3 |
---|
188 | * |
---|
189 | * @return : 1 for success , 0 for failed |
---|
190 | */ |
---|
191 | int BBBIO_PWMSS_Status(unsigned int PWMID) |
---|
192 | { |
---|
193 | int param_error = 1; |
---|
194 | volatile unsigned int* reg; |
---|
195 | unsigned int reg_value ; |
---|
196 | |
---|
197 | if (memh == 0) |
---|
198 | param_error = 0; |
---|
199 | |
---|
200 | if (PWMID > 2) /* if input is not EPWMSS 0~ WPEMSS 2 */ |
---|
201 | param_error = 0; |
---|
202 | |
---|
203 | if (param_error == 0) { |
---|
204 | #ifdef BBBIO_LIB_DBG |
---|
205 | printf("BBBIO_PWM_Status: parameter error!\n"); |
---|
206 | #endif |
---|
207 | return 0; |
---|
208 | } |
---|
209 | |
---|
210 | reg =(void *)CM_ptr + BBBIO_PWMSS_CTRL; |
---|
211 | |
---|
212 | reg_value = *reg >> PWMID & 0x01 ; |
---|
213 | if(reg_value == 0) { |
---|
214 | printf("PWMSS [%d] Timebase clock Disable , Control Module [pwmss_ctrl register]\n", PWMID); |
---|
215 | } |
---|
216 | else { |
---|
217 | reg=(void *)pwmss_ptr[PWMID] + PWMSS_CLKSTATUS; |
---|
218 | reg_value = *reg ; |
---|
219 | |
---|
220 | printf("PWMSS [%d] :\tCLKSTOP_ACK %d , CLK_EN_ACK %d , CLKSTOP_ACK %d , CLK_EN_ACK %d , CLKSTOP_ACK %d , CLK_EN_ACK %d\n", |
---|
221 | PWMID , |
---|
222 | reg_value >>9 & 0x1 , |
---|
223 | reg_value >>8 & 0x1 , |
---|
224 | reg_value >>5 & 0x1 , |
---|
225 | reg_value >>4 & 0x1 , |
---|
226 | reg_value >>1 & 0x1 , |
---|
227 | reg_value >>0 & 0x1 ); |
---|
228 | } |
---|
229 | return 1 ; |
---|
230 | } |
---|
231 | /* ----------------------------------------------------------------------------------------------- */ |
---|
232 | /* PWMSS setting |
---|
233 | * set pluse rgument of epwm module |
---|
234 | * |
---|
235 | * @param PWMID : EPWMSS number , 0~2 |
---|
236 | * @param HZ : pluse HZ |
---|
237 | * @param dutyA : Duty Cycle in ePWM A |
---|
238 | * @param dutyB : Duty Cycle in ePWM B |
---|
239 | * |
---|
240 | * @return : 1 for success , 0 for failed |
---|
241 | * |
---|
242 | * @example : BBBIO_PWMSS_Setting(0 , 50.0f , 50.0f , 25.0f); // Generate 50HZ pwm in PWM0 , |
---|
243 | * // duty cycle is 50% for ePWM0A , 25% for ePWM0B |
---|
244 | * |
---|
245 | * @Note : |
---|
246 | * find an number nearst 65535 for TBPRD , to improve duty precision, |
---|
247 | * |
---|
248 | * Using big TBPRD can increase the range of CMPA and CMPB , |
---|
249 | * and it means we can get better precision on duty cycle. |
---|
250 | * |
---|
251 | * EX : 20.25% duty cycle |
---|
252 | * on TBPRD = 62500 , CMPA = 12656.25 ( .25 rejection) , real duty : 20.2496% (12656 /62500) |
---|
253 | * on TBPRD = 6250 , CMPA = 1265.625 ( .625 rejection), real duty : 20.24% (1265 6250) |
---|
254 | * on TBPRD = 500 , CMPA = 101.25 ( .25 rejection) , real duty : 20.2% (101/500) |
---|
255 | * |
---|
256 | * Divisor = CLKDIV * HSPCLKDIV |
---|
257 | * 1 TBPRD : 10 ns (default) |
---|
258 | * 65535 TBPRD : 655350 ns |
---|
259 | * 65535 TBPRD : 655350 * Divisor ns = X TBPRD : Cyclens |
---|
260 | * |
---|
261 | * accrooding to that , we must find a Divisor value , let X nearest 65535 . |
---|
262 | * so , Divisor must Nearest Cyclens/655350 |
---|
263 | */ |
---|
264 | |
---|
265 | int BBBIO_PWMSS_Setting(unsigned int PWMID , float HZ ,float dutyA ,float dutyB) |
---|
266 | { |
---|
267 | int param_error = 1; |
---|
268 | volatile unsigned short* reg16 ; |
---|
269 | if (memh == 0) |
---|
270 | param_error = 0; |
---|
271 | if (PWMID > 2) // if input is not EPWMSS 0~ WPEMSS 2 |
---|
272 | param_error = 0; |
---|
273 | if (HZ < 0 ) |
---|
274 | param_error = 0; |
---|
275 | if(dutyA < 0.0f || dutyA > 100.0f || dutyB < 0.0f || dutyB > 100.0f) |
---|
276 | param_error = 0; |
---|
277 | |
---|
278 | if (param_error == 0) { |
---|
279 | #ifdef BBBIO_LIB_DBG |
---|
280 | printf("BBBIO_PWMSS_Setting: parameter error!\n"); |
---|
281 | #endif |
---|
282 | return 0; |
---|
283 | } |
---|
284 | |
---|
285 | dutyA /= 100.0f ; |
---|
286 | dutyB /= 100.0f ; |
---|
287 | |
---|
288 | /* compute neccessary TBPRD */ |
---|
289 | float Cyclens =0.0f ; |
---|
290 | float Divisor =0; |
---|
291 | int i , j ; |
---|
292 | const float CLKDIV_div[] = {1.0 ,2.0 ,4.0 ,8.0 ,16.0 ,32.0 , 64.0 , 128.0}; |
---|
293 | const float HSPCLKDIV_div[] ={1.0 ,2.0 ,4.0 ,6.0 ,8.0 ,10.0 , 12.0 , 14.0}; |
---|
294 | int NearCLKDIV =7; |
---|
295 | int NearHSPCLKDIV =7; |
---|
296 | int NearTBPRD =0; |
---|
297 | |
---|
298 | Cyclens = 1000000000.0f / HZ ; /* 10^9 / HZ , comput time per cycle (ns) */ |
---|
299 | |
---|
300 | |
---|
301 | Divisor = (Cyclens / 655350.0f) ; /* am335x provide (128*14) divider , and per TBPRD means 10 ns when divider /1 , |
---|
302 | * and max TBPRD is 65535 , so , the max cycle is 128*14* 65535 *10ns |
---|
303 | */ |
---|
304 | #ifdef BBBIO_LIB_DBG |
---|
305 | printf("Cyclens %f , Divisor %f\n", Cyclens, Divisor); |
---|
306 | #endif |
---|
307 | |
---|
308 | if(Divisor > (128 * 14)) { |
---|
309 | #ifdef BBBIO_LIB_DBG |
---|
310 | printf("BBBIO_PWMSS_Setting : Can't generate %f HZ \n", HZ); |
---|
311 | #endif |
---|
312 | return 0; |
---|
313 | } |
---|
314 | else { |
---|
315 | /* using Exhaustive Attack metho */ |
---|
316 | for(i = 0 ; i < 8 ; i ++) { |
---|
317 | for(j = 0 ; j < 8 ; j ++) { |
---|
318 | if((CLKDIV_div[i] * HSPCLKDIV_div[j]) < (CLKDIV_div[NearCLKDIV] * HSPCLKDIV_div[NearHSPCLKDIV]) && |
---|
319 | ((CLKDIV_div[i] * HSPCLKDIV_div[j]) > Divisor)) { |
---|
320 | NearCLKDIV = i ; |
---|
321 | NearHSPCLKDIV = j ; |
---|
322 | } |
---|
323 | } |
---|
324 | } |
---|
325 | #ifdef BBBIO_LIB_DBG |
---|
326 | printf("nearest CLKDIV %f , HSPCLKDIV %f\n" ,CLKDIV_div[NearCLKDIV] ,HSPCLKDIV_div[NearHSPCLKDIV]); |
---|
327 | #endif |
---|
328 | NearTBPRD = (Cyclens / (10.0 *CLKDIV_div[NearCLKDIV] *HSPCLKDIV_div[NearHSPCLKDIV])) ; |
---|
329 | |
---|
330 | #ifdef BBBIO_LIB_DBG |
---|
331 | printf("nearest TBPRD %d, %f %f\n ",NearTBPRD,NearTBPRD * dutyA, NearTBPRD * dutyB); |
---|
332 | #endif |
---|
333 | |
---|
334 | /* setting clock diver and freeze time base */ |
---|
335 | reg16=(void*)epwm_ptr[PWMID] +EPWM_TBCTL; |
---|
336 | *reg16 = TBCTL_CTRMODE_FREEZE | (NearCLKDIV << 10) | (NearHSPCLKDIV << 7); |
---|
337 | |
---|
338 | /* setting duty A and duty B */ |
---|
339 | reg16=(void*)epwm_ptr[PWMID] +EPWM_CMPB; |
---|
340 | *reg16 =(unsigned short)((float)NearTBPRD * dutyB); |
---|
341 | |
---|
342 | reg16=(void*)epwm_ptr[PWMID] +EPWM_CMPA; |
---|
343 | *reg16 =(unsigned short)((float)NearTBPRD * dutyA); |
---|
344 | |
---|
345 | reg16=(void*)epwm_ptr[PWMID] +EPWM_TBPRD; |
---|
346 | *reg16 =(unsigned short)NearTBPRD; |
---|
347 | |
---|
348 | /* reset time base counter */ |
---|
349 | reg16 = (void *)epwm_ptr[PWMID] + EPWM_TBCNT; |
---|
350 | *reg16 = 0; |
---|
351 | } |
---|
352 | return 1; |
---|
353 | } |
---|
354 | /* ----------------------------------------------------------------------------------------------- */ |
---|
355 | /* Enable/Disable ehrPWM module |
---|
356 | * @param PWMID : PWMSS number , 0~2 |
---|
357 | * |
---|
358 | * @return : void |
---|
359 | * |
---|
360 | * @example : BBBIO_PWMSS_Enable(0) ;// Enable PWMSS 0 |
---|
361 | */ |
---|
362 | |
---|
363 | void BBBIO_ehrPWM_Enable(unsigned int PWMSS_ID) |
---|
364 | { |
---|
365 | volatile unsigned short *reg16 ; |
---|
366 | |
---|
367 | reg16=(void*)epwm_ptr[PWMSS_ID] +EPWM_AQCTLA; |
---|
368 | *reg16 = 0x2 | ( 0x3 << 4) ; |
---|
369 | |
---|
370 | reg16=(void*)epwm_ptr[PWMSS_ID] +EPWM_AQCTLB; |
---|
371 | *reg16 = 0x2 | ( 0x3 << 8) ; |
---|
372 | |
---|
373 | reg16 = (void *)epwm_ptr[PWMSS_ID] + EPWM_TBCNT; |
---|
374 | *reg16 = 0; |
---|
375 | |
---|
376 | reg16=(void *)epwm_ptr[PWMSS_ID] + EPWM_TBCTL; |
---|
377 | *reg16 &= ~0x3; |
---|
378 | } |
---|
379 | |
---|
380 | void BBBIO_ehrPWM_Disable(unsigned int PWMSS_ID) |
---|
381 | { |
---|
382 | volatile unsigned short *reg16 ; |
---|
383 | reg16=(void *)epwm_ptr[PWMSS_ID] + EPWM_TBCTL; |
---|
384 | *reg16 |= 0x3; |
---|
385 | |
---|
386 | reg16=(void*)epwm_ptr[PWMSS_ID] +EPWM_AQCTLA; |
---|
387 | *reg16 = 0x1 | ( 0x3 << 4) ; |
---|
388 | |
---|
389 | reg16=(void*)epwm_ptr[PWMSS_ID] +EPWM_AQCTLB; |
---|
390 | *reg16 = 0x1 | ( 0x3 << 8) ; |
---|
391 | |
---|
392 | reg16 = (void *)epwm_ptr[PWMSS_ID] + EPWM_TBCNT; |
---|
393 | *reg16 = 0; |
---|
394 | } |
---|
395 | //-------------------------------------------------------- |
---|
396 | |
---|
397 | |
---|
398 | |
---|
399 | |
---|
400 | |
---|
401 | |
---|
402 | |
---|
403 | |
---|
404 | |
---|
405 | |
---|
406 | |
---|
407 | |
---|