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

Apply F4 DMA2 errata if LED_STRIP is using DMA2 #10880

Closed
wants to merge 1 commit into from

Conversation

SteveCEvans
Copy link
Member

The errata at https://www.st.com/resource/en/errata_sheet/dm00037591-stm32f405407xx-and-stm32f415417xx-device-limitations-stmicroelectronics.pdf, section 2.1.10, reports an errata that corruption may occur on DMA2 if AHB peripherals (eg GPIO ports) are, accessed concurrently with APB peripherals (eg SPI busses).

Bitbang DSHOT uses DMA2 to write to GPIO ports and this has already been handled to not enable DMA on an SPI bus using DMA2. There are instances where the LED_STRIP driver may also use a timer associated with DMA2, and it is this case that this PR addresses.

The MATEKF411 target, for example, defines the LED_STRIP resource thus:

resource LED_STRIP 1 A08

Referring to Table 9, Alternate function mapping, in the STM32F411CE data sheet it can be seen that pin A08 is associated only with TIM1.

image

From the BF CLI we can see that the only DMA streams associated with TIM1 are on DMA2.

# dma pin A08 list
# 0: DMA2 Stream 6 Channel 0
# 1: DMA2 Stream 1 Channel 6
# 2: DMA2 Stream 3 Channel 6

This PR ensures that under such circumstances if LED_STRIP is disabled then DMA will be enabled for the gyro and marked as owned by GYRO_CS thus:

# dma show

Currently active DMA:
--------------------
DMA1 Stream 0: MOTOR 3
DMA1 Stream 1: FREE
DMA1 Stream 2: FREE
DMA1 Stream 3: MOTOR 4
DMA1 Stream 4: MOTOR 1
DMA1 Stream 5: MOTOR 2
DMA1 Stream 6: FREE
DMA1 Stream 7: FREE
DMA2 Stream 0: ADC 1
DMA2 Stream 1: FREE
DMA2 Stream 2: GYRO_CS
DMA2 Stream 3: GYRO_CS
DMA2 Stream 4: FREE
DMA2 Stream 5: FREE
DMA2 Stream 6: FREE
DMA2 Stream 7: FREE

Whereas if LED_STRIP is enabled, we instead get the following indicating the gyro SPI access will be polled only.

# dma show

Currently active DMA:
--------------------
DMA1 Stream 0: MOTOR 3
DMA1 Stream 1: FREE
DMA1 Stream 2: FREE
DMA1 Stream 3: MOTOR 4
DMA1 Stream 4: MOTOR 1
DMA1 Stream 5: MOTOR 2
DMA1 Stream 6: FREE
DMA1 Stream 7: FREE
DMA2 Stream 0: ADC 1
DMA2 Stream 1: FREE
DMA2 Stream 2: FREE
DMA2 Stream 3: FREE
DMA2 Stream 4: FREE
DMA2 Stream 5: FREE
DMA2 Stream 6: LED_STRIP
DMA2 Stream 7: FREE

The following explores the issue of DMA stream assignment on F4 processors a little more, and this will be significant when #10573 is merged which supports using DMA to retrieve gyro data over SPI and achieve much tighter gyro and PID cycle times.

There are compromises presented by the F4 processors with respect to DMA. Using the MATEKF411 as an example, with no motors or LED strip enabled the following DMA streams are assigned supporting DMA access for both OSD and gyro.

# dma show

Currently active DMA:
--------------------
DMA1 Stream 0: FREE
DMA1 Stream 1: FREE
DMA1 Stream 2: FREE
DMA1 Stream 3: OSD_CS
DMA1 Stream 4: OSD_CS
DMA1 Stream 5: FREE
DMA1 Stream 6: FREE
DMA1 Stream 7: FREE
DMA2 Stream 0: ADC 1
DMA2 Stream 1: FREE
DMA2 Stream 2: GYRO_CS
DMA2 Stream 3: GYRO_CS
DMA2 Stream 4: FREE
DMA2 Stream 5: FREE
DMA2 Stream 6: FREE
DMA2 Stream 7: FREE

If the motors are enabled using DSHOT with the default settings it can be seen that the timer based DSHOT uses streams that would otherwise be available for the OSD.

# get dshot
dshot_idle_value = 500
Allowed range: 0 - 2000
Default value: 550

dshot_burst = AUTO
Allowed values: OFF, ON, AUTO
Default value: OFF

dshot_bidir = ON
Allowed values: OFF, ON
Default value: OFF

dshot_bitbang = OFF
Allowed values: OFF, ON, AUTO
Default value: AUTO

dshot_bitbang_timer = TIM1
Allowed values: AUTO, TIM1, TIM8
Default value: AUTO

beeper_dshot_beacon_tone = 1
Allowed range: 1 - 5

# dma show

Currently active DMA:
--------------------
DMA1 Stream 0: MOTOR 3
DMA1 Stream 1: FREE
DMA1 Stream 2: FREE
DMA1 Stream 3: MOTOR 4
DMA1 Stream 4: MOTOR 1
DMA1 Stream 5: MOTOR 2
DMA1 Stream 6: FREE
DMA1 Stream 7: FREE
DMA2 Stream 0: ADC 1
DMA2 Stream 1: FREE
DMA2 Stream 2: GYRO_CS
DMA2 Stream 3: GYRO_CS
DMA2 Stream 4: FREE
DMA2 Stream 5: FREE
DMA2 Stream 6: FREE
DMA2 Stream 7: FREE

If anything but the simplest of OSD displays are used this will impact flight performance.

If, however, DSHOT is enabled using bit-banged DMA the OSD DMA is available, but the gyro DMA is not.

# get dshot
dshot_idle_value = 500
Allowed range: 0 - 2000
Default value: 550

dshot_burst = AUTO
Allowed values: OFF, ON, AUTO
Default value: OFF

dshot_bidir = ON
Allowed values: OFF, ON
Default value: OFF

dshot_bitbang = ON
Allowed values: OFF, ON, AUTO
Default value: AUTO

dshot_bitbang_timer = TIM1
Allowed values: AUTO, TIM1, TIM8
Default value: AUTO

beeper_dshot_beacon_tone = 1
Allowed range: 1 - 5

# dma show

Currently active DMA:
--------------------
DMA1 Stream 0: FREE
DMA1 Stream 1: FREE
DMA1 Stream 2: FREE
DMA1 Stream 3: OSD_CS
DMA1 Stream 4: OSD_CS
DMA1 Stream 5: FREE
DMA1 Stream 6: FREE
DMA1 Stream 7: FREE
DMA2 Stream 0: ADC 1
DMA2 Stream 1: DSHOT_BITBANG 2
DMA2 Stream 2: FREE
DMA2 Stream 3: FREE
DMA2 Stream 4: FREE
DMA2 Stream 5: FREE
DMA2 Stream 6: FREE
DMA2 Stream 7: FREE

Given that the gyro DMA is no longer available, one might think there's no harm is then enabling the LED_STRIP, however as the F411 does not have TIM8, TIM1 may be used by either bit banged DSHOT or LED_STRIP, but not both.

# dma show

Currently active DMA:
--------------------
DMA1 Stream 0: FREE
DMA1 Stream 1: FREE
DMA1 Stream 2: FREE
DMA1 Stream 3: OSD_CS
DMA1 Stream 4: OSD_CS
DMA1 Stream 5: FREE
DMA1 Stream 6: FREE
DMA1 Stream 7: FREE
DMA2 Stream 0: ADC 1
DMA2 Stream 1: FREE
DMA2 Stream 2: FREE
DMA2 Stream 3: FREE
DMA2 Stream 4: FREE
DMA2 Stream 5: FREE
DMA2 Stream 6: LED_STRIP
DMA2 Stream 7: FREE

Therefore in order to enable LED_STRIP it is necessary to disable big-banged DSHOT resulting in the following.

# dma show

Currently active DMA:
--------------------
DMA1 Stream 0: MOTOR 3
DMA1 Stream 1: FREE
DMA1 Stream 2: FREE
DMA1 Stream 3: MOTOR 4
DMA1 Stream 4: MOTOR 1
DMA1 Stream 5: MOTOR 2
DMA1 Stream 6: FREE
DMA1 Stream 7: FREE
DMA2 Stream 0: ADC 1
DMA2 Stream 1: FREE
DMA2 Stream 2: FREE
DMA2 Stream 3: FREE
DMA2 Stream 4: FREE
DMA2 Stream 5: FREE
DMA2 Stream 6: LED_STRIP
DMA2 Stream 7: FREE

DMA is no longer available for either the OSD or gyro.

LEDs are clearly less important than flight performance, and arguably so is the OSD, so one might consider disabling both of these and achieving the following DMA stream assignment.

# dma show

Currently active DMA:
--------------------
DMA1 Stream 0: MOTOR 3
DMA1 Stream 1: FREE
DMA1 Stream 2: FREE
DMA1 Stream 3: MOTOR 4
DMA1 Stream 4: MOTOR 1
DMA1 Stream 5: MOTOR 2
DMA1 Stream 6: FREE
DMA1 Stream 7: FREE
DMA2 Stream 0: ADC 1
DMA2 Stream 1: FREE
DMA2 Stream 2: GYRO_CS
DMA2 Stream 3: GYRO_CS
DMA2 Stream 4: FREE
DMA2 Stream 5: FREE
DMA2 Stream 6: FREE
DMA2 Stream 7: FREE

Contrast this with the FURYF4OSD with by having more considered motor pin assignments is able to achieve the following. This supports four motors, OSD, FLASH and gyro SPI DMAs.

# dma show

Currently active DMA:
--------------------
DMA1 Stream 0: FLASH_CS
DMA1 Stream 1: MOTOR 4
DMA1 Stream 2: MOTOR 3
DMA1 Stream 3: OSD_CS
DMA1 Stream 4: OSD_CS
DMA1 Stream 5: FLASH_CS
DMA1 Stream 6: MOTOR 1
DMA1 Stream 7: MOTOR 2
DMA2 Stream 0: GYRO_CS
DMA2 Stream 1: FREE
DMA2 Stream 2: FREE
DMA2 Stream 3: GYRO_CS
DMA2 Stream 4: ADC 1
DMA2 Stream 5: FREE
DMA2 Stream 6: FREE
DMA2 Stream 7: FREE

However enabling LED_STRIP results in a conflict as shown below whereby MOTOR 3 can't be mapped.

# dma show

Currently active DMA:
--------------------
DMA1 Stream 0: FLASH_CS
DMA1 Stream 1: MOTOR 4
DMA1 Stream 2: LED_STRIP
DMA1 Stream 3: OSD_CS
DMA1 Stream 4: OSD_CS
DMA1 Stream 5: FLASH_CS
DMA1 Stream 6: MOTOR 1
DMA1 Stream 7: MOTOR 2
DMA2 Stream 0: GYRO_CS
DMA2 Stream 1: FREE
DMA2 Stream 2: FREE
DMA2 Stream 3: GYRO_CS
DMA2 Stream 4: ADC 1
DMA2 Stream 5: FREE
DMA2 Stream 6: FREE
DMA2 Stream 7: FREE

If one really must use LED_STRIP then enabling bit-banged DSHOT will result in the following assignment, forcing the gyro's SPI access to be polled.

# dma show

Currently active DMA:
--------------------
DMA1 Stream 0: FLASH_CS
DMA1 Stream 1: FREE
DMA1 Stream 2: LED_STRIP
DMA1 Stream 3: OSD_CS
DMA1 Stream 4: OSD_CS
DMA1 Stream 5: FLASH_CS
DMA1 Stream 6: FREE
DMA1 Stream 7: FREE
DMA2 Stream 0: FREE
DMA2 Stream 1: DSHOT_BITBANG 1
DMA2 Stream 2: DSHOT_BITBANG 2
DMA2 Stream 3: FREE
DMA2 Stream 4: ADC 1
DMA2 Stream 5: FREE
DMA2 Stream 6: FREE
DMA2 Stream 7: FREE

@haslinghuis haslinghuis added this to the 4.3 milestone Aug 3, 2021
Copy link
Member

@mikeller mikeller left a comment

Choose a reason for hiding this comment

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

Bugger - I wasn't aware that the DMA2 hardware problem also affects the use of DMA for individual GPIO pins - this will make resource allocation on F4 tricky. :-(

@@ -88,6 +90,10 @@ void setUsedLedCount(unsigned ledCount);

bool isWS2811LedStripReady(void);

#ifdef STM32F4
Copy link
Member

Choose a reason for hiding this comment

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

There is no need to make the contents of header files conditional - this is normally not done in Betaflight, unless it serves to avoid build problems.

@@ -221,4 +221,12 @@ void ws2811LedStripDMAEnable(void)
TIM_Cmd(timer, ENABLE);
xDMA_Cmd(dmaRef, ENABLE);
}

#ifdef STM32F4
bool ws2811LedStripDMA2Errata(void)
Copy link
Member

Choose a reason for hiding this comment

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

'ws2811LedStripUsesDma2()` to make this a bit more indicative of what it returns?

*/
const bool dshotBitbangActive = isDshotBitbangActive(&motorConfig()->dev);
const bool dshotBitbangActive = isDshotBitbangActive(&motorConfig()->dev) || ws2811LedStripDMA2Errata();
Copy link
Member

Choose a reason for hiding this comment

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

dshotBitbangActive isn't correct any more - dma2HasErrataConflict or dma2isUsed?

@SteveCEvans
Copy link
Member Author

SteveCEvans commented Aug 3, 2021

Sorry to have wasted your time on this @mikeller. I realise that, just like timer based DSHOT the LED_STRIP DMA uses a peripheral target of a timer's capture/compare register which is mapped on the APB1/2 bus, not the AHB bus. Therefore this errata does not apply in this case.

Therefore abandoning this PR as not needed. The following configuration is possible on a MATEKF411.

# dma show

Currently active DMA:
--------------------
DMA1 Stream 0: MOTOR 3
DMA1 Stream 1: FREE
DMA1 Stream 2: FREE
DMA1 Stream 3: MOTOR 4
DMA1 Stream 4: MOTOR 1
DMA1 Stream 5: MOTOR 2
DMA1 Stream 6: FREE
DMA1 Stream 7: FREE
DMA2 Stream 0: ADC 1
DMA2 Stream 1: FREE
DMA2 Stream 2: GYRO_CS
DMA2 Stream 3: GYRO_CS
DMA2 Stream 4: FREE
DMA2 Stream 5: FREE
DMA2 Stream 6: LED_STRIP
DMA2 Stream 7: FREE

@SteveCEvans SteveCEvans closed this Aug 3, 2021
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.

None yet

3 participants