• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2022 ASR Microelectronics (Shanghai) Co., Ltd. All rights reserved.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include <stdio.h>
17 #include "duet_cm4.h"
18 #include "duet.h"
19 #include "duet_gpio.h"
20 
21 duet_gpio_cb_t g_duet_gpio_handler[DUET_GPIO_TOTAL_NUM];
22 // gpio pinmux function table
23 const uint32_t GPIO_PINMUX_FUN[DUET_GPIO_TOTAL_NUM] = {
24     0, 0, 0, 0, 1, 1, 0, 0,
25     0, 0, 2, 0, 0, 0, 4, 4,
26     0, 0, 0, 0, 0, 0, 0, 0
27 };
28 
GPIO_IRQHandler(void)29 void GPIO_IRQHandler(void)
30 {
31     // duet_intrpt_enter();
32     for (int i = 0; i < DUET_GPIO_TOTAL_NUM; i++) {
33         if (i < DUET_GPIO_NUM_PER_GROUP) {
34             // gpio group0 irq
35             if (GPIO_GROUP0->INTSTATUS & (0x0001 << i)) {
36                 // clear GPIO GROUP0 interrupt
37                 GPIO_GROUP0->INTSTATUS = (0x0001 << i);
38                 if (g_duet_gpio_handler[i].cb) {
39                     g_duet_gpio_handler[i].cb(g_duet_gpio_handler[i].arg);
40                 }
41             }
42         } else {
43             // gpio group1 irq
44             if (GPIO_GROUP1->INTSTATUS & (0x0001 << (i - DUET_GPIO_NUM_PER_GROUP))) {
45                 // clear GPIO GROUP1 interrupt
46                 GPIO_GROUP1->INTSTATUS = (0x0001 << (i - DUET_GPIO_NUM_PER_GROUP));
47                 if (g_duet_gpio_handler[i].cb) {
48                     g_duet_gpio_handler[i].cb(g_duet_gpio_handler[i].arg);
49                 }
50             }
51         }
52     }
53     // duet_intrpt_exit();
54 }
55 
56 /**
57  * Initialises a GPIO pin
58  *
59  * @note  Prepares a GPIO pin for use.
60  *
61  * @param[in]  gpio           the gpio pin which should be initialised
62  * @param[in]  configuration  A structure containing the required gpio configuration
63  *
64  * @return  0 : on success, EIO : if an error occurred with any step
65  */
duet_gpio_init(duet_gpio_dev_t * gpio)66 int32_t duet_gpio_init(duet_gpio_dev_t *gpio)
67 {
68     uint32_t reg_value;
69     if (NULL == gpio) {
70         return EIO;
71     }
72     // pinmux setting
73     if (gpio->port < 8) {
74         reg_value = REG_RD(PINMUX_CTRL_REG0) & (~(0x0000000F << (4 * gpio->port)));
75         REG_WR(PINMUX_CTRL_REG0, (reg_value | (GPIO_PINMUX_FUN[gpio->port] << (4 * gpio->port))));
76     } else if (gpio->port < 16) {
77         reg_value = REG_RD(PINMUX_CTRL_REG1) & (~(0x0000000F << (4 * (gpio->port - 8))));
78         REG_WR(PINMUX_CTRL_REG1, (reg_value | (GPIO_PINMUX_FUN[gpio->port] << (4 * (gpio->port - 8)))));
79     } else if (gpio->port < 24) {
80         reg_value = REG_RD(PINMUX_CTRL_REG2) & (~(0x0000000F << (4 * (gpio->port - 16))));
81         REG_WR(PINMUX_CTRL_REG2, (reg_value | (GPIO_PINMUX_FUN[gpio->port] << (4 * (gpio->port - 16)))));
82     }
83 #if (defined DUET_A0V1)
84     else if (gpio->port < 32) {
85         reg_value = REG_RD(PINMUX_CTRL_REG3) & (~(0x0000000F << (4 * (gpio->port - 24))));
86         REG_WR(PINMUX_CTRL_REG3, (reg_value | (GPIO_PINMUX_FUN[gpio->port] << (4 * (gpio->port - 24)))));
87     }
88 #endif
89     else {
90         return EIO;
91     }
92     if (gpio->port < DUET_GPIO_NUM_PER_GROUP) {
93         switch (gpio->config) {
94             case DUET_ANALOG_MODE:
95                 break;
96             case DUET_IRQ_MODE:
97             case DUET_INPUT_PULL_UP:
98                 if (GPIO_GROUP0->OUTENSET & (1 << gpio->port)) {
99                     GPIO_GROUP0->OUTENCLR = (1 << gpio->port);
100                 }
101                 reg_value = REG_RD(HW_CTRL_PE_PS);
102                 REG_WR(HW_CTRL_PE_PS, (reg_value & (~(1 << gpio->port))));
103                 reg_value = REG_RD(PAD_PS_REG);
104                 REG_WR(PAD_PS_REG, (reg_value | (1 << gpio->port)));
105                 reg_value = REG_RD(PAD_PE_REG);
106                 REG_WR(PAD_PE_REG, (reg_value | (1 << gpio->port)));
107                 break;
108             case DUET_INPUT_PULL_DOWN:
109                 if (GPIO_GROUP0->OUTENSET & (1 << gpio->port)) {
110                     GPIO_GROUP0->OUTENCLR = (1 << gpio->port);
111                 }
112                 reg_value = REG_RD(HW_CTRL_PE_PS);
113                 REG_WR(HW_CTRL_PE_PS, (reg_value & (~(1 << gpio->port))));
114                 reg_value = REG_RD(PAD_PS_REG);
115                 REG_WR(PAD_PS_REG, (reg_value & (~(1 << gpio->port))));
116                 reg_value = REG_RD(PAD_PE_REG);
117                 REG_WR(PAD_PE_REG, (reg_value | (1 << gpio->port)));
118                 break;
119             case DUET_INPUT_HIGH_IMPEDANCE:
120                 if (GPIO_GROUP0->OUTENSET & (1 << gpio->port)) {
121                     GPIO_GROUP0->OUTENCLR = (1 << gpio->port);
122                 }
123                 break;
124             case DUET_OUTPUT_PUSH_PULL:
125             case DUET_OUTPUT_OPEN_DRAIN_NO_PULL:
126             case DUET_OUTPUT_OPEN_DRAIN_PULL_UP:
127                 if (!(GPIO_GROUP0->OUTENSET & (1 << gpio->port))) {
128                     GPIO_GROUP0->OUTENSET = (1 << gpio->port);
129                 }
130                 break;
131             default:
132                 return EIO;
133                 // break;
134         }
135     } else { // if(gpio->port < 32/24)
136         switch (gpio->config) {
137             case DUET_ANALOG_MODE:
138                 break;
139             case DUET_IRQ_MODE:
140                 break;
141             case DUET_INPUT_PULL_UP:
142                 if (GPIO_GROUP1->OUTENSET & (1 << (gpio->port - DUET_GPIO_NUM_PER_GROUP))) {
143                     GPIO_GROUP1->OUTENCLR = (1 << (gpio->port - DUET_GPIO_NUM_PER_GROUP));
144                 }
145                 reg_value = REG_RD(HW_CTRL_PE_PS);
146                 REG_WR(HW_CTRL_PE_PS, (reg_value & (~(1 << gpio->port))));
147                 reg_value = REG_RD(PAD_PS_REG);
148                 REG_WR(PAD_PS_REG, (reg_value | (1 << gpio->port)));
149                 reg_value = REG_RD(PAD_PE_REG);
150                 REG_WR(PAD_PE_REG, (reg_value | (1 << gpio->port)));
151                 break;
152             case DUET_INPUT_PULL_DOWN:
153                 if (GPIO_GROUP1->OUTENSET & (1 << (gpio->port - DUET_GPIO_NUM_PER_GROUP))) {
154                     GPIO_GROUP1->OUTENCLR = (1 << (gpio->port - DUET_GPIO_NUM_PER_GROUP));
155                 }
156                 reg_value = REG_RD(HW_CTRL_PE_PS);
157                 REG_WR(HW_CTRL_PE_PS, (reg_value & (~(1 << gpio->port))));
158                 reg_value = REG_RD(PAD_PS_REG);
159                 REG_WR(PAD_PS_REG, (reg_value & (~(1 << gpio->port))));
160                 reg_value = REG_RD(PAD_PE_REG);
161                 REG_WR(PAD_PE_REG, (reg_value | (1 << gpio->port)));
162                 break;
163             case DUET_INPUT_HIGH_IMPEDANCE:
164                 if (GPIO_GROUP1->OUTENSET & (1 << (gpio->port - DUET_GPIO_NUM_PER_GROUP))) {
165                     GPIO_GROUP1->OUTENCLR = (1 << (gpio->port - DUET_GPIO_NUM_PER_GROUP));
166                 }
167                 break;
168             case DUET_OUTPUT_PUSH_PULL:
169             case DUET_OUTPUT_OPEN_DRAIN_NO_PULL:
170             case DUET_OUTPUT_OPEN_DRAIN_PULL_UP:
171                 if (!(GPIO_GROUP1->OUTENSET & (1 << (gpio->port - DUET_GPIO_NUM_PER_GROUP)))) {
172                     GPIO_GROUP1->OUTENSET = (1 << (gpio->port - DUET_GPIO_NUM_PER_GROUP));
173                 }
174                 break;
175             default:
176                 return EIO;
177                 // break;
178         }
179     }
180     return 0;
181 }
182 
183 /**
184  * Sets an output GPIO pin high
185  *
186  * @note  Using this function on a gpio pin which is set to input mode is undefined.
187  *
188  * @param[in]  gpio  the gpio pin which should be set high
189  *
190  * @return  0 : on success, EIO : if an error occurred with any step
191  */
duet_gpio_output_high(duet_gpio_dev_t * gpio)192 int32_t duet_gpio_output_high(duet_gpio_dev_t *gpio)
193 {
194     if (NULL == gpio) {
195         return EIO;
196     }
197     if (gpio->port < DUET_GPIO_NUM_PER_GROUP) {
198         GPIO_GROUP0->DATAOUT |= (1 << gpio->port);
199     } else if (gpio->port < DUET_GPIO_TOTAL_NUM) {
200         GPIO_GROUP1->DATAOUT |= (1 << (gpio->port - DUET_GPIO_NUM_PER_GROUP));
201     } else {
202         return EIO;
203     }
204     return 0;
205 }
206 
207 /**
208  * Sets an output GPIO pin low
209  *
210  * @note  Using this function on a gpio pin which is set to input mode is undefined.
211  *
212  * @param[in]  gpio  the gpio pin which should be set low
213  *
214  * @return  0 : on success, EIO : if an error occurred with any step
215  */
duet_gpio_output_low(duet_gpio_dev_t * gpio)216 int32_t duet_gpio_output_low(duet_gpio_dev_t *gpio)
217 {
218     if (NULL == gpio) {
219         return EIO;
220     }
221     if (gpio->port < DUET_GPIO_NUM_PER_GROUP) {
222         GPIO_GROUP0->DATAOUT &= ~(1 << gpio->port);
223     } else if (gpio->port < DUET_GPIO_TOTAL_NUM) {
224         GPIO_GROUP1->DATAOUT &= ~(1 << (gpio->port - DUET_GPIO_NUM_PER_GROUP));
225     } else {
226         return EIO;
227     }
228     return 0;
229 }
230 
231 /**
232  * Get the state of an output GPIO pin. Using this function on a
233  * gpio pin which is set to input mode will return an undefined value.
234  *
235  * @param[in]  gpio   the gpio pin which should be read
236  * @param[in]  value  gpio value
237  *
238  * @return  0 : on success, EIO : if an error occurred with any step
239  *
240  * note: defined by asr
241  */
duet_gpio_output_get(duet_gpio_dev_t * gpio,uint32_t * value)242 int32_t duet_gpio_output_get(duet_gpio_dev_t *gpio, uint32_t *value)
243 {
244     if (NULL == gpio) {
245         return EIO;
246     }
247     if (gpio->port < DUET_GPIO_NUM_PER_GROUP) {
248         *value = (GPIO_GROUP0->DATAOUT >> (gpio->port)) & 1;
249     } else if (gpio->port < DUET_GPIO_TOTAL_NUM) {
250         *value = (GPIO_GROUP1->DATAOUT >> ((gpio->port - DUET_GPIO_NUM_PER_GROUP))) & 1;
251     } else {
252         return EIO;
253     }
254     return 0;
255 }
256 
257 /**
258  * Trigger an output GPIO pin's output. Using this function on a
259  * gpio pin which is set to input mode is undefined.
260  *
261  * @param[in]  gpio  the gpio pin which should be set low
262  *
263  * @return  0 : on success, EIO : if an error occurred with any step
264  */
duet_gpio_output_toggle(duet_gpio_dev_t * gpio)265 int32_t duet_gpio_output_toggle(duet_gpio_dev_t *gpio)
266 {
267     uint32_t value;
268     if (NULL == gpio) {
269         return EIO;
270     }
271     if (0 == duet_gpio_output_get(gpio, &value)) {
272         if (value) {
273             return duet_gpio_output_low(gpio);
274         } else {
275             return duet_gpio_output_high(gpio);
276         }
277     } else {
278         return EIO;
279     }
280 }
281 
282 /**
283  * Get the state of an input GPIO pin. Using this function on a
284  * gpio pin which is set to output mode will return an undefined value.
285  *
286  * @param[in]  gpio   the gpio pin which should be read
287  * @param[in]  value  gpio value
288  *
289  * @return  0 : on success, EIO : if an error occurred with any step
290  */
duet_gpio_input_get(duet_gpio_dev_t * gpio,uint32_t * value)291 int32_t duet_gpio_input_get(duet_gpio_dev_t *gpio, uint32_t *value)
292 {
293     if (NULL == gpio) {
294         return EIO;
295     }
296     if (gpio->port < DUET_GPIO_NUM_PER_GROUP) {
297         *value = (GPIO_GROUP0->DATA >> gpio->port) & 1;
298     } else if (gpio->port < DUET_GPIO_TOTAL_NUM) {
299         *value = (GPIO_GROUP1->DATA >> (gpio->port - DUET_GPIO_NUM_PER_GROUP)) & 1;
300     } else {
301         return EIO;
302     }
303     return 0;
304 }
305 
306 /**
307  * Enables an interrupt trigger for an input GPIO pin.
308  * Using this function on a gpio pin which is set to
309  * output mode is undefined.
310  *
311  * @param[in]  gpio     the gpio pin which will provide the interrupt trigger
312  * @param[in]  trigger  the type of trigger (rising/falling edge)
313  * @param[in]  handler  a function pointer to the interrupt handler
314  * @param[in]  arg      an argument that will be passed to the interrupt handler
315  *
316  * @return  0 : on success, EIO : if an error occurred with any step
317  */
duet_gpio_enable_irq(duet_gpio_dev_t * gpio,duet_gpio_irq_trigger_t trigger,duet_gpio_irq_handler_t handler,void * arg)318 int32_t duet_gpio_enable_irq(duet_gpio_dev_t *gpio, duet_gpio_irq_trigger_t trigger,
319                              duet_gpio_irq_handler_t handler, void *arg)
320 {
321     if (NULL == gpio) {
322         return EIO;
323     }
324     g_duet_gpio_handler[gpio->port].cb = handler;
325     g_duet_gpio_handler[gpio->port].arg = arg;
326     if (gpio->port < DUET_GPIO_NUM_PER_GROUP) {
327         switch (trigger) {
328             case DUET_IRQ_TRIGGER_RISING_EDGE:
329                 GPIO_GROUP0->INTTYPESET = (1 << gpio->port); // edge or level trig
330                 GPIO_GROUP0->INTPOLSET = (1 << gpio->port); // trig polarity
331                 break;
332             case DUET_IRQ_TRIGGER_FALLING_EDGE:
333                 GPIO_GROUP0->INTTYPESET = (1 << gpio->port);
334                 GPIO_GROUP0->INTPOLCLR = (1 << gpio->port);
335                 break;
336             case DUET_IRQ_TRIGGER_BOTH_EDGES:
337             default:
338                 return EIO;
339         }
340         GPIO_GROUP0->INTENSET = (1 << gpio->port); // int enable
341     } else if (gpio->port < DUET_GPIO_TOTAL_NUM) {
342         switch (trigger) {
343             case DUET_IRQ_TRIGGER_RISING_EDGE:
344                 GPIO_GROUP1->INTTYPESET = (1 << (gpio->port - DUET_GPIO_NUM_PER_GROUP));
345                 GPIO_GROUP1->INTPOLSET = (1 << (gpio->port - DUET_GPIO_NUM_PER_GROUP));
346                 break;
347             case DUET_IRQ_TRIGGER_FALLING_EDGE:
348                 GPIO_GROUP1->INTTYPESET = (1 << (gpio->port - DUET_GPIO_NUM_PER_GROUP));
349                 GPIO_GROUP1->INTPOLCLR = (1 << (gpio->port - DUET_GPIO_NUM_PER_GROUP));
350                 break;
351             case DUET_IRQ_TRIGGER_BOTH_EDGES:
352             default:
353                 return EIO;
354         }
355         GPIO_GROUP1->INTENSET = (1 << (gpio->port - DUET_GPIO_NUM_PER_GROUP));
356     } else {
357         return EIO;
358     }
359     NVIC_EnableIRQ(GPIO_IRQn); // 0x10
360     return 0;
361 }
362 
363 /**
364  * Disables an interrupt trigger for an input GPIO pin.
365  * Using this function on a gpio pin which has not been set up
366  * using @ref duet_gpio_input_irq_enable is undefined.
367  *
368  * @param[in]  gpio  the gpio pin which provided the interrupt trigger
369  *
370  * @return  0 : on success, EIO : if an error occurred with any step
371  */
duet_gpio_disable_irq(duet_gpio_dev_t * gpio)372 int32_t duet_gpio_disable_irq(duet_gpio_dev_t *gpio)
373 {
374     if (NULL == gpio) {
375         return EIO;
376     }
377     g_duet_gpio_handler[gpio->port].cb = NULL;
378     g_duet_gpio_handler[gpio->port].arg = NULL;
379     // NVIC_DisableIRQ(GPIO_IRQn); // common use
380     if (gpio->port < DUET_GPIO_NUM_PER_GROUP) {
381         GPIO_GROUP0->INTENCLR = (1 << gpio->port);
382         GPIO_GROUP0->INTTYPECLR = (1 << gpio->port);
383         GPIO_GROUP0->INTPOLCLR = (1 << gpio->port);
384     } else if (gpio->port < DUET_GPIO_TOTAL_NUM) {
385         GPIO_GROUP1->INTTYPECLR = (1 << (gpio->port - DUET_GPIO_NUM_PER_GROUP));
386         GPIO_GROUP1->INTPOLCLR = (1 << (gpio->port - DUET_GPIO_NUM_PER_GROUP));
387         GPIO_GROUP1->INTENCLR = (1 << (gpio->port - DUET_GPIO_NUM_PER_GROUP));
388     } else {
389         return EIO;
390     }
391     return 0;
392 }
393 
394 /**
395  * Disables an interrupt trigger for an input GPIO pin.
396  * Using this function on a gpio pin which has not been set up
397  * using @ref duet_gpio_input_irq_enable is undefined.
398  *
399  * @param[in]  gpio  the gpio pin which provided the interrupt trigger
400  *
401  * @return  0 : on success, EIO : if an error occurred with any step
402  */
duet_gpio_clear_irq(duet_gpio_dev_t * gpio)403 int32_t duet_gpio_clear_irq(duet_gpio_dev_t *gpio)
404 {
405     if (NULL == gpio) {
406         return EIO;
407     }
408 
409     if (gpio->port < DUET_GPIO_NUM_PER_GROUP) {
410         // GPIO interrupt status
411         if (GPIO_GROUP0->INTSTATUS & (1 << gpio->port)) {
412             // clear GPIO interrupt status
413             GPIO_GROUP0->INTSTATUS = (1 << gpio->port);
414         }
415     } else if (gpio->port < DUET_GPIO_TOTAL_NUM) {
416         if (GPIO_GROUP1->INTSTATUS & (1 << (gpio->port - DUET_GPIO_NUM_PER_GROUP))) {
417             GPIO_GROUP1->INTSTATUS = (1 << (gpio->port - DUET_GPIO_NUM_PER_GROUP));
418         }
419     } else {
420         return EIO;
421     }
422 
423     return 0;
424 }
425 
426 /**
427  * Set a GPIO pin in default state.
428  *
429  * @param[in]  gpio  the gpio pin which should be deinitialised
430  *
431  * @return  0 : on success, EIO : if an error occurred with any step
432  */
duet_gpio_finalize(duet_gpio_dev_t * gpio)433 int32_t duet_gpio_finalize(duet_gpio_dev_t *gpio)
434 {
435     if (NULL == gpio) {
436         return EIO;
437     }
438     if (gpio->port < DUET_GPIO_NUM_PER_GROUP) {
439         if (GPIO_GROUP0->OUTENSET & (1 << gpio->port)) {
440             GPIO_GROUP0->OUTENCLR = (1 << gpio->port);
441         }
442     } else if (gpio->port < DUET_GPIO_TOTAL_NUM) {
443         if (GPIO_GROUP1->OUTENSET & (1 << (gpio->port - DUET_GPIO_NUM_PER_GROUP))) {
444             GPIO_GROUP1->OUTENCLR = (1 << (gpio->port - DUET_GPIO_NUM_PER_GROUP));
445         }
446     } else {
447         return EIO;
448     }
449     duet_gpio_disable_irq(gpio);
450     duet_gpio_clear_irq(gpio);
451     return 0;
452 }
453