@@ -31,6 +31,7 @@ extern "C"
3131{
3232#endif
3333
34+ static void ap3_gpio_update_int_en (gpio_irq_t * obj );
3435uint32_t ap3_gpio_enable_interrupts (uint32_t ui32Pin , am_hal_gpio_intdir_e eIntDir );
3536/** GPIO IRQ HAL structure. gpio_irq_s is declared in the target's HAL
3637*/
@@ -70,20 +71,19 @@ int gpio_irq_init(gpio_irq_t *obj, PinName pin, gpio_irq_handler handler, uintpt
7071 //grab the correct irq control object
7172 ap3_gpio_irq_control_t * control = & gpio_irq_control [pin ];
7273
73- //Register locally
74+ // Register locally
7475 control -> pad = pin ;
7576 control -> handler = handler ;
7677 control -> id = context ;
7778 control -> events = IRQ_NONE ;
7879
79- //Attach to object
80+ // Attach to object
8081 obj -> control = control ;
8182
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 ;
8485
85- //Enable GPIO IRQ's in the NVIC
86- gpio_irq_enable (obj );
86+ // Make sure the GPIO IRQ is enabled in NVIC
8787 NVIC_SetVector ((IRQn_Type )GPIO_IRQn , (uint32_t )am_gpio_isr );
8888 NVIC_EnableIRQ ((IRQn_Type )GPIO_IRQn );
8989 return 0 ;
@@ -99,7 +99,18 @@ void am_gpio_isr(void)
9999 if (gpio_int_mask & 0x0000000000000001 ) {
100100 am_hal_gpio_interrupt_clear (AM_HAL_GPIO_BIT (pinNum ));
101101 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 );
103114 }
104115 gpio_int_mask >>= 1 ;
105116 pinNum ++ ;
@@ -112,6 +123,8 @@ void am_gpio_isr(void)
112123*/
113124void gpio_irq_free (gpio_irq_t * obj )
114125{
126+ // Make sure interrupt can't trigger
127+ gpio_irq_disable (obj );
115128}
116129
117130/** Enable/disable pin IRQ event
@@ -121,20 +134,21 @@ void gpio_irq_free(gpio_irq_t *obj)
121134* @param enable The enable flag
122135*/
123136void gpio_irq_set (gpio_irq_t * obj , gpio_irq_event event , uint32_t enable )
124- {
125- //Clear state
126- obj -> control -> events &= (~event );
137+ {
127138 if (enable ) {
128- //Reset if enabled
129139 obj -> control -> events |= event ;
130140 }
141+ else {
142+ obj -> control -> events &= ~event ;
143+ }
131144
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
133149 am_hal_gpio_intdir_e ap3_int_dir = 0x00 ;
134150 switch (obj -> control -> events ) {
135151 case IRQ_NONE :
136- ap3_int_dir = AM_HAL_GPIO_PIN_INTDIR_NONE ;
137- break ;
138152 case IRQ_RISE :
139153 ap3_int_dir = AM_HAL_GPIO_PIN_INTDIR_LO2HI ;
140154 break ;
@@ -146,7 +160,17 @@ void gpio_irq_set(gpio_irq_t *obj, gpio_irq_event event, uint32_t enable)
146160 break ;
147161 }
148162
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+
149168 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+ }
150174}
151175
152176/** Enable GPIO IRQ
@@ -156,8 +180,8 @@ void gpio_irq_set(gpio_irq_t *obj, gpio_irq_event event, uint32_t enable)
156180*/
157181void gpio_irq_enable (gpio_irq_t * obj )
158182{
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 );
161185}
162186
163187/** Disable GPIO IRQ
@@ -167,11 +191,27 @@ void gpio_irq_enable(gpio_irq_t *obj)
167191*/
168192void gpio_irq_disable (gpio_irq_t * obj )
169193{
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 );
172196}
173197
174198/**@}*/
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+
175215uint32_t ap3_gpio_enable_interrupts (uint32_t ui32Pin , am_hal_gpio_intdir_e eIntDir )
176216{
177217 uint32_t ui32Padreg , ui32AltPadCfg , ui32GPCfg ;
@@ -208,7 +248,8 @@ uint32_t ap3_gpio_enable_interrupts(uint32_t ui32Pin, am_hal_gpio_intdir_e eIntD
208248
209249 ui32GPCfgShft = ((ui32Pin & 0x7 ) << 2 );
210250
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 );
212253
213254 ui32GPCfgClearMask = ~((uint32_t )0xF << ui32GPCfgShft );
214255
0 commit comments