@@ -69,7 +69,7 @@ static const PinMap PinMap_PWM[] = {
69
69
{NC , NC , 0 }
70
70
};
71
71
72
- static float pwm_clock ;
72
+ static float pwm_clock_mhz ;
73
73
74
74
void pwmout_init (pwmout_t * obj , PinName pin ) {
75
75
PWMName pwm = (PWMName )pinmap_peripheral (pin , PinMap_PWM );
@@ -78,7 +78,9 @@ void pwmout_init(pwmout_t* obj, PinName pin) {
78
78
}
79
79
obj -> pwm_name = pwm ;
80
80
81
- float clkval = clock_hal_get_fllclk () / 1000000.0f ;
81
+ uint32_t pwm_base_clock ;
82
+ clock_manager_get_frequency (kBusClock , & pwm_base_clock );
83
+ float clkval = (float )pwm_base_clock / 1000000.0f ;
82
84
uint32_t clkdiv = 0 ;
83
85
while (clkval > 1 ) {
84
86
clkdiv ++ ;
@@ -88,17 +90,23 @@ void pwmout_init(pwmout_t* obj, PinName pin) {
88
90
}
89
91
}
90
92
91
- pwm_clock = clkval ;
93
+ pwm_clock_mhz = clkval ;
92
94
uint32_t channel = pwm & 0xF ;
93
95
uint32_t instance = pwm >> TPM_SHIFT ;
94
96
clock_manager_set_gate (kClockModuleFTM , instance , true);
95
97
ftm_hal_set_tof_frequency (instance , 3 );
96
- ftm_hal_set_clock_ps (instance , (ftm_clock_ps_t )clkdiv );
97
98
ftm_hal_set_clock_source (instance , kClock_source_FTM_SystemClk );
98
- ftm_hal_set_channel_edge_level (instance , channel , 2 );
99
+ ftm_hal_set_clock_ps (instance , (ftm_clock_ps_t )clkdiv );
100
+ ftm_hal_set_counter_init_val (instance , 0 );
99
101
// default to 20ms: standard for servos, and fine for e.g. brightness control
100
102
pwmout_period_ms (obj , 20 );
101
103
pwmout_write (obj , 0 );
104
+ ftm_config_t config = {
105
+ .mode = kFtmEdgeAlignedPWM ,
106
+ .channel = channel ,
107
+ .edge_mode = {.ftm_pwm_edge_mode = kFtmHighTrue }
108
+ };
109
+ ftm_hal_enable_pwm_mode (instance , & config );
102
110
103
111
// Wire pinout
104
112
pinmap_pinout (pin , PinMap_PWM );
@@ -116,11 +124,14 @@ void pwmout_write(pwmout_t* obj, float value) {
116
124
uint16_t mod = ftm_hal_get_mod (obj -> pwm_name >> TPM_SHIFT );
117
125
uint32_t new_count = (uint32_t )((float )(mod ) * value );
118
126
ftm_hal_set_channel_count_value (obj -> pwm_name >> TPM_SHIFT , obj -> pwm_name & 0xF , new_count );
127
+ ftm_hal_set_counter (obj -> pwm_name >> TPM_SHIFT , 0 );
119
128
}
120
129
121
130
float pwmout_read (pwmout_t * obj ) {
122
131
uint16_t count = ftm_hal_get_channel_count_value (obj -> pwm_name >> TPM_SHIFT , obj -> pwm_name & 0xF , 0 );
123
132
uint16_t mod = ftm_hal_get_mod (obj -> pwm_name >> TPM_SHIFT );
133
+ if (mod == 0 )
134
+ return 0.0 ;
124
135
float v = (float )(count ) / (float )(mod );
125
136
return (v > 1.0f ) ? (1.0f ) : (v );
126
137
}
@@ -135,10 +146,13 @@ void pwmout_period_ms(pwmout_t* obj, int ms) {
135
146
136
147
// Set the PWM period, keeping the duty cycle the same.
137
148
void pwmout_period_us (pwmout_t * obj , int us ) {
149
+ uint32_t instance = obj -> pwm_name >> TPM_SHIFT ;
138
150
float dc = pwmout_read (obj );
139
- ftm_hal_set_mod (obj -> pwm_name >> TPM_SHIFT , (uint32_t )(pwm_clock * (float )us ));
151
+ // Stop FTM clock to ensure instant update of MOD register
152
+ ftm_hal_set_clock_source (instance , kClock_source_FTM_None );
153
+ ftm_hal_set_mod (instance , (uint32_t )(pwm_clock_mhz * (float )us ) - 1 );
140
154
pwmout_write (obj , dc );
141
-
155
+ ftm_hal_set_clock_source ( instance , kClock_source_FTM_SystemClk );
142
156
}
143
157
144
158
void pwmout_pulsewidth (pwmout_t * obj , float seconds ) {
@@ -150,6 +164,6 @@ void pwmout_pulsewidth_ms(pwmout_t* obj, int ms) {
150
164
}
151
165
152
166
void pwmout_pulsewidth_us (pwmout_t * obj , int us ) {
153
- uint32_t value = (uint32_t )(pwm_clock * (float )us );
167
+ uint32_t value = (uint32_t )(pwm_clock_mhz * (float )us );
154
168
ftm_hal_set_channel_count_value (obj -> pwm_name >> TPM_SHIFT , obj -> pwm_name & 0xF , value );
155
169
}
0 commit comments