Intel® Quark™ Microcontroller Software Interface 1.4.0 Intel® Quark™ Microcontroller BSP

- Main Page
- Modules
- Data Structures
- Files

- File List

qm_pwm.c
1 /*
2 * {% copyright %}
3 */
4
5 #include "qm_pwm.h"
6
7 /* Store callback information for each PWM channel. */
8 static void (*callback[QM_PWM_NUM][QM_PWM_ID_NUM])(void *data,
9 uint32_t int_status);
10 static void *callback_data[QM_PWM_NUM][QM_PWM_ID_NUM];
11
12 #if (NUM_PWM_CONTROLLER_INTERRUPTS > 1)
13 const uint32_t pwm_isr_vectors[QM_PWM_ID_NUM] = {
14 QM_IRQ_PWM_0_INT_0_PRIORITY, QM_IRQ_PWM_0_INT_1_PRIORITY,
15 QM_IRQ_PWM_0_INT_2_PRIORITY, QM_IRQ_PWM_0_INT_3_PRIORITY};
16 #endif /* NUM_PWM_CONTROLLER_INTERRUPTS > 1 */
17
18 #ifndef UNIT_TEST
19 qm_pwm_reg_t *qm_pwm[QM_PWM_NUM] = {(qm_pwm_reg_t *)(QM_PWM_BASE)};
20 #endif /* UNIT_TEST */
21
22 #if (NUM_PWM_CONTROLLER_INTERRUPTS > 1)
23 /*
24 * If there is more than one interrupt line for PWM, use a common handler
25 * and only clear the corresponding interrupt IRQ.
26 */
27 /* Interrupt service routine handler for PWM channels. */
28 static void pwm_isr_handler(const qm_pwm_t pwm, const qm_pwm_id_t id)
29 {
30 qm_pwm_reg_t *const controller = QM_PWM[pwm];
31 /* Check for callback function. */
32 if (callback[pwm][id]) {
33 (callback[pwm][id])(callback_data[pwm][id], BIT(id));
34 }
35
36 /* Clear interrupt on read. */
37 controller->timer[id].eoi;
38 QM_ISR_EOI(pwm_isr_vectors[id]);
39 }
40
41 QM_ISR_DECLARE(qm_pwm_0_isr_0)
42 {
43 pwm_isr_handler(QM_PWM_0, QM_PWM_ID_0);
44 }
45
46 QM_ISR_DECLARE(qm_pwm_0_isr_1)
47 {
48 pwm_isr_handler(QM_PWM_0, QM_PWM_ID_1);
49 }
50
51 QM_ISR_DECLARE(qm_pwm_0_isr_2)
52 {
53 pwm_isr_handler(QM_PWM_0, QM_PWM_ID_2);
54 }
55
56 QM_ISR_DECLARE(qm_pwm_0_isr_3)
57 {
58 pwm_isr_handler(QM_PWM_0, QM_PWM_ID_3);
59 }
60
61 #else /* NUM_PWM_CONTROLLER_INTERRUPTS > 1 */
62 QM_ISR_DECLARE(qm_pwm_0_isr_0)
63 {
64 qm_pwm_reg_t *const controller = QM_PWM[QM_PWM_0];
65 uint32_t int_status = controller->timersintstatus;
66 uint8_t pwm_id = 0;
67
68 for (; pwm_id < QM_PWM_ID_NUM; pwm_id++) {
69 if (int_status & BIT(pwm_id)) {
70 if (callback[QM_PWM_0][pwm_id]) {
71 (*callback[QM_PWM_0][pwm_id])(
72 callback_data[QM_PWM_0][pwm_id],
73 BIT(pwm_id));
74 controller->timer[pwm_id].eoi;
75 }
76 }
77 }
78 QM_ISR_EOI(QM_IRQ_PWM_0_INT_VECTOR);
79 }
80
81 #endif /* NUM_PWM_CONTROLLER_INTERRUPTS > 1 */
82
83 int qm_pwm_start(const qm_pwm_t pwm, const qm_pwm_id_t id)
84 {
85 QM_CHECK(pwm < QM_PWM_NUM, -EINVAL);
86 QM_CHECK(id < QM_PWM_ID_NUM, -EINVAL);
87
88 qm_pwm_reg_t *const controller = QM_PWM[pwm];
89 controller->timer[id].controlreg |= PWM_START;
90
91 return 0;
92 }
93
94 int qm_pwm_stop(const qm_pwm_t pwm, const qm_pwm_id_t id)
95 {
96 QM_CHECK(pwm < QM_PWM_NUM, -EINVAL);
97 QM_CHECK(id < QM_PWM_ID_NUM, -EINVAL);
98
99 qm_pwm_reg_t *const controller = QM_PWM[pwm];
100
101 controller->timer[id].controlreg &= ~PWM_START;
102
103 return 0;
104 }
105
106 int qm_pwm_set_config(const qm_pwm_t pwm, const qm_pwm_id_t id,
107 const qm_pwm_config_t *const cfg)
108 {
109 QM_CHECK(pwm < QM_PWM_NUM, -EINVAL);
110 QM_CHECK(id < QM_PWM_ID_NUM, -EINVAL);
111 QM_CHECK(cfg != NULL, -EINVAL);
112 QM_CHECK(cfg->mode <= QM_PWM_MODE_PWM, -EINVAL);
113 QM_CHECK(0 < cfg->lo_count, -EINVAL);
114 /* If mode is PWM, hi_count must be > 0, otherwise don't care. */
115 QM_CHECK(cfg->mode == QM_PWM_MODE_PWM ? 0 != cfg->hi_count : 1,
116 -EINVAL);
117
118 qm_pwm_reg_t *const controller = QM_PWM[pwm];
119 controller->timer[id].loadcount = cfg->lo_count - 1;
120 controller->timer[id].controlreg =
121 (cfg->mode | (cfg->mask_interrupt << QM_PWM_INTERRUPT_MASK_OFFSET));
122 controller->timer_loadcount2[id] = cfg->hi_count - 1;
123
124 /* Assign user callback function. */
125 callback[pwm][id] = cfg->callback;
126 callback_data[pwm][id] = cfg->callback_data;
127
128 return 0;
129 }
130
131 int qm_pwm_set(const qm_pwm_t pwm, const qm_pwm_id_t id,
132 const uint32_t lo_count, const uint32_t hi_count)
133 {
134 QM_CHECK(pwm < QM_PWM_NUM, -EINVAL);
135 QM_CHECK(id < QM_PWM_ID_NUM, -EINVAL);
136 QM_CHECK(0 < lo_count, -EINVAL);
137 /* If mode is PWM, hi_count must be > 0, otherwise don't care. */
138 QM_CHECK(((QM_PWM[pwm]->timer[id].controlreg & QM_PWM_CONF_MODE_MASK) ==
139 QM_PWM_MODE_PWM
140 ? 0 < hi_count
141 : 1),
142 -EINVAL);
143
144 qm_pwm_reg_t *const controller = QM_PWM[pwm];
145 controller->timer[id].loadcount = lo_count - 1;
146 controller->timer_loadcount2[id] = hi_count - 1;
147
148 return 0;
149 }
150
151 int qm_pwm_get(const qm_pwm_t pwm, const qm_pwm_id_t id,
152 uint32_t *const lo_count, uint32_t *const hi_count)
153 {
154 QM_CHECK(pwm < QM_PWM_NUM, -EINVAL);
155 QM_CHECK(id < QM_PWM_ID_NUM, -EINVAL);
156 QM_CHECK(lo_count != NULL, -EINVAL);
157 QM_CHECK(hi_count != NULL, -EINVAL);
158
159 qm_pwm_reg_t *const controller = QM_PWM[pwm];
160 *lo_count = controller->timer[id].loadcount;
161 *hi_count = controller->timer_loadcount2[id];
162
163 return 0;
164 }
165
166 #if (ENABLE_RESTORE_CONTEXT)
167 int qm_pwm_save_context(const qm_pwm_t pwm, qm_pwm_context_t *const ctx)
168 {
169 QM_CHECK(pwm < QM_PWM_NUM, -EINVAL);
170 QM_CHECK(ctx != NULL, -EINVAL);
171
172 qm_pwm_reg_t *const controller = QM_PWM[pwm];
173 uint8_t i;
174
175 for (i = 0; i < QM_PWM_ID_NUM; i++) {
176 ctx->channel[i].loadcount = controller->timer[i].loadcount;
177 ctx->channel[i].controlreg = controller->timer[i].controlreg;
178 ctx->channel[i].loadcount2 = controller->timer_loadcount2[i];
179 }
180
181 return 0;
182 }
183
184 int qm_pwm_restore_context(const qm_pwm_t pwm,
185 const qm_pwm_context_t *const ctx)
186 {
187 QM_CHECK(pwm < QM_PWM_NUM, -EINVAL);
188 QM_CHECK(ctx != NULL, -EINVAL);
189
190 qm_pwm_reg_t *const controller = QM_PWM[pwm];
191 uint8_t i;
192
193 for (i = 0; i < QM_PWM_ID_NUM; i++) {
194 controller->timer[i].loadcount = ctx->channel[i].loadcount;
195 controller->timer[i].controlreg = ctx->channel[i].controlreg;
196 controller->timer_loadcount2[i] = ctx->channel[i].loadcount2;
197 }
198
199 return 0;
200 }
201 #else
202 int qm_pwm_save_context(const qm_pwm_t pwm, qm_pwm_context_t *const ctx)
203 {
204 (void)pwm;
205 (void)ctx;
206
207 return 0;
208 }
209
210 int qm_pwm_restore_context(const qm_pwm_t pwm,
211 const qm_pwm_context_t *const ctx)
212 {
213 (void)pwm;
214 (void)ctx;
215
216 return 0;
217 }
218 #endif /* ENABLE_RESTORE_CONTEXT */
qm_pwm_config_t::callback
void(* callback)(void *data, uint32_t int_status)
User callback.
Definition: qm_pwm.h:53
qm_pwm_config_t::lo_count
uint32_t lo_count
Number of cycles the PWM output is driven low.
Definition: qm_pwm.h:38
qm_pwm_set
int qm_pwm_set(const qm_pwm_t pwm, const qm_pwm_id_t id, const uint32_t lo_count, const uint32_t hi_count)
Set the next period values of a PWM channel.
Definition: qm_pwm.c:131
qm_pwm_restore_context
int qm_pwm_restore_context(const qm_pwm_t pwm, const qm_pwm_context_t *const ctx)
Restore PWM peripheral's context.
Definition: qm_pwm.c:184
qm_pwm_config_t::callback_data
void * callback_data
Callback user data.
Definition: qm_pwm.h:54
qm_pwm_start
int qm_pwm_start(const qm_pwm_t pwm, const qm_pwm_id_t id)
Start a PWM/timer channel.
Definition: qm_pwm.c:83
qm_pwm_config_t::mode
qm_pwm_mode_t mode
Pwm mode.
Definition: qm_pwm.h:45
qm_pwm_reg_t::timer
qm_pwm_channel_t timer[QM_PWM_ID_NUM]
2 Timers.
Definition: qm_soc_regs.h:399
qm_pwm_channel_t::loadcount
QM_RW uint32_t loadcount
Load Coun.t.
Definition: qm_soc_regs.h:390
qm_pwm_context_t
PWM context type.
Definition: qm_soc_regs.h:702
qm_pwm_reg_t
PWM / Timer register map.
Definition: qm_soc_regs.h:398
qm_pwm_context_t::loadcount
uint32_t loadcount
Load Count 1.
Definition: qm_soc_regs.h:704
qm_pwm_config_t
QM PWM / Timer configuration type.
Definition: qm_pwm.h:33
qm_pwm_set_config
int qm_pwm_set_config(const qm_pwm_t pwm, const qm_pwm_id_t id, const qm_pwm_config_t *const cfg)
Change the configuration of a PWM channel.
Definition: qm_pwm.c:106
qm_pwm_reg_t::timer_loadcount2
QM_RW uint32_t timer_loadcount2[QM_PWM_ID_NUM]
Timer Load Count 2.
Definition: qm_soc_regs.h:406
qm_pwm_reg_t::timersintstatus
QM_RW uint32_t timersintstatus
Timers Interrupt Status.
Definition: qm_soc_regs.h:401
qm_pwm_save_context
int qm_pwm_save_context(const qm_pwm_t pwm, qm_pwm_context_t *const ctx)
Save PWM peripheral's context.
Definition: qm_pwm.c:167
qm_pwm_config_t::mask_interrupt
bool mask_interrupt
Mask interrupt.
Definition: qm_pwm.h:44
QM_ISR_DECLARE
QM_ISR_DECLARE(qm_pwm_0_isr_0)
ISR for PWM 0 Channel 0 interrupt.
Definition: qm_pwm.c:41
qm_pwm_id_t
qm_pwm_id_t
PWM ID type.
Definition: qm_soc_regs.h:386
qm_pwm_stop
int qm_pwm_stop(const qm_pwm_t pwm, const qm_pwm_id_t id)
Stop a PWM/timer channel.
Definition: qm_pwm.c:94
qm_pwm_channel_t::controlreg
QM_RW uint32_t controlreg
Control.
Definition: qm_soc_regs.h:392
qm_pwm_context_t::loadcount2
uint32_t loadcount2
Load Count 2.
Definition: qm_soc_regs.h:705
qm_pwm_channel_t::eoi
QM_RW uint32_t eoi
End Of Interrupt.
Definition: qm_soc_regs.h:393
qm_pwm_t
qm_pwm_t
Number of PWM / Timer controllers.
Definition: qm_soc_regs.h:383
qm_pwm_get
int qm_pwm_get(const qm_pwm_t pwm, const qm_pwm_id_t id, uint32_t *const lo_count, uint32_t *const hi_count)
Get the current period values of a PWM channel.
Definition: qm_pwm.c:151
qm_pwm_config_t::hi_count
uint32_t hi_count
Number of cycles the PWM output is driven high.
Definition: qm_pwm.h:43
qm_pwm_context_t::controlreg
uint32_t controlreg
Control Register.
Definition: qm_soc_regs.h:706