Appiko
hal_pwm.c
1 
19 #include "hal_pwm.h"
20 #include "nrf_assert.h"
21 #include "hal_gpio.h"
22 #include "stddef.h"
23 
24 #if ISR_MANAGER == 1
25 #include "isr_manager.h"
26 #endif
27 
31 #define PWM_ID CONCAT_2(NRF_PWM,PWM_USED)
32 #define PWM_IRQN PWM_IRQN_a(PWM_USED)
33 #define PWM_IRQ_Handler PWM_IRQ_Handler_a(PWM_USED)
34 
35 #define PWM_IRQN_a(n) PWM_IRQN_b(n)
36 #define PWM_IRQN_b(n) PWM##n##_IRQn
37 
38 #define PWM_IRQ_Handler_a(n) PWM_IRQ_Handler_b(n)
39 #define PWM_IRQ_Handler_b(n) PWM##n##_IRQHandler
40 
42 static struct
43 {
44  uint32_t pin_num;
45  uint32_t irq_mask;
46  void (*handler)(hal_pwm_irq_mask_t irq_source);
47 }cxt;
48 
49 static void call_handler(hal_pwm_irq_mask_t irq_source)
50 {
51  if(cxt.handler != NULL)
52  {
53  cxt.handler(irq_source);
54  }
55 }
56 #if ISR_MANAGER == 1
57 void hal_pwm_Handler (void)
58 #else
59 void PWM_IRQ_Handler(void)
60 #endif
61 {
62  if(PWM_ID->EVENTS_STOPPED == 1)
63  {
64 #if ISR_MANAGER == 0
65  PWM_ID->EVENTS_STOPPED = 0;
66  (void) PWM_ID->EVENTS_STOPPED;
67 #endif
68  call_handler(HAL_PWM_IRQ_STOPPED_MASK);
69  }
70 
71  if(PWM_ID->EVENTS_SEQSTARTED[0] == 1)
72  {
73 #if ISR_MANAGER == 0
74  PWM_ID->EVENTS_SEQSTARTED[0] = 0;
75  (void) PWM_ID->EVENTS_SEQSTARTED[0];
76 #endif
77  call_handler(HAL_PWM_IRQ_SEQSTARTED0_MASK);
78  }
79 
80  if(PWM_ID->EVENTS_SEQSTARTED[1] == 1)
81  {
82 #if ISR_MANAGER == 0
83  PWM_ID->EVENTS_SEQSTARTED[1] = 0;
84  (void) PWM_ID->EVENTS_SEQSTARTED[1];
85 #endif
86  call_handler(HAL_PWM_IRQ_SEQSTARTED1_MASK);
87  }
88 
89  if(PWM_ID->EVENTS_SEQEND[0] == 1)
90  {
91 #if ISR_MANAGER == 0
92  PWM_ID->EVENTS_SEQEND[0] = 0;
93  (void) PWM_ID->EVENTS_SEQEND[0];
94 #endif
95  call_handler(HAL_PWM_IRQ_SEQEND0_MASK);
96  }
97 
98  if(PWM_ID->EVENTS_SEQEND[1] == 1)
99  {
100 #if ISR_MANAGER == 0
101  PWM_ID->EVENTS_SEQEND[1] = 0;
102  (void) PWM_ID->EVENTS_SEQEND[1];
103 #endif
104  call_handler(HAL_PWM_IRQ_SEQEND1_MASK);
105  }
106 
107  if(PWM_ID->EVENTS_PWMPERIODEND == 1)
108  {
109 #if ISR_MANAGER == 0
110  PWM_ID->EVENTS_PWMPERIODEND = 0;
111  (void) PWM_ID->EVENTS_PWMPERIODEND;
112 #endif
113  call_handler(HAL_PWM_IRQ_PWMPERIODEND_MASK);
114  }
115 
116  if(PWM_ID->EVENTS_LOOPSDONE == 1)
117  {
118 #if ISR_MANAGER == 0
119  PWM_ID->EVENTS_LOOPSDONE = 0;
120  (void) PWM_ID->EVENTS_LOOPSDONE;
121 #endif
122  call_handler(HAL_PWM_IRQ_LOOPSDONE_MASK);
123  }
124 }
125 
126 void hal_pwm_init(hal_pwm_init_t * init_config)
127 {
128  ASSERT((init_config->pin_num > 0)
129  && (init_config->pin_num <= HAL_PWM_MAX_PIN_NUM));
130 
131  cxt.pin_num = init_config->pin_num;
132 
133  //Pins can only be assigned when PWM is disabled
134  PWM_ID->ENABLE = (PWM_ENABLE_ENABLE_Disabled << PWM_ENABLE_ENABLE_Pos);
135 
136  PWM_ID->INTEN = 0;
137  PWM_ID->TASKS_STOP = 1;
138 
139  switch(init_config->pin_num)
140  {
141  case 1:
142  hal_gpio_cfg_high_output(init_config->pins[0], init_config->pin_idle_state[0]);
143  PWM_ID->PSEL.OUT[0] = (init_config->pins[0] << PWM_PSEL_OUT_PIN_Pos) |
144  (PWM_PSEL_OUT_CONNECT_Connected << PWM_PSEL_OUT_CONNECT_Pos);
145  PWM_ID->PSEL.OUT[1] = (0 << PWM_PSEL_OUT_PIN_Pos) |
146  (PWM_PSEL_OUT_CONNECT_Disconnected << PWM_PSEL_OUT_CONNECT_Pos);
147  PWM_ID->PSEL.OUT[2] = (0 << PWM_PSEL_OUT_PIN_Pos) |
148  (PWM_PSEL_OUT_CONNECT_Disconnected << PWM_PSEL_OUT_CONNECT_Pos);
149  PWM_ID->PSEL.OUT[3] = (0 << PWM_PSEL_OUT_PIN_Pos) |
150  (PWM_PSEL_OUT_CONNECT_Disconnected << PWM_PSEL_OUT_CONNECT_Pos);
151  break;
152  case 2: //2 pin would be used with grouped decoder loading
153  hal_gpio_cfg_high_output(init_config->pins[0], init_config->pin_idle_state[0]);
154  PWM_ID->PSEL.OUT[0] = (init_config->pins[0] << PWM_PSEL_OUT_PIN_Pos) |
155  (PWM_PSEL_OUT_CONNECT_Connected << PWM_PSEL_OUT_CONNECT_Pos);
156  hal_gpio_cfg_high_output(init_config->pins[1], init_config->pin_idle_state[1]);
157  PWM_ID->PSEL.OUT[2] = (init_config->pins[1] << PWM_PSEL_OUT_PIN_Pos) |
158  (PWM_PSEL_OUT_CONNECT_Connected << PWM_PSEL_OUT_CONNECT_Pos);
159  PWM_ID->PSEL.OUT[1] = (0 << PWM_PSEL_OUT_PIN_Pos) |
160  (PWM_PSEL_OUT_CONNECT_Disconnected << PWM_PSEL_OUT_CONNECT_Pos);
161  PWM_ID->PSEL.OUT[3] = (0 << PWM_PSEL_OUT_PIN_Pos) |
162  (PWM_PSEL_OUT_CONNECT_Disconnected << PWM_PSEL_OUT_CONNECT_Pos);
163  break;
164  case 3:
165  case 4:
166  //Configure the pins as output with the appropriate idle state
167  for(uint32_t i = 0; i < init_config->pin_num; i++)
168  {
169  hal_gpio_cfg_high_output(init_config->pins[i], init_config->pin_idle_state[i]);
170  PWM_ID->PSEL.OUT[i] = (init_config->pins[i] << PWM_PSEL_OUT_PIN_Pos) |
171  (PWM_PSEL_OUT_CONNECT_Connected << PWM_PSEL_OUT_CONNECT_Pos);
172  }
173  //The rest of the channels of PWM are unused
174  for(uint32_t i = init_config->pin_num; i < HAL_PWM_MAX_PIN_NUM; i++)
175  {
176  PWM_ID->PSEL.OUT[i] = (0 << PWM_PSEL_OUT_PIN_Pos) |
177  (PWM_PSEL_OUT_CONNECT_Disconnected << PWM_PSEL_OUT_CONNECT_Pos);
178  }
179  break;
180  default:
181  break;
182  }
183 
184  PWM_ID->PRESCALER = (init_config->oper_freq <<
185  PWM_PRESCALER_PRESCALER_Pos);
186  PWM_ID->MODE = (init_config->oper_mode << PWM_MODE_UPDOWN_Pos);
187 
188  NVIC_SetPriority(PWM0_IRQn, init_config->irq_priority);
189  NVIC_EnableIRQ(PWM0_IRQn);
190 }
191 
192 void hal_pwm_start(hal_pwm_start_t * start_config)
193 {
194  //Only 3 channels available in waveform decoder load mode
195  ASSERT(((start_config->decoder_load == HAL_PWM_LOAD_WAVE_FORM)
196  && (cxt.pin_num == HAL_PWM_MAX_PIN_NUM)) == false);
197 
198  PWM_ID->INTEN = 0;
199  PWM_ID->TASKS_STOP = 1;
200 
201  PWM_ID->ENABLE = (PWM_ENABLE_ENABLE_Enabled << PWM_ENABLE_ENABLE_Pos);
202  PWM_ID->COUNTERTOP = (start_config->countertop << PWM_COUNTERTOP_COUNTERTOP_Pos);
203  PWM_ID->LOOP = (start_config->loop << PWM_LOOP_CNT_Pos);
204  PWM_ID->DECODER = (start_config->decoder_load << PWM_DECODER_LOAD_Pos) |
205  (start_config->decoder_trigger << PWM_DECODER_MODE_Pos);
206  PWM_ID->SHORTS = start_config->shorts_mask;
207 
208  PWM_ID->SEQ[0].PTR = ((uint32_t) start_config->seq_config[0].seq_values
209  << PWM_SEQ_PTR_PTR_Pos);
210  PWM_ID->SEQ[0].CNT = (start_config->seq_config[0].len) << PWM_SEQ_CNT_CNT_Pos;
211  PWM_ID->SEQ[0].REFRESH = start_config->seq_config[0].repeats - 1;
212  PWM_ID->SEQ[0].ENDDELAY = start_config->seq_config[0].end_delay;
213 
214  PWM_ID->SEQ[1].PTR = ((uint32_t) start_config->seq_config[1].seq_values
215  << PWM_SEQ_PTR_PTR_Pos);
216  PWM_ID->SEQ[1].CNT = (start_config->seq_config[1].len) << PWM_SEQ_CNT_CNT_Pos;
217  PWM_ID->SEQ[1].REFRESH = start_config->seq_config[1].repeats - 1;
218  PWM_ID->SEQ[1].ENDDELAY = start_config->seq_config[1].end_delay;
219 
220  cxt.irq_mask = start_config->interrupt_masks;
221  cxt.handler = start_config->irq_handler;
222 
223  //No interrupts when this is zero
224  PWM_ID->INTEN = start_config->interrupt_masks;
225 
226  PWM_ID->TASKS_SEQSTART[0] = 1;
227 }
228 
229 void hal_pwm_stop(void)
230 {
231  PWM_ID->INTEN = 0;
232  PWM_ID->TASKS_STOP = 1;
233  PWM_ID->ENABLE = (PWM_ENABLE_ENABLE_Disabled << PWM_ENABLE_ENABLE_Pos);
234 }
uint32_t shorts_mask
Select the shortcuts that need to be enabled. OR the values in hal_pwm_short_mask_t to enable them.
Definition: hal_pwm.h:191
Interrupt on SEQSTARTED[0] event.
Definition: hal_pwm.h:147
hal_pwm_irq_mask_t
PWM interrupts.
Definition: hal_pwm.h:142
uint32_t repeats
Number of times a particular value should be played. Only for HAL_PWM_STEP_INTERNAL mode.
Definition: hal_pwm.h:133
uint32_t * pins
Pointer to array containing the pins number used by hal pwm.
Definition: hal_pwm.h:166
uint32_t interrupt_masks
Select the interrupts that need to be enabled OR the values in hal_pwm_irq_mask_t to enable them.
Definition: hal_pwm.h:194
uint16_t len
Number of 16-bit values in the buffer pointed by seq_values.
Definition: hal_pwm.h:130
uint32_t countertop
Maximum count of the counter. This and oper_freq decide the frequency of the resulting PWM waveform.
Definition: hal_pwm.h:186
hal_pwm_decoder_load_t decoder_load
Select the way in which the data pointed in seq_config is loaded into to the various channels.
Definition: hal_pwm.h:197
uint32_t irq_priority
IRQ priority with which the irq_handler in hal_pwm_start_t is called.
Definition: hal_pwm.h:176
void hal_pwm_start(hal_pwm_start_t *start_config)
Start the PWM generation based on the configuration provided.
Definition: hal_pwm.c:192
uint16_t * seq_values
Pointer to an array containing the PWM duty cycle values. This array present in the data RAM should p...
Definition: hal_pwm.h:128
Interrupt on PWMPERIODEND event.
Definition: hal_pwm.h:155
#define ASSERT(expression)
Macro for runtime assertion of an expression. If the expression is false the assert_nrf_callback func...
Definition: nrf_assert.h:48
hal_pwm_freq_t oper_freq
Select the operating frequency of the hal pwm module.
Definition: hal_pwm.h:172
Interrupt on SEQEND[1] event.
Definition: hal_pwm.h:153
uint32_t loop
The number of times the pattern of both seq_config must be repeated.
Definition: hal_pwm.h:188
#define HAL_PWM_MAX_PIN_NUM
Definition: hal_pwm.h:51
hal_pwm_dec_trigger_t decoder_trigger
Select when the next data is loaded to the PWM.
Definition: hal_pwm.h:199
bool * pin_idle_state
Pointer to array having the state of pins when PWM generation isn't on.
Definition: hal_pwm.h:168
uint32_t pin_num
Number of pins to be used by hal pwm. Maximum is HAL_PWM_MAX_PIN_NUM.
Definition: hal_pwm.h:170
void hal_pwm_stop(void)
Stop the PWM generation.
Definition: hal_pwm.c:229
Interrupt on SEQEND[0] event.
Definition: hal_pwm.h:151
Interrupt on SEQSTARTED[1] event.
Definition: hal_pwm.h:149
hal_pwm_mode_t oper_mode
Select the operating mode (Up or Up&Down) of the module's counter.
Definition: hal_pwm.h:174
Interrupt on STOPPED event.
Definition: hal_pwm.h:145
hal_pwm_sequence_config_t seq_config[2]
The two configurations for the sequences. If loop is zero only the first sequence is played once....
Definition: hal_pwm.h:203
Struct for initializing the hal pwm module.
Definition: hal_pwm.h:163
void hal_pwm_init(hal_pwm_init_t *init_config)
Initialize the HAL PWM module. Can be called again to change the initialization configuration.
Definition: hal_pwm.c:126
Interrupt on LOOPSDONE event.
Definition: hal_pwm.h:157
uint32_t end_delay
Additional number of cycles that the last PWM value is to be played after the end....
Definition: hal_pwm.h:136
Struct containing the configuration for starting the hal pwm module.
Definition: hal_pwm.h:182
1st three channels have their own 16 bit values, 4th one is the wave counter.
Definition: hal_pwm.h:104
void(* irq_handler)(hal_pwm_irq_mask_t irq_source)
the handler called based on the interrupt generated with the argument providing the source of the int...
Definition: hal_pwm.h:206