source: EcnlProtoTool/trunk/asp3_dcre/mbed/targets/TARGET_RENESAS/TARGET_RZA1XX/pwmout_api.c@ 439

Last change on this file since 439 was 439, checked in by coas-nagasima, 4 years ago

mrubyを2.1.1に更新

  • Property svn:eol-style set to native
  • Property svn:mime-type set to text/x-csrc;charset=UTF-8
File size: 14.9 KB
Line 
1/* mbed Microcontroller Library
2 * Copyright (c) 2006-2013 ARM Limited
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16#include "mbed_assert.h"
17#include "pwmout_api.h"
18#include "cmsis.h"
19#include "PeripheralPins.h"
20#include "RZ_A1_Init.h"
21#include "iodefine.h"
22#include "gpio_addrdefine.h"
23#include "mbed_drv_cfg.h"
24#include "mtu2.h"
25
26#define MTU2_PWM_OFFSET 0x20
27
28#ifdef FUNC_MOTOR_CTL_PWM
29typedef enum {
30 PWM1A = 0,
31 PWM1B,
32 PWM1C,
33 PWM1D,
34 PWM1E,
35 PWM1F,
36 PWM1G,
37 PWM1H,
38 PWM2A = 0x10,
39 PWM2B,
40 PWM2C,
41 PWM2D,
42 PWM2E,
43 PWM2F,
44 PWM2G,
45 PWM2H,
46} PWMType;
47
48static const PWMType PORT[] = {
49 PWM1A, // PWM_PWM1A
50 PWM1B, // PWM_PWM1B
51 PWM1C, // PWM_PWM1C
52 PWM1D, // PWM_PWM1D
53 PWM1E, // PWM_PWM1E
54 PWM1F, // PWM_PWM1F
55 PWM1G, // PWM_PWM1G
56 PWM1H, // PWM_PWM1H
57 PWM2A, // PWM_PWM2A
58 PWM2B, // PWM_PWM2B
59 PWM2C, // PWM_PWM2C
60 PWM2D, // PWM_PWM2D
61 PWM2E, // PWM_PWM2E
62 PWM2F, // PWM_PWM2F
63 PWM2G, // PWM_PWM2G
64 PWM2H, // PWM_PWM2H
65};
66
67static __IO uint16_t *PWM_MATCH[] = {
68 &PWMPWBFR_1A, // PWM_PWM1A
69 &PWMPWBFR_1A, // PWM_PWM1B
70 &PWMPWBFR_1C, // PWM_PWM1C
71 &PWMPWBFR_1C, // PWM_PWM1D
72 &PWMPWBFR_1E, // PWM_PWM1E
73 &PWMPWBFR_1E, // PWM_PWM1F
74 &PWMPWBFR_1G, // PWM_PWM1G
75 &PWMPWBFR_1G, // PWM_PWM1H
76 &PWMPWBFR_2A, // PWM_PWM2A
77 &PWMPWBFR_2A, // PWM_PWM2B
78 &PWMPWBFR_2C, // PWM_PWM2C
79 &PWMPWBFR_2C, // PWM_PWM2D
80 &PWMPWBFR_2E, // PWM_PWM2E
81 &PWMPWBFR_2E, // PWM_PWM2F
82 &PWMPWBFR_2G, // PWM_PWM2G
83 &PWMPWBFR_2G, // PWM_PWM2H
84};
85
86static uint16_t init_period_ch1 = 0;
87static uint16_t init_period_ch2 = 0;
88static int32_t period_ch1 = 1;
89static int32_t period_ch2 = 1;
90#endif
91
92#ifdef FUMC_MTU2_PWM
93#define MTU2_PWM_SIGNAL 2
94
95typedef enum {
96 TIOC0A = 0,
97 TIOC0B,
98 TIOC0C,
99 TIOC0D,
100 TIOC1A = 0x10,
101 TIOC1B,
102 TIOC2A = 0x20,
103 TIOC2B,
104 TIOC3A = 0x30,
105 TIOC3B,
106 TIOC3C,
107 TIOC3D,
108 TIOC4A = 0x40,
109 TIOC4B,
110 TIOC4C,
111 TIOC4D,
112} MTU2_PWMType;
113
114static const MTU2_PWMType MTU2_PORT[] = {
115 TIOC0A, // PWM_TIOC0A
116 TIOC0C, // PWM_TIOC0C
117 TIOC1A, // PWM_TIOC1A
118 TIOC2A, // PWM_TIOC2A
119 TIOC3A, // PWM_TIOC3A
120 TIOC3C, // PWM_TIOC3C
121 TIOC4A, // PWM_TIOC4A
122 TIOC4C, // PWM_TIOC4C
123};
124
125static __IO uint16_t *MTU2_PWM_MATCH[][MTU2_PWM_SIGNAL] = {
126 { &MTU2TGRA_0, &MTU2TGRB_0 }, // PWM_TIOC0A
127 { &MTU2TGRC_0, &MTU2TGRD_0 }, // PWM_TIOC0C
128 { &MTU2TGRA_1, &MTU2TGRB_1 }, // PWM_TIOC1A
129 { &MTU2TGRA_2, &MTU2TGRB_2 }, // PWM_TIOC2A
130 { &MTU2TGRA_3, &MTU2TGRB_3 }, // PWM_TIOC3A
131 { &MTU2TGRC_3, &MTU2TGRD_3 }, // PWM_TIOC3C
132 { &MTU2TGRA_4, &MTU2TGRB_4 }, // PWM_TIOC4A
133 { &MTU2TGRC_4, &MTU2TGRD_4 }, // PWM_TIOC4C
134};
135
136static __IO uint8_t *TCR_MATCH[] = {
137 &MTU2TCR_0,
138 &MTU2TCR_1,
139 &MTU2TCR_2,
140 &MTU2TCR_3,
141 &MTU2TCR_4,
142};
143
144static __IO uint8_t *TIORH_MATCH[] = {
145 &MTU2TIORH_0,
146 &MTU2TIOR_1,
147 &MTU2TIOR_2,
148 &MTU2TIORH_3,
149 &MTU2TIORH_4,
150};
151
152static __IO uint8_t *TIORL_MATCH[] = {
153 &MTU2TIORL_0,
154 NULL,
155 NULL,
156 &MTU2TIORL_3,
157 &MTU2TIORL_4,
158};
159
160static __IO uint16_t *TGRA_MATCH[] = {
161 &MTU2TGRA_0,
162 &MTU2TGRA_1,
163 &MTU2TGRA_2,
164 &MTU2TGRA_3,
165 &MTU2TGRA_4,
166};
167
168static __IO uint16_t *TGRC_MATCH[] = {
169 &MTU2TGRC_0,
170 NULL,
171 NULL,
172 &MTU2TGRC_3,
173 &MTU2TGRC_4,
174};
175
176static __IO uint8_t *TMDR_MATCH[] = {
177 &MTU2TMDR_0,
178 &MTU2TMDR_1,
179 &MTU2TMDR_2,
180 &MTU2TMDR_3,
181 &MTU2TMDR_4,
182};
183
184static int MAX_PERIOD[] = {
185 125000,
186 503000,
187 2000000,
188 2000000,
189 2000000,
190};
191
192typedef enum {
193 MTU2_PULSE = 0,
194 MTU2_PERIOD
195} MTU2Signal;
196
197static uint16_t init_mtu2_period_ch[5] = {0};
198static int32_t mtu2_period_ch[5] = {1, 1, 1, 1, 1};
199#endif
200
201void pwmout_init(pwmout_t* obj, PinName pin) {
202 // determine the channel
203 PWMName pwm = (PWMName)pinmap_peripheral(pin, PinMap_PWM);
204 MBED_ASSERT(pwm != (PWMName)NC);
205
206 if (pwm >= MTU2_PWM_OFFSET) {
207#ifdef FUMC_MTU2_PWM
208 /* PWM by MTU2 */
209 int tmp_pwm;
210
211 // power on
212 mtu2_init();
213
214 obj->pwm = pwm;
215 tmp_pwm = (int)(obj->pwm - MTU2_PWM_OFFSET);
216 if (((uint32_t)MTU2_PORT[tmp_pwm] & 0x00000040) == 0x00000040) {
217 obj->ch = 4;
218 MTU2TOER |= 0x36;
219 } else if (((uint32_t)MTU2_PORT[tmp_pwm] & 0x00000030) == 0x00000030) {
220 obj->ch = 3;
221 MTU2TOER |= 0x09;
222 } else if (((uint32_t)MTU2_PORT[tmp_pwm] & 0x00000020) == 0x00000020) {
223 obj->ch = 2;
224 } else if (((uint32_t)MTU2_PORT[tmp_pwm] & 0x00000010) == 0x00000010) {
225 obj->ch = 1;
226 } else {
227 obj->ch = 0;
228 }
229 // Wire pinout
230 pinmap_pinout(pin, PinMap_PWM);
231
232 int bitmask = 1 << (pin & 0xf);
233
234 *PMSR(PINGROUP(pin)) = (bitmask << 16) | 0;
235
236 // default duty 0.0f
237 pwmout_write(obj, 0);
238 if (init_mtu2_period_ch[obj->ch] == 0) {
239 // default period 1ms
240 pwmout_period_us(obj, 1000);
241 init_mtu2_period_ch[obj->ch] = 1;
242 }
243#endif
244 } else {
245#ifdef FUNC_MOTOR_CTL_PWM
246 /* PWM */
247 // power on
248 CPGSTBCR3 &= ~(CPG_STBCR3_BIT_MSTP30);
249
250 obj->pwm = pwm;
251 if (((uint32_t)PORT[obj->pwm] & 0x00000010) == 0x00000010) {
252 obj->ch = 2;
253 PWMPWPR_2 = 0x00;
254 } else {
255 obj->ch = 1;
256 PWMPWPR_1 = 0x00;
257 }
258
259 // Wire pinout
260 pinmap_pinout(pin, PinMap_PWM);
261
262 // default to 491us: standard for servos, and fine for e.g. brightness control
263 pwmout_write(obj, 0);
264 if ((obj->ch == 2) && (init_period_ch2 == 0)) {
265 pwmout_period_us(obj, 491);
266 init_period_ch2 = 1;
267 }
268 if ((obj->ch == 1) && (init_period_ch1 == 0)) {
269 pwmout_period_us(obj, 491);
270 init_period_ch1 = 1;
271 }
272#endif
273 }
274}
275
276void pwmout_free(pwmout_t* obj) {
277 pwmout_write(obj, 0);
278 mtu2_free();
279}
280
281void pwmout_write(pwmout_t* obj, float value) {
282 uint32_t wk_cycle;
283
284 if (obj->pwm >= MTU2_PWM_OFFSET) {
285#ifdef FUMC_MTU2_PWM
286 /* PWM by MTU2 */
287 int tmp_pwm;
288
289 if (value < 0.0f) {
290 value = 0.0f;
291 } else if (value > 1.0f) {
292 value = 1.0f;
293 } else {
294 // Do Nothing
295 }
296 tmp_pwm = (int)(obj->pwm - MTU2_PWM_OFFSET);
297 wk_cycle = *MTU2_PWM_MATCH[tmp_pwm][MTU2_PERIOD] & 0xffff;
298 // set channel match to percentage
299 if (value == 1.0f) {
300 *MTU2_PWM_MATCH[tmp_pwm][MTU2_PULSE] = (uint16_t)(wk_cycle - 1);
301 } else {
302 *MTU2_PWM_MATCH[tmp_pwm][MTU2_PULSE] = (uint16_t)((float)wk_cycle * value);
303 }
304#endif
305 } else {
306#ifdef FUNC_MOTOR_CTL_PWM
307 uint16_t v;
308
309 /* PWM */
310 if (value < 0.0f) {
311 value = 0.0f;
312 } else if (value > 1.0f) {
313 value = 1.0f;
314 } else {
315 // Do Nothing
316 }
317
318 if (obj->ch == 2) {
319 wk_cycle = PWMPWCYR_2 & 0x03ff;
320 } else {
321 wk_cycle = PWMPWCYR_1 & 0x03ff;
322 }
323
324 // set channel match to percentage
325 v = (uint16_t)((float)wk_cycle * value);
326 *PWM_MATCH[obj->pwm] = (v | ((PORT[obj->pwm] & 1) << 12));
327#endif
328 }
329}
330
331float pwmout_read(pwmout_t* obj) {
332 uint32_t wk_cycle;
333 float value;
334
335 if (obj->pwm >= MTU2_PWM_OFFSET) {
336#ifdef FUMC_MTU2_PWM
337 /* PWM by MTU2 */
338 uint32_t wk_pulse;
339 int tmp_pwm;
340
341 tmp_pwm = (int)(obj->pwm - MTU2_PWM_OFFSET);
342 wk_cycle = *MTU2_PWM_MATCH[tmp_pwm][MTU2_PERIOD] & 0xffff;
343 wk_pulse = *MTU2_PWM_MATCH[tmp_pwm][MTU2_PULSE] & 0xffff;
344 value = ((float)wk_pulse / (float)wk_cycle);
345#endif
346 } else {
347#ifdef FUNC_MOTOR_CTL_PWM
348 /* PWM */
349 if (obj->ch == 2) {
350 wk_cycle = PWMPWCYR_2 & 0x03ff;
351 } else {
352 wk_cycle = PWMPWCYR_1 & 0x03ff;
353 }
354 value = ((float)(*PWM_MATCH[obj->pwm] & 0x03ff) / (float)wk_cycle);
355#endif
356 }
357
358 return (value > 1.0f) ? (1.0f) : (value);
359}
360
361void pwmout_period(pwmout_t* obj, float seconds) {
362 pwmout_period_us(obj, seconds * 1000000.0f);
363}
364
365void pwmout_period_ms(pwmout_t* obj, int ms) {
366 pwmout_period_us(obj, ms * 1000);
367}
368
369#ifdef FUNC_MOTOR_CTL_PWM
370static void set_duty_again(__IO uint16_t *p_pwmpbfr, uint16_t last_cycle, uint16_t new_cycle){
371 uint16_t wk_pwmpbfr;
372 float value;
373 uint16_t v;
374
375 wk_pwmpbfr = *p_pwmpbfr;
376 value = ((float)(wk_pwmpbfr & 0x03ff) / (float)last_cycle);
377 v = (uint16_t)((float)new_cycle * value);
378 *p_pwmpbfr = (v | (wk_pwmpbfr & 0x1000));
379}
380#endif
381
382#ifdef FUMC_MTU2_PWM
383static void set_mtu2_duty_again(__IO uint16_t *p_pwmpbfr, uint16_t last_cycle, uint16_t new_cycle){
384 uint16_t wk_pwmpbfr;
385 float value;
386
387 wk_pwmpbfr = *p_pwmpbfr;
388 value = ((float)(wk_pwmpbfr & 0xffff) / (float)last_cycle);
389 *p_pwmpbfr = (uint16_t)((float)new_cycle * value);
390}
391#endif
392
393// Set the PWM period, keeping the duty cycle the same.
394void pwmout_period_us(pwmout_t* obj, int us) {
395 uint32_t pclk_base;
396 uint32_t wk_cycle;
397 uint32_t wk_cks = 0;
398 uint16_t wk_last_cycle;
399
400 if (obj->pwm >= MTU2_PWM_OFFSET) {
401#ifdef FUMC_MTU2_PWM
402 uint64_t wk_cycle_mtu2;
403 int max_us = 0;
404
405 /* PWM by MTU2 */
406 int tmp_pwm;
407 uint8_t tmp_tcr_up;
408 uint8_t tmp_tstr_sp;
409 uint8_t tmp_tstr_st;
410
411 max_us = MAX_PERIOD[obj->ch];
412 if (us > max_us) {
413 us = max_us;
414 } else if (us < 1) {
415 us = 1;
416 } else {
417 // Do Nothing
418 }
419
420 if (RZ_A1_IsClockMode0() == false) {
421 pclk_base = (uint32_t)CM1_RENESAS_RZ_A1_P0_CLK;
422 } else {
423 pclk_base = (uint32_t)CM0_RENESAS_RZ_A1_P0_CLK;
424 }
425
426 wk_cycle_mtu2 = (uint64_t)pclk_base * us;
427 while (wk_cycle_mtu2 >= 65535000000) {
428 if ((obj->ch == 1) && (wk_cks == 3)) {
429 wk_cks+=2;
430 } else if ((obj->ch == 2) && (wk_cks == 3)) {
431 wk_cycle_mtu2 >>= 2;
432 wk_cks+=3;
433 }
434 wk_cycle_mtu2 >>= 2;
435 wk_cks++;
436 }
437 wk_cycle = (uint32_t)(wk_cycle_mtu2 / 1000000);
438
439 tmp_pwm = (int)(obj->pwm - MTU2_PWM_OFFSET);
440 if (((uint8_t)MTU2_PORT[tmp_pwm] & 0x02) == 0x02) {
441 tmp_tcr_up = 0xC0;
442 } else {
443 tmp_tcr_up = 0x40;
444 }
445 if ((obj->ch == 4) || (obj->ch == 3)) {
446 tmp_tstr_sp = ~(0x38 | (1 << (obj->ch + 3)));
447 tmp_tstr_st = (1 << (obj->ch + 3));
448 } else {
449 tmp_tstr_sp = ~(0x38 | (1 << obj->ch));
450 tmp_tstr_st = (1 << obj->ch);
451 }
452 // Counter Stop
453 MTU2TSTR &= tmp_tstr_sp;
454 wk_last_cycle = *MTU2_PWM_MATCH[tmp_pwm][MTU2_PERIOD] & 0xffff;
455 *TCR_MATCH[obj->ch] = tmp_tcr_up | wk_cks;
456 *TIORH_MATCH[obj->ch] = 0x21;
457 if ((obj->ch == 0) || (obj->ch == 3) || (obj->ch == 4)) {
458 *TIORL_MATCH[obj->ch] = 0x21;
459 }
460 *MTU2_PWM_MATCH[tmp_pwm][MTU2_PERIOD] = (uint16_t)wk_cycle; // Set period
461
462 // Set duty again(TGRA)
463 set_mtu2_duty_again(TGRA_MATCH[obj->ch], wk_last_cycle, wk_cycle);
464 if ((obj->ch == 0) || (obj->ch == 3) || (obj->ch == 4)) {
465 // Set duty again(TGRC)
466 set_mtu2_duty_again(TGRC_MATCH[obj->ch], wk_last_cycle, wk_cycle);
467 }
468 *TMDR_MATCH[obj->ch] = 0x02; // PWM mode 1
469
470 // Counter Start
471 MTU2TSTR |= tmp_tstr_st;
472 // Save for future use
473 mtu2_period_ch[obj->ch] = us;
474#endif
475 } else {
476#ifdef FUNC_MOTOR_CTL_PWM
477 /* PWM */
478 if (us > 491) {
479 us = 491;
480 } else if (us < 1) {
481 us = 1;
482 } else {
483 // Do Nothing
484 }
485
486 if (RZ_A1_IsClockMode0() == false) {
487 pclk_base = (uint32_t)CM1_RENESAS_RZ_A1_P0_CLK / 10000;
488 } else {
489 pclk_base = (uint32_t)CM0_RENESAS_RZ_A1_P0_CLK / 10000;
490 }
491
492 wk_cycle = pclk_base * us;
493 while (wk_cycle >= 102350) {
494 wk_cycle >>= 1;
495 wk_cks++;
496 }
497 wk_cycle = (wk_cycle + 50) / 100;
498
499 if (obj->ch == 2) {
500 wk_last_cycle = PWMPWCYR_2 & 0x03ff;
501 PWMPWCR_2 = 0xc0 | wk_cks;
502 PWMPWCYR_2 = (uint16_t)wk_cycle;
503
504 // Set duty again
505 set_duty_again(&PWMPWBFR_2A, wk_last_cycle, wk_cycle);
506 set_duty_again(&PWMPWBFR_2C, wk_last_cycle, wk_cycle);
507 set_duty_again(&PWMPWBFR_2E, wk_last_cycle, wk_cycle);
508 set_duty_again(&PWMPWBFR_2G, wk_last_cycle, wk_cycle);
509
510 // Counter Start
511 PWMPWCR_2 |= 0x08;
512
513 // Save for future use
514 period_ch2 = us;
515 } else {
516 wk_last_cycle = PWMPWCYR_1 & 0x03ff;
517 PWMPWCR_1 = 0xc0 | wk_cks;
518 PWMPWCYR_1 = (uint16_t)wk_cycle;
519
520 // Set duty again
521 set_duty_again(&PWMPWBFR_1A, wk_last_cycle, wk_cycle);
522 set_duty_again(&PWMPWBFR_1C, wk_last_cycle, wk_cycle);
523 set_duty_again(&PWMPWBFR_1E, wk_last_cycle, wk_cycle);
524 set_duty_again(&PWMPWBFR_1G, wk_last_cycle, wk_cycle);
525
526 // Counter Start
527 PWMPWCR_1 |= 0x08;
528
529 // Save for future use
530 period_ch1 = us;
531 }
532#endif
533 }
534}
535
536void pwmout_pulsewidth(pwmout_t* obj, float seconds) {
537 pwmout_pulsewidth_us(obj, seconds * 1000000.0f);
538}
539
540void pwmout_pulsewidth_ms(pwmout_t* obj, int ms) {
541 pwmout_pulsewidth_us(obj, ms * 1000);
542}
543
544void pwmout_pulsewidth_us(pwmout_t* obj, int us) {
545 float value = 0;
546
547 if (obj->pwm >= MTU2_PWM_OFFSET) {
548#ifdef FUMC_MTU2_PWM
549 /* PWM by MTU2 */
550 if (mtu2_period_ch[obj->ch] != 0) {
551 value = (float)us / (float)mtu2_period_ch[obj->ch];
552 }
553#endif
554 } else {
555#ifdef FUNC_MOTOR_CTL_PWM
556 /* PWM */
557 if (obj->ch == 2) {
558 if (period_ch2 != 0) {
559 value = (float)us / (float)period_ch2;
560 }
561 } else {
562 if (period_ch1 != 0) {
563 value = (float)us / (float)period_ch1;
564 }
565 }
566#endif
567 }
568 pwmout_write(obj, value);
569}
Note: See TracBrowser for help on using the repository browser.