-
Notifications
You must be signed in to change notification settings - Fork 7.6k
drivers: gpio: add interrupt support for the CH32V family #89139
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
Conversation
bf5e86b
to
453af71
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.
Pull Request Overview
This PR introduces external interrupt support for the CH32V family by adding a dedicated WCH EXTI driver and integrating it with the GPIO driver, including new DTS nodes and device tree bindings.
- Added new header and driver files for the WCH EXTI controller
- Updated DTS files and bindings to include EXTI support for multiple CH32V variants
- Enabled interrupt configuration in the GPIO driver and updated board DTS files to activate the exti nodes
Reviewed Changes
Copilot reviewed 14 out of 14 changed files in this pull request and generated 1 comment.
Show a summary per file
File | Description |
---|---|
include/zephyr/drivers/interrupt_controller/wch_exti.h | New header defining interface and types for the WCH EXTI driver |
dts/riscv/wch/ch32v208/ch32v208.dtsi, ch32v0/ch32v006.dtsi, ch32v0/ch32v003.dtsi | New DTS node for EXTI configuration on different CH32V variants |
dts/bindings/interrupt-controller/wch,exti.yaml | Added binding documentation for the WCH EXTI controller |
drivers/interrupt_controller/intc_wch_exti.c | New EXTI controller driver implementation |
drivers/gpio/wch_gpio_ch32v00x.c | Updated GPIO driver to support interrupt configuration via EXTI |
Kconfig & CMakeLists.txt files | Integrated the new driver with build and configuration systems |
boards/wch//.dts | Enabled the EXTI node in board configurations |
5c366e1
to
96cc4c5
Compare
Rebased on main. |
Rebased to fix an unrelated CI error. |
@SoftwareArchitekt could you check my feedback and re-review please? |
gpio_fire_callbacks(&data->callbacks, dev, BIT(line)); | ||
} | ||
|
||
static int gpio_ch32v00x_configure_exti(const struct device *dev, gpio_pin_t pin) |
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 lines are new added, so could it be done?
@@ -7,6 +7,7 @@ | |||
#include <zephyr/drivers/clock_control.h> | |||
#include <zephyr/drivers/gpio.h> | |||
#include <zephyr/drivers/gpio/gpio_utils.h> | |||
#include <zephyr/drivers/interrupt_controller/wch_exti.h> |
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.
yes, the code in c-files are only compiled by device-tree entry. but in header are some variables which takes some memory. pls check it again
return 0; | ||
} | ||
|
||
static int gpio_ch32v00x_pin_interrupt_configure(const struct device *dev, gpio_pin_t pin, |
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.
Same reply as above.
wch_exti_set_trigger(pin, WCH_EXTI_TRIGGER_FALLING_EDGE | | ||
WCH_EXTI_TRIGGER_RISING_EDGE); | ||
break; | ||
default: |
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.
ditto
const struct device *dev = user; | ||
struct gpio_ch32v00x_data *data = dev->data; | ||
|
||
gpio_fire_callbacks(&data->callbacks, dev, BIT(line)); |
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.
why assigning the data here to local variable (on stack) instead of direct using in gpio_fire_callbacks?
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.
For consistent style. Zephyr drivers typically have an initial variable block where data
, config
, and regs
are resolved as needed. These are then used in the body.
case DT_REG_ADDR(DT_NODELABEL(gpioa)): | ||
port_id = 0; | ||
break; | ||
#if DT_NODE_EXISTS(DT_NODELABEL(gpiob)) |
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 this also be done on the other banks? I would never think about, that parts of device tree comes so in driver. It could help in future and the defines doesn't take memory
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.
No, this switch is based on the hardware capabilities, not what is enabled (i.e. status = "okay") in Devicetree. All CH32V devices have GPIOA, but at least the CH32V003 does not have GPIOB.
enum gpio_int_mode mode, | ||
enum gpio_int_trig trigger) | ||
{ | ||
int err; |
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.
could you assign here a 0? I like to have always clear declaration
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 understand the intent, but that's not Zephyr style and, with a modern compiler, lets through more bugs.
For example, if you initialise err to zero, and you intended to write:
err = do_something();
if (err < 0) { return err; }
but instead you wrote:
if (do_something() < 0) {
return err;
}
then the compiler will let this logic bug through. If you have the use of uninitialized variable warning on, then the compiler would warn.
{ | ||
EXTI_TypeDef *regs = (EXTI_TypeDef *)DT_INST_REG_ADDR(0); | ||
|
||
regs->INTENR |= BIT(line); |
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.
where I can find error checking of parameter line?
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's no real Zephyr policy on validating arguments.
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.
A couple items I found from testing this on my custom v305 board. Thanks for working on this!
if (callback != NULL && registration->callback != NULL) { | ||
return -EALREADY; | ||
} |
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.
Needs a check similar to the STM32 EXTI one, to just return 0 if a caller attempts to configure with the exact same callback and user:
if (callback != NULL && registration->callback != NULL) { | |
return -EALREADY; | |
} | |
if (registration->callback == callback && registration->user == user) { | |
return 0; | |
} | |
if (callback != NULL && registration->callback != NULL) { | |
return -EALREADY; | |
} |
Without this, the test_gpio_config_twice_trigger
test fails.
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.
Done
drivers/gpio/wch_gpio_ch32v00x.c
Outdated
BUILD_ASSERT(ARRAY_SIZE(afio->EXTICR) == 4); | ||
|
||
cr_id = pin / 4; | ||
bit0 = (pin % 4) << 4; |
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.
From testing here, this logic looks slightly off. Need to multiply by 4, not shift:
bit0 = (pin % 4) << 4; | |
bit0 = (pin % 4) * 4; |
With this in place, on top of my work in #91966 I can run the tests/drivers/gpio
on my custom v305 board, with the -X gpio_loopback
in place, and they all pass:
❯ west twister --device-testing -p wch32v305pad --device-serial /dev/ttyACM0 --west-runner wlink --west-flash -T tests/drivers/gpio -X gpio_loopback
Renaming output directory to /home/peter/git/zmk/zephyr/twister-out.7
INFO - Using Ninja..
INFO - Zephyr version: 9996afb64654
INFO - Using 'zephyr' toolchain.
INFO - Building initial testsuite list...
INFO - Writing JSON report /home/peter/git/zmk/zephyr/twister-out/testplan.json
Device testing on:
| Platform | ID | Serial device |
|-----------------------|------|-----------------|
| wch32v305pad/ch32v305 | | /dev/ttyACM0 |
INFO - JOBS: 8
INFO - Adding tasks to the queue...
INFO - Added initial list of jobs to queue
INFO - Total complete: 4/ 4 100% built (not run): 0, filtered: 17, failed: 0, error: 0
INFO - 18 test scenarios (18 configurations) selected, 17 configurations filtered (14 by static filter, 3 at runtime).
INFO - 1 of 1 executed test configurations passed (100.00%), 0 built (not run), 0 failed, 0 errored, with no warnings in 42.31 seconds.
INFO - 7 of 7 executed test cases passed (100.00%) on 1 out of total 1094 platforms (0.09%).
INFO - 1 test configurations executed on platforms, 0 test configurations were only built.
Hardware distribution summary:
| Board | ID | Counter | Failures |
|-----------------------|------|-----------|------------|
| wch32v305pad/ch32v305 | | 1 | 0 |
INFO - Saving reports...
INFO - Writing JSON report /home/peter/git/zmk/zephyr/twister-out/twister.json
INFO - Writing xunit report /home/peter/git/zmk/zephyr/twister-out/twister.xml...
INFO - Writing xunit report /home/peter/git/zmk/zephyr/twister-out/twister_report.xml...
INFO - Run completed
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.
Nice! Done.
Rebased on main. |
The WCH External Trigger and Interrupt controller (EXTI) supports between 8 and 22 lines where each line can trigger an interrupt on rising edge, falling edge, or both edges. Lines are assigned to a group, and each group has a separate interrupt. On the CH32V003/6, there is one group of 8 lines, while on the CH32V208 there are multiple groups with between one and six lines per group. In the same way as the STM32 and GD32, define an EXTI driver that configures the peripheral and an internal interface that can configure individual lines. Signed-off-by: Michael Hope <michaelh@juju.nz>
The WCH GPIO peripheral integrates with the EXTI and supports firing interrupts when a GPIO pin changes. Add optional support for firing a callback on rising edge, falling edge, or both edges. Tested on the `linkw` and the `ch32v006evt` using `samples/basic/button`. Signed-off-by: Michael Hope <michaelh@juju.nz>
Now that Zephyr has support, enable by default. Signed-off-by: Michael Hope <michaelh@juju.nz>
|
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.
LGTM. Cherry picked the changes onto my v305 work and the full GPIO tests pass.
@VynDragon @nordicjm PTAL. I'd submit this before Friday's freeze if practical. |
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.
Took a quick look at the code and tested button sample on linkw that now works. Looks good to me.
The WCH External Trigger and Interrupt controller (EXTI) supports
between 8 and 22 lines where each line can trigger an interrupt on
rising edge, falling edge, or both edges. Lines are assigned to a
group, and each group has a separate interrupt. On the CH32V003/6,
there is one group of 8 lines, while on the CH32V208 there are
multiple groups with between one and six lines per group.
In the same way as the STM32 and GD32, define an EXTI driver that
configures the peripheral and an internal interface that can configure
individual lines. Bind into the GPIO driver.
Tested on the
linkw
and thech32v006evt
usingsamples/basic/button
. Note that thelinkw
default stack size is too small for the sample.