2424 * THE SOFTWARE.
2525 */
2626
27- #include "py/runtime.h"
28- #include "py/mphal.h"
29- #include "modmachine.h"
27+ #include "py/runtime.h"
28+ #include "py/mphal.h"
29+ #include "modmachine.h"
3030
3131// port-specific includes
32- #include "machine_pin_phy.h"
33- #include "mplogger.h"
32+ #include "machine_pin_phy.h"
33+ #include "mplogger.h"
34+
35+ #define pwm_assert_raise_val (msg , ret ) if (ret != CY_RSLT_SUCCESS) { \
36+ mp_raise_msg_varg(&mp_type_ValueError, MP_ERROR_TEXT(msg), ret); \
37+ }
3438
3539typedef struct _machine_pwm_obj_t {
3640 mp_obj_base_t base ;
@@ -39,14 +43,12 @@ typedef struct _machine_pwm_obj_t {
3943 uint32_t fz ;
4044 uint8_t duty_type ;
4145 mp_int_t duty ;
42- // bool invert;
4346} machine_pwm_obj_t ;
4447
4548static machine_pwm_obj_t * pwm_obj [MAX_PWM_OBJS ] = { NULL };
4649
4750static inline machine_pwm_obj_t * pwm_obj_alloc () {
48- for (uint8_t i = 0 ; i < MAX_PWM_OBJS ; i ++ )
49- {
51+ for (uint8_t i = 0 ; i < MAX_PWM_OBJS ; i ++ ) {
5052 if (pwm_obj [i ] == NULL ) {
5153 pwm_obj [i ] = mp_obj_malloc (machine_pwm_obj_t , & machine_pwm_type );
5254 return pwm_obj [i ];
@@ -57,8 +59,7 @@ static inline machine_pwm_obj_t *pwm_obj_alloc() {
5759}
5860
5961static inline void pwm_obj_free (machine_pwm_obj_t * pwm_obj_ptr ) {
60- for (uint8_t i = 0 ; i < MAX_PWM_OBJS ; i ++ )
61- {
62+ for (uint8_t i = 0 ; i < MAX_PWM_OBJS ; i ++ ) {
6263 if (pwm_obj [i ] == pwm_obj_ptr ) {
6364 pwm_obj [i ] = NULL ;
6465 }
@@ -72,74 +73,83 @@ enum {
7273 DUTY_NS
7374};
7475
75- static void mp_machine_pwm_freq_set (machine_pwm_obj_t * self , mp_int_t freq );
76+ /* Unit conversion macros */
77+ #define pwm_duty_cycle_ns_to_u16 (duty_ns , fz ) ((int)(((float)(duty_ns * fz) / (float)1000000000) * (float)65536) - 1)
78+ #define pwm_duty_cycle_u16_to_ns (duty_u16 , fz ) ((int)(((float)(duty_u16 + 1) / (float)65536) * ((float)1000000000 / (float)fz)))
79+ #define pwm_duty_cycle_u16_to_percent (duty_u16 ) ((float)((duty_u16) * 100) / (float)65535)
80+ #define pwm_freq_to_period_us (fz ) ((uint32_t)(1000000 / fz))
81+ #define pwm_period_ns_to_us (period_ns ) ((uint32_t)(period_ns / 1000))
82+
83+ static void pwm_duty_ns_assert (mp_int_t duty_ns , uint32_t fz ) {
84+ if (duty_ns > (int )(1000000000 / fz )) {
85+ mp_raise_msg_varg (& mp_type_ValueError , MP_ERROR_TEXT ("PWM duty in ns is larger than the period %d ns" ), (int )(1000000000 / fz ));
86+ }
87+ }
7688
77- static cy_rslt_t pwm_freq_duty_set (cyhal_pwm_t * pwm_obj , uint32_t fz , float duty_cycle ) {
78- return cyhal_pwm_set_duty_cycle (pwm_obj , duty_cycle * 100 , fz ); // duty_cycle in percentage
89+ static inline void pwm_freq_duty_set (cyhal_pwm_t * pwm_obj , uint32_t fz , mp_int_t duty_cycle ) {
90+ cy_rslt_t ret = cyhal_pwm_set_duty_cycle (pwm_obj , pwm_duty_cycle_u16_to_percent (duty_cycle ), fz );
91+ pwm_assert_raise_val ("PWM frequency and duty cycle set failed with return code %lx !" , ret );
7992}
8093
81- static inline cy_rslt_t pwm_duty_set_ns (cyhal_pwm_t * pwm_obj , uint32_t fz , uint32_t pulse_width ) {
82- return cyhal_pwm_set_period (pwm_obj , 1000000 / fz , pulse_width / 1000 ); // !# * --> /
94+ static void pwm_duty_set_ns (cyhal_pwm_t * pwm_obj , uint32_t fz , uint32_t pulse_width ) {
95+ cy_rslt_t ret = cyhal_pwm_set_period (pwm_obj , pwm_freq_to_period_us (fz ), pwm_period_ns_to_us (pulse_width ));
96+ pwm_assert_raise_val ("PWM period set failed with return code %lx !" , ret );
8397}
8498
85- /*STATIC inline cy_rslt_t pwm_advanced_init(machine_pwm_obj_t *machine_pwm_obj) {
86- return cyhal_pwm_init_adv(&machine_pwm_obj->pwm_obj, machine_pwm_obj->pin, NC, CYHAL_PWM_LEFT_ALIGN, true, 0, true, NULL); // complimentary pin set as not connected
87- }*/
99+ static void pwm_config (machine_pwm_obj_t * self ) {
100+ if (self -> duty_type == DUTY_U16 ) {
101+ pwm_freq_duty_set (& self -> pwm_obj , self -> fz , self -> duty );
102+ } else {
103+ pwm_duty_set_ns (& self -> pwm_obj , self -> fz , self -> duty );
104+ }
105+ }
88106
89107static void mp_machine_pwm_print (const mp_print_t * print , mp_obj_t self_in , mp_print_kind_t kind ) {
90108 machine_pwm_obj_t * self = MP_OBJ_TO_PTR (self_in );
91- mp_printf (print , "frequency=%u duty_cycle=%f" , self -> fz , (double )self -> duty );
109+ mp_obj_t pin = mp_obj_new_int (self -> pin );
110+ const char * pin_name = mp_obj_str_get_str (pin_name_by_addr (pin ));
111+ mp_printf (print , "PWM(\"%s\",freq=%u, duty_u16=%f)" , pin_name , self -> fz , (double )self -> duty );
92112}
93113
94114static void mp_machine_pwm_init_helper (machine_pwm_obj_t * self ,
95115 size_t n_args , const mp_obj_t * pos_args , mp_map_t * kw_args ) {
96116 enum { ARG_freq , ARG_duty_u16 , ARG_duty_ns };
97- // enum { ARG_freq, ARG_duty_u16, ARG_duty_ns, ARG_invert };
117+
98118 static const mp_arg_t allowed_args [] = {
99- { MP_QSTR_freq , MP_ARG_INT , {.u_int = VALUE_NOT_SET } },
119+ { MP_QSTR_freq , MP_ARG_REQUIRED | MP_ARG_INT , {.u_int = VALUE_NOT_SET } },
100120 { MP_QSTR_duty_u16 , MP_ARG_KW_ONLY | MP_ARG_INT , {.u_int = VALUE_NOT_SET } },
101121 { MP_QSTR_duty_ns , MP_ARG_KW_ONLY | MP_ARG_INT , {.u_int = VALUE_NOT_SET } },
102- // { MP_QSTR_invert, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = VALUE_NOT_SET} },
103122 };
104123
105124 // Parse the arguments.
106125 mp_arg_val_t args [MP_ARRAY_SIZE (allowed_args )];
107126 mp_arg_parse_all (n_args , pos_args , kw_args ,
108127 MP_ARRAY_SIZE (allowed_args ), allowed_args , args );
109- // self->active = 1;
110128
111129 if ((args [ARG_freq ].u_int != VALUE_NOT_SET )) {
112- // pwm_freq_duty_set(&self->pwm_obj, args[ARG_freq].u_int, self->duty);
113130 self -> fz = args [ARG_freq ].u_int ;
114131 }
115132
116- if ((args [ARG_duty_u16 ].u_int != VALUE_NOT_SET )) {
117- float val = (float )(args [ARG_duty_u16 ].u_int ) / (float )65535 ;
118- pwm_freq_duty_set (& self -> pwm_obj , self -> fz , val );
119- self -> duty = args [ARG_duty_u16 ].u_int ;
120- self -> duty_type = DUTY_U16 ;
133+ if ((args [ARG_duty_u16 ].u_int != VALUE_NOT_SET ) &&
134+ (args [ARG_duty_ns ].u_int != VALUE_NOT_SET )) {
135+ mp_raise_ValueError (MP_ERROR_TEXT ("PWM duty should be specified only in one format" ));
121136 }
122137
123- if (args [ARG_duty_ns ].u_int != VALUE_NOT_SET ) {
124- pwm_duty_set_ns (& self -> pwm_obj , self -> fz , args [ARG_duty_ns ].u_int );
138+ if ((args [ARG_duty_u16 ].u_int != VALUE_NOT_SET )) {
139+ self -> duty = args [ARG_duty_u16 ].u_int > 65535 ? 65535 : args [ARG_duty_u16 ].u_int ;
140+ self -> duty_type = DUTY_U16 ;
141+ } else if (args [ARG_duty_ns ].u_int != VALUE_NOT_SET ) {
142+ pwm_duty_ns_assert (args [ARG_duty_ns ].u_int , self -> fz );
125143 self -> duty = args [ARG_duty_ns ].u_int ;
126144 self -> duty_type = DUTY_NS ;
145+ } else {
146+ mp_raise_ValueError (MP_ERROR_TEXT ("PWM duty should be specified in either ns or u16" ));
127147 }
128148
129- // inverts the respective output if the value is True
130- /*if (args[ARG_invert].u_int != VALUE_NOT_SET) {
131- self->invert = args[ARG_invert].u_int;
132- if (self->invert == 1) {
133- cyhal_pwm_free(&self->pwm_obj);
134- cy_rslt_t result = pwm_advanced_init(self);
135- if (result != CY_RSLT_SUCCESS) {
136- mp_raise_msg_varg(&mp_type_ValueError, MP_ERROR_TEXT("PWM initialisation failed with return code %lx ! and invert output is not available"), result);
137- }
138- self->duty_type = DUTY_U16;
139- self->duty = ((1) - ((self->duty) / 65535)) * 65535;
140- }
141- }*/
142- cyhal_pwm_start (& self -> pwm_obj );
149+ pwm_config (self );
150+
151+ cy_rslt_t result = cyhal_pwm_start (& self -> pwm_obj );
152+ pwm_assert_raise_val ("PWM start failed with return code %lx !" , result );
143153}
144154
145155static mp_obj_t mp_machine_pwm_make_new (const mp_obj_type_t * type , size_t n_args , size_t n_kw , const mp_obj_t * all_args ) {
@@ -151,16 +161,10 @@ static mp_obj_t mp_machine_pwm_make_new(const mp_obj_type_t *type, size_t n_args
151161 self -> pin = pin_addr_by_name (all_args [0 ]);
152162 self -> duty_type = DUTY_NOT_SET ;
153163 self -> fz = -1 ;
154- // self->invert = -1;
155164
156- // Initialize PWM
157165 cy_rslt_t result = cyhal_pwm_init (& self -> pwm_obj , self -> pin , NULL );
158-
159- // To check whether PWM init is successful
160- if (result != CY_RSLT_SUCCESS ) {
161- assert_pin_phy_used (result );
162- mp_raise_msg_varg (& mp_type_ValueError , MP_ERROR_TEXT ("PWM initialisation failed with return code %lx !" ), result );
163- }
166+ assert_pin_phy_used (result );
167+ pwm_assert_raise_val ("PWM initialisation failed with return code %lx !" , result );
164168
165169 // Process the remaining parameters.
166170 mp_map_t kw_args ;
@@ -171,17 +175,17 @@ static mp_obj_t mp_machine_pwm_make_new(const mp_obj_type_t *type, size_t n_args
171175}
172176
173177static void mp_machine_pwm_deinit (machine_pwm_obj_t * self ) {
174- cyhal_pwm_stop (& self -> pwm_obj );
178+ cy_rslt_t result = cyhal_pwm_stop (& self -> pwm_obj );
179+ pwm_assert_raise_val ("PWM stop failed with return code %lx !" , result );
175180 cyhal_pwm_free (& self -> pwm_obj );
176181 pwm_obj_free (self );
177182}
178183
179184static mp_obj_t mp_machine_pwm_duty_get_u16 (machine_pwm_obj_t * self ) {
180185 if (self -> duty_type == DUTY_NS ) {
181- // duty_cycle = pulsewidth(ns)*freq(hz);
182- return mp_obj_new_float (((self -> duty ) * (self -> fz ) * 65535 ) / 1000000000 - 1 );
186+ return mp_obj_new_int (pwm_duty_cycle_ns_to_u16 (self -> duty , self -> fz ));
183187 } else {
184- return mp_obj_new_float (self -> duty );
188+ return mp_obj_new_int (self -> duty );
185189 }
186190}
187191
@@ -190,39 +194,38 @@ static void mp_machine_pwm_duty_set_u16(machine_pwm_obj_t *self, mp_int_t duty_u
190194 // Check the value is more than the max value
191195 self -> duty = duty_u16 > 65535 ? 65535 : duty_u16 ;
192196 self -> duty_type = DUTY_U16 ;
193- pwm_freq_duty_set ( & self -> pwm_obj , self -> fz , ( float )( self -> duty ) / ( float ) 65535 ); // s conversion of duty_u16 into dutyu16/65535
197+ pwm_config ( self );
194198}
195199
196200static mp_obj_t mp_machine_pwm_duty_get_ns (machine_pwm_obj_t * self ) {
197201 if (self -> duty_type == DUTY_U16 ) {
198- return mp_obj_new_float ((( self -> duty ) * 1000000000 ) / (( self -> fz ) * 65535 )); // pw (ns) = duty_cycle*10^9/fz
202+ return mp_obj_new_int ( pwm_duty_cycle_u16_to_ns ( self -> duty , self -> fz ));
199203 } else {
200- return mp_obj_new_float (self -> duty );
204+ return mp_obj_new_int (self -> duty );
201205 }
202206}
203207
204208// sets the pulse width in nanoseconds
205209static void mp_machine_pwm_duty_set_ns (machine_pwm_obj_t * self , mp_int_t duty_ns ) {
210+ pwm_duty_ns_assert (duty_ns , self -> fz );
206211 self -> duty = duty_ns ;
207212 self -> duty_type = DUTY_NS ;
208- pwm_duty_set_ns ( & self -> pwm_obj , self -> fz , duty_ns );
213+ pwm_config ( self );
209214}
210215
211216static mp_obj_t mp_machine_pwm_freq_get (machine_pwm_obj_t * self ) {
212217 return MP_OBJ_NEW_SMALL_INT (self -> fz );
213-
214218}
215219
216220static void mp_machine_pwm_freq_set (machine_pwm_obj_t * self , mp_int_t freq ) {
217- self -> fz = freq ;
218- pwm_freq_duty_set (& self -> pwm_obj , freq , self -> duty );
219221 if (self -> duty_type == DUTY_NS ) {
220- self -> duty = ((self -> duty ) * (self -> fz ) * 65535 ) / 1000000000 ;
221- mp_machine_pwm_duty_set_ns (self , self -> duty );
222+ pwm_duty_ns_assert (self -> duty , freq );
222223 }
224+ self -> fz = freq ;
225+ pwm_config (self );
223226}
224227
225- void mod_pwm_deinit () {
228+ void machine_pwm_deinit_all () {
226229 for (uint8_t i = 0 ; i < MAX_PWM_OBJS ; i ++ ) {
227230 if (pwm_obj [i ] != NULL ) {
228231 mp_machine_pwm_deinit (pwm_obj [i ]);
0 commit comments