@@ -353,11 +353,45 @@ ap3_err_t ap3_change_channel(uint8_t padNumber)
353
353
}
354
354
}
355
355
356
+
357
+ // **********************************************
358
+ // ap3_pwm_output
359
+ // - This function allows you to specify an arbitrary pwm output signal with a given frame width (fw) and time high (th).
360
+ // - Due to contraints of the hardware th must be lesser than fw by at least 2.
361
+ // - Furthermore fw must be at least 3 to see any high pulses
362
+ //
363
+ // This causes the most significant deviations for small values of fw. For example:
364
+ //
365
+ // th = 0, fw = 2 --> 0% duty cycle as expected
366
+ // th = 1, fw = 2 --> 100% duty cycle --- expected 50%, so 50% error ---
367
+ // th = 2, fw = 2 --> 100% duty cycle as expected
368
+ //
369
+ // th = 0, fw = 3 --> 0% duty cycle as expected
370
+ // th = 1, fw = 3 --> 33% duty cycle as expected
371
+ // th = 2, fw = 3 --> 100% duty cycle --- expected 66%, so 33% error ---
372
+ // th = 3, fw = 3 --> 100% duty cycle as expected
373
+ //
374
+ // th = 0, fw = 4 --> 0% duty cycle as expected
375
+ // th = 1, fw = 4 --> 25% duty cycle as expected
376
+ // th = 2, fw = 4 --> 50% duty cycle as expected
377
+ // th = 3, fw = 4 --> 100% duty cycle --- expected 75%, so 25% error ---
378
+ // th = 4, fw = 4 --> 100% duty cycle as expected
379
+ //
380
+ // ...
381
+ //
382
+ // Then we conclude that for the case th == (fw - 1) the duty cycle will be 100% and
383
+ // the percent error from the expected duty cycle will be 100/fw
384
+ // **********************************************
385
+
356
386
ap3_err_t ap3_pwm_output (uint8_t pin, uint32_t th, uint32_t fw, uint32_t clk)
357
387
{
358
388
// handle configuration, if necessary
359
389
ap3_err_t retval = AP3_OK;
360
390
391
+ if ( fw > 0 ){ // reduce fw so that the user's desired value is the period
392
+ fw--;
393
+ }
394
+
361
395
ap3_gpio_pad_t pad = ap3_gpio_pin2pad (pin);
362
396
if ((pad == AP3_GPIO_PAD_UNUSED) || (pad >= AP3_GPIO_MAX_PADS))
363
397
{
@@ -402,9 +436,7 @@ ap3_err_t ap3_pwm_output(uint8_t pin, uint32_t th, uint32_t fw, uint32_t clk)
402
436
}
403
437
}
404
438
else
405
- {
406
- const uint8_t n = 0 ; // use the zeroeth index into the options for any pd except 37 and 39
407
-
439
+ { // Use the 0th index of the outcfg_tbl to select the functions
408
440
timer = OUTCTIMN (ctx, 0 );
409
441
if (OUTCTIMB (ctx, 0 ))
410
442
{
@@ -416,6 +448,21 @@ ap3_err_t ap3_pwm_output(uint8_t pin, uint32_t th, uint32_t fw, uint32_t clk)
416
448
}
417
449
}
418
450
451
+ // Ensure that th is not greater than the fw
452
+ if (th > fw){
453
+ th = fw;
454
+ }
455
+
456
+ // Test for AM_HAL_CTIMER_OUTPUT_FORCE0 or AM_HAL_CTIMER_OUTPUT_FORCE1
457
+ if (( th == 0 ) || ( fw == 0 ))
458
+ {
459
+ output = AM_HAL_CTIMER_OUTPUT_FORCE0;
460
+ }
461
+ else if ( th == fw )
462
+ {
463
+ output = AM_HAL_CTIMER_OUTPUT_FORCE1;
464
+ }
465
+
419
466
// Configure the pin
420
467
am_hal_ctimer_output_config (timer,
421
468
segment,
@@ -455,17 +502,14 @@ ap3_err_t ap3_pwm_output(uint8_t pin, uint32_t th, uint32_t fw, uint32_t clk)
455
502
456
503
am_hal_ctimer_start (timer, segment);
457
504
458
- // todo: check fw and th -- if they are the same then change the mode to "force output high" to avoid noise
459
- // todo: handle the case where th==0 in a more elegant way (i.e. set mode to "force output low")
460
-
461
505
return AP3_OK;
462
506
}
463
507
464
508
ap3_err_t analogWriteResolution (uint8_t res)
465
509
{
466
- if (res > 15 )
510
+ if (res > 16 )
467
511
{
468
- _analogWriteBits = 15 ; // max out the resolution when this happens
512
+ _analogWriteBits = 16 ; // max out the resolution when this happens
469
513
return AP3_ERR;
470
514
}
471
515
_analogWriteBits = res;
@@ -475,28 +519,22 @@ ap3_err_t analogWriteResolution(uint8_t res)
475
519
ap3_err_t analogWrite (uint8_t pin, uint32_t val)
476
520
{
477
521
// Determine the high time based on input value and the current resolution setting
478
- uint32_t fsv = (0x01 << _analogWriteBits); // full scale value for the current resolution setting
479
- val = val % fsv; // prevent excess
480
- uint32_t clk = AM_HAL_CTIMER_HFRC_12MHZ; // Use an Ambiq HAL provided value to select which clock
481
- // uint32_t fw = 32768; // Choose the frame width in clock periods (32768 -> ~ 350 Hz)
482
- // uint32_t th = (uint32_t)( (fw * val) / fsv );
483
-
484
- if (val == 0 )
485
- {
486
- val = 1 ; // todo: change this so that when val==0 we set the mode to "force output low"
487
- }
488
- if (val == fsv)
489
- {
490
- val -= 1 ; // todo: change this so that when val==fsv we just set the mode to "force output high"
522
+ uint32_t fw = 0xFFFF ; // Choose the frame width in clock periods (32767 -> ~ 180 Hz)
523
+ if ( val == ((0x01 << _analogWriteBits ) - 1 ) ){
524
+ val = fw; // Enable FORCE1
525
+ }else {
526
+ val <<= (16 - _analogWriteBits); // Shift over the value to fill available resolution
491
527
}
492
- return ap3_pwm_output (pin, val, fsv, clk);
528
+ uint32_t clk = AM_HAL_CTIMER_HFRC_12MHZ; // Use an Ambiq HAL provided value to select which clock
529
+
530
+ return ap3_pwm_output (pin, val, fw, clk);
493
531
}
494
532
495
533
ap3_err_t servoWriteResolution (uint8_t res)
496
534
{
497
- if (res > 15 )
535
+ if (res > 16 )
498
536
{
499
- _servoWriteBits = 15 ; // max out the resolution when this happens
537
+ _servoWriteBits = 16 ; // max out the resolution when this happens
500
538
return AP3_ERR;
501
539
}
502
540
_servoWriteBits = res;
0 commit comments