38
38
#include "supervisor/shared/translate.h"
39
39
#include "periph.h"
40
40
41
+ // Debug print support set to 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,33 @@ 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 DISMAP: %x %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
+ base -> SM [i ].DISMAP [0 ], base -> SM [i ].DISMAP [1 ]);
108
+ }
109
+
110
+ }
111
+ #else
112
+ #define DBGPrintf (p ,...)
113
+ inline void debug_print_flexpwm_registers (PWM_Type * base ) {
114
+ }
115
+ #endif
116
+
86
117
pwmout_result_t common_hal_pwmio_pwmout_construct (pwmio_pwmout_obj_t * self ,
87
118
const mcu_pin_obj_t * pin ,
88
119
uint16_t duty ,
@@ -93,6 +124,9 @@ pwmout_result_t common_hal_pwmio_pwmout_construct(pwmio_pwmout_obj_t *self,
93
124
94
125
const uint32_t pwm_count = sizeof (mcu_pwm_list ) / sizeof (mcu_pwm_obj_t );
95
126
127
+ DBGPrintf (& mp_plat_print , ">>> common_hal_pwmio_pwmout_construct called: pin: %p %u freq:%u duty:%u var:%u\n" ,
128
+ self -> pin -> gpio , self -> pin -> number , frequency , duty , variable_frequency );
129
+
96
130
for (uint32_t i = 0 ; i < pwm_count ; ++ i ) {
97
131
if (mcu_pwm_list [i ].pin != pin ) {
98
132
continue ;
@@ -107,6 +141,8 @@ pwmout_result_t common_hal_pwmio_pwmout_construct(pwmio_pwmout_obj_t *self,
107
141
return PWMOUT_INVALID_PIN ;
108
142
}
109
143
144
+ DBGPrintf (& mp_plat_print , "\tFound in PWM List\n" );
145
+
110
146
config_periph_pin (self -> pwm );
111
147
112
148
pwm_config_t pwmConfig ;
@@ -138,33 +174,67 @@ pwmout_result_t common_hal_pwmio_pwmout_construct(pwmio_pwmout_obj_t *self,
138
174
139
175
pwmConfig .prescale = self -> prescaler ;
140
176
177
+ DBGPrintf (& mp_plat_print , "\tCall PWM_Init\n" );
141
178
if (PWM_Init (self -> pwm -> pwm , self -> pwm -> submodule , & pwmConfig ) == kStatus_Fail ) {
142
179
return PWMOUT_INVALID_PIN ;
143
180
}
144
181
145
- pwm_signal_param_t pwmSignal = {
146
- .pwmChannel = self -> pwm -> channel ,
147
- .level = kPWM_HighTrue ,
148
- .dutyCyclePercent = 0 , // avoid an initial transient
149
- .deadtimeValue = 0 , // allow 100% duty cycle
150
- };
151
-
152
182
// Disable all fault inputs
153
183
self -> pwm -> pwm -> SM [self -> pwm -> submodule ].DISMAP [0 ] = 0 ;
154
184
self -> pwm -> pwm -> SM [self -> pwm -> submodule ].DISMAP [1 ] = 0 ;
155
185
156
- status_t status = PWM_SetupPwm (self -> pwm -> pwm , self -> pwm -> submodule , & pwmSignal , 1 , kPWM_EdgeAligned , frequency , PWM_SRC_CLK_FREQ );
157
-
158
- if (status != kStatus_Success ) {
159
- return PWMOUT_INITIALIZATION_ERROR ;
186
+ DBGPrintf (& mp_plat_print , "\tCall PWM_SetupPwm %p %x %u\n" , self -> pwm -> pwm , self -> pwm -> submodule );
187
+ // ========================================================================================================
188
+ // Not calling the PWM_SetupPwm as it was setup to only work for PWM output on chan A and B but not X
189
+ // I have done some experimenting, probably could try others, but again they do not work with X.
190
+ // Most of the code checks to see if A if not, then it assume B.
191
+ //
192
+ // Instead I set it up to work similar to what the Teensy 4.x code does.
193
+ //
194
+ // That is we set the PWM_CTRL_FULL_MASK, which then uses base->SM[submodule].VAL1 to control
195
+ // when the timer is reset, so it sets up your cycle/frequency. But then this implies that X channel
196
+ // which uses 0, 1 has to be handled specially. So for the different channels:
197
+ // A - Uses VAL2 to turn on (0) and VAL3=duty to turn off
198
+ // B - Uses VAL4 to turn on (0) and VAL5 to turn off
199
+ // X - As mentioned above VAL1 turns off, but it's set to the timing for frequency. so
200
+ // VAL0 turns on, so we set it to VAL1 - duty
201
+ //
202
+ PWM_Type * base = self -> pwm -> pwm ;
203
+ uint8_t submodule = self -> pwm -> submodule ;
204
+
205
+ uint32_t mask = 1 << submodule ;
206
+ uint32_t olddiv = base -> SM [submodule ].VAL1 + 1 ;
207
+ if (self -> pulse_count != olddiv ) {
208
+ base -> MCTRL |= PWM_MCTRL_CLDOK (mask );
209
+ base -> SM [submodule ].CTRL = PWM_CTRL_PRSC_MASK | PWM_CTRL_PRSC (self -> prescaler );
210
+ base -> SM [submodule ].VAL1 = self -> pulse_count - 1 ;
211
+ base -> SM [submodule ].CTRL2 = PWM_CTRL2_INDEP_MASK | PWM_CTRL2_WAITEN_MASK | PWM_CTRL2_DBGEN_MASK ;
212
+
213
+ if (olddiv == 1 ) {
214
+ base -> SM [submodule ].CTRL = PWM_CTRL_FULL_MASK ;
215
+ base -> SM [submodule ].VAL0 = 0 ;
216
+ base -> SM [submodule ].VAL2 = 0 ;
217
+ base -> SM [submodule ].VAL3 = 0 ;
218
+ base -> SM [submodule ].VAL4 = 0 ;
219
+ base -> SM [submodule ].VAL5 = 0 ;
220
+ } else {
221
+ base -> SM [submodule ].VAL0 = (base -> SM [submodule ].VAL0 * self -> pulse_count ) / olddiv ;
222
+ base -> SM [submodule ].VAL3 = (base -> SM [submodule ].VAL3 * self -> pulse_count ) / olddiv ;
223
+ base -> SM [submodule ].VAL5 = (base -> SM [submodule ].VAL5 * self -> pulse_count ) / olddiv ;
224
+ }
225
+ base -> MCTRL |= PWM_MCTRL_LDOK (mask );
160
226
}
227
+ debug_print_flexpwm_registers (self -> pwm -> pwm );
228
+
161
229
PWM_SetPwmLdok (self -> pwm -> pwm , 1 << self -> pwm -> submodule , true);
162
230
163
231
PWM_StartTimer (self -> pwm -> pwm , 1 << self -> pwm -> submodule );
164
232
165
233
234
+ DBGPrintf (& mp_plat_print , "\tCall common_hal_pwmio_pwmout_set_duty_cycle\n" );
166
235
common_hal_pwmio_pwmout_set_duty_cycle (self , duty );
167
236
237
+ DBGPrintf (& mp_plat_print , "\tReturn OK\n" );
168
238
return PWMOUT_OK ;
169
239
}
170
240
@@ -185,26 +255,38 @@ void common_hal_pwmio_pwmout_set_duty_cycle(pwmio_pwmout_obj_t *self, uint16_t d
185
255
// we do not use PWM_UpdatePwmDutycycle because ...
186
256
// * it works in integer percents
187
257
// * it can't set the "X" duty cycle
258
+ // As mentioned in the setting up of the frequency code
259
+ // A - Uses VAL2 to turn on (0) and VAL3=duty to turn off
260
+ // B - Uses VAL4 to turn on (0) and VAL5 to turn off
261
+ // X - As mentioned above VAL1 turns off, but it's set to the timing for frequency. so
262
+ // VAL0 turns on, so we set it to VAL1 - duty
263
+
264
+ DBGPrintf (& mp_plat_print , "common_hal_pwmio_pwmout_set_duty_cycle %u\n" , duty );
188
265
self -> duty_cycle = duty ;
266
+ PWM_Type * base = self -> pwm -> pwm ;
267
+ uint8_t mask = 1 << self -> pwm -> submodule ;
189
268
if (duty == 65535 ) {
190
269
self -> duty_scaled = self -> pulse_count + 1 ;
191
270
} else {
192
271
self -> duty_scaled = ((uint32_t )duty * self -> pulse_count + self -> pulse_count / 2 ) / 65535 ;
193
272
}
194
273
switch (self -> pwm -> channel ) {
195
274
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 ;
275
+ base -> SM [self -> pwm -> submodule ].VAL0 = self -> pulse_count - self -> duty_scaled ;
276
+ base -> OUTEN |= PWM_OUTEN_PWMX_EN ( mask ) ;
198
277
break ;
199
278
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 ;
279
+ base -> SM [self -> pwm -> submodule ].VAL3 = self -> duty_scaled ;
280
+ base -> OUTEN |= PWM_OUTEN_PWMA_EN ( mask ) ;
202
281
break ;
203
282
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 ;
283
+ base -> SM [self -> pwm -> submodule ].VAL5 = self -> duty_scaled ;
284
+ base -> OUTEN |= PWM_OUTEN_PWMB_EN ( mask ) ;
206
285
}
207
286
PWM_SetPwmLdok (self -> pwm -> pwm , 1 << self -> pwm -> submodule , true);
287
+
288
+ debug_print_flexpwm_registers (self -> pwm -> pwm );
289
+
208
290
}
209
291
210
292
uint16_t common_hal_pwmio_pwmout_get_duty_cycle (pwmio_pwmout_obj_t * self ) {
0 commit comments