1 | // Purpose of this example:
|
2 | // Explanation of GPIO and INTC modules on AVR32 UC3 chips.
|
3 |
|
4 | // Hardware requirements:
|
5 | // EVK1101 & JTAGICE mkII.
|
6 |
|
7 | // Application description:
|
8 | // LED0 always blinks steadily.
|
9 | // Press on PB2 and LED1 is turned on. Release PB2 and LED1 is turned off.
|
10 | // Press on PB3 and LED2 is turned on. Release PB3 and LED2 is turned off.
|
11 |
|
12 |
|
13 | //_____ I N C L U D E S ___________________________________________________
|
14 |
|
15 | #include "compiler.h"
|
16 | #include "board.h"
|
17 | #include "gpio.h"
|
18 | #include "pm.h"
|
19 | #include "intc.h"
|
20 |
|
21 |
|
22 |
|
23 | //--------------------------------------------------------------------------
|
24 | __attribute__((__interrupt__))
|
25 | static void int_handler_port1_line0 (void)
|
26 | {
|
27 | if( gpio_get_pin_interrupt_flag( GPIO_PUSH_BUTTON_0 ) )
|
28 | { // PB2 generated the interrupt.
|
29 | LED_Toggle( LED1 );
|
30 | // Clear the interrupt flag of the pin PB2 is mapped to.
|
31 | gpio_clear_pin_interrupt_flag(GPIO_PUSH_BUTTON_0);
|
32 | }
|
33 | if( gpio_get_pin_interrupt_flag( GPIO_PUSH_BUTTON_1 ) )
|
34 | { // PB3 generated the interrupt.
|
35 | LED_Toggle( LED2 );
|
36 | // Clear the interrupt flag of the pin PB3 is mapped to.
|
37 | gpio_clear_pin_interrupt_flag(GPIO_PUSH_BUTTON_1);
|
38 | }
|
39 | }
|
40 | //--------------------------------------------------------------------------
|
41 |
|
42 |
|
43 | //--------------------------------------------------------------------------
|
44 | int main(void)
|
45 | {
|
46 | int i = 0;
|
47 | int j = 0;
|
48 | int x = 0;
|
49 |
|
50 |
|
51 | // switch to oscillator 0
|
52 | pm_switch_to_osc0(&AVR32_PM, FOSC0, OSC0_STARTUP);
|
53 |
|
54 | // Set all leds initial state.
|
55 | LED_Off( LED0 | LED1 | LED2 | LED3 );
|
56 |
|
57 | // GPIO config
|
58 | // configure push button to produce IT on input change
|
59 | // NOTE 1: GPIO_PUSH_BUTTON_0 & GPIO_PUSH_BUTTON_1 are defines you can find in
|
60 | // evk1101.h under /BOARDS/EVK1101/.
|
61 | // See the implementation of gpio_enable_pin_interrupt() in gpio.c under
|
62 | // /DRIVERS/GPIO/.
|
63 | gpio_enable_pin_interrupt(GPIO_PUSH_BUTTON_0 , GPIO_PIN_CHANGE); // PB2
|
64 | gpio_enable_pin_interrupt(GPIO_PUSH_BUTTON_1 , GPIO_PIN_CHANGE); // PB3
|
65 | // NOTE 2: GPIO_PUSH_BUTTON_0 & GPIO_PUSH_BUTTON_1 are in the same port.
|
66 | // (i.e. port 1, cf section 21.5 of the UC3B0256 datasheet for the computation
|
67 | // of a port knowing the pin, and see the evk1101 schematics (or the evk1101.h
|
68 | // file) + the section 12.8 of the UC3B0256 datasheet to know the pin mapping
|
69 | // of the pushbuttons).
|
70 | // Consider GPIO_PUSH_BUTTON_0 as an example: from evk1101.h, we see that
|
71 | // GPIO_PUSH_BUTTON_0 is AVR32_PIN_PB02. Open the UC3B0256 datasheet, go to
|
72 | // section 12.8, in the array look for pin PB02, we see that it is mapped to
|
73 | // GPIO 34. Using section 21.5, the formula to know the port of a pin is:
|
74 | // GPIO port = floor((GPIO number) / 32), so for GPIO_PUSH_BUTTON_0 we get:
|
75 | // floor(34/32) = 1.
|
76 | // Applying the same reasoning for GPIO_PUSH_BUTTON_1 (which is GPIO 35), we
|
77 | // find that it belongs to port 1 too.
|
78 |
|
79 | // NOTE 3: the 32 in the formula 'GPIO port = floor((GPIO number) / 32)'
|
80 | // corresponds to the fact that "The pins are managed as 32-bit ports" (see
|
81 | // section 21.5 second sentence): i.e. every port holds 32 pins max.
|
82 |
|
83 | // Interrupts config
|
84 | Disable_global_interrupt ();
|
85 | INTC_init_interrupts ();
|
86 | // register push button handler for PB2 and PB3
|
87 | INTC_register_interrupt( &int_handler_port1_line0, AVR32_GPIO_IRQ_0 + (GPIO_PUSH_BUTTON_0/8), INT0);
|
88 | INTC_register_interrupt( &int_handler_port1_line0, AVR32_GPIO_IRQ_0 + (GPIO_PUSH_BUTTON_1/8), INT0);
|
89 | // NOTE 4: reading section 21.4.7, paragraph 2:
|
90 | // "In every port there are four interrupt lines connected to the interrupt
|
91 | // controller. Every eigth interrupts in the port are ored together to form an
|
92 | // interrupt line."
|
93 | // So, for example, for port 1 :
|
94 | // GPIO32->GPIO39 : port 1 interrupt line 0 (for int-of-pin32, int-of-pin33,
|
95 | // int-of-pin34, int-of-pin35, int-of-pin36, int-of-pin37,
|
96 | // int-of-pin38 and int-of-pin39)
|
97 | // GPIO40->GPIO47 : port 1 interrupt line 1,
|
98 | // GPIO48->GPIO55 : port 1 interrupt line 2,
|
99 | // GPIO56->GPIO63 : port 1 interrupt line 3.
|
100 | //
|
101 | // That is why we use the formula "AVR32_GPIO_IRQ_0 + (GPIO_PUSH_BUTTON_0/8)"
|
102 | // to register the PB2; AVR32_GPIO_IRQ_0 is used as the base interrupt line
|
103 | // and we add '(GPIO_PUSH_BUTTON_0/8)' to register the corresponding interrupt
|
104 | // line.
|
105 |
|
106 | // NOTE 5: Since PB2 and PB3 are mapped to the GPIO pin GPIO34 and GPIO35, we
|
107 | // see that they belong to the same interrupt line. Two consequences in this
|
108 | // particular case:
|
109 | // 1) it's no use to register both. We left both registration in the code for
|
110 | // clarity's sake.
|
111 | // 2) we'll discriminate the cause of the interrupt (PB2 or PB3) in the
|
112 | // interrupt handler looking at the gpio_port1.ifr register.
|
113 | // See int_handler_gpio0() implementation.
|
114 |
|
115 | Enable_global_interrupt ();
|
116 |
|
117 | while (TRUE)
|
118 | {
|
119 | if (i == 100000)
|
120 | {
|
121 | i = 0;
|
122 | if (j == 2)
|
123 | {
|
124 | x = !x;
|
125 | if (x == 0)
|
126 | {
|
127 | LED_Off (LED0);
|
128 | }
|
129 | else
|
130 | {
|
131 | LED_On (LED0);
|
132 | }
|
133 | j = 0;
|
134 | }
|
135 | j++;
|
136 | }
|
137 | i++;
|
138 | }
|
139 | }
|