Speed tweek for gpioSetValue
[hackover2013-badge-firmware.git] / core / gpio / gpio.c
1 /**************************************************************************/
2 /*!
3 @file gpio.c
4 @author K. Townsend (microBuilder.eu)
5 @date 22 March 2010
6 @version 0.10
7
8 @section DESCRIPTION
9
10 Controls the general purpose digital IO.
11
12 @section LICENSE
13
14 Software License Agreement (BSD License)
15
16 Copyright (c) 2010, microBuilder SARL
17 All rights reserved.
18
19 Redistribution and use in source and binary forms, with or without
20 modification, are permitted provided that the following conditions are met:
21 1. Redistributions of source code must retain the above copyright
22 notice, this list of conditions and the following disclaimer.
23 2. Redistributions in binary form must reproduce the above copyright
24 notice, this list of conditions and the following disclaimer in the
25 documentation and/or other materials provided with the distribution.
26 3. Neither the name of the copyright holders nor the
27 names of its contributors may be used to endorse or promote products
28 derived from this software without specific prior written permission.
29
30 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY
31 EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
32 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
33 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY
34 DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
35 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
36 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
37 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
38 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
39 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
40 */
41 /**************************************************************************/
42
43 #include "gpio.h"
44
45 #ifdef CFG_CHIBI
46 #include "drivers/rf/chibi/chb_drvr.h"
47 volatile uint32_t chibi_counter = 0;
48 #endif
49
50 #ifdef CFG_ALTRESET
51 #include "core/cpu/cpu.h"
52 #endif
53
54 static bool _gpioInitialised = false;
55
56 /**************************************************************************/
57 /*!
58 @brief IRQ Handler for GPIO port 0 (currently checks pin 0.1)
59
60 @note By default, this IRQ handler is probably disabled in
61 projectconfig.h (see GPIO_ENABLE_IRQ0), but you can use
62 the code below as a model to implement this interrupt
63 handler in an appropriate place in your project.
64 */
65 /**************************************************************************/
66 #if defined GPIO_ENABLE_IRQ0
67 void PIOINT0_IRQHandler(void)
68 {
69 uint32_t regVal;
70
71 regVal = gpioIntStatus(0, 1);
72 if (regVal)
73 {
74 gpioIntClear(0, 1);
75 }
76 return;
77 }
78 #endif
79
80 /**************************************************************************/
81 /*!
82 @brief IRQ Handler for GPIO port 1 (currently checks pin 1.1)
83 */
84 /**************************************************************************/
85 #if defined GPIO_ENABLE_IRQ1
86 void PIOINT1_IRQHandler(void)
87 {
88 uint32_t regVal;
89
90 #if defined CFG_ALTRESET && CFG_ALTRESET_PORT == 1
91 regVal = gpioIntStatus(CFG_ALTRESET_PORT, CFG_ALTRESET_PIN);
92 if (regVal)
93 {
94 // Cause a reset and wait
95 cpuReset();
96 }
97 #endif
98
99 #ifdef CFG_CHIBI
100 // Check for interrupt on 1.8
101 regVal = gpioIntStatus(1, 8);
102 if (regVal)
103 {
104 chibi_counter++;
105 chb_ISR_Handler();
106 gpioIntClear(1, 8);
107 }
108 #else
109 regVal = gpioIntStatus(1, 1);
110 if ( regVal )
111 {
112 gpioIntClear(1, 1);
113 }
114 #endif
115
116 return;
117 }
118 #endif
119
120 /**************************************************************************/
121 /*!
122 @brief IRQ Handler for GPIO port 2 (currently checks pin 2.1)
123
124 @note By default, this IRQ handler is probably disabled in
125 projectconfig.h (see GPIO_ENABLE_IRQ2), but you can use
126 the code below as a model to implement this interrupt
127 handler in an appropriate place in your project.
128 */
129 /**************************************************************************/
130 #if defined GPIO_ENABLE_IRQ2
131 void PIOINT2_IRQHandler(void)
132 {
133 uint32_t regVal;
134
135 regVal = gpioIntStatus(2, 1);
136 if ( regVal )
137 {
138 gpioIntClear(2, 1);
139 }
140 return;
141 }
142 #endif
143
144 /**************************************************************************/
145 /*!
146 @brief IRQ Handler for GPIO port 3 (currently checks pin 3.1)
147
148 @note By default, this IRQ handler is probably disabled in
149 projectconfig.h (see GPIO_ENABLE_IRQ3), but you can use
150 the code below as a model to implement this interrupt
151 handler in an appropriate place in your project.
152 */
153 /**************************************************************************/
154 #if defined GPIO_ENABLE_IRQ3
155 void PIOINT3_IRQHandler(void)
156 {
157 uint32_t regVal;
158
159 regVal = gpioIntStatus(3, 1);
160 if ( regVal )
161 {
162 gpioIntClear(3, 1);
163 }
164 return;
165 }
166 #endif
167
168 /**************************************************************************/
169 /*!
170 @brief Initialises GPIO and enables the GPIO interrupt
171 handler for all GPIO ports.
172 */
173 /**************************************************************************/
174 void gpioInit (void)
175 {
176 /* Enable AHB clock to the GPIO domain. */
177 SCB_SYSAHBCLKCTRL |= (SCB_SYSAHBCLKCTRL_GPIO);
178
179 /* Set up NVIC when I/O pins are configured as external interrupts. */
180 NVIC_EnableIRQ(EINT0_IRQn);
181 NVIC_EnableIRQ(EINT1_IRQn);
182 NVIC_EnableIRQ(EINT2_IRQn);
183 NVIC_EnableIRQ(EINT3_IRQn);
184
185 /* Set initialisation flag */
186 _gpioInitialised = true;
187
188 return;
189 }
190
191 /**************************************************************************/
192 /*!
193 @brief Sets the direction (input/output) for a specific port pin
194
195 @param[in] portNum
196 The port number (0..3)
197 @param[in] bitPos
198 The bit position (0..11)
199 @param[in] dir
200 The pin direction (gpioDirection_Input or
201 gpioDirection_Output)
202 */
203 /**************************************************************************/
204 void gpioSetDir (uint32_t portNum, uint32_t bitPos, gpioDirection_t dir)
205 {
206 if (!_gpioInitialised) gpioInit();
207
208 // Get the appropriate register (handled this way to optimise code size)
209 REG32 *gpiodir = &GPIO_GPIO0DIR;
210 switch (portNum)
211 {
212 case 0:
213 gpiodir = &GPIO_GPIO0DIR;
214 break;
215 case 1:
216 gpiodir = &GPIO_GPIO1DIR;
217 break;
218 case 2:
219 gpiodir = &GPIO_GPIO2DIR;
220 break;
221 case 3:
222 gpiodir = &GPIO_GPIO3DIR;
223 break;
224 }
225
226 // Toggle dir
227 dir == gpioDirection_Output ? (*gpiodir |= (1 << bitPos)) : (*gpiodir &= ~(1 << bitPos));
228 }
229
230 /**************************************************************************/
231 /*!
232 @brief Gets the value for a specific port pin
233
234 @param[in] portNum
235 The port number (0..3)
236 @param[in] bitPos
237 The bit position (0..31)
238
239 @return The current value for the specified port pin (0..1)
240 */
241 /**************************************************************************/
242 uint32_t gpioGetValue (uint32_t portNum, uint32_t bitPos)
243 {
244 if (!_gpioInitialised) gpioInit();
245
246 uint32_t value = 0;
247
248 switch (portNum)
249 {
250 case 0:
251 value = (GPIO_GPIO0DATA & (1 << bitPos)) ? 1 : 0;
252 break;
253 case 1:
254 value = (GPIO_GPIO1DATA & (1 << bitPos)) ? 1 : 0;
255 break;
256 case 2:
257 value = (GPIO_GPIO2DATA & (1 << bitPos)) ? 1 : 0;
258 break;
259 case 3:
260 value = (GPIO_GPIO3DATA & (1 << bitPos)) ? 1 : 0;
261 break;
262 default:
263 break;
264 }
265
266 return value;
267 }
268
269 /**************************************************************************/
270 /*!
271 @brief Sets the value for a specific port pin (only relevant when a
272 pin is configured as output).
273
274 @param[in] portNum
275 The port number (0..3)
276 @param[in] bitPos
277 The bit position (0..31)
278 @param[in] bitValue
279 The value to set for the specified bit (0..1). 0 will set
280 the pin low and 1 will set the pin high.
281 */
282 /**************************************************************************/
283 void gpioSetValue (uint32_t portNum, uint32_t bitPos, uint32_t bitVal)
284 {
285 if (!_gpioInitialised) gpioInit();
286
287 // // Get the appropriate register (handled this way to optimise code size)
288 // REG32 *gpiodata = &GPIO_GPIO0DATA;
289 // switch (portNum)
290 // {
291 // case 0:
292 // gpiodata = &GPIO_GPIO0DATA;
293 // break;
294 // case 1:
295 // gpiodata = &GPIO_GPIO1DATA;
296 // break;
297 // case 2:
298 // gpiodata = &GPIO_GPIO2DATA;
299 // break;
300 // case 3:
301 // gpiodata = &GPIO_GPIO3DATA;
302 // break;
303 // }
304 //
305 // // Toggle value
306 // bitVal == 1 ? (*gpiodata |= (1 << bitPos)) : (*gpiodata &= ~(1 << bitPos));
307
308 // Take advantage of the fact the GPIO registers are bit-banded
309 (*(pREG32 ((GPIO_GPIO0_BASE + (portNum << 16)) + ((1 << bitPos) << 2)))) = bitVal ? 0xFFF : 0;
310 }
311
312 /**************************************************************************/
313 /*!
314 @brief Sets the interrupt sense, event, etc.
315
316 @param[in] portNum
317 The port number (0..3)
318 @param[in] bitPos
319 The bit position (0..31)
320 @param[in] sense
321 Whether the interrupt should be configured as edge or level
322 sensitive.
323 @param[in] edge
324 Whether one edge or both trigger an interrupt.
325 @param[in] event
326 Whether the rising or the falling edge (high or low)
327 should be used to trigger the interrupt.
328
329 @section Example
330
331 @code
332 // Initialise gpio
333 gpioInit();
334 // Set GPIO1.8 to input
335 gpioSetDir(1, 8, gpioDirection_Input);
336 // Disable the internal pullup/down resistor on P1.8
337 gpioSetPullup (&IOCON_PIO1_8, gpioPullupMode_Inactive);
338 // Setup an interrupt on GPIO1.8
339 gpioSetInterrupt(1, // Port
340 8, // Pin
341 gpioInterruptSense_Edge, // Edge/Level Sensitive
342 gpioInterruptEdge_Single, // Single/Double Edge
343 gpioInterruptEvent_ActiveHigh); // Rising/Falling
344 // Enable the interrupt
345 gpioIntEnable(1, 8);
346 @endcode
347 */
348 /**************************************************************************/
349 void gpioSetInterrupt (uint32_t portNum, uint32_t bitPos, gpioInterruptSense_t sense, gpioInterruptEdge_t edge, gpioInterruptEvent_t event)
350 {
351 if (!_gpioInitialised) gpioInit();
352
353 // Get the appropriate register (handled this way to optimise code size)
354 REG32 *gpiois = &GPIO_GPIO0IS; // Interrupt sense (edge or level sensitive)
355 REG32 *gpioibe = &GPIO_GPIO0IBE; // Interrupt both edges (0 = int controlled by GPIOIEV, 1 = both edges trigger interrupt)
356 REG32 *gpioiev = &GPIO_GPIO0IEV; // 0 = falling edge or low, 1 = rising edge or high (depending on GPIOIS)
357 switch (portNum)
358 {
359 case 0:
360 gpiois = &GPIO_GPIO0IS;
361 gpioibe = &GPIO_GPIO0IBE;
362 gpioiev = &GPIO_GPIO0IEV;
363 break;
364 case 1:
365 gpiois = &GPIO_GPIO1IS;
366 gpioibe = &GPIO_GPIO1IBE;
367 gpioiev = &GPIO_GPIO1IEV;
368 break;
369 case 2:
370 gpiois = &GPIO_GPIO2IS;
371 gpioibe = &GPIO_GPIO2IBE;
372 gpioiev = &GPIO_GPIO2IEV;
373 break;
374 case 3:
375 gpiois = &GPIO_GPIO3IS;
376 gpioibe = &GPIO_GPIO3IBE;
377 gpioiev = &GPIO_GPIO3IEV;
378 break;
379 }
380
381 if (sense == gpioInterruptSense_Edge)
382 {
383 *gpiois &= ~(0x1<<bitPos);
384 edge == gpioInterruptEdge_Single ? (*gpioibe &= ~(0x1<<bitPos)) : (*gpioibe |= (0x1<<bitPos));
385 }
386 else
387 {
388 *gpiois |= (0x1<<bitPos);
389 }
390
391 event == gpioInterruptEvent_ActiveHigh ? (*gpioiev &= ~(0x1<<bitPos)) : (*gpioiev |= (0x1<<bitPos));
392
393 return;
394 }
395
396 /**************************************************************************/
397 /*!
398 @brief Enables the interrupt mask for a specific port pin
399
400 @param[in] portNum
401 The port number (0..3)
402 @param[in] bitPos
403 The bit position (0..31)
404 */
405 /**************************************************************************/
406 void gpioIntEnable (uint32_t portNum, uint32_t bitPos)
407 {
408 if (!_gpioInitialised) gpioInit();
409
410 switch (portNum)
411 {
412 case 0:
413 GPIO_GPIO0IE |= (0x1<<bitPos);
414 break;
415 case 1:
416 GPIO_GPIO1IE |= (0x1<<bitPos);
417 break;
418 case 2:
419 GPIO_GPIO2IE |= (0x1<<bitPos);
420 break;
421 case 3:
422 GPIO_GPIO3IE |= (0x1<<bitPos);
423 break;
424 default:
425 break;
426 }
427 return;
428 }
429
430 /**************************************************************************/
431 /*!
432 @brief Disables the interrupt mask for a specific port pin
433
434 @param[in] portNum
435 The port number (0..3)
436 @param[in] bitPos
437 The bit position (0..31)
438 */
439 /**************************************************************************/
440 void gpioIntDisable (uint32_t portNum, uint32_t bitPos)
441 {
442 if (!_gpioInitialised) gpioInit();
443
444 switch (portNum)
445 {
446 case 0:
447 GPIO_GPIO0IE &= ~(0x1<<bitPos);
448 break;
449 case 1:
450 GPIO_GPIO1IE &= ~(0x1<<bitPos);
451 break;
452 case 2:
453 GPIO_GPIO2IE &= ~(0x1<<bitPos);
454 break;
455 case 3:
456 GPIO_GPIO3IE &= ~(0x1<<bitPos);
457 break;
458 default:
459 break;
460 }
461 return;
462 }
463
464 /**************************************************************************/
465 /*!
466 @brief Gets the interrupt status for a specific port pin
467
468 @param[in] portNum
469 The port number (0..3)
470 @param[in] bitPos
471 The bit position (0..31)
472
473 @return The interrupt status for the specified port pin (0..1)
474 */
475 /**************************************************************************/
476 uint32_t gpioIntStatus (uint32_t portNum, uint32_t bitPos)
477 {
478 if (!_gpioInitialised) gpioInit();
479
480 uint32_t regVal = 0;
481
482 switch (portNum)
483 {
484 case 0:
485 if (GPIO_GPIO0MIS & (0x1<<bitPos))
486 {
487 regVal = 1;
488 }
489 break;
490 case 1:
491 if (GPIO_GPIO1MIS & (0x1<<bitPos))
492 {
493 regVal = 1;
494 }
495 break;
496 case 2:
497 if (GPIO_GPIO2MIS & (0x1<<bitPos))
498 {
499 regVal = 1;
500 }
501 break;
502 case 3:
503 if (GPIO_GPIO3MIS & (0x1<<bitPos))
504 {
505 regVal = 1;
506 }
507 break;
508 default:
509 break;
510 }
511 return ( regVal );
512 }
513
514 /**************************************************************************/
515 /*!
516 @brief Clears the interrupt for a port pin
517
518 @param[in] portNum
519 The port number (0..3)
520 @param[in] bitPos
521 The bit position (0..31)
522 */
523 /**************************************************************************/
524 void gpioIntClear (uint32_t portNum, uint32_t bitPos)
525 {
526 if (!_gpioInitialised) gpioInit();
527
528 switch (portNum)
529 {
530 case 0:
531 GPIO_GPIO0IC |= (0x1<<bitPos);
532 break;
533 case 1:
534 GPIO_GPIO1IC |= (0x1<<bitPos);
535 break;
536 case 2:
537 GPIO_GPIO2IC |= (0x1<<bitPos);
538 break;
539 case 3:
540 GPIO_GPIO3IC |= (0x1<<bitPos);
541 break;
542 default:
543 break;
544 }
545 return;
546 }
547
548 /**************************************************************************/
549 /*!
550 @brief Configures the internal pullup/down resistor for GPIO pins
551 (only relevant for pins configured as inputs)
552
553 @param[in] ioconReg
554 A pointer to the IOCON registry value corresponding to
555 the pin you wish to change (for example: &IOCON_PIO2_0
556 for GPIO pin 2.0).
557 @param[in] mode
558 The 'mode' that the pin should be set to, which must be
559 correspond to a value defined in gpioPullupMode_t
560
561 @warning By default, all GPIO pins have the internal pull-up
562 resistor enabled. This may cause unusual behaviour if
563 care isn't taken to set the internal resistor to an
564 appropriate state.
565
566 @section Example
567
568 @code
569 // Initialise gpio
570 gpioInit();
571 // Set GPIO1.8 to input
572 gpioSetDir(1, 8, gpioDirection_Input);
573 // Disable the internal pullup/down resistor on P1.8
574 gpioSetPullup(&IOCON_PIO1_8, gpioPullupMode_Inactive);
575 @endcode
576 */
577 /**************************************************************************/
578 void gpioSetPullup (volatile uint32_t *ioconReg, gpioPullupMode_t mode)
579 {
580 if (!_gpioInitialised) gpioInit();
581
582 // ToDo: Disable interrupts while we are doing this?
583
584 *ioconReg &= ~(IOCON_COMMON_MODE_MASK);
585 *ioconReg |= mode;
586
587 // ToDo: Re-enable interrupts?
588 };
This page took 0.073512 seconds and 5 git commands to generate.