ruuvi.drivers.c ${PROJECT_VERSION}
Drivers for external sensors and peripherals on embedded systems.
Loading...
Searching...
No Matches
ruuvi_nrf5_sdk15_gpio_pwm.c
Go to the documentation of this file.
1
15#if (RUUVI_NRF5_SDK15_GPIO_PWM_ENABLED || DOXYGEN || CEEDLING)
16#include "ruuvi_driver_error.h"
18
19#include <stdbool.h>
20#include "nrf_pwm.h"
21#include "nrf_drv_pwm.h"
22
23#define RI_GPIO_PWM_DRIVER 0
24#define RI_GPIO_PWM_PLAYBACK_OK (0)
25#define RI_GPIO_PWM_PLAYBACK_COUNT (1)
26#define RI_GPIO_PWM_DRIVER_PIN_POINT (0)
27#define RI_GPIO_PWM_SEQ_DELAY (0)
28#define RI_GPIO_PWM_SEQ_REPEATS (1)
29
30#define RI_GPIO_PWM_MAX_FREQ (16000000.00f)
31#define RI_GPIO_PWM_MIN_FREQ (2.00f)
32
33#define RI_GPIO_PWM_MAX_DUTY (1.00f)
34#define RI_GPIO_PWM_MIN_DUTY (0.00f)
35
36#define RI_GPIO_PWM_CHANNEL_UNUSED (0)
37
38#define RI_GPIO_PWM_MIN_TOP_VALUE (1U)
39#define RI_GPIO_PWM_MIN_REST_FOR_TOP (0.999999f)
40
41#define RI_GPIO_PWM_FREQ_COUNT (8)
42
43#define RI_GPIO_PWM_BASE_FREQ_16MHZ (RI_GPIO_PWM_MAX_FREQ)
44#define RI_GPIO_PWM_BASE_FREQ_8MHZ (8000000.00f)
45#define RI_GPIO_PWM_BASE_FREQ_4MHZ (4000000.00f)
46#define RI_GPIO_PWM_BASE_FREQ_2MHZ (2000000.00f)
47#define RI_GPIO_PWM_BASE_FREQ_1MHZ (1000000.00f)
48#define RI_GPIO_PWM_BASE_FREQ_500KHZ (500000.00f)
49#define RI_GPIO_PWM_BASE_FREQ_250KHZ (250000.00f)
50#define RI_GPIO_PWM_BASE_FREQ_125KHZ (125000.00f)
51
53static bool m_gpio_pwm_is_init = false;
54static bool m_gpio_pwm_is_start = false;
55static nrf_drv_pwm_t m_pwm = NRF_DRV_PWM_INSTANCE (RI_GPIO_PWM_DRIVER);
56
57static float const freq[RI_GPIO_PWM_FREQ_COUNT] =
58{
67};
68
80
81
83{
85
86 if (!m_gpio_pwm_is_init)
87 {
88 m_gpio_pwm_is_init = true;
89 res = RD_SUCCESS;
90 }
91
92 return res;
93}
94
96{
98
99 if (false == m_gpio_pwm_is_init)
100 {
101 res = RD_SUCCESS;
102 }
103 else
104 {
105 m_gpio_pwm_is_init = false;
106 res = RD_SUCCESS;
107 }
108
109 return res;
110}
111
113{
114 return m_gpio_pwm_is_init;
115}
116
117static bool ri_gpio_pwm_is_start (void)
118{
119 return m_gpio_pwm_is_start;
120}
121
122
126static inline uint8_t ruuvi_to_nrf_pin_pwm_map (const ri_gpio_id_t pin)
127{
128 return ( (pin >> 3) & 0xE0) + (pin & 0x1F);
129}
130
131static nrf_pwm_clk_t ruuvi_get_base_config (float * const frequency,
132 float * const duty_cycle,
133 uint16_t * p_top)
134{
135 nrf_pwm_clk_t clock = NRF_PWM_CLK_16MHz;
136 float f_rest_min = RI_GPIO_PWM_MIN_REST_FOR_TOP;
137 float m_freq = (*frequency);
138 float m_duty = (*duty_cycle);
139 float m_top;
140
141 for (uint8_t i = 0; i < RI_GPIO_PWM_FREQ_COUNT ; i++)
142 {
143 if (freq[i] >= m_freq)
144 {
145 float f_rest = (freq[i] / m_freq) -
146 (uint32_t) (freq[i] / m_freq);
147
148 if (f_rest_min >= f_rest)
149 {
150 m_top = (freq[i] / m_freq) * m_duty;
151
152 if (m_top >= RI_GPIO_PWM_MIN_TOP_VALUE)
153 {
154 f_rest_min = f_rest;
155 clock = (nrf_pwm_clk_t) i;
156 (*p_top) = (freq[i] / m_freq);
157 }
158 }
159 }
160 }
161
162 return clock;
163}
164
166 float * const frequency, float * const duty_cycle)
167{
169
170 if ( (true == ri_gpio_pwm_is_init()) &&
171 (true == ri_gpio_is_init()))
172 {
173 if (true == ri_gpio_pwm_is_start ())
174 {
176 {
178 }
179 }
180
181 if ( (duty_cycle == NULL) || (frequency == NULL))
182 {
183 res = RD_ERROR_NULL;
184 }
185 else
186 {
187 if ( (RI_GPIO_PWM_MIN_DUTY > (*duty_cycle)) ||
188 (RI_GPIO_PWM_MAX_DUTY < (*duty_cycle)) ||
189 (RI_GPIO_PWM_MAX_FREQ < (*frequency)) ||
190 (RI_GPIO_PWM_MIN_FREQ > (*frequency)) ||
191 ( (RI_GPIO_MODE_OUTPUT_STANDARD != mode) &&
193 {
195 }
196 else
197 {
198 uint16_t top = RI_GPIO_PWM_MIN_TOP_VALUE;
199 nrf_pwm_clk_t clock = ruuvi_get_base_config (frequency, duty_cycle, &top);
200 uint8_t out_pin = (ruuvi_to_nrf_pin_pwm_map (pin) | NRF_DRV_PWM_PIN_INVERTED);
201 nrf_drv_pwm_config_t config = NRF_DRV_PWM_DEFAULT_CONFIG;
202 config.output_pins[RI_GPIO_PWM_DRIVER_PIN_POINT] = out_pin;
203 config.base_clock = clock;
204 config.top_value = top;
205
206 if ( (NRF_SUCCESS == ri_gpio_configure (pin, mode)) &&
207 (NRF_SUCCESS == nrf_drv_pwm_init (&m_pwm, &config, NULL)))
208 {
209 uint16_t steps_duty = (uint16_t) (top * (*duty_cycle));
210 static nrf_pwm_values_individual_t seq_values;
211 seq_values.channel_0 = steps_duty;
212 seq_values.channel_1 = RI_GPIO_PWM_CHANNEL_UNUSED;
213 seq_values.channel_2 = RI_GPIO_PWM_CHANNEL_UNUSED;
214 seq_values.channel_3 = RI_GPIO_PWM_CHANNEL_UNUSED;
215 nrf_pwm_sequence_t const seq =
216 {
217 .values.p_individual = &seq_values,
218 .length = NRF_PWM_VALUES_LENGTH (seq_values),
219 .repeats = RI_GPIO_PWM_SEQ_REPEATS,
220 .end_delay = RI_GPIO_PWM_SEQ_DELAY
221 };
222
223 if (RI_GPIO_PWM_PLAYBACK_OK == nrf_drv_pwm_simple_playback (&m_pwm, &seq,
225 NRF_DRV_PWM_FLAG_LOOP))
226 {
227 res = RD_SUCCESS;
228 m_gpio_pwm_is_start = true;
229 }
230 }
231 }
232 }
233 }
234
235 return res;
236}
237
239{
241 bool wait = true;
242
243 if (true == nrf_drv_pwm_stop (&m_pwm, wait))
244 {
245 nrf_drv_pwm_uninit (&m_pwm);
246 m_gpio_pwm_is_start = false;
247 res = RD_SUCCESS;
248 }
249
250 return res;
251}
253#endif
#define RD_ERROR_INVALID_PARAM
Invalid Parameter.
#define RD_ERROR_NULL
Null Pointer.
uint32_t rd_status_t
bitfield for representing errors
#define RD_SUCCESS
Internal Error.
#define RD_ERROR_INVALID_STATE
Invalid state, operation disallowed in this state.
#define RI_GPIO_PWM_MIN_DUTY
#define RI_GPIO_PWM_BASE_FREQ_4MHZ
#define RI_GPIO_PWM_MIN_TOP_VALUE
#define RI_GPIO_PWM_PLAYBACK_OK
#define RI_GPIO_PWM_CHANNEL_UNUSED
#define RI_GPIO_PWM_PLAYBACK_COUNT
#define RI_GPIO_PWM_MAX_DUTY
#define RI_GPIO_PWM_BASE_FREQ_500KHZ
#define RI_GPIO_PWM_SEQ_REPEATS
#define RI_GPIO_PWM_MIN_REST_FOR_TOP
bool ri_gpio_is_init(void)
return true if GPIO is init, false otherwise.
rd_status_t ri_gpio_configure(const ri_gpio_id_t pin, const ri_gpio_mode_t mode)
Configure a pin of a port into a mode. If there are several ports the platform driver must implement ...
rd_status_t ri_gpio_pwm_stop(const ri_gpio_id_t pin)
Stop PWM on given pin.
#define RI_GPIO_PWM_MIN_FREQ
#define RI_GPIO_PWM_BASE_FREQ_2MHZ
#define RI_GPIO_PWM_DRIVER
#define RI_GPIO_PWM_BASE_FREQ_125KHZ
#define RI_GPIO_PWM_MAX_FREQ
bool ri_gpio_pwm_is_init(void)
Check if PWM is initialized.
#define RI_GPIO_PWM_BASE_FREQ_250KHZ
#define RI_GPIO_PWM_SEQ_DELAY
#define RI_GPIO_PWM_BASE_FREQ_8MHZ
#define RI_GPIO_PWM_FREQ_COUNT
#define RI_GPIO_PWM_DRIVER_PIN_POINT
rd_status_t ri_gpio_pwm_init(void)
Run any necessary initialization for PWM.
#define RI_GPIO_PWM_BASE_FREQ_16MHZ
rd_status_t ri_gpio_pwm_start(const ri_gpio_id_t pin, const ri_gpio_mode_t mode, float *const frequency, float *const duty_cycle)
Start PWM on given pin at given frequency and duty cycle.
rd_status_t ri_gpio_pwm_uninit(void)
Uninitialize PWM.
#define RI_GPIO_PWM_BASE_FREQ_1MHZ
@ RI_GPIO_PWM_BASE_NUM_FREQ_500KHZ
@ RI_GPIO_PWM_BASE_NUM_FREQ_8MHZ
@ RI_GPIO_PWM_BASE_NUM_FREQ_1MHZ
@ RI_GPIO_PWM_BASE_NUM_FREQ_125KHZ
@ RI_GPIO_PWM_BASE_NUM_FREQ_250KHZ
@ RI_GPIO_PWM_BASE_NUM_FREQ_2MHZ
@ RI_GPIO_PWM_BASE_NUM_FREQ_4MHZ
@ RI_GPIO_PWM_BASE_NUM_FREQ_16MHZ
Header to enable and disable module compilation.
Ruuvi error codes and error check function.
uint16_t ri_gpio_id_t
port<<8 + pin
@ RI_GPIO_MODE_OUTPUT_STANDARD
Push-pull output, can be written.
@ RI_GPIO_MODE_OUTPUT_HIGHDRIVE
Push-pull output, can be written. Higher current drive than standard.