|
18 | 18 | #include "cmsis.h"
|
19 | 19 | #include "pinmap.h"
|
20 | 20 | #include "error.h"
|
| 21 | +#include "fsl_ftm_hal.h" |
| 22 | +#include "fsl_mcg_hal.h" |
| 23 | +#include "fsl_clock_manager.h" |
21 | 24 |
|
22 | 25 | static const PinMap PinMap_PWM[] = {
|
23 |
| - {NC , NC , 0} |
| 26 | + {PTB18, PWM_17, 3}, |
| 27 | + {NC , NC , 0} |
24 | 28 | };
|
25 | 29 |
|
26 |
| -#define PWM_CLOCK_MHZ (0.75) // (48)MHz / 64 = (0.75)MHz |
| 30 | +static float pwm_clock; |
27 | 31 |
|
28 | 32 | void pwmout_init(pwmout_t* obj, PinName pin) {
|
29 |
| - |
| 33 | + PWMName pwm = (PWMName)pinmap_peripheral(pin, PinMap_PWM); |
| 34 | + if (pwm == (PWMName)NC) { |
| 35 | + error("PwmOut pin mapping failed"); |
| 36 | + } |
| 37 | + obj->pwm_name = pwm; |
| 38 | + |
| 39 | + float clkval = clock_hal_get_fllclk() / 1000000.0f; |
| 40 | + uint32_t clkdiv = 0; |
| 41 | + while (clkval > 1) { |
| 42 | + clkdiv++; |
| 43 | + clkval /= 2.0f; |
| 44 | + if (clkdiv == 7) |
| 45 | + break; |
| 46 | + } |
| 47 | + uint32_t channel = pwm & 0xF; |
| 48 | + uint32_t instance = pwm >> TPM_SHIFT; |
| 49 | + clock_manager_set_gate(kClockModuleFTM, instance, true); |
| 50 | + ftm_hal_set_clock_ps(instance, (ftm_clock_ps_t)clkdiv); |
| 51 | + ftm_hal_set_clock_source(instance, kClock_source_FTM_SystemClk); |
| 52 | + ftm_hal_set_channel_edge_level(instance, channel, 2); |
| 53 | + // default to 20ms: standard for servos, and fine for e.g. brightness control |
| 54 | + pwmout_period_ms(obj, 20); |
| 55 | + pwmout_write (obj, 0); |
| 56 | + |
| 57 | + // Wire pinout |
| 58 | + pinmap_pinout(pin, PinMap_PWM); |
30 | 59 | }
|
31 | 60 |
|
32 |
| -void pwmout_free(pwmout_t* obj) {} |
| 61 | +void pwmout_free(pwmout_t* obj) { |
| 62 | +} |
33 | 63 |
|
34 | 64 | void pwmout_write(pwmout_t* obj, float value) {
|
35 |
| - |
| 65 | + if (value < 0.0f) { |
| 66 | + value = 0.0f; |
| 67 | + } else if (value > 1.0f) { |
| 68 | + value = 1.0f; |
| 69 | + } |
| 70 | + uint16_t mod = ftm_hal_get_mod(obj->pwm_name >> TPM_SHIFT); |
| 71 | + uint32_t new_count = (uint32_t)((float)(mod) * value); |
| 72 | + ftm_hal_set_channel_count_value(obj->pwm_name >> TPM_SHIFT, obj->pwm_name & 0xF, new_count); |
| 73 | + // *obj->CNT = 0; |
36 | 74 | }
|
37 | 75 |
|
38 | 76 | float pwmout_read(pwmout_t* obj) {
|
39 |
| - return 1; |
| 77 | + uint16_t count = ftm_hal_get_channel_count_value(obj->pwm_name >> TPM_SHIFT, obj->pwm_name & 0xF, 0); |
| 78 | + uint16_t mod = ftm_hal_get_mod(obj->pwm_name >> TPM_SHIFT); |
| 79 | + float v = (float)(count) / (float)(mod); |
| 80 | + return (v > 1.0f) ? (1.0f) : (v); |
40 | 81 | }
|
41 | 82 |
|
42 | 83 | void pwmout_period(pwmout_t* obj, float seconds) {
|
43 |
| - |
| 84 | + pwmout_period_us(obj, seconds * 1000000.0f); |
44 | 85 | }
|
45 | 86 |
|
46 | 87 | void pwmout_period_ms(pwmout_t* obj, int ms) {
|
| 88 | + pwmout_period_us(obj, ms * 1000); |
47 | 89 | }
|
48 | 90 |
|
49 | 91 | // Set the PWM period, keeping the duty cycle the same.
|
50 | 92 | void pwmout_period_us(pwmout_t* obj, int us) {
|
| 93 | + float dc = pwmout_read(obj); |
| 94 | + ftm_hal_set_mod(obj->pwm_name >> TPM_SHIFT, (uint32_t)(pwm_clock * (float)us)); |
| 95 | + pwmout_write(obj, dc); |
| 96 | + |
51 | 97 | }
|
52 | 98 |
|
53 | 99 | void pwmout_pulsewidth(pwmout_t* obj, float seconds) {
|
54 |
| - |
| 100 | + pwmout_pulsewidth_us(obj, seconds * 1000000.0f); |
55 | 101 | }
|
56 | 102 |
|
57 | 103 | void pwmout_pulsewidth_ms(pwmout_t* obj, int ms) {
|
| 104 | + pwmout_pulsewidth_us(obj, ms * 1000); |
58 | 105 | }
|
59 | 106 |
|
60 | 107 | void pwmout_pulsewidth_us(pwmout_t* obj, int us) {
|
61 |
| - |
| 108 | + uint32_t value = (uint32_t)(pwm_clock * (float)us); |
| 109 | + ftm_hal_set_channel_count_value(obj->pwm_name >> TPM_SHIFT, obj->pwm_name & 0xF, value); |
62 | 110 | }
|
0 commit comments