-
Notifications
You must be signed in to change notification settings - Fork 7.3k
drivers: add imx7d pwm driver #8794
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
Codecov Report
@@ Coverage Diff @@
## master #8794 +/- ##
=======================================
Coverage 52.25% 52.25%
=======================================
Files 196 196
Lines 24802 24802
Branches 5155 5155
=======================================
Hits 12961 12961
Misses 9762 9762
Partials 2079 2079 Continue to review full report at Codecov.
|
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.
+1 for doc changes
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.
Please update samples/basic/blink_led/sample.yaml
and tests/drivers/pwm/pwm_api/testcase.yaml
to include the colibri board. This will ensure that we build the driver in CI
drivers/pwm/pwm_imx.c
Outdated
} else { | ||
PWM_PWMCR_REG(base) = PWM_PWMCR_SWR(1); | ||
do { | ||
k_busy_wait(500); |
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 we have to busy-wait? Can we k_sleep instead?
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.
Would put 500 along with PWM_PWMSWR_LOOP define, so the values are written close together.
drivers/pwm/pwm_imx.c
Outdated
k_busy_wait(500); | ||
cr = PWM_PWMCR_REG(base); | ||
} while ((PWM_PWMCR_SWR(cr)) && | ||
(wait_count++ < PWM_PWMSWR_LOOP)); |
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.
PWM_PWMSWR_LOOP
should be a Kconfig option
* Description : Get clock frequency applys to the PWM module | ||
* | ||
*END**************************************************************************/ | ||
uint32_t get_pwm_clock_freq(PWM_Type *base) |
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 can see why you did this, but I still want to avoid modifying ext/ files. Can you implement in soc.c instead?
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 clock_freq.c came originally from "FreeRTOS_BSP_1.0.1_iMX7D/examples/imx7d_val_m4/clock_freq.c" and I put it inside "ext/hal/nxp/imx/devices/MCIMX7D/" path following yours and @stanislav-poboril suggestion.
What should I do in this case? Move all get_pwm_clock_freq related stuff to "arch/arm/soc/nxp_imx/mcimx7_m4/" folder?
Should I have to isolate the changes for "ext/hal/nxp/imx/drivers/ccm_imx7d.h" in another header with other enums inside the "arch/arm/soc/nxp_imx/mcimx7_m4/" folder as well?
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 clock_freq.c should stay in the ext folder, unmodified. The get_pwm_clock_freq() function and related changes should be either moved to soc.c (or similar soc related location) or Zephyr has a mechanism for this which is probably preferred but would require a little more effort - see drivers/clock_control/ folder and the file clock_control_mcux_ccm.c.
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.
@MaureenHelm and @stanislav-poboril ,
This should be addressed now.
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.
Just to be clear, did you write get_pwm_clock_freq()
yourself following the pattern from clock_freq.c, or did you copy the function from somewhere? I assumed the former in my previous comment.
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, I wrote the function by myself following the same pattern from the other functions.
I found some issues with the pwm_api test related to asserts in the i.MX UART Driver. This PR depends on the PR #8938. |
drivers/pwm/pwm_imx.c
Outdated
return -EINVAL; | ||
} | ||
|
||
duty_cycle = 100 * pulse_cycles / period_cycles; |
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 duty_cycle variable is used for logging only. Maybe the formula can be written directly in the logging statement. But compiler would probably optimize it anyway if log not used.
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.
Another reason to move the formula is to avoid a compiler warning when you build with logging turned off.
drivers/pwm/pwm_imx.c
Outdated
struct imx_pwm_data *data = DEV_DATA(dev); | ||
u8_t duty_cycle; | ||
unsigned int period_ms; | ||
bool enable = imx_pwm_is_enabled(base); |
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.
Would rename to enabled or is_enabled. At the end of the function, PWM should be enabled anyway (unless there is an error in parameters etc).
drivers/pwm/pwm_imx.c
Outdated
} else { | ||
PWM_PWMCR_REG(base) = PWM_PWMCR_SWR(1); | ||
do { | ||
k_busy_wait(500); |
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.
Would put 500 along with PWM_PWMSWR_LOOP define, so the values are written close together.
drivers/pwm/pwm_imx.c
Outdated
if (period_cycles > 2) { | ||
period_cycles -= 2; | ||
} else { | ||
period_cycles = 0; |
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.
If the period_cycles < 2, should the function return error?
drivers/pwm/pwm_imx.c
Outdated
|
||
if (data->period_cycles != period_cycles) { | ||
data->period_cycles = period_cycles; | ||
PWM_PWMPR_REG(base) = period_cycles; |
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.
If there are still some data in the sample register FIFO, say 1-3, could this happen:
- We change the period to another value.
- Samples in the FIFO were meant to be output with the previous period value.
- But they will be output with the new period value, it may even be shorter than the sample value.
This is probably not very usual to change the period and I know the hardware does not allow to handle it better, though (unless we maintain our own fifo with both the cycle and period and set the HW FIFO low watermark to 1 and change the period in interrupt at the last moment).
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.
Maybe in the "if (enable)" block it can wait for a full cycle if there is still 1,2,3 or 4 words of data in the FIFO. I think this way it will only configure a new period cycle if the FIFO is empty.
What do you think?
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 best would be to try it. But then it could be perhaps too late to set the new period - there could be delays between stream of output with different cycles, which means FIFO would be emptied and the last cycle would repeat once more before changing the period.
I think the peripheral was created with the following use case in mind where period is set once and then the FIFO is filled ahead of time to keep it from underflowing (or let it underflow and repeat the same cycle until stopped or changing the cycle).
My previous comment would be probably relevant in a scenario, where the exact number of cycles has to be output (some sort of audio output?), but then I think it probably does not makes a sense to change the period duration.
Well I am not sure at the end if we should do anything about this.
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.
Perhaps we can leave as is (I used the same approach as the Linux kernel driver) for now and add a comment in the source code about this specific scenario that is not covered?
@MaureenHelm,
What do you think?
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 handled a similar case in pwm_mcux_ftm.c by logging a warning. You can do the same here for now.
zephyr/drivers/pwm/pwm_mcux_ftm.c
Line 61 in 16ff8ca
SYS_LOG_WRN("Changing period cycles from %d to %d" |
drivers/pwm/pwm_imx.c
Outdated
return -EINVAL; | ||
} | ||
|
||
duty_cycle = 100 * pulse_cycles / period_cycles; |
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.
Another reason to move the formula is to avoid a compiler warning when you build with logging turned off.
drivers/pwm/pwm_imx.c
Outdated
|
||
if (data->period_cycles != period_cycles) { | ||
data->period_cycles = period_cycles; | ||
PWM_PWMPR_REG(base) = period_cycles; |
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 handled a similar case in pwm_mcux_ftm.c by logging a warning. You can do the same here for now.
zephyr/drivers/pwm/pwm_mcux_ftm.c
Line 61 in 16ff8ca
SYS_LOG_WRN("Changing period cycles from %d to %d" |
def_bool y | ||
|
||
config PWM_2 | ||
def_bool n |
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 def_bool n
are redundant. I think all but PWM_1 should be removed.
@ulfalizer Will you please confirm?
7eb88c0
to
276a17f
Compare
@MaureenHelm and @stanislav-poboril , All comments should be addressed now. |
} else { | ||
PWM_PWMCR_REG(base) = PWM_PWMCR_SWR(1); | ||
do { | ||
k_sleep(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 didn't realize before that the k_busy_wait(500) is 500 microseconds, vs k_sleep(1) is one millisecond, but due to the default quantum is 10 milliseconds in Zephyr/ARM, it will sleep 10 milliseconds or more (unless kernel parameters are changed, you have maybe changed the system tick to 1 ms). Is this ok?
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.
Just two small nits
drivers/pwm/pwm_imx.c
Outdated
k_sleep(1); | ||
cr = PWM_PWMCR_REG(base); | ||
} while ((PWM_PWMCR_SWR(cr)) && | ||
(wait_count++ < CONFIG_PWM_PWMSWR_LOOP)); |
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 should be ++wait_count
drivers/pwm/pwm_imx.c
Outdated
(wait_count++ < CONFIG_PWM_PWMSWR_LOOP)); | ||
|
||
if (PWM_PWMCR_SWR(cr)) | ||
SYS_LOG_WRN("software reset timeout\n"); |
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.
Need to wrap in braces
This patch adds the get_pwm_clock_freq function to be used by the i.MX PWM driver. Signed-off-by: Diego Sueiro <[email protected]>
Adds the PWM shim driver for i.MX Signed-off-by: Diego Sueiro <[email protected]>
Adds definitions, devicetree entries and clock controller configurations for PWM peripheral. Signed-off-by: Diego Sueiro <[email protected]>
Adds configurations and pinmux to support PWM on colibri_imx7d_m4 Signed-off-by: Diego Sueiro <[email protected]>
Adds the appropriated configuration for colibri_imx7d_m4 board in blink_led sample app. Signed-off-by: Diego Sueiro <[email protected]>
Adds the appropriated configuration for colibri_imx7d_m4 board in pwm_api tests. Signed-off-by: Diego Sueiro <[email protected]>
This pull request is to add PWM driver for mcimx7_m4 arch and colibri_imx7d_m4 board.
The implementation was tested on the colibri_imx7d_m4 board by compiling and running the samples/basic/blink_led and tests/drivers/pwm/pwm_api/ applications (PWM characteristics were verified using a Saleae Logic Analyzer) using the PWM_1 interface.