@@ -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