pwm.c
00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036 #include <mc1322x.h>
00037 #include <stdlib.h>
00038 #include "pwm.h"
00039
00040 static struct {
00041 uint32_t period;
00042 uint32_t guard;
00043 uint32_t pad_forced;
00044 } pwm_info[4];
00045
00046 static inline void pad_set_output(int timer_num) {
00047 switch (timer_num) {
00048 case 0: GPIO->DATA_SEL.TMR0_PIN = 1; GPIO->PAD_DIR.TMR0_PIN = 1; break;
00049 case 1: GPIO->DATA_SEL.TMR1_PIN = 1; GPIO->PAD_DIR.TMR1_PIN = 1; break;
00050 case 2: GPIO->DATA_SEL.TMR2_PIN = 1; GPIO->PAD_DIR.TMR2_PIN = 1; break;
00051 case 3: GPIO->DATA_SEL.TMR3_PIN = 1; GPIO->PAD_DIR.TMR3_PIN = 1; break;
00052 default: break;
00053 }
00054 }
00055
00056 static inline void pad_set_zero(int timer_num) {
00057 switch (timer_num) {
00058 case 0: GPIO->DATA_RESET.TMR0_PIN = 1; GPIO->FUNC_SEL.TMR0_PIN = 0; break;
00059 case 1: GPIO->DATA_RESET.TMR1_PIN = 1; GPIO->FUNC_SEL.TMR1_PIN = 0; break;
00060 case 2: GPIO->DATA_RESET.TMR2_PIN = 1; GPIO->FUNC_SEL.TMR2_PIN = 0; break;
00061 case 3: GPIO->DATA_RESET.TMR3_PIN = 1; GPIO->FUNC_SEL.TMR3_PIN = 0; break;
00062 default: break;
00063 }
00064 }
00065
00066 static inline void pad_set_one(int timer_num) {
00067 switch (timer_num) {
00068 case 0: GPIO->DATA_SET.TMR0_PIN = 1; GPIO->FUNC_SEL.TMR0_PIN = 0; break;
00069 case 1: GPIO->DATA_SET.TMR1_PIN = 1; GPIO->FUNC_SEL.TMR1_PIN = 0; break;
00070 case 2: GPIO->DATA_SET.TMR2_PIN = 1; GPIO->FUNC_SEL.TMR2_PIN = 0; break;
00071 case 3: GPIO->DATA_SET.TMR3_PIN = 1; GPIO->FUNC_SEL.TMR3_PIN = 0; break;
00072 default: break;
00073 }
00074 }
00075
00076 static inline void pad_set_normal(int timer_num) {
00077 switch (timer_num) {
00078 case 0: GPIO->FUNC_SEL.TMR0_PIN = 1; break;
00079 case 1: GPIO->FUNC_SEL.TMR1_PIN = 1; break;
00080 case 2: GPIO->FUNC_SEL.TMR2_PIN = 1; break;
00081 case 3: GPIO->FUNC_SEL.TMR3_PIN = 1; break;
00082 default: break;
00083 }
00084 }
00085
00086
00087
00088
00089
00090
00091
00092 uint32_t pwm_init_ex(int timer_num, uint32_t rate, uint32_t duty, int enable_timer)
00093 {
00094 uint32_t actual_rate;
00095 volatile struct TMR_struct *timer = TMR_ADDR(timer_num);
00096 int log_divisor = 0;
00097 uint32_t period, guard;
00098
00099
00100 TMR0->ENBL &= ~(1 << timer_num);
00101
00102
00103 for (log_divisor = 0; log_divisor < 8; log_divisor++)
00104 {
00105 int denom = (rate * (1 << log_divisor));
00106 period = (REF_OSC + denom/2) / denom;
00107 if (period <= 65535)
00108 break;
00109 }
00110 if (log_divisor >= 8)
00111 {
00112 period = 65535;
00113 log_divisor = 7;
00114 }
00115
00116
00117
00118
00119 guard = 32 >> log_divisor;
00120 if (guard < 2) guard = 2;
00121
00122
00123 if (period < ((guard * 3) / 2))
00124 period = guard + 4;
00125
00126
00127 pwm_info[timer_num].period = period;
00128 pwm_info[timer_num].guard = guard;
00129 actual_rate = REF_OSC / (period * (1 << log_divisor));
00130
00131
00132 pwm_duty_ex(timer_num, duty);
00133 timer->SCTRLbits = (struct TMR_SCTRL) {
00134 .OEN = 1,
00135 };
00136 timer->CSCTRLbits = (struct TMR_CSCTRL) {
00137 .CL1 = 0x01,
00138 };
00139 timer->COMP1 = timer->CMPLD1;
00140 timer->CNTR = timer->LOAD;
00141 timer->CTRLbits = (struct TMR_CTRL) {
00142 .COUNT_MODE = 1,
00143 .PRIMARY_CNT_SOURCE = 8 + log_divisor,
00144 .LENGTH = 1,
00145 .OUTPUT_MODE = 6,
00146 };
00147
00148 pad_set_output(timer_num);
00149 pad_set_normal(timer_num);
00150
00151 if (enable_timer) {
00152 TMR0->ENBL |= (1 << timer_num);
00153 }
00154
00155
00156
00157
00158 return actual_rate;
00159 }
00160
00161
00162
00163
00164
00165 void pwm_duty_ex(int timer_num, uint32_t duty)
00166 {
00167 uint16_t comp1, load;
00168 volatile struct TMR_struct *timer = TMR_ADDR(timer_num);
00169 uint32_t period = pwm_info[timer_num].period;
00170
00171 duty = (duty * period + 32767) / 65536;
00172
00173
00174
00175
00176
00177
00178
00179
00180
00181
00182
00183
00184
00185
00186
00187
00188
00189
00190
00191 if (duty == 0) {
00192 pad_set_zero(timer_num);
00193 pwm_info[timer_num].pad_forced = 1;
00194 return;
00195 }
00196
00197 if (duty >= period) {
00198 pad_set_one(timer_num);
00199 pwm_info[timer_num].pad_forced = 1;
00200 return;
00201 }
00202
00203 if (pwm_info[timer_num].pad_forced) {
00204 pad_set_normal(timer_num);
00205 pwm_info[timer_num].pad_forced = 0;
00206 }
00207
00208 comp1 = (period - duty) - 1;
00209 load = (65536 - duty);
00210
00211
00212 uint32_t old_INTCNTL = ITC->INTCNTL;
00213 ITC->INTCNTL = 0;
00214
00215 if (TMR0->ENBL & (1 << timer_num))
00216 {
00217
00218
00219
00220 uint32_t tmp1, tmp2;
00221 asm volatile (
00222 "1: \n\t"
00223 "ldrh %[tmp1], %[comp] \n\t"
00224 "ldrh %[tmp2], %[count] \n\t"
00225 "sub %[tmp1], %[tmp1], %[tmp2] \n\t"
00226 "lsl %[tmp1], %[tmp1], #16 \n\t"
00227 "lsr %[tmp1], %[tmp1], #16 \n\t"
00228 "cmp %[tmp1], %[guard] \n\t"
00229 "bls 1b \n\t"
00230
00231 "strh %[ld1], %[cmpld] \n\t"
00232 "strh %[ld2], %[load] \n\t"
00233 :
00234 [tmp1] "=&l" (tmp1),
00235 [tmp2] "=&l" (tmp2),
00236 [cmpld] "=m" (timer->CMPLD1),
00237 [load] "=m" (timer->LOAD)
00238 :
00239 [comp] "m" (timer->COMP1),
00240 [count] "m" (timer->CNTR),
00241 [ld1] "l" (comp1),
00242 [ld2] "l" (load),
00243 [guard] "l" (pwm_info[timer_num].guard)
00244 : "memory"
00245 );
00246 } else {
00247
00248 timer->CMPLD1 = comp1;
00249 timer->LOAD = load;
00250 }
00251
00252
00253 ITC->INTCNTL = old_INTCNTL;
00254 }