-
Notifications
You must be signed in to change notification settings - Fork 7k
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
drivers: led_strip: ws2812_gpio: Add support for nRF52 SOC #72050
drivers: led_strip: ws2812_gpio: Add support for nRF52 SOC #72050
Conversation
Hello @chaim-zax, and thank you very much for your first pull request to the Zephyr project! |
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.
Don't think I really like this, what SoC was this tested on? E.g. nRF52810 has no instruction cache, nRF52840 has an optional instruction cache, was this generated/tested with it on or off since that's going to have a big impact
Good remark. It was testing on an nRF52840 with the instruction cache enabled (NRF_ENABLE_ICACHE). I checked the datasheets of all the nRF52's to check if they used the same ARM CPU and same (internal) clock structure. I did not take the impact of the instruction cache into account. Because I currently only have hardware to validate the nRF52840 I would like to suggest to change the CONFIG_SOC_SERIES_NRF52X define in the driver to CONFIG_SOC_NRF52840. |
Hi @chaim-zax, I am not very fond of the GPIO method for controlling an LED strip :) I think this should only be used for debugging purposes or when the other methods (SPI, I2S) cannot be used. So I don't like the |
I'm using the Adafruit Feather nRF52840 Express which has a single RGB LED, so you can consider this a debug LED if you like. I initially started with the ws2812_spi driver, which worked. But this solution needs a minimum of two pins to configure SPI, the MOSI and CLK lines. Because I do not want to waste pins the GPIO solutions seems the only way to control the RGB LED using a single pin. I'm not fond of bit-banging my self as well, but for a single user LED it seems like a reasonable solution. Isn't is up to the end user to decide which driver to use, and if it fits the application? Perhaps the description of the driver should be extended to indicate these limitations? |
Sorry, I mean debugging as debugging the LED strip controller itself.
Yes you are right, it is up to the end user to decide which driver to use. But it's up to maintainers to decide which code makes sense to maintain :) The That's being said I am not sure what the right direction is and I'd like to hear from others.
Let's wait for others to express their opinion. |
Thanks for the explanation. I can understand perfectly if this driver is deprecated and phased out. If that's the case I suggest to update the documentation/description so developers are aware. If this is not the case I don't mind to extend it a bit and make the timing related parameters available in the device tree so it could be used in a more generic way. For me personally it's just about getting some hands on experience with Zephyr. Let me know what you want to do. |
I'm OK with this driver still being here, it's up to people to ensure if they use it that it works for their end application - for some applications this might be absolutely fine. Though should probably have a depends on/select for the instruction cache on nrf52x devices |
Agree
So I guess the question is how do we support the end user in making sure it 'works'. Do we only support (specific) hardware/SoC if we can guarantee its correct behavior, do we expect the end user to patch this driver them selves if not, do we extend the driver to make it configurable (using the device tree)? |
I am not against expanding the scope of support. However, if we extend it, we should replace it with more general-purpose logic. I don't think it's desirable to add #ifdef for each board. In this PR, the number of nop is changed, but is it possible to calculate it based on the clock frequency that can be obtained from dts? (We can use LOOPIFY macro here.) |
Thanks for your input. I was thinking about using the .rept directive to create a compile time loop of nop's. Could you provide a reference to the LOOPIFY macro, I couldn't find it. It shouldn't be to hard to supply the loop values using the device tree. I'm not sure how easy it is to calculate the values based on a clock frequency. As thedjnK indicated there can be optimizations (like caching) which could make these calculations impossible, although for some SoC's it might work. I wouldn't mind to make a first implementation based on the .rept directive which gets its value from dts, possibly calculating the default values derived from the clock frequency. |
It is a LISTIFY that is correct. Excuse me. https://docs.zephyrproject.org/apidoc/latest/group__sys-util.html#ga81cbc0233cf73048d65b76f716653af6 |
@chaim-zax, it would be a nice contribution. Thanks for your help |
Thank you for the clarification. I'll have a look after my (short) holiday and start on an implementation using LISTIFY. Shall I close this pull request and create a new one when I'm ready, or update this pull request? |
Frequently recreating the PR is not a good idea as it will make it difficult to follow the discussion process. |
d8a99f3
to
121cfb7
Compare
I've updated the pull request to see if I'm heading in the right direction. It's not the final pull request. I have tried to make the timing dynamic based on a clock frequency, unfortunately C macro's don't support arithmetic operations like division (e.g. CLOCK_FREQ / DELAY_T1H). The LISTIFY macro only works if the resulting count argument (LEN) is an integer, and not a formula. If anyone has some ideas how to solve this I would very much like to hear it. |
dc8d7c2
to
7ce785a
Compare
@thedjnK @simonguinot |
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.
Thanks for this pathc @chaim-zax. Please, see my comments below.
drivers/led_strip/Kconfig.ws2812
Outdated
|
||
config DELAY_T1H | ||
int | ||
default $(div,$(mul,750,$(dt_node_int_prop_int,/cpus/cpu@0,clock-frequency)),1000000000) |
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 would prefer to store delays in nanoseconds with these Kconfig options and let the driver do the conversion to number of nops. It would be nice to spare users these calculations :)
In addition, there are different WS2812 compatible models out there, with different timing specifications. For example, for the Everlight B1414 controller, each bit is described with a 1.2 us pulse:
- T0H: 300 ns
- T0L: 900 ns
- T1H: 900 ns
- T1L: 300 ns
So if the timings in nanoseconds can be configured here, then this would allow to use the ws2812_gpio
driver with these controllers.
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 would prefer to store delays in nanoseconds with these Kconfig options and let the driver do the conversion to number of nops. It would be nice to spare users these calculations :)
It is not possible by LISTIFY limitation.
The macro accepts only numeric value, and cannot calculate in C.
zephyr/include/zephyr/sys/util_macro.h
Line 428 in 3240b03
* @param LEN The length of the sequence. Must be an integer literal less |
The LISTIFY macro concatinate the argument to UTIL_LISTIFY_#ARG, so ARG must be a numerical literal.
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.
That's correct, the driver implements delays by adding (compile time) 'nop' asm instructions. The LISTIFY macro (which does this) can only do this with constant values. @soburi did a great job making this even possible by adding the option to use arithmetic functions to Kconfig files. Currently I don't see any other way of doing 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.
OK, then maybe we can have in Kconfig DELAY_T{0,1}{L,H}_NS
configured by user with values in nanoseconds (understandable by a human) and DELAY_T{0,1}{L,H}_NOP
hidden, with number of nops and selected/computed automatically from the previous options ?
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 don't think this will be a problem. I'll have a look. Although the cpu clock-frequency in the dts tree might not always be available.
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 answer.
Add frequency property to "worldsemi,ws2812-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.
Indeed, there is still an option to move some of these properties to the device tree. This would allow to do the calculations from nanoseconds to nop's as well (not the most pretty option, using both dts and Kconfig files), and possibly have a frequency option there too. @simonguinot what's your take on 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.
I don't think this will be a problem. I'll have a look. Although the cpu
clock-frequency
in the dts tree might not always be available.
Note that you can use a second default
as a fallback if the clock-frequency property is missing. For example:
default $(div,$(mul,750,$(dt_node_int_prop_int,/cpus/cpu@0,clock-frequency)),1000000000) \
if $(dt_node_has_prop,/cpus/cpu@0,clock-frequency)
default 12
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.
Indeed, there is still an option to move some of these properties to the device tree. This would allow to do the calculations from nanoseconds to nop's as well (not the most pretty option, using both dts and Kconfig files), and possibly have a frequency option there too. @simonguinot what's your take on this?
I understand the limitation. So we can't offer nanosecond configuration to the user but we have to stick to NOPs.
Here are my suggestions:
- we add new properties to the
ws2812-gpio
DT bindings to allow the user to configure the number of NOPs for the T0L, T0H, T1L and T1H periods. There is no reason for not offering DT configuration like the other ws2812 bindings. - we write a clear and user friendly description for these new properties. So the user will be able to configure them wisely :)
- we add the corresponding Kconfig options (as in your patch), with the first
default
set to the DT value, the second to a value calculated based on theclock-frequency
property (if available) and the ws2812 timings (as found in the specification) and a thirddefault
fallback set to an hardcoded value (also wisely chosen). And we allow the user to override these values from their own configuration.
How does that sound ? :)
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.
Sounds good, thanks for the feedback!
@soburi do you have any remarks on this, shall I just go ahead with the implementation as described here?
drivers/led_strip/Kconfig.ws2812
Outdated
int | ||
default $(div,$(mul,500,$(dt_node_int_prop_int,/cpus/cpu@0,clock-frequency)),1000000000) | ||
help | ||
inter-bit low pulse delay: 500 nsec |
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.
And we should probably use the WS2812 default values:
- T0H: 350 ns
- T0L: 800 ns
- T1H: 700 ns
- T1L: 600 ns
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 new implementation is based on the current (old) behavior of the driver, but I have no problem changing this. It makes sense to use the WS2812 default values. Aren't there concerns to break existing applications were this driver might already be in use?
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 there are. But we already crossed that bridge by using clock-frequency
to compute the default value...
The idea here is to salvage the driver by making it more generic and configurable. So I think the risk is acceptable. We'll try to minimize it by testing the new driver version with several WS2812-compatible controllers and several boards.
And of course we'll leave a note in the release notes :)
drivers/led_strip/Kconfig.ws2812
Outdated
if WS2812_STRIP_GPIO | ||
|
||
config DELAY_T1H | ||
int |
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.
Note that the prompt is missing on all these new options. And then the bbc_microbit
board configuration of the led_strip
sample can't be used:
$ west build -b bbc_microbit samples/drivers/led_strip
...
Merged configuration '/home/simon/src/zephyrproject/zephyr/samples/drivers/led_strip/boards/bbc_microbit.conf'
error: DELAY_T1H (defined at drivers/led_strip/Kconfig.ws2812:49) is assigned in a configuration
file, but is not directly user-configurable (has no prompt). It gets its value indirectly from other
symbols. See http://docs.zephyrproject.org/latest/kconfig.html#CONFIG_DELAY_T1H and/or look up
DELAY_T1H in the menuconfig/guiconfig interface. The Application Development Primer, Setting
Configuration Values, and Kconfig - Tips and Best Practices sections of the manual might be helpful
too.
CMake Error at /home/simon/src/zephyrproject/zephyr/cmake/modules/kconfig.cmake:389 (message):
command failed with return code: 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'll make sure this fix this, and do some better testing next time ;-)
7ce785a
to
571d915
Compare
@simonguinot @soburi I made an attempt to implement the solution suggested. Please let me know what 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.
Looks acceptable. Compliance needs fixing
description: Number of NOP assembly operations to create a 350 nsec delay for an 0 bit (high pulse) | ||
|
||
delay_t0l: | ||
type: int | ||
description: Number of NOP assembly operations to create a 800 nsec delay for an 0 bit (low pulse) |
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 0 bit
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.
Thanks, will fix.
Thanks @chaim-zax. I'll look at it soon. |
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.
It looks good to me ! I like it :) The driver is much more generic and configurable with this patch.
Please see below for few comments.
Also, I will play a bit with the driver on some of my boards.
571d915
to
7007654
Compare
…ndend The current driver contains assembly code which is specific for the nRF51 SOC which makes it incompatible with other SOC's. This patch adds support for other nRF SOC's as well. The timing is calucated based on the CPU clock frequency, but can be configured manually as well if needed. Changes have been verified on a Adafruit Feather nRF52840 Express board, which contains a single NeoPixel RGB LED. Timings have been verified using a scope connected to the WS1812 data line. Signed-off-by: Chaim Zax <chaim.zax@zaxx.pro>
7007654
to
7df7d30
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.
Good work !
Hi @chaim-zax! To celebrate this milestone and showcase your contribution, we'd love to award you the Zephyr Technical Contributor badge. If you're interested, please claim your badge by filling out this form: Claim Your Zephyr Badge. Thank you for your valuable input, and we look forward to seeing more of your contributions in the future! 🪁 |
The current driver contains assembly code which is specific for the nRF51 SOC which makes it incompatible with other SOC's. This patch adds support for the nRF52 SOC's as well. The change has minimal impact on existing code to make sure it's fully compatible with the nRF51.
Changes have been verified on a Adafruit Feather nRF52840 Express board, which contains a single NeoPixel RGB LED. Timings have been verified using a scope connected to the WS2812 data line.