Skip to content
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: modernize ws2812 drivers #20393

Merged
merged 1 commit into from
Dec 11, 2019

Conversation

mbolivar
Copy link
Contributor

@mbolivar mbolivar commented Nov 6, 2019

This is the only led_strip driver using GPIO.

@jhedberg are you still using this, btw?

@mbolivar
Copy link
Contributor Author

mbolivar commented Nov 6, 2019

@mnkp this driver is exactly why I would like to have a "fast" gpio API, for reference.

Copy link
Collaborator

@pabigot pabigot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks trivial, but I believe the desire is to take advantage of the fact we're touching these drivers to also complete the conversion to devicetree at the same time.

Looking at this my immediate questions are "what's the active level" (which would normally be or'd in from the devicetree node), and "should this be GPIO_OUTPUT_INIT_LOW or _HIGH".

@mbolivar
Copy link
Contributor Author

mbolivar commented Nov 6, 2019

This looks trivial, but I believe the desire is to take advantage of the fact we're touching these drivers to also complete the conversion to devicetree at the same time.

If I'm going to do that, I want to know if people think I should create a unified set of bindings for this and the other driver for the same LED strip.

Apart from the GPIO driver there is also a SPI driver for the same hardware. I was thinking of unifying the bindings similarly to how devices with I2C or SPI based drivers work (e.g. https://elixir.bootlin.com/linux/latest/source/Documentation/devicetree/bindings/iio/accel/lis302.txt).

Worth doing?

@pabigot
Copy link
Collaborator

pabigot commented Nov 6, 2019

Worth doing?

I couldn't say. The bitbang implementation seems significantly more limited than the SPI one, e.g. wrt pixel order. If the bindings are unified, should we try to support common functionality, or just blow up if the devicetree properties don't match the implemented behavior? Is there value in evolving the bitbang driver or is it obsolete so we should deprecate it and let it expire unmolested (beyond the minimal necessary changes currently in this PR)?

If it's worth enhancing it then a unified binding seems to make sense. E.g. the way lis2dh (or eeprom in #19972) is done where the interface yaml includes common yaml.

@jhedberg
Copy link
Member

jhedberg commented Nov 6, 2019

@jhedberg are you still using this, btw?

@mbolivar not actively, but I do have the HW. It was used for some micro:bit demos: https://www.kitronik.co.uk/5625-zip-halo-for-the-bbc-microbit.html

@mbolivar
Copy link
Contributor Author

mbolivar commented Nov 6, 2019

Is there value in evolving the bitbang driver or is it obsolete so we should deprecate it and let it expire unmolested (beyond the minimal necessary changes currently in this PR)?

I ultimately want the bit-banging driver to be the "main" driver, but I can't do that portably without fast generic GPIO routines, which of course we have deferred work on. (The SPI driver's use of memory is an obscenity, but it's the only portable way to manage this thing that I could find within Zephyr's current driver APIs.)

So I guess what I'll do is create a separate binding for the SPI driver, and let the bit-bang driver take the main worldsemi,ws2812 compatible. That will be a breaking change, but I don't think anybody's using this stuff. I just wrote it for fun a while ago.

@mbolivar not actively, but I do have the HW. It was used for some micro:bit demos: https://www.kitronik.co.uk/5625-zip-halo-for-the-bbc-microbit.html

OK, let's keep it then, and generalize it when we have the GPIO driver API to make it possible to get rid of the inline assembly.

@sslupsky
Copy link
Contributor

Stumbled across this issue today. You may want to have a look at this repo if you are not already familiar with it. Looks like a pretty well used and designed led driver api.

https://github.com/FastLED/FastLED

@mnkp
Copy link
Member

mnkp commented Nov 12, 2019

This driver would be a good testcase for fast GPIO API (yes, we need it).

The PR could be approved as is, but @mbolivar if you're planning to add DTS bindings we're going to wait :-)

@mbolivar
Copy link
Contributor Author

The PR could be approved as is, but @mbolivar if you're planning to add DTS bindings we're going to wait :-)

I'm halfway done with this. I have the SPI driver "fully" dt-ized (right now the conversion was only partial) and still need to do the DT one.

I'll try to get this done tomorrow.

@mbolivar
Copy link
Contributor Author

Stumbled across this issue today. You may want to have a look at this repo if you are not already familiar with it. Looks like a pretty well used and designed led driver api.

https://github.com/FastLED/FastLED

Thanks for the pointer.

We are familiar with that library -- you can see the discussion in #11917 for details, for example it is mentioned here:

#11917 (comment)

FastLED makes extensive use of C++ templates to get its job done, though, so we need a different approach for Zephyr.

@sslupsky
Copy link
Contributor

Thank you @mbolivar for the link. Interesting read indeed.

I do not quite understand the meaning of your last comment regarding C++. Is Zephyr not intended to be used in a C++ environment?

@pabigot
Copy link
Collaborator

pabigot commented Nov 13, 2019

By policy Zephyr currently disallows use of C++ except within applications, so it's not suitable for a raw GPIO interface.

@mbolivar
Copy link
Contributor Author

Right -- we can only use C (and assembly) from drivers, which is the layer we're discussing here.

@jfischer-no
Copy link
Collaborator

Right -- we can only use C (and assembly) from drivers, which is the layer we're discussing here.

I would be happy if this driver continues to use assembler, it is a very nice example.

@mbolivar
Copy link
Contributor Author

I would be happy if this driver continues to use assembler, it is a very nice example.

I would be unhappy if the driver continues to use assembler :).

It is not portable. This implementation is nrf51 only.

@jfischer-no
Copy link
Collaborator

I would be happy if this driver continues to use assembler, it is a very nice example.

I would be unhappy if the driver continues to use assembler :).

It is not portable. This implementation is nrf51 only.

a) anyway a good example b) can be made portable, at least for Cortex-Mx

@mbolivar
Copy link
Contributor Author

I would be happy if this driver continues to use assembler, it is a very nice example.

I would be unhappy if the driver continues to use assembler :).
It is not portable. This implementation is nrf51 only.

a) anyway a good example

drivers/ is not a place for example code.

b) can be made portable, at least for Cortex-Mx

The point of #11917 is to make the GPIO portions portable for all devices supported by zephyr, not just some.

The nop-loops in the assembly are not GPIO related of course, but I see the precision timeout work that was recently merged as a good starting point for making that portable too, also without assembly.

@jfischer-no
Copy link
Collaborator

The nop-loops in the assembly are not GPIO related of course, but I see the precision timeout work that was recently merged as a good starting point for making that portable too, also without assembly.

I think it would not help, you need to lock interrupts anyway to fulfill the timings.

@mbolivar
Copy link
Contributor Author

mbolivar commented Nov 13, 2019

The nop-loops in the assembly are not GPIO related of course, but I see the precision timeout work that was recently merged as a good starting point for making that portable too, also without assembly.

I think it would not help, you need to lock interrupts anyway to fulfill the timings.

Of course you need to call irq_lock() while you are sending the pulses.

My point is that now we have a portable way to convert nanoseconds to cycles, e.g. k_ns_to_cyc_ceil32(). That feels like a necessary ingredient to know how to portably halt while generating the pulse. Am I missing something here?

@jfischer-no
Copy link
Collaborator

jfischer-no commented Nov 13, 2019

My point is that now we have a portable way to convert nanoseconds to cycles, e.g. k_ns_to_cyc_ceil32(). That feels like a necessary ingredient to know how to portably halt while generating the pulse. Am I missing something here?

No, that is indeed great, I plan to use it in bit-bang swd driver to determine the number of nops. But TBH I have no idea how it would be useful to use it with C code.

@mbolivar mbolivar changed the title drivers: led_strip: convert ws2812b_sw to new GPIO API [DNM] drivers: led_strip: convert ws2812b_sw to new GPIO API Nov 14, 2019
@mbolivar
Copy link
Contributor Author

kicking ci

@mbolivar mbolivar reopened this Nov 19, 2019
@mbolivar mbolivar force-pushed the topic-gpio branch 2 times, most recently from aa9d226 to c98ab1a Compare November 20, 2019 19:36
@mbolivar
Copy link
Contributor Author

@mnkp please take another look at ws2812_gpio.c when you get a chance. I've made it multi-instance, but deleted the color channel order control. If that's OK for you I'll update the SPI driver in the same way and we should be good to go.

Thanks!

@mbolivar
Copy link
Contributor Author

@jhedberg I've moved the assembly around a bit so it'll be easier to swap out when we get the "fast gpio" routines. In doing so, I noticed that this constraint also looked incorrect:

				[p] "r" (pin)

This should be "l", not "r", AFAICT: the Arm ARM I checked said both Rd and Rn need to be r0-r7 for the str instruction. Mostly an FYI, but please check if you want.

@jhedberg
Copy link
Member

@mbolivar looks nice and clean! Are you verifying the correctness of the generated signal with actual HW, a logic analyser, or some other way? I'll try to find some time to test this PR on the ZIP Halo I have.

@mbolivar
Copy link
Contributor Author

@mbolivar looks nice and clean!

Thanks!

Are you verifying the correctness of the generated signal with actual HW, a logic analyser, or some other way? I'll try to find some time to test this PR on the ZIP Halo I have.

I've got a Saleae hooked up to an nrf51_pca10028 for GPIO driver timing.

  • 0 bits are ~.35 usec wide
  • 1 bits ~0.85 usec
  • inter-bit times are 1.25-1.6 usec depending on the transition

The 1 bits are pushing the limit if you believe the datasheet, but are well within the empirical limits in the blog post. I could drop a nop from T1H if you'd like to make that tighter.

I am also visually testing on a 16 pixel GRBW ring from Adafruit.

@mbolivar mbolivar added the DNM This PR should not be merged (Do Not Merge) label Nov 21, 2019
@mbolivar
Copy link
Contributor Author

Marked DNM until @mnkp has a chance to review, since I need to make SPI driver changes depending on his response.

@mnkp
Copy link
Member

mnkp commented Nov 22, 2019

@mbolivar looks nice and clean!

I second! Sorry for a delayed review, not much free time these days.

@mbolivar
Copy link
Contributor Author

Sorry for a delayed review, not much free time these days.

No problem! There was no rush, I just didn't want it merged halfway done.

I've updated the SPI driver to match the GPIO changes. I had to put back the Kconfig file in the led_ws2812 sample to make the build system select the SPI driver by default.

Leaving DNM on for now as I'm traveling for a US holiday and won't re-test the SPI driver until next week.

Copy link
Member

@mnkp mnkp left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM with minor comments.

drivers/led_strip/ws2812_spi.c Outdated Show resolved Hide resolved
drivers/led_strip/ws2812_spi.c Show resolved Hide resolved
drivers/led_strip/Kconfig.ws2812 Show resolved Hide resolved
drivers/led_strip/ws2812_gpio.c Show resolved Hide resolved
Convert the GPIO based driver to the new GPIO API. (Only the
gpio_configure() call is affected).

Move configuration to DT where appropriate for both SPI and GPIO
drivers, only leaving the SPI vs. GPIO decision in Kconfig (in
addition to the basic enable for the driver.) Move some files around
to clean up as a result of this change.

led_ws2812 sample changes:

- make the pattern easier to look at by emitting less light

- use led_strip alias from DT to get strip device, allocate
  appropriate struct led_rgb buffer, etc.

- move the pins around and remove 96b_carbon support (I have no board
  to test with)

GPIO driver specific changes:

- str is required to write OUTSET/OUTCLR, not strb. The registers
  are word-sized.

- the str[b] registers must all be in r0-r7, so "l" is the correct GCC
  inline assembly constraint for both "base" and "pin"

SPI driver specific changes:

- match the GPIO driver in not supporting the update_channels API
  method, which never made sense for this type of strip

- return -ENOMEM when the user tries to send more pixel data
  than we have buffer space for instead of -EINVAL

Signed-off-by: Martí Bolívar <marti.bolivar@nordicsemi.no>
@mbolivar mbolivar added area: GPIO and removed DNM This PR should not be merged (Do Not Merge) labels Dec 4, 2019
@mbolivar
Copy link
Contributor Author

mbolivar commented Dec 4, 2019

I've retested on nrf51_pca10028 and nrf52_pca10040, so removing DNM.

@mnkp I've responded to your comments, please take another look when you get a chance.

@galak galak merged commit 7288603 into zephyrproject-rtos:topic-gpio Dec 11, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

10 participants