Closed sebglatz closed 1 year ago
@davids5 do you have any hints on how to debug this?
Did you get any further with this? running into similar issues
Did you get any further with this? running into similar issues
@FrankvVeelen What hardware do you have exactly and what are you seeing? Specific lights, flight controller, how it's connected, etc.
I have a PX4 FMU v6x without IO controller. The neopixels are connected to PWM_FMU7
and PWM_FMU8
via a level translator (from 3.3V to 5V) What i have done is, starting with a "clean" release 1.13.2 repository EDIT: (commit 2295ee91649f30f6135139ff38be5289ec2d5246
):
#define BOARD_HAS_N_S_RGB_LED 4
// # define S_RGB_LED_CHANNELN 1 / channel 2N /
- Add the following to default.px4board:
CONFIG_BOARD_COMPILE_DEFINITIONS="-DUSE_S_RGB_LED_DMA" CONFIG_DRIVERS_LIGHTS_NEOPIXEL=y
This then doesn't compile because of a change in ```stm32_dmasetup```, so i rewrote
// stm32_dmasetup(dma_handle, // _TIM_REG(STM32_GTIM_DMAR_OFFSET), // (uint32_t) bits, // arraySize(bits), // SLED_DMA_SCR);
into:
struct stm32_dma_config_s config; config.paddr = _TIM_REG(STM32_GTIM_DMAR_OFFSET); config.maddr = (uint32_t) bits; config.ndata = arraySize(bits); config.cfg1 = SLED_DMA_SCR; config.cfg2 = 0; stm32_dmasetup(dma_handle, &config);
Which then didn't compile because of ```DMAMUX1_TIM12_CH1``` didn't exist.
I have very little knowledge of STM32s and DMA, but I figured I'd try changing an unused DMA map to be ```DMAMUX1_TIM12_CH1```. I then got it to compile, but it throws hardfaults everytime I do ```neopixel start``` in the mavlink console.
@FrankvVeelen Did you validate that the dma_handle
from stm32_dmachannel(S_RGB_LED_DMA);
is not null?
Where did DMAMUX1_TIM12_CH1
come from? I do not see a DMA source from TIM12 in arch/arm/src/stm32h7/hardware/stm32h7x3xx_dmamux.h
Also is It needs to be a in a DMAMAP_DMA12_XXXX like entry to provide a DMA{1|2} and a mux
Hey @davids5 , thanks for taking a look at the problem. DMAMUX1_TIM12_CH1
was my shot in the dark at trying to get it to work, since DMA TIM12 does not seem to exist. Thanks for the pointer to DMAMAP_DMA12_XXXX
!
Here is where I'm at now: I have for now changed the part in my board_config.h to:
# define S_RGB_LED_DMA DMAMAP_DMA12_TIM1CH2_1
# define S_RGB_LED_TIMER 1 /* timer 12 */
# define S_RGB_LED_CHANNEL 2 /* channel 1 */
// # define S_RGB_LED_CHANNELN 1 /* channel 2N */
# define S_RGB_LED_TIM_GPIO GPIO_TIM1_CH2OUT_2 // GPIO_TIM12_CH2OUT_2
In my understanding this should result in a LED control on PWM_FMU3
. The code now compiles, and the FCU doesn't crash upon neopixel start
. However the LEDs are also not driven.
I have verified that the dma_handle
is not null. At the moment I do not have access to a scope, but i will at a later moment. Is there any other way to verify that "something" is actually happening?
Another question I have: Since I have already produced a few PCBs for the flight controllers, I'm kind of stuck with using FMU7 & FMU8 for two different sets of LEDs. Both of those use TIM12. Is it not possible to use DMA with TIM12? Would it be possible with some changes in software, or is there a hardware limitation in the stm?
Hey @davids5 , thanks for taking a look at the problem.
DMAMUX1_TIM12_CH1
was my shot in the dark at trying to get it to work, since DMA TIM12 does not seem to exist. Thanks for the pointer toDMAMAP_DMA12_XXXX
!Here is where I'm at now: I have for now changed the part in my board_config.h to:
# define S_RGB_LED_DMA DMAMAP_DMA12_TIM1CH2_1 # define S_RGB_LED_TIMER 1 /* timer 12 */ # define S_RGB_LED_CHANNEL 2 /* channel 1 */ // # define S_RGB_LED_CHANNELN 1 /* channel 2N */ # define S_RGB_LED_TIM_GPIO GPIO_TIM1_CH2OUT_2 // GPIO_TIM12_CH2OUT_2
In my understanding this should result in a LED control on
PWM_FMU3
. The code now compiles, and the FCU doesn't crash uponneopixel start
. However the LEDs are also not driven. I have verified that thedma_handle
is not null. At the moment I do not have access to a scope, but i will at a later moment. Is there any other way to verify that "something" is actually happening?
There are only 8 channels per DMA see for the utilization for the DMA . Yow may need trade off one of the DMA2 selections Maybe the debug console
Another question I have: Since I have already produced a few PCBs for the flight controllers, I'm kind of stuck with using FMU7 & FMU8 for two different sets of LEDs. Both of those use TIM12. Is it not possible to use DMA with TIM12? Would it be possible with some changes in software, or is there a hardware limitation in the stm?
Refer to DMAMUX1, DMA1 and DMA2 connections in the STM32H7 reference manual. I think only tim12_trgo
is supported. IIRC the code needs to do synchronous update on the DMA request from the compare request and that is not wired to the DMA mux.
I am not sure what your application is, to advise you on how to solve the issues.
Hey there again,
I have got it "working" with PWM_FMU5
. The leds turn on and respond to changes. The problem I'm still having is that the reset part of the protocol does not seem to work. I have got access to my oscilloscope today, and i can see all bits being transmitted as they should be, but the reset voltage seems to be randomly high or low (the time in between bits being sent).
Looking at the code I dont see any obvious way in which this bit would be set either, do you have an idea how it should be set? If needed I can provide some oscilloscope shots.
@FrankvVeelen It has been a while since worked on this. I though it is was the lack of a transition that constituted a reset. Do you have the datasheet?
I understand @davids5 . Thanks for your time providing this support. These are the "official" Adafruit ones. The datasheet specifies a "low voltage time" of >50us. The specific ones i use are a little bit different WS2812B-V5 and specify a "low voltage time" of >280us. All different versions I looked at do specify a low voltage time. It could of-course be the case that some modules do allow a no-transition time, but it's not what the spec says.
Maybe we could add driving the voltage low on the dma_callback, or somehow make sure that the last bit drives the output low? If you have any advice on what would be the best way to drive the output low in between packets, I can test it on my setup. I will also test with some official adafruit neopixels to see if they behave any different.
Ok it is bad memory on my part....So it needs to be low. The toggle happens on compare. So 2 things might be happening:
1 )There is is comment: * [hi][lo]:{8 * 3 * 8} [ffff] Last DMA will set the output low
Note line 407 memset(bits, 0, sizeof(bits));
and you try to set it to memset(bits, 0xff, sizeof(bits));
2) The DMA completion is happening before the timer finishes and disabled the timer. The solution could be adding 1 more 16 bit word to bits and DMA all of bits but populate only the date in uint32_t i = 0, leds = 0; i < arraySize(bits) - 2
Hey @davids5, that works to pull the line low in between transfers. I have found one more issue now though, which is that the data seems to be buffered somewhere and the timing seems to be off.
When i use led_control off
in the mavlink console, the very first bit is updated to low, but the other bits aren't. If i repeat led_control off
it turns all bits off. If i then do led_control on
it only turns on the 1st bit. If i repeat led_control on
it turns all bits on.
Furthermore, there seem to be 9 bits for the first LED, instead of 8. It seems that this is a timing issue, but playing with the size of bits
doesn't seem to work.
Any idea what this could be?
Could it be Line 387. Preloading the first bit? , try writing it to a 1 (SLED_rCCR = 1);
To see what the code is doing you can use the PROBE() macros. see board.h but avoid the FMU channel you are using! Adding PROBE(1,0) before the stm32_dmastart
and PROBE(1,1); in the dma_callback
will help to see the timing relative to the bit stream.
Hello again @davids5 :). Setting SLED_rCCR = 0xFFFF;
has fixed the 9th bit problem. Another problem I had was "random" glitches in the output, which I fixed by not initializing the channel I'm using as PWM output channel.
The output looks great now, and the LEDs are breathing happily :). I think I am now at the final issue: when adding neopixel start
to either rc.board_defaults
or rc.sensors
the driver makes the first led green and then seems to crash. The driver reports to be controlling the leds when calling neopixel status
, but no output is send to the gpio. The driver also doesn't respond well to neopixel stop
, resulting in a timeout. If I then restart the driver with neopixel start
the FCU crashes and restarts, once again turning the first LED green.
Maybe the driver is started before some of its' resources become available? If so could we delay starting the driver? I don't need the driver during startup.
@FrankvVeelen, it could be an issues with the pwm output driver. To test it try adding a return 0;
to the main. extern "C" __EXPORT int pwm_out_main(int argc, char *argv[]);
If not, then it is time to debug the hardfault.
@FrankvVeelen Also what are all the DMA assignments?
Hey there again, I have got it "working" with
PWM_FMU5
. The leds turn on and respond to changes. The problem I'm still having is that the reset part of the protocol does not seem to work. I have got access to my oscilloscope today, and i can see all bits being transmitted as they should be, but the reset voltage seems to be randomly high or low (the time in between bits being sent).Looking at the code I dont see any obvious way in which this bit would be set either, do you have an idea how it should be set? If needed I can provide some oscilloscope shots.
Hey @FrankvVeelen How did you choose your GPIOs?
I am trying to do this but no luck so far!
Would be great if you could give a hint.
@davids5 Is there anyway I can find GPIO Map for 6x board? Like how I can find the way GPIO_TIM1_CH2OUT_2
is defined?
I have followed the above steps and the code did compile and start the neopixel driver. The driver reports to be controlling the leds when calling neopixel status, but no output is send to the gpio.
GPIO_TIM1_CH2OUT_2 corresponds to which AUX pin on cube carrier board? Where can you see the labels for each AUX_X pin? How do I send the led_control commands to neopixel?
@FrankvVeelen, can you summarize all the steps and final changes you made to successfully get neopixel driver to perform led_control? @davids5 or anyone with solutions for this?
This issue has been mentioned on Discussion Forum for PX4, Pixhawk, QGroundControl, MAVSDK, MAVLink. There might be relevant details there:
https://discuss.px4.io/t/neopixel-led-driver-control/42096/1
Describe the bug
Running the neopixel driver on a holybro pixhawk 6x does not produce the expected signal. I use the dma-version of this driver:
srgbled_dma.cpp
and the latest release (v1.13.2).To Reproduce
Added to
fmu-v6x/src/board_config.h
:Build and flash, then in nsh:
neopixel start
Expected behavior
I would expect to see a pwm-like signal on pin FMU_CH1 of two different duty-cycles. Total bit time is 1200 ns, 0b1(600ns|600ns) 0b0(300ns|900ns).
Log Files and Screenshots
The signal on FMU_CH1 is either constantly zero, or if I enable DMA-debug-prints and disable DMA on the serial console (because it would freeze otherwise) I get a weird non-const signal with some pulses that have nothing to do with the expected behaviour.
log: https://logs.px4.io/plot_app?log=b063b920-a603-4820-9d73-71acd0f30f78
Drone (please complete the following information):
holybro pixhawk 6x on baseboard mini, powered with USBC.
Additional context
With print statements in
stm32h7/stm32_dma.c
(for debugging), the serial console freezes. Configuring the serial console without DMA would solve the freezing issue.