38
38
#include "supervisor/shared/translate.h"
39
39
#include "periph.h"
40
40
41
+ // Debug print support set to none zero to enable debug printing
42
+ #define ENABLE_DEBUG_PRINTING 0
43
+
44
+
41
45
static void config_periph_pin (const mcu_pwm_obj_t * periph ) {
42
46
IOMUXC_SetPinMux (
43
47
periph -> pin -> mux_reg , periph -> mux_mode ,
@@ -83,6 +87,32 @@ static int calculate_pulse_count(uint32_t frequency, uint8_t *prescaler) {
83
87
return 0 ;
84
88
}
85
89
90
+ // ==========================================================
91
+ // Debug code
92
+ // ==========================================================
93
+ #if ENABLE_DEBUG_PRINTING
94
+ #define DBGPrintf mp_printf
95
+ extern void debug_print_flexpwm_registers (PWM_Type * base );
96
+
97
+ void debug_print_flexpwm_registers (PWM_Type * base ) {
98
+ mp_printf (& mp_plat_print ,
99
+ "\t\tPWM OUTEN:%x MASK:%x SWCOUT:%x DTSRCSEL:%x MCTRL:%x MCTRL2:%x FCTRL:%x FSTS:%x FFILT:%x FTST:%x FCTRL2:%x\n" ,
100
+ base -> OUTEN , base -> MASK , base -> SWCOUT , base -> DTSRCSEL , base -> MCTRL , base -> MCTRL2 , base -> FCTRL ,
101
+ base -> FSTS , base -> FFILT , base -> FTST , base -> FCTRL2 );
102
+ for (uint8_t i = 0 ; i < 4 ; i ++ ) {
103
+ mp_printf (& mp_plat_print ,
104
+ "\t\t(%u) INIT:%x CTRL2:%x CTRL:%x VAL0:%x VAL1:%x VAL2:%x VAL3:%x VAL4:%x VAL5:%x OCTRL:%x DTCNT0:%x DTCNT1:%x\n" , i ,
105
+ base -> SM [i ].INIT , base -> SM [i ].CTRL2 , base -> SM [i ].CTRL , base -> SM [i ].VAL0 , base -> SM [i ].VAL1 , base -> SM [i ].VAL2 ,
106
+ base -> SM [i ].VAL3 , base -> SM [i ].VAL4 , base -> SM [i ].VAL5 , base -> SM [i ].OCTRL , base -> SM [i ].DTCNT0 , base -> SM [i ].DTCNT1 );
107
+ }
108
+
109
+ }
110
+ #else
111
+ #define DBGPrintf (p ,...)
112
+ inline void debug_print_flexpwm_registers (PWM_Type * base ) {
113
+ }
114
+ #endif
115
+
86
116
pwmout_result_t common_hal_pwmio_pwmout_construct (pwmio_pwmout_obj_t * self ,
87
117
const mcu_pin_obj_t * pin ,
88
118
uint16_t duty ,
@@ -93,6 +123,9 @@ pwmout_result_t common_hal_pwmio_pwmout_construct(pwmio_pwmout_obj_t *self,
93
123
94
124
const uint32_t pwm_count = sizeof (mcu_pwm_list ) / sizeof (mcu_pwm_obj_t );
95
125
126
+ DBGPrintf (& mp_plat_print , ">>> common_hal_pwmio_pwmout_construct called: pin: %p %u freq:%u duty:%u var:%u\n" ,
127
+ self -> pin -> gpio , self -> pin -> number , frequency , duty , variable_frequency );
128
+
96
129
for (uint32_t i = 0 ; i < pwm_count ; ++ i ) {
97
130
if (mcu_pwm_list [i ].pin != pin ) {
98
131
continue ;
@@ -107,6 +140,8 @@ pwmout_result_t common_hal_pwmio_pwmout_construct(pwmio_pwmout_obj_t *self,
107
140
return PWMOUT_INVALID_PIN ;
108
141
}
109
142
143
+ DBGPrintf (& mp_plat_print , "\tFound in PWM List\n" );
144
+
110
145
config_periph_pin (self -> pwm );
111
146
112
147
pwm_config_t pwmConfig ;
@@ -138,33 +173,81 @@ pwmout_result_t common_hal_pwmio_pwmout_construct(pwmio_pwmout_obj_t *self,
138
173
139
174
pwmConfig .prescale = self -> prescaler ;
140
175
176
+ DBGPrintf (& mp_plat_print , "\tCall PWM_Init\n" );
141
177
if (PWM_Init (self -> pwm -> pwm , self -> pwm -> submodule , & pwmConfig ) == kStatus_Fail ) {
142
178
return PWMOUT_INVALID_PIN ;
143
179
}
144
180
181
+ // Disable all fault inputs
182
+ self -> pwm -> pwm -> SM [self -> pwm -> submodule ].DISMAP [0 ] = 0 ;
183
+ self -> pwm -> pwm -> SM [self -> pwm -> submodule ].DISMAP [1 ] = 0 ;
184
+
185
+ DBGPrintf (& mp_plat_print , "\tCall PWM_SetupPwm %p %x %u\n" , self -> pwm -> pwm , self -> pwm -> submodule );
186
+ #if 0
187
+ // Not calling the PWM_SetupPwm as it was setup to only work for PWM output on chan A and B but not X
188
+ // I have done some experimenting, probably could try others, but again they do not work with X.
189
+ // Most of the code checks to see if A if not, then it assume B.
145
190
pwm_signal_param_t pwmSignal = {
146
191
.pwmChannel = self -> pwm -> channel ,
147
192
.level = kPWM_HighTrue ,
148
193
.dutyCyclePercent = 0 , // avoid an initial transient
149
194
.deadtimeValue = 0 , // allow 100% duty cycle
150
195
};
151
-
152
- // Disable all fault inputs
153
- self -> pwm -> pwm -> SM [self -> pwm -> submodule ].DISMAP [0 ] = 0 ;
154
- self -> pwm -> pwm -> SM [self -> pwm -> submodule ].DISMAP [1 ] = 0 ;
155
-
156
196
status_t status = PWM_SetupPwm (self -> pwm -> pwm , self -> pwm -> submodule , & pwmSignal , 1 , kPWM_EdgeAligned , frequency , PWM_SRC_CLK_FREQ );
157
197
158
198
if (status != kStatus_Success ) {
159
199
return PWMOUT_INITIALIZATION_ERROR ;
160
200
}
201
+ #else
202
+ // ========================================================================================================
203
+ // Instead I set it up to work similar to what the Teensy 4.x code does.
204
+ //
205
+ // That is we set the PWM_CTRL_FULL_MASK, which then uses base->SM[submodule].VAL1 to control
206
+ // when the timer is reset, so it sets up your cycle/frequency. But then this implies that X channel
207
+ // which uses 0, 1 has to be handled specially. So for the different channels:
208
+ // A - Uses VAL2 to turn on (0) and VAL3=duty to turn off
209
+ // B - Uses VAL4 to turn on (0) and VAL5 to turn off
210
+ // X - As mentioned above VAL1 turns off, but its set to the timing for freqency. so
211
+ // VAL0 turns on, so we set it to VAL1 - duty
212
+ //
213
+ PWM_Type * base = self -> pwm -> pwm ;
214
+ uint8_t submodule = self -> pwm -> submodule ;
215
+
216
+ uint32_t mask = 1 << submodule ;
217
+ uint32_t olddiv = base -> SM [submodule ].VAL1 + 1 ;
218
+ if (self -> pulse_count != olddiv ) {
219
+ base -> MCTRL |= PWM_MCTRL_CLDOK (mask );
220
+ base -> SM [submodule ].CTRL = PWM_CTRL_PRSC_MASK | PWM_CTRL_PRSC (self -> prescaler );
221
+ base -> SM [submodule ].VAL1 = self -> pulse_count - 1 ;
222
+ base -> SM [submodule ].CTRL2 = PWM_CTRL2_INDEP_MASK | PWM_CTRL2_WAITEN_MASK | PWM_CTRL2_DBGEN_MASK ;
223
+
224
+ if (olddiv == 1 ) {
225
+ base -> SM [submodule ].CTRL = PWM_CTRL_FULL_MASK ;
226
+ base -> SM [submodule ].VAL0 = 0 ;
227
+ base -> SM [submodule ].VAL2 = 0 ;
228
+ base -> SM [submodule ].VAL3 = 0 ;
229
+ base -> SM [submodule ].VAL4 = 0 ;
230
+ base -> SM [submodule ].VAL5 = 0 ;
231
+ } else {
232
+ base -> SM [submodule ].VAL0 = (base -> SM [submodule ].VAL0 * self -> pulse_count ) / olddiv ;
233
+ base -> SM [submodule ].VAL3 = (base -> SM [submodule ].VAL3 * self -> pulse_count ) / olddiv ;
234
+ base -> SM [submodule ].VAL5 = (base -> SM [submodule ].VAL5 * self -> pulse_count ) / olddiv ;
235
+ }
236
+ base -> MCTRL |= PWM_MCTRL_LDOK (mask );
237
+ }
238
+ debug_print_flexpwm_registers (self -> pwm -> pwm );
239
+
240
+ #endif
241
+
161
242
PWM_SetPwmLdok (self -> pwm -> pwm , 1 << self -> pwm -> submodule , true);
162
243
163
244
PWM_StartTimer (self -> pwm -> pwm , 1 << self -> pwm -> submodule );
164
245
165
246
247
+ DBGPrintf (& mp_plat_print , "\tCall common_hal_pwmio_pwmout_set_duty_cycle\n" );
166
248
common_hal_pwmio_pwmout_set_duty_cycle (self , duty );
167
249
250
+ DBGPrintf (& mp_plat_print , "\tReturn OK\n" );
168
251
return PWMOUT_OK ;
169
252
}
170
253
@@ -185,26 +268,38 @@ void common_hal_pwmio_pwmout_set_duty_cycle(pwmio_pwmout_obj_t *self, uint16_t d
185
268
// we do not use PWM_UpdatePwmDutycycle because ...
186
269
// * it works in integer percents
187
270
// * it can't set the "X" duty cycle
271
+ // As mentioned in the setting up of the frequency code
272
+ // A - Uses VAL2 to turn on (0) and VAL3=duty to turn off
273
+ // B - Uses VAL4 to turn on (0) and VAL5 to turn off
274
+ // X - As mentioned above VAL1 turns off, but its set to the timing for freqency. so
275
+ // VAL0 turns on, so we set it to VAL1 - duty
276
+
277
+ DBGPrintf (& mp_plat_print , "common_hal_pwmio_pwmout_set_duty_cycle %u\n" , duty );
188
278
self -> duty_cycle = duty ;
279
+ PWM_Type * base = self -> pwm -> pwm ;
280
+ uint8_t mask = 1 << self -> pwm -> submodule ;
189
281
if (duty == 65535 ) {
190
282
self -> duty_scaled = self -> pulse_count + 1 ;
191
283
} else {
192
284
self -> duty_scaled = ((uint32_t )duty * self -> pulse_count + self -> pulse_count / 2 ) / 65535 ;
193
285
}
194
286
switch (self -> pwm -> channel ) {
195
287
case kPWM_PwmX :
196
- self -> pwm -> pwm -> SM [self -> pwm -> submodule ].VAL0 = 0 ;
197
- self -> pwm -> pwm -> SM [ self -> pwm -> submodule ]. VAL1 = self -> duty_scaled ;
288
+ base -> SM [self -> pwm -> submodule ].VAL0 = self -> pulse_count - self -> duty_scaled ;
289
+ base -> OUTEN |= PWM_OUTEN_PWMX_EN ( mask ) ;
198
290
break ;
199
291
case kPWM_PwmA :
200
- self -> pwm -> pwm -> SM [self -> pwm -> submodule ].VAL2 = 0 ;
201
- self -> pwm -> pwm -> SM [ self -> pwm -> submodule ]. VAL3 = self -> duty_scaled ;
292
+ base -> SM [self -> pwm -> submodule ].VAL3 = self -> duty_scaled ;
293
+ base -> OUTEN |= PWM_OUTEN_PWMA_EN ( mask ) ;
202
294
break ;
203
295
case kPWM_PwmB :
204
- self -> pwm -> pwm -> SM [self -> pwm -> submodule ].VAL4 = 0 ;
205
- self -> pwm -> pwm -> SM [ self -> pwm -> submodule ]. VAL5 = self -> duty_scaled ;
296
+ base -> SM [self -> pwm -> submodule ].VAL5 = self -> duty_scaled ;
297
+ base -> OUTEN |= PWM_OUTEN_PWMB_EN ( mask ) ;
206
298
}
207
299
PWM_SetPwmLdok (self -> pwm -> pwm , 1 << self -> pwm -> submodule , true);
300
+
301
+ debug_print_flexpwm_registers (self -> pwm -> pwm );
302
+
208
303
}
209
304
210
305
uint16_t common_hal_pwmio_pwmout_get_duty_cycle (pwmio_pwmout_obj_t * self ) {
0 commit comments