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

Rewrite APA102 support #10894

Merged
merged 9 commits into from
Dec 30, 2020
Merged

Rewrite APA102 support #10894

merged 9 commits into from
Dec 30, 2020

Conversation

aldehir
Copy link

@aldehir aldehir commented Nov 8, 2020

Description

The APA102 source was broken by commit 16a15c1 as it did not include the quantum header. This PR addresses that, as well as other issues with transferring bytes over the SPI interface, i.e. it was not setting the clock pin back to low after sending a bit.

The deviation when sending the end frame is kept, but updated to the latest from the referenced project.

Additionally, these changes expose the global LED brightness parameter of the APA102. Brightness values are configurable through APA102_DEFAULT_BRIGHTNESS and APA102_MAX_BRIGHTNESS.

Question: Since it is using the QMK macros, does this still belong in under drivers/avr?

Types of Changes

  • Core
  • Bugfix
  • New feature
  • Enhancement/optimization
  • Keyboard (addition or update)
  • Keymap/layout/userspace (addition or update)
  • Documentation

Issues Fixed or Closed by This PR

Checklist

  • My code follows the code style of this project: C, Python
  • I have read the PR Checklist document and have made the appropriate changes.
  • My change requires a change to the documentation.
  • I have updated the documentation accordingly.
  • I have read the CONTRIBUTING document.
  • I have added tests to cover my changes.
  • I have tested the changes and verified that they work and don't break anything (as well as I can manage).

@github-actions github-actions bot added the core label Nov 8, 2020
@Duckle29 Duckle29 self-assigned this Nov 10, 2020
@Duckle29
Copy link
Contributor

I'll give this a look and test once my LEDs arrive. It seems I originally wrote this code, but it has never worked. Thanks for the PR 👍

drivers/avr/apa102.c Outdated Show resolved Hide resolved
@tzarc tzarc requested a review from a team November 16, 2020 03:20
@noroadsleft noroadsleft deleted the branch qmk:develop November 28, 2020 20:02
@tzarc tzarc reopened this Nov 28, 2020
@aldehir
Copy link
Author

aldehir commented Nov 29, 2020

Commit a906bed114c4919ec79e8ebecfe9cbc1412a9f75 adds a delay for ARM devices. From testing, it seems the APA102 LEDs cannot handle a pulse width less than 40 ns. I added a delay of 200 ns between clock high to low, just to be safe.

I did move the driver up a directory, since the avr directory no longer seemed appropriate. That being said, being in the drivers/ directory does not feel right either. I would appreciate some input on where this driver can live.

@Duckle29
Copy link
Contributor

Duckle29 commented Nov 29, 2020

@aldehir I'm interested in how you're testing this on QMK? Also while the nop based code is pretty neat, it's not that readable, instead I think wait_us(x) is preferred. Testing on AVR wait_us(0.1) gives me a bit over 200 ns wide clock pulses. Interestingly, testing this on an STM32F303 (proton-c), that doesn't seem to make much of a difference, the clock pulse is around 20 µs regardless.
image

The datasheet also seems to suggest that anything over 15ns is fine, what kind of behavior did you observer under 40ns?
image

Which ARM board did you test on, and which pins? 20 us is slow enough that I can see it "animate" on a ring of 40 LEDs so I'd like to get it lower than that :(
https://gfycat.com/linearselfreliantgermanpinscher (Proton-c with no delay, 8x slower)

I also opened a PR against your fork to get this driver situated in a generic location, and tied in to the make build system :) aldehir#1

I'm curious if you can work your changes into that and report back how it performs? :)

Thanks :)

@Duckle29
Copy link
Contributor

I also did some maths, and for a board with 100 LEDs, you have about 40 µs per bit if you want to hit 60fps refresh rate, however that doesn't account for dwell time, so I'd say a goal of 10 µs for the send-bit function would be neat :)

@aldehir
Copy link
Author

aldehir commented Nov 29, 2020

@Duckle29 I hooked up an oscilloscope to the clock output (pin B5), and observed the following:

At < 40 ns the LEDs do not function as expected. Video
lt40_delay

At > 40 ns the LEDs light up just fine. Video
gt40ns_delay

I also noticed that a wait_us() on my STM32F303 discovery board does not go lower than 20 us, mimicking your findings. I found this article that provides some insight. Using with a custom chconf.h, I was able to lower that to 10 us by increasing CH_CFG_ST_FREQUENCY from 100 KHz to 1 MHz. Unfortunately, even that seems too slow for animation effects. I could not find a way to reduce that without resorting to busy looping with NOPs. I'm open to suggestions!

@Duckle29
Copy link
Contributor

Yeah after playing more with it today I agree with your findings. I've made a few changes and described the reasons in the PR against your fork (linked above) :)

The APA102 source was broken by commit 16a15c1 as it did not include the
quantum header. This commit addresses that, as well as other issues with
transferring bytes over the SPI interface, i.e. it was not setting the
clock pin back to low after sending a bit.

The deviation when sending the end frame is kept, but updated to the
latest from the referenced project.

Finally, these changes expose the global LED brightness parameter
of the APA102. Brightness values are configurable through
`APA102_DEFAULT_BRIGHTNESS` and `APA102_MAX_BRIGHTNESS`.
Copy link
Contributor

@Duckle29 Duckle29 left a comment

Choose a reason for hiding this comment

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

Apart from the requested changes. I also saw that the headers on the apa102.[c|h] files were wrong, so those should be updated.

Something simple like

/* Copyright 2020 you
 * Copyright 2017 Mikkel (Duckle29)
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

on both files should do

I'd also suggest adding the changes to keyboards/handwired/onekey I made in my PR. They make testing easier and gives a target that you can test compilation against with a simple make handwired/onekey:apa102

I'd add the clock pin definition on pro micro, elite-c and proton-c, and add an apa102 keymap.

add to proton_c config.h (B13 was chosen as it's the next available pin close to DI)

#define RGB_CI_PIN B13

add to pro micro and elite_c config.h (B1 was chosen as it's the same position as the proton_c pin chosen)

#define RGB_CI_PIN B1

And for the keymap, copy the rgb folder and rename it apa102, change the rules.mk file to RGBLIGHT_ENABLE = APA102
in keymap.c add

#include QMK_KEYBOARD_H
#include "apa102.h" // Only needed if you want to use the global brigthness function
// ...
void keyboard_post_init_user(void) {
    apa102_set_brightness(5);
// ...

As for the loop unrolling. I'm okay with leaving that as is, it does cost 74 bytes, which for some on AVR might be a problem, but as no-one is currently relying on this driver for AVR boards, it's fine.

common_features.mk Outdated Show resolved Hide resolved
common_features.mk Outdated Show resolved Hide resolved
common_features.mk Outdated Show resolved Hide resolved
Copy link
Contributor

@Duckle29 Duckle29 left a comment

Choose a reason for hiding this comment

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

I like it, and it compiles and runs, and doesn't seem to clash with ws2812! :)

@Duckle29 Duckle29 requested a review from tzarc December 3, 2020 01:52
@bhartshorn
Copy link

bhartshorn commented Dec 28, 2020

I've been fighting with the old driver all afternoon before noticing this PR. I'll give your work a test drive on Pro Micro. 👍

EDIT: Works great for solid colors, haven't tested any other modes (don't really need/want, not sure I have space). Good work, should merge if there's no outstanding complaints.

@aldehir @tzarc

Copy link
Member

@zvecr zvecr left a comment

Choose a reason for hiding this comment

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

wrong radio button woops

Copy link
Member

@zvecr zvecr left a comment

Choose a reason for hiding this comment

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

Not a fan of the apa102 parent folder, but that can be fixed once its in develop.

@zvecr zvecr merged commit 4f2f21d into qmk:develop Dec 30, 2020
BorisTestov pushed a commit to BorisTestov/qmk_firmware that referenced this pull request May 23, 2024
* Rewrite APA102 support

The APA102 source was broken by commit a9831d3 as it did not include the
quantum header. This commit addresses that, as well as other issues with
transferring bytes over the SPI interface, i.e. it was not setting the
clock pin back to low after sending a bit.

The deviation when sending the end frame is kept, but updated to the
latest from the referenced project.

Finally, these changes expose the global LED brightness parameter
of the APA102. Brightness values are configurable through
`APA102_DEFAULT_BRIGHTNESS` and `APA102_MAX_BRIGHTNESS`.

* Fix typo in led brightness extern

* Move driver out of AVR directory and add delay for ARM

* Experimental APA102 support on AVR and ARM

Co-authored-by: Alde Rojas <hello@alde.io>

* Refactor apa102_send_byte() calls to a loop

* Implement io_wait function for ARM

* Move APA102 drivers to own directory, fix copyright notice

* Add APA102 keymap to handwired/onekey

* Simplify RGBLIGHT_ENABLE/DRIVER option handling

Co-authored-by: Mikkel Jeppesen <2756925+Duckle29@users.noreply.github.com>
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.

8 participants