-
Notifications
You must be signed in to change notification settings - Fork 1.3k
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
Initial Apollo3 Implementation #205
base: master
Are you sure you want to change the base?
Conversation
@oclyke please test and review this PR, thank you! |
@oclyke @santaimpersonator hiya please let me know the right person at sparkfun or ambiq to review this PR, thank you :) |
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.
Generally looks good, but the mapping between Arduino "pin" and Apollo3 "pad" needs to be implemented.
Adafruit_NeoPixel.cpp
Outdated
pin = p; | ||
#if defined(AM_PART_APOLLO3) | ||
apollo3SetPin(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.
After updating the pin
variable either pin
or p
can be used to refer to the new pin number. The usage in the standard pinMode
call uses p
while the specialized call for Apollo3 uses pin
. This may be more confusing/harder to maintain in the future. Because p
is already in use my rec. would be to use p
in the specialized call 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.
Agreed, although now I'm modifying the value of p
to the Apollo3 mapped pad, which might also be slightly confusing.
apollo3.cpp
Outdated
@brief Set the NeoPixel output pin number. | ||
@param p Arduino pin number (-1 = no pin). | ||
*/ | ||
void Adafruit_NeoPixel::apollo3SetPin(uint16_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.
As written this function will likely confuse users b/c NeoPixel output may be mapped incorrectly. The input parameter here is the Arduino pin while the calls to am_hal_gpio_xxx
expect the Apollo3 pad number. The mapping is dependent on the board variant and uses ap3_gpio_pad_t ap3_gpio_pin2pad(ap3_gpio_pin_t pin);
which is available wherever "Arduino.h" is included.
This applies to any/all cases in this file where the pin is passed directly into an Ambiq HAL function.
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 decided to apply the pin-to-Apollo3 pad mapping in the Adafruit_NeoPixel.cpp setPin
function. That way, the mapping only needs to be performed a single time instead of every Ambiq HAL function, and we can avoid that extra function call in every show()
.
@ladyada thanks for the reminder :) |
Signed-off-by: Carey Sonsino <[email protected]>
@oclyke I found a pretty slick way to implement the timing using a Table 818: Counter/Timer Pad Configuration in the Apollo3 Blue Datasheet shows the possible pad-to-timer configurations:
I admittedly do not fully grasp the I see a bunch of possibly useful stuff with the I guess I'm just wondering if you have any suggestions on how I might automatically configure the |
I'm going to look into a different strategy. Even though I really like this |
@csonsino excellent work! It shows that you've taken the time to develop a good solution. Thanks! I too have struggled with the PWM peripherals... I'll see if I can convey what I learned. Automatic Configuration Based on PadYou're spot-on that the tables in Now of course the Apollo3 Arduino core is still pretty alpha and I can't guarantee anything but what I'd suggest doing is trying to see if you can use It is also possible that I could make those copies of the tables public and that you (and others in the future) could use them how you please. I'm not sure yet if there is any major reason not to do that. Secondary OutputsFirst of all there are only 32 PWM capable pads on the Apollo3 so the user will already need to make sure they are connecting to a supported pin - but it turns out that only 16 of those outputs can be completely independent of one another. It took me a lot of read-throughs of the ctimer section of the datasheet to understand this but effectively the secondary output has to share a common period with the primary output. This makes it very challenging (impossible?) to write BLE InterferenceOkay so obviously we will need to keep track of where all our dedicated interrupt vectors are headed (defined) but that's another problem for another day. Do you know what the BLE code is using the ctimer for (I can't look into it RN and I only remember seeing it as a cursory glance). The reason I ask is because I am working on porting mbed os for the Apollo3 and depending on the resolution needed for BLE the ctimer could possibly be replaced by a software timer / thread. Keep up the great work and let me know if there is anything useful that we could collaborate on within the core itself. |
Great, I think that the code in the The big problem that I keep running into is clock speed. I almost need access to the full 48MHz clock in order to schedule things appropriately. With the 12MHz clock, it's tough to do anything else when I need to schedule an interrupt 5 clock cycles away. Half a microsecond timing is not easy. With such few cycles to spare, even function call overhead becomes significant. Forget trying to also process BLE stuff. I'm crossing my fingers that the mbed os port solves some of the timing issues. It's possible that multithreading would make things work better together. As far as the current BLE example code, if I'm interpreting it correctly I believe that it's using the ctimer as the reference for the wsf framework (Wicentric Software Foundation BLE stack). That stack might be using the timer to keep track of all BLE related functions- beacons, connection intervals, etc. |
I haven't gotten to take a look at your data output method yet. How exactly are you utilizing the CTimer module? Are you shifting out the data one bit at a time? Is there possibly a way to schedule a series of bit sequences all in hardware? If you could give me a quick overview of your method that would be helpful. I'm not sure that the mbed port will make this problem any easier - especially if the data output is not handled primarily in HW. I only see it adding a lot of overhead in task switching. There's a method of driving one-wire LEDs that I have wanted to try out for quite some time but have never gotten around to -- it might be worth looking into here. That is to use a SPI port and send out a pattern on MOSI that matches the necessary timing. For example WS2812 LEDs have T1H, T1L, T0H, and T0L timing to account for. The GCD of those times is 0.05 us, which is the width of a single bit on a 20 MHz SPI transmission. The WS2812 datasheet says that TH+TL is roughly constant for 1's and 0's so we might assume that they should be 1.2 us wide each. Then each 1 or 0 code would be comprised of 24 bits of SPI data. At 20 MHz: So then one byte of LED data would take 3*8 = 24 bytes of data to be sent out over SPI. At first this seems like far too much overhead but the advantage is that the SPI transfer can be run by DMA. A small-ish buffer (say 240 bytes or so) could be pre-filled with the necessary codes to control 10 LEDs, then while that data is transferred out a second buffer could be filled with data for the next 10 and so on. Filling buffers would not take long provided the desired LED data. Let me know what you think - I've wanted to try this method out for quite some time but never got around to it. |
I tried to run in an Artemis ATP with Adafruit Neopixel 16 led ring (and a logic level shifter) without success. Compiles without errors but leds don't lit up. |
I'm not sure what the ATP is doing, but from my experience if the application loop is doing anything other than controlling the LEDs, then they won't light up. I have implemented the I've been trying to find the time to investigate the solution suggested by @oclyke, but haven't gotten to it yet. Other microcontrollers with slower clocks can deal with LED control and BLE at the same time (my particular need), so this seems like it should be a solvable problem. |
Well, I just installed the library from your forked repo and tried to run the "simple" example, using a 16 LED ring from adafruit. The version I installed is the one with the noop method. I saw a couple of libraries that implemented a method of sending data using DMA and hardware SPI. They implemented a conversion where the "1 bits where replaced by "110" and the "0" bits to "100", then send these stream over SPI. Since the neopixels use HI pulses for one and zero they could adjust the spi clock about 3 times the led clock and let the SPI chip do the heavy lifting. The drawback is that it uses 3 times more RAM. Do you think we can implement something similar in the artemis board? |
@ernestocurty Yes I think that is a worthwhile pursuit. Using 3x the ram would be acceptable if you could use a small(ish) buffer to push out the next N led's data. (see here) I won't personally be able to get to this for quite a while. In the meantime if you or anyone else could tack onto this PR that would be great! |
@oclyke, I believe this is task is above my humble coding skills, but with some support (e.g. some references to read) I may be able to embrace it. For the immediate needs of my project I'll test the APA102 LEDs. Since they run in standard SPI protocol, they may be easier to get running |
@oclyke, I apologize for missing your explanation for the same theme in the previous answer. |
@ernestocurty Don't worry 'bout it! I'll keep an eye out here to see how it goes. I don't have any fantastic resources to share above/beyond the respective datasheets but if you get your feet wet with SPI on the APA102s then that would be a good foundation for the WS2812s I think. |
Unable to compile for ArtemisATP....need help for pin definition |
I came across this(https://github.com/konkers/light_stick) and thought it might help anyone working on trying to adapt the Apollo3 to use SPI to improve the timing issues. After I have a good rest, I may try to see if I can make this work with what @csonsino has done as I'd love to get my artemis thing plus running some audio reactive projects. |
Hmmm. I don't know if I would merge that. It's a proof of concept, and I never quite got it working in an application that included any other functionality. A while back I attempted @oclyke's SPI MOSI suggestion but I didn't have much success. I'll see if I can dig up that code & take a look with an o-scope. |
okidoke, just checkin in on some old PRs :) please let me know when it could be ready for merging. we could try adding apollo3 to our CI as well once ready |
Is there any progress? I still failed to light a ws2812 on apollo3 board. Neopixel with
Does not light it. FastLED get only white and green(?). |
This change adds initial Apollo3 support.
The majority of the functionality is contained in the new
apollo3.cpp
file, but some minor modifications were made toAdafruit_NeoPixel.cpp
in thesetPin()
function (support for Apollo3 fast GPIO configuration). Function prototypes were added toAdafruit_NeoPixel.h
.Changes to existing code have been wrapped in a
AM_PART_APOLLO3
definition check, so existing platforms should not be affected.I would note that this is a very initial implementation, using the
noop
timing hack. I would prefer to have a more robust timing implementation (interrupts, DMA, etc). We should be able to put this out there for folks to use in the short term, and transparently swap out the timing implementation when a better solution is in place.This code was tested using a SparkFun RedBoard Artemis Nano, with the
simple
andstrandtest
example apps.