Fahrplan: Finale Version.
[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 Sets the interrupt sense, event, etc.
233
234 @param[in] portNum
235 The port number (0..3)
236 @param[in] bitPos
237 The bit position (0..31)
238 @param[in] sense
239 Whether the interrupt should be configured as edge or level
240 sensitive.
241 @param[in] edge
242 Whether one edge or both trigger an interrupt.
243 @param[in] event
244 Whether the rising or the falling edge (high or low)
245 should be used to trigger the interrupt.
246
247 @section Example
248
249 @code
250 // Initialise gpio
251 gpioInit();
252 // Set GPIO1.8 to input
253 gpioSetDir(1, 8, gpioDirection_Input);
254 // Disable the internal pullup/down resistor on P1.8
255 gpioSetPullup (&IOCON_PIO1_8, gpioPullupMode_Inactive);
256 // Setup an interrupt on GPIO1.8
257 gpioSetInterrupt(1, // Port
258 8, // Pin
259 gpioInterruptSense_Edge, // Edge/Level Sensitive
260 gpioInterruptEdge_Single, // Single/Double Edge
261 gpioInterruptEvent_ActiveHigh); // Rising/Falling
262 // Enable the interrupt
263 gpioIntEnable(1, 8);
264 @endcode
265 */
266 /**************************************************************************/
267 void gpioSetInterrupt (uint32_t portNum, uint32_t bitPos, gpioInterruptSense_t sense, gpioInterruptEdge_t edge, gpioInterruptEvent_t event)
268 {
269 if (!_gpioInitialised) gpioInit();
270
271 // Get the appropriate register (handled this way to optimise code size)
272 REG32 *gpiois = &GPIO_GPIO0IS; // Interrupt sense (edge or level sensitive)
273 REG32 *gpioibe = &GPIO_GPIO0IBE; // Interrupt both edges (0 = int controlled by GPIOIEV, 1 = both edges trigger interrupt)
274 REG32 *gpioiev = &GPIO_GPIO0IEV; // 0 = falling edge or low, 1 = rising edge or high (depending on GPIOIS)
275 switch (portNum)
276 {
277 case 0:
278 gpiois = &GPIO_GPIO0IS;
279 gpioibe = &GPIO_GPIO0IBE;
280 gpioiev = &GPIO_GPIO0IEV;
281 break;
282 case 1:
283 gpiois = &GPIO_GPIO1IS;
284 gpioibe = &GPIO_GPIO1IBE;
285 gpioiev = &GPIO_GPIO1IEV;
286 break;
287 case 2:
288 gpiois = &GPIO_GPIO2IS;
289 gpioibe = &GPIO_GPIO2IBE;
290 gpioiev = &GPIO_GPIO2IEV;
291 break;
292 case 3:
293 gpiois = &GPIO_GPIO3IS;
294 gpioibe = &GPIO_GPIO3IBE;
295 gpioiev = &GPIO_GPIO3IEV;
296 break;
297 }
298
299 if (sense == gpioInterruptSense_Edge)
300 {
301 *gpiois &= ~(0x1<<bitPos);
302 edge == gpioInterruptEdge_Single ? (*gpioibe &= ~(0x1<<bitPos)) : (*gpioibe |= (0x1<<bitPos));
303 }
304 else
305 {
306 *gpiois |= (0x1<<bitPos);
307 }
308
309 event == gpioInterruptEvent_ActiveLow ? (*gpioiev &= ~(0x1<<bitPos)) : (*gpioiev |= (0x1<<bitPos));
310
311 return;
312 }
313
314 /**************************************************************************/
315 /*!
316 @brief Enables the interrupt mask for a specific port pin
317
318 @param[in] portNum
319 The port number (0..3)
320 @param[in] bitPos
321 The bit position (0..31)
322 */
323 /**************************************************************************/
324 void gpioIntEnable (uint32_t portNum, uint32_t bitPos)
325 {
326 if (!_gpioInitialised) gpioInit();
327
328 switch (portNum)
329 {
330 case 0:
331 GPIO_GPIO0IE |= (0x1<<bitPos);
332 break;
333 case 1:
334 GPIO_GPIO1IE |= (0x1<<bitPos);
335 break;
336 case 2:
337 GPIO_GPIO2IE |= (0x1<<bitPos);
338 break;
339 case 3:
340 GPIO_GPIO3IE |= (0x1<<bitPos);
341 break;
342 default:
343 break;
344 }
345 return;
346 }
347
348 /**************************************************************************/
349 /*!
350 @brief Disables the interrupt mask for a specific port pin
351
352 @param[in] portNum
353 The port number (0..3)
354 @param[in] bitPos
355 The bit position (0..31)
356 */
357 /**************************************************************************/
358 void gpioIntDisable (uint32_t portNum, uint32_t bitPos)
359 {
360 if (!_gpioInitialised) gpioInit();
361
362 switch (portNum)
363 {
364 case 0:
365 GPIO_GPIO0IE &= ~(0x1<<bitPos);
366 break;
367 case 1:
368 GPIO_GPIO1IE &= ~(0x1<<bitPos);
369 break;
370 case 2:
371 GPIO_GPIO2IE &= ~(0x1<<bitPos);
372 break;
373 case 3:
374 GPIO_GPIO3IE &= ~(0x1<<bitPos);
375 break;
376 default:
377 break;
378 }
379 return;
380 }
381
382 /**************************************************************************/
383 /*!
384 @brief Gets the interrupt status for a specific port pin
385
386 @param[in] portNum
387 The port number (0..3)
388 @param[in] bitPos
389 The bit position (0..31)
390
391 @return The interrupt status for the specified port pin (0..1)
392 */
393 /**************************************************************************/
394 uint32_t gpioIntStatus (uint32_t portNum, uint32_t bitPos)
395 {
396 if (!_gpioInitialised) gpioInit();
397
398 uint32_t regVal = 0;
399
400 switch (portNum)
401 {
402 case 0:
403 if (GPIO_GPIO0MIS & (0x1<<bitPos))
404 {
405 regVal = 1;
406 }
407 break;
408 case 1:
409 if (GPIO_GPIO1MIS & (0x1<<bitPos))
410 {
411 regVal = 1;
412 }
413 break;
414 case 2:
415 if (GPIO_GPIO2MIS & (0x1<<bitPos))
416 {
417 regVal = 1;
418 }
419 break;
420 case 3:
421 if (GPIO_GPIO3MIS & (0x1<<bitPos))
422 {
423 regVal = 1;
424 }
425 break;
426 default:
427 break;
428 }
429 return ( regVal );
430 }
431
432 /**************************************************************************/
433 /*!
434 @brief Clears the interrupt for a port pin
435
436 @param[in] portNum
437 The port number (0..3)
438 @param[in] bitPos
439 The bit position (0..31)
440 */
441 /**************************************************************************/
442 void gpioIntClear (uint32_t portNum, uint32_t bitPos)
443 {
444 if (!_gpioInitialised) gpioInit();
445
446 switch (portNum)
447 {
448 case 0:
449 GPIO_GPIO0IC |= (0x1<<bitPos);
450 break;
451 case 1:
452 GPIO_GPIO1IC |= (0x1<<bitPos);
453 break;
454 case 2:
455 GPIO_GPIO2IC |= (0x1<<bitPos);
456 break;
457 case 3:
458 GPIO_GPIO3IC |= (0x1<<bitPos);
459 break;
460 default:
461 break;
462 }
463 return;
464 }
465
466 /**************************************************************************/
467 /*!
468 @brief Configures the internal pullup/down resistor for GPIO pins
469 (only relevant for pins configured as inputs)
470
471 @param[in] ioconReg
472 A pointer to the IOCON registry value corresponding to
473 the pin you wish to change (for example: &IOCON_PIO2_0
474 for GPIO pin 2.0).
475 @param[in] mode
476 The 'mode' that the pin should be set to, which must be
477 correspond to a value defined in gpioPullupMode_t
478
479 @warning By default, all GPIO pins have the internal pull-up
480 resistor enabled. This may cause unusual behaviour if
481 care isn't taken to set the internal resistor to an
482 appropriate state.
483
484 @section Example
485
486 @code
487 // Initialise gpio
488 gpioInit();
489 // Set GPIO1.8 to input
490 gpioSetDir(1, 8, gpioDirection_Input);
491 // Disable the internal pullup/down resistor on P1.8
492 gpioSetPullup(&IOCON_PIO1_8, gpioPullupMode_Inactive);
493 @endcode
494 */
495 /**************************************************************************/
496 void gpioSetPullup (volatile uint32_t *ioconReg, gpioPullupMode_t mode)
497 {
498 if (!_gpioInitialised) gpioInit();
499
500 // ToDo: Disable interrupts while we are doing this?
501
502 *ioconReg &= ~(IOCON_COMMON_MODE_MASK);
503 *ioconReg |= mode;
504
505 // ToDo: Re-enable interrupts?
506 };
This page took 0.075896 seconds and 5 git commands to generate.