@@ -31,6 +31,7 @@ extern "C"
31
31
{
32
32
#endif
33
33
34
+ static void ap3_gpio_update_int_en (gpio_irq_t * obj );
34
35
uint32_t ap3_gpio_enable_interrupts (uint32_t ui32Pin , am_hal_gpio_intdir_e eIntDir );
35
36
/** GPIO IRQ HAL structure. gpio_irq_s is declared in the target's HAL
36
37
*/
@@ -70,20 +71,19 @@ int gpio_irq_init(gpio_irq_t *obj, PinName pin, gpio_irq_handler handler, uintpt
70
71
//grab the correct irq control object
71
72
ap3_gpio_irq_control_t * control = & gpio_irq_control [pin ];
72
73
73
- //Register locally
74
+ // Register locally
74
75
control -> pad = pin ;
75
76
control -> handler = handler ;
76
77
control -> id = context ;
77
78
control -> events = IRQ_NONE ;
78
79
79
- //Attach to object
80
+ // Attach to object
80
81
obj -> control = control ;
81
82
82
- //Make sure the interrupt is set to none to reflect the new events value
83
- ap3_gpio_enable_interrupts ( control -> pad , AM_HAL_GPIO_PIN_INTDIR_NONE ) ;
83
+ // Start with the IRQ "enabled", but don't actually enable it till something is attached
84
+ obj -> irq_requested_enabled = true ;
84
85
85
- //Enable GPIO IRQ's in the NVIC
86
- gpio_irq_enable (obj );
86
+ // Make sure the GPIO IRQ is enabled in NVIC
87
87
NVIC_SetVector ((IRQn_Type )GPIO_IRQn , (uint32_t )am_gpio_isr );
88
88
NVIC_EnableIRQ ((IRQn_Type )GPIO_IRQn );
89
89
return 0 ;
@@ -99,7 +99,18 @@ void am_gpio_isr(void)
99
99
if (gpio_int_mask & 0x0000000000000001 ) {
100
100
am_hal_gpio_interrupt_clear (AM_HAL_GPIO_BIT (pinNum ));
101
101
ap3_gpio_irq_control_t irq_ctrl = gpio_irq_control [pinNum ];
102
- ((gpio_irq_handler )irq_ctrl .handler )(irq_ctrl .id , irq_ctrl .events );
102
+
103
+ uint8_t event = irq_ctrl .events ;
104
+ if (event == (IRQ_RISE | IRQ_FALL ))
105
+ {
106
+ // This pin is configured for both rise and fall events. However, this MCU does not have separate
107
+ // status registers for tracking rising/falling interrupts.
108
+ // So, read the pin to figure out which interrupt happened. It's not totally foolproof but
109
+ // it should work in most cases.
110
+ event = am_hal_gpio_input_read (irq_ctrl .pad ) ? IRQ_RISE : IRQ_FALL ;
111
+ }
112
+
113
+ ((gpio_irq_handler )irq_ctrl .handler )(irq_ctrl .id , event );
103
114
}
104
115
gpio_int_mask >>= 1 ;
105
116
pinNum ++ ;
@@ -112,6 +123,8 @@ void am_gpio_isr(void)
112
123
*/
113
124
void gpio_irq_free (gpio_irq_t * obj )
114
125
{
126
+ // Make sure interrupt can't trigger
127
+ gpio_irq_disable (obj );
115
128
}
116
129
117
130
/** Enable/disable pin IRQ event
@@ -121,20 +134,21 @@ void gpio_irq_free(gpio_irq_t *obj)
121
134
* @param enable The enable flag
122
135
*/
123
136
void gpio_irq_set (gpio_irq_t * obj , gpio_irq_event event , uint32_t enable )
124
- {
125
- //Clear state
126
- obj -> control -> events &= (~event );
137
+ {
127
138
if (enable ) {
128
- //Reset if enabled
129
139
obj -> control -> events |= event ;
130
140
}
141
+ else {
142
+ obj -> control -> events &= ~event ;
143
+ }
131
144
132
- // Map enabled events to a value the reflects the ambiq hal/register values
145
+ // Map enabled events to a value the reflects the ambiq hal/register values.
146
+ // Note that we don't want to actually set INTDIR_NONE, because this disables reading the pin (!!)
147
+ // So instead, if asked to disable the IRQ, we leave LO2HIGH interrupt enabled in the PINCFG register but
148
+ // don't enable the interrupt for this pin in the register
133
149
am_hal_gpio_intdir_e ap3_int_dir = 0x00 ;
134
150
switch (obj -> control -> events ) {
135
151
case IRQ_NONE :
136
- ap3_int_dir = AM_HAL_GPIO_PIN_INTDIR_NONE ;
137
- break ;
138
152
case IRQ_RISE :
139
153
ap3_int_dir = AM_HAL_GPIO_PIN_INTDIR_LO2HI ;
140
154
break ;
@@ -146,7 +160,17 @@ void gpio_irq_set(gpio_irq_t *obj, gpio_irq_event event, uint32_t enable)
146
160
break ;
147
161
}
148
162
163
+ // If switching to NONE, disable the IRQ first
164
+ if (obj -> control -> events == IRQ_NONE ) {
165
+ ap3_gpio_update_int_en (obj );
166
+ }
167
+
149
168
ap3_gpio_enable_interrupts (obj -> control -> pad , ap3_int_dir );
169
+
170
+ // Otherwise enable IRQ now
171
+ if (obj -> control -> events != IRQ_NONE ) {
172
+ ap3_gpio_update_int_en (obj );
173
+ }
150
174
}
151
175
152
176
/** Enable GPIO IRQ
@@ -156,8 +180,8 @@ void gpio_irq_set(gpio_irq_t *obj, gpio_irq_event event, uint32_t enable)
156
180
*/
157
181
void gpio_irq_enable (gpio_irq_t * obj )
158
182
{
159
- am_hal_gpio_interrupt_clear ( AM_HAL_GPIO_BIT ( obj -> control -> pad )) ;
160
- am_hal_gpio_interrupt_enable ( AM_HAL_GPIO_BIT ( obj -> control -> pad ) );
183
+ obj -> irq_requested_enabled = true ;
184
+ ap3_gpio_update_int_en ( obj );
161
185
}
162
186
163
187
/** Disable GPIO IRQ
@@ -167,11 +191,27 @@ void gpio_irq_enable(gpio_irq_t *obj)
167
191
*/
168
192
void gpio_irq_disable (gpio_irq_t * obj )
169
193
{
170
- am_hal_gpio_interrupt_clear ( AM_HAL_GPIO_BIT ( obj -> control -> pad )) ;
171
- am_hal_gpio_interrupt_disable ( AM_HAL_GPIO_BIT ( obj -> control -> pad ) );
194
+ obj -> irq_requested_enabled = false ;
195
+ ap3_gpio_update_int_en ( obj );
172
196
}
173
197
174
198
/**@}*/
199
+
200
+ // Based on the enabled events and irq_requested_enabled, enable or disable the IRQ
201
+ static void ap3_gpio_update_int_en (gpio_irq_t * obj )
202
+ {
203
+ if (obj -> irq_requested_enabled && obj -> control -> events != IRQ_NONE ) {
204
+ // Enable!
205
+ am_hal_gpio_interrupt_clear (AM_HAL_GPIO_BIT (obj -> control -> pad ));
206
+ am_hal_gpio_interrupt_enable (AM_HAL_GPIO_BIT (obj -> control -> pad ));
207
+ }
208
+ else {
209
+ // Disable
210
+ am_hal_gpio_interrupt_disable (AM_HAL_GPIO_BIT (obj -> control -> pad ));
211
+ }
212
+ }
213
+
214
+
175
215
uint32_t ap3_gpio_enable_interrupts (uint32_t ui32Pin , am_hal_gpio_intdir_e eIntDir )
176
216
{
177
217
uint32_t ui32Padreg , ui32AltPadCfg , ui32GPCfg ;
@@ -208,7 +248,8 @@ uint32_t ap3_gpio_enable_interrupts(uint32_t ui32Pin, am_hal_gpio_intdir_e eIntD
208
248
209
249
ui32GPCfgShft = ((ui32Pin & 0x7 ) << 2 );
210
250
211
- ui32GPCfgAddr = AM_REGADDR (GPIO , CFGA ) + ((ui32Pin >> 1 ) & ~0x3 );
251
+ // 8 pins per register, and each register is 32 bits wide
252
+ ui32GPCfgAddr = AM_REGADDR (GPIO , CFGA ) + (ui32Pin / 8 ) * sizeof (uint32_t );
212
253
213
254
ui32GPCfgClearMask = ~((uint32_t )0xF << ui32GPCfgShft );
214
255
0 commit comments