-
Notifications
You must be signed in to change notification settings - Fork 3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
InterruptIn changes in NCS36510 HAL. #2938
Conversation
Can you share the test results - how was this tested? |
@@ -143,16 +140,17 @@ void gpio_mode(gpio_t *obj, PinMode mode) | |||
void gpio_dir(gpio_t *obj, PinDirection direction) | |||
{ | |||
/* Enable the GPIO clock */ | |||
CLOCK_ENABLE(CLOCK_GPIO); | |||
if(!CLOCK_IS_ENABLED(CLOCK_GPIO)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Formatting needs to match https://docs.mbed.com/docs/mbed-os-handbook/en/5.1/cont/code_style/
/* Enable the GPIO clock */ | ||
CLOCK_ENABLE(CLOCK_GPIO); | ||
if(!CLOCK_IS_ENABLED(CLOCK_GPIO)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@@ -186,12 +186,12 @@ int gpio_read(gpio_t *obj) | |||
int ret; | |||
|
|||
/* Enable the GPIO clock */ | |||
CLOCK_ENABLE(CLOCK_GPIO); | |||
if(!CLOCK_IS_ENABLED(CLOCK_GPIO)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
GpioReg_pt gpioBase; | ||
|
||
/* Enable the GPIO clock */ | ||
CLOCK_ENABLE(CLOCK_GPIO); | ||
if(!CLOCK_IS_ENABLED(CLOCK_GPIO)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@@ -146,7 +146,10 @@ int gpio_irq_init(gpio_irq_t *obj, PinName pin, gpio_irq_handler handler, uint32 | |||
gpioIds[pin] = id; | |||
|
|||
/* Enable the GPIO clock */ | |||
CLOCK_ENABLE(CLOCK_GPIO); | |||
if(!CLOCK_IS_ENABLED(CLOCK_GPIO)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@@ -179,7 +183,10 @@ int gpio_irq_init(gpio_irq_t *obj, PinName pin, gpio_irq_handler handler, uint32 | |||
void gpio_irq_free(gpio_irq_t *obj) | |||
{ | |||
/* Enable the GPIO clock */ | |||
CLOCK_ENABLE(CLOCK_GPIO); | |||
if(!CLOCK_IS_ENABLED(CLOCK_GPIO)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
/* Enable the GPIO clock */ | ||
CLOCK_ENABLE(CLOCK_GPIO); | ||
if(!CLOCK_IS_ENABLED(CLOCK_GPIO)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@@ -239,9 +246,12 @@ void gpio_irq_set(gpio_irq_t *obj, gpio_irq_event event, uint32_t enable) | |||
void gpio_irq_enable(gpio_irq_t *obj) | |||
{ | |||
/* Enable the GPIO clock */ | |||
CLOCK_ENABLE(CLOCK_GPIO); | |||
if(!CLOCK_IS_ENABLED(CLOCK_GPIO)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
/* Enable the GPIO clock */ | ||
CLOCK_ENABLE(CLOCK_GPIO); | ||
if(!CLOCK_IS_ENABLED(CLOCK_GPIO)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
|
||
default: | ||
break; | ||
case PushPullPullDown: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
obj->GPIOMEMBASE->IRQ_POLARITY_CLEAR = (IO_ALL ^ (obj->pinMask)); | ||
} | ||
break; | ||
case IRQ_RISE: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I did run AStyle on this code before submitting a PR. The result is that AStyle shows changes in files but they don't seem to show up in the PR. Is it recommended to format files manually or is running AStyle the preferred method? Please let us know for future PRs.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What about the disables of GPIO_CLOCK in other modules like I2C and serial?
@@ -83,6 +83,7 @@ | |||
#define CLOCK_ENABLE(a) CLOCKREG->PDIS.WORD &= ~(1 << a) | |||
#define CLOCK_DISABLE(a) CLOCKREG->PDIS.WORD |= (uint32_t)(1 << a) | |||
|
|||
#define CLOCK_IS_ENABLED(a) ((CLOCKREG->PDIS.WORD >> a) & 1)?0:1 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is dangerous due to lack of enclosing brackets. Indeed, I believe all your uses of it actually fail.
Actually, no, they do work, but rather by accident - the first expression gets boolean inverted before being fed to the ?, so the right answer comes out.
Does it actually matter if you "enable" a clock that is already enabled anyway? Just a write to the peripheral may be as fast as the read to check if it is enabled.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@0xc0170 suggested in a previous pull request that this implementation be changed from calling an enable function repeatedly. Instead check for the clock and enable only if required.
I have added enclosing brackets.
obj->GPIOMEMBASE->IRQ_POLARITY_SET = (obj->pinMask); | ||
obj->GPIOMEMBASE->ANYEDGE_SET = IO_NONE; | ||
|
||
obj->GPIOMEMBASE->W_IN |= obj->pinMask; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Assuming the datasheet I have is correct this is wrong, as is the comment above - you should never be performing read-modify-write on any of these registers.
obj->GPIOMEMBASE->IRQ_EDGE |= obj->pinMask; | ||
obj->GPIOMEMBASE->IRQ_POLARITY_SET |= obj->pinMask; | ||
obj->GPIOMEMBASE->IRQ_ENABLE_SET |= obj->pinMask; | ||
obj->GPIOMEMBASE->ANYEDGE_SET |= IO_NONE; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This presumably should be ANYEDGE_CLEAR = obj->pinMask;
obj->GPIOMEMBASE->W_IN |= obj->pinMask; | ||
obj->GPIOMEMBASE->IRQ_EDGE |= obj->pinMask; | ||
obj->GPIOMEMBASE->IRQ_POLARITY_SET |= obj->pinMask; | ||
obj->GPIOMEMBASE->IRQ_ENABLE_SET |= obj->pinMask; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should interrupts really be enabled initially, before irq_set or irq_enable is called? I'm not sure.
} | ||
break; | ||
case IRQ_RISE: | ||
obj->GPIOMEMBASE->IRQ_EDGE |= obj->pinMask; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Again, wrong by the data sheet.
obj->GPIOMEMBASE->IRQ_POLARITY_SET |= obj->pinMask; | ||
} else if (enable == 0) { | ||
/* Disable rising edge */ | ||
obj->GPIOMEMBASE->IRQ_POLARITY_SET |= (IO_ALL ^ (obj->pinMask)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
enable 0 doesn't mean "disable rising edge" - it's a request to disable the interrupts.
I'd suggest two separate tests - one to program IRQ_POLARITY_SET or CLEAR depending on event, and a separate one to program IRQ_ENABLE_SET or IRQ_ENABLE_CLEAR depending on enable.
And again, all of those just being = obj->pinMask
, if my register map is correct. (And it seems logical to me).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have taken care of all the comments above. Would I need to rebase again, since the structure of mbed-os has changed since this PR was generated?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have rebased my fork on the latest mbed-os structure. Let me know if I need to do something more on my side.
177322b
to
20e6a05
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Seems better. Does it work for 2 buttons now?
I'm still worried by all the CLOCK_DISABLE(CLOCK_GPIO) in other drivers. Would it be a good idea to remove those?
@@ -82,6 +82,7 @@ | |||
|
|||
#define CLOCK_ENABLE(a) CLOCKREG->PDIS.WORD &= ~(1 << a) | |||
#define CLOCK_DISABLE(a) CLOCKREG->PDIS.WORD |= (uint32_t)(1 << a) | |||
#define CLOCK_IS_ENABLED(a) (((CLOCKREG->PDIS.WORD) >> a) & 1)?0:1 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The brackets need to be around the entire expression. Otherwise something like if (!CLOCK_IS_ENABLED(foo) && something_else)
would go horribly wrong.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Taken care and modified.
|
||
obj->GPIOMEMBASE->W_IN = (IO_ALL ^ (obj->pinMask)); | ||
/* Make the pin as output in order to release it */ | ||
obj->GPIOMEMBASE->W_OUT = obj->pinMask; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do you really want to make the pin an output? Start driving your input line high or low? Surely not.
Don't you just want to disable the interrupt, but leave the pin as it is?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Taken care and modified.
if (enable == 1) { | ||
/* Enable rising edge */ | ||
obj->GPIOMEMBASE->IRQ_POLARITY_SET = (obj->pinMask); | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This if is the same, and so no longer needs to be in the switch.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Rebase and conflict resolution went horribly wrong and original files were chosen during an auto merge process. Hence none of the recent changes in my fork came out during the rebase. This piece of code has been modified in this checkin.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My comment still applies - you're repeating the same enable code in each case of the switch - the enable code does not depend on the mode, and it doesn't need to be in the switch.
@@ -157,10 +161,8 @@ int gpio_irq_init(gpio_irq_t *obj, PinName pin, gpio_irq_handler handler, uint32 | |||
* then change this setting to obj->GPIOMEMBASE->W_IN |= obj->pinMask. All parameter setting needs to change from = to |= | |||
*/ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This comment is obsolete and wrong, so should be removed. (Although have you actually tested it with two inputs now? That's what we were trying to get working - the two buttons.)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have tested with two buttons as well as the same button triggering two inputs. Both scenarios are working.
CLOCK_ENABLE(CLOCK_GPIO); | ||
if(!CLOCK_IS_ENABLED(CLOCK_GPIO)) { | ||
CLOCK_ENABLE(CLOCK_GPIO); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd like to ask @0xc0170 whether he really thinks this is worthwhile. Reading the hardware to find out if it's worth writing to the hardware? More code, and probably no faster - usually 1 read instead of 1 write.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The GPIO disable in other drivers was also part of a rebase and automerge gone horribly wrong. I hope it is reflected in my latest checkin and pull request. Please let me know.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd like to ask @0xc0170 whether he really thinks this is worthwhile
It's not, good point !
/morph test |
Result: SUCCESSYour command has finished executing! Here's what you wrote!
Outputmbed Build Number: 0 All builds and test passed! |
Is this merged with the main branch? The label status has not changed over the last couple of days. All the tests have passed in the checklist. |
What do you think about checking if gpio is enabled vs just enable the gpio clocks? The question asked above. It would be useful to provide more details in the commit messages |
…c and gpio_irq_api.c
I have reverted GPIO clock enablement code to a previous implementation which was present in older version of the code. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Okay, but still a couple of minor concerns.
@@ -178,10 +169,11 @@ int gpio_irq_init(gpio_irq_t *obj, PinName pin, gpio_irq_handler handler, uint32 | |||
*/ | |||
void gpio_irq_free(gpio_irq_t *obj) | |||
{ | |||
/* Enable the GPIO clock */ | |||
/* Enable the GPIO clock which may have been switched off by other drivers */ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Really you need to ensure no other driver does turn it off - assuming the clock needs to stay running for the interrupts to work, not just for the register access? (If the clock only needed to be on for the register access, you could disable it at the end of the function).
if (enable == 1) { | ||
/* Enable rising edge */ | ||
obj->GPIOMEMBASE->IRQ_POLARITY_SET = (obj->pinMask); | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My comment still applies - you're repeating the same enable code in each case of the switch - the enable code does not depend on the mode, and it doesn't need to be in the switch.
IRQ enable code moved out of switch case. Regarding clock disable of GPIO from other drivers, other code may need modification and testing. Hence CLOCK_ENABLE(CLOCK_GPIO) remains in code for now. |
break; | ||
|
||
default: | ||
/* No event is set */ | ||
break; | ||
} | ||
/* Enable the IRQ based on enable parameter */ | ||
if (enable == 1) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I personally would simplify further to just if (enable) {} else {}
, on the assumption that it is supposed to be a boolean, even if not declared as that. But this is fine.
The IRQ API is void gpio_irq_set(gpio_irq_t *obj, gpio_irq_event event, uint32_t enable) |
Hard to say whether that's better or worse, as it's not actually documented anywhere (as far as I can see) that the "enable" value is specifically 1. Generally speaking writing Specifically writing it like this means you are expecting future expansion, so deliberately want to do nothing if 2 is passed. I personally think if passed 2, it's probably better to enable. Quick survey of 4 other drivers showed the 3 doing But I don't actually really care - this is fine if you prefer it. It seems safe to assume (given all the different current driver behaviour) that extra values will never be used. |
Done. Check is now against if(enable) else. |
All changes in place now. All checks have passed. |
/morph test |
Result: SUCCESSYour command has finished executing! Here's what you wrote!
Outputmbed Build Number: 0 All builds and test passed! |
Ports for Upcoming Targets Fixes and Changes 2966: Add kw24 support ARMmbed/mbed-os#2966 3068: MultiTech mDot - clean up PeripheralPins.c and add new pin names ARMmbed/mbed-os#3068 3089: Kinetis HAL: Remove clock initialization code from serial and ticker ARMmbed/mbed-os#3089 2943: [NRF5] NVIC_SetVector functionality ARMmbed/mbed-os#2943 2938: InterruptIn changes in NCS36510 HAL. ARMmbed/mbed-os#2938 3108: Fix sleep function for NRF52. ARMmbed/mbed-os#3108 3076: STM32F1: Correct timer master value reading ARMmbed/mbed-os#3076 3085: Add LOWPOWERTIMER capability for NUCLEO_F303ZE ARMmbed/mbed-os#3085 3046: [BEETLE] Update BLE stack on Beetle board ARMmbed/mbed-os#3046 3122: [Silicon Labs] Update of Silicon Labs HAL ARMmbed/mbed-os#3122 3022: OnSemi RAM usage fix ARMmbed/mbed-os#3022 3121: STM32F3: Correct UART4 and UART5 defines when using DEVICE_SERIAL_ASYNCH ARMmbed/mbed-os#3121 3142: Targets- NUMAKER_PFM_NUC47216 remove mbed 2 ARMmbed/mbed-os#3142
Notes:
Description
A few sentences describing the overall goals of the pull request's commits.
Status
READY/IN DEVELOPMENT/HOLD
Migrations
If this PR changes any APIs or behaviors, give a short description of what API users should do when this PR is merged.
YES | NO
Related PRs
List related PRs against other branches:
Todos
Deploy notes
Notes regarding the deployment of this PR. These should note any
required changes in the build environment, tools, compilers, etc.
Steps to test or reproduce
Outline the steps to test or reproduce the PR here.