@@ -265,6 +265,11 @@ void hm2_pwmgen_force_write(hostmot2_t *hm2) {
265265 }
266266
267267 hm2 -> pwmgen .pwm_mode_reg [i ] |= (double_buffered << 5 );
268+ if (hm2 -> pwmgen .instance [i ].hal .param .dither ) {
269+ hm2 -> pwmgen .pwm_mode_reg [i ] |= (1 << 6 );
270+ }
271+
272+
268273 }
269274
270275
@@ -287,6 +292,7 @@ void hm2_pwmgen_force_write(hostmot2_t *hm2) {
287292 for (i = 0 ; i < hm2 -> pwmgen .num_instances ; i ++ ) {
288293 hm2 -> pwmgen .instance [i ].written_output_type = hm2 -> pwmgen .instance [i ].hal .param .output_type ;
289294 hm2 -> pwmgen .instance [i ].written_offset_mode = hm2 -> pwmgen .instance [i ].hal .param .offset_mode ;
295+ hm2 -> pwmgen .instance [i ].written_dither = hm2 -> pwmgen .instance [i ].hal .param .dither ;
290296 hm2 -> pwmgen .instance [i ].written_enable = * hm2 -> pwmgen .instance [i ].hal .pin .enable ;
291297 }
292298
@@ -309,7 +315,7 @@ void hm2_pwmgen_write(hostmot2_t *hm2) {
309315 // check output type
310316 for (i = 0 ; i < hm2 -> pwmgen .num_instances ; i ++ ) {
311317 if (hm2 -> pwmgen .instance [i ].hal .param .output_type != hm2 -> pwmgen .instance [i ].written_output_type ) {
312- goto force_write ;
318+ goto force_write ;
313319 }
314320 }
315321 // check offset mode
@@ -318,6 +324,13 @@ void hm2_pwmgen_write(hostmot2_t *hm2) {
318324 goto force_write ;
319325 }
320326 }
327+
328+ // update dither?
329+ for (i = 0 ; i < hm2 -> pwmgen .num_instances ; i ++ ) {
330+ if (hm2 -> pwmgen .instance [i ].hal .param .dither != hm2 -> pwmgen .instance [i ].written_dither ) {
331+ goto force_write ;
332+ }
333+
321334 // check pwm & pdm frequency
322335 if (hm2 -> pwmgen .hal -> param .pwm_frequency != hm2 -> pwmgen .written_pwm_frequency ) goto force_write ;
323336 if (hm2 -> pwmgen .hal -> param .pdm_frequency != hm2 -> pwmgen .written_pdm_frequency ) goto force_write ;
@@ -329,6 +342,8 @@ void hm2_pwmgen_write(hostmot2_t *hm2) {
329342 }
330343 }
331344
345+ }
346+
332347 return ;
333348
334349force_write :
@@ -346,12 +361,17 @@ int hm2_pwmgen_parse_md(hostmot2_t *hm2, int md_index) {
346361 //
347362 // some standard sanity checks
348363 //
349-
350- if (!hm2_md_is_consistent_or_complain (hm2 , md_index , 0 , 5 , 4 , 0x0003 )) {
351- HM2_ERR ("inconsistent Module Descriptor!\n" );
352- return - EINVAL ;
353- }
354-
364+ hm2 -> pwmgen .firmware_supports_dither = 0 ;
365+ if (hm2_md_is_consistent (hm2 , md_index , 0 , 5 , 4 , 0x0003 )) {
366+ // OK, standard old firmware
367+ } else if (hm2_md_is_consistent (hm2 , md_index , 1 , 5 , 4 , 0x0003 )) {
368+ // OK, firmware with dither capability
369+ hm2 -> pwmgen .firmware_supports_dither = 1 ;
370+ } else {
371+ HM2_ERR ("Unsupported PWM firmware version" );
372+ return - EINVAL ;
373+ }
374+
355375 if (hm2 -> pwmgen .num_instances != 0 ) {
356376 HM2_ERR (
357377 "found duplicate Module Descriptor for %s (inconsistent firmware), not loading driver\n" ,
@@ -477,15 +497,22 @@ int hm2_pwmgen_parse_md(hostmot2_t *hm2, int md_index) {
477497 HM2_ERR ("error adding pin '%s', aborting\n" , name );
478498 goto fail1 ;
479499 }
480-
500+
481501 // parameters
482502 rtapi_snprintf (name , sizeof (name ), "%s.pwmgen.%02d.offset-mode" , hm2 -> llio -> name , i );
483503 r = hal_param_bit_new (name , HAL_RW , & (hm2 -> pwmgen .instance [i ].hal .param .offset_mode ), hm2 -> llio -> comp_id );
484504 if (r < 0 ) {
485505 HM2_ERR ("error adding param '%s', aborting\n" , name );
486506 goto fail1 ;
487507 }
488-
508+ if (hm2 -> pwmgen .firmware_supports_dither ) {
509+ rtapi_snprintf (name , sizeof (name ), "%s.pwmgen.%02d.dither" , hm2 -> llio -> name , i );
510+ r = hal_param_bit_new (name , HAL_RW , & (hm2 -> pwmgen .instance [i ].hal .param .dither ), hm2 -> llio -> comp_id );
511+ if (r < 0 ) {
512+ HM2_ERR ("error adding param '%s', aborting\n" , name );
513+ goto fail1 ;
514+ }
515+ }
489516 rtapi_snprintf (name , sizeof (name ), "%s.pwmgen.%02d.scale" , hm2 -> llio -> name , i );
490517 r = hal_param_float_new (name , HAL_RW , & (hm2 -> pwmgen .instance [i ].hal .param .scale ), hm2 -> llio -> comp_id );
491518 if (r < 0 ) {
@@ -509,11 +536,13 @@ int hm2_pwmgen_parse_md(hostmot2_t *hm2, int md_index) {
509536 // init hal objects
510537 * (hm2 -> pwmgen .instance [i ].hal .pin .enable ) = 0 ;
511538 * (hm2 -> pwmgen .instance [i ].hal .pin .value ) = 0.0 ;
512- hm2 -> pwmgen .instance [i ].hal .param .scale = 1.0 ;
539+ hm2 -> pwmgen .instance [i ].hal .param .dither = 0 ;
540+ hm2 -> pwmgen .instance [i ].hal .param .scale = 1.0 ;
513541 hm2 -> pwmgen .instance [i ].hal .param .offset_mode = 0 ;
514542 hm2 -> pwmgen .instance [i ].hal .param .output_type = HM2_PWMGEN_OUTPUT_TYPE_PWM ;
515543 hm2 -> pwmgen .instance [i ].written_output_type = -666 ; // force an update at the start
516544 hm2 -> pwmgen .instance [i ].written_enable = -666 ; // force an update at the start
545+ hm2 -> pwmgen .instance [i ].written_dither = -666 ; // force an update at the start
517546 }
518547 }
519548
@@ -576,12 +605,13 @@ void hm2_pwmgen_print_module(hostmot2_t *hm2) {
576605
577606void hm2_pwmgen_prepare_tram_write (hostmot2_t * hm2 ) {
578607 int i ;
579-
608+ double topdrop ;
580609 if (hm2 -> pwmgen .num_instances <= 0 ) return ;
581610
582611 for (i = 0 ; i < hm2 -> pwmgen .num_instances ; i ++ ) {
583612 double scaled_value ;
584613 double abs_duty_cycle ;
614+ double register_value ;
585615 int bits ;
586616
587617 scaled_value = * hm2 -> pwmgen .instance [i ].hal .pin .value / hm2 -> pwmgen .instance [i ].hal .param .scale ;
@@ -609,7 +639,15 @@ void hm2_pwmgen_prepare_tram_write(hostmot2_t *hm2) {
609639 } else {
610640 bits = hm2 -> pwmgen .pwm_bits ;
611641 }
612- hm2 -> pwmgen .pwm_value_reg [i ] = abs_duty_cycle * (double )((1 << bits ) - 1 );
642+ // With normal PWM, the max PWM register value is 0xNFF.X
643+ // but for dithered PWM the max value is 0xNFE.F
644+ // the topdrop value is chosen to generate these max values
645+ if (hm2 -> pwmgen .instance [i ].hal .param .dither == 0 ) {
646+ topdrop = 1 ;
647+ } else {
648+ topdrop = 1.0625 ;
649+ }
650+ register_value = abs_duty_cycle * (double )((1 << bits ) - topdrop );
613651
614652 } else {
615653 // offset PWM/PDM modes where 0 PWM value = 50% duty cycle also choose active low
@@ -618,9 +656,17 @@ void hm2_pwmgen_prepare_tram_write(hostmot2_t *hm2) {
618656 } else {
619657 bits = hm2 -> pwmgen .pwm_bits - 1 ;
620658 }
621- hm2 -> pwmgen .pwm_value_reg [i ] = scaled_value * (double )(((1 << bits ) - 1 ))+ (1 << bits );
659+ // With normal PWM, the max PWM register value is 0xNFF.X
660+ // but for dithered PWM the max value is 0xNFE.F
661+ // the topdrop value is chosen to generate these max values
662+ if (hm2 -> pwmgen .instance [i ].hal .param .dither == 0 ) {
663+ topdrop = 1 ;
664+ } else {
665+ topdrop = 1.0625 ;
666+ }
667+ register_value = scaled_value * (double )(((1 << bits ) - topdrop ))+ (1 << bits );
622668 }
623- hm2 -> pwmgen .pwm_value_reg [i ] <<= 16 ;
669+ hm2 -> pwmgen .pwm_value_reg [i ] = register_value * 65536 ;
624670 if (scaled_value < 0 ) {
625671 hm2 -> pwmgen .pwm_value_reg [i ] |= (1 << 31 );
626672 }
0 commit comments