Fahren von WS2812 mit DMA auf STM32F302

Ich versuche, einige WS2812-LEDs anzusteuern, die ein (400 ns hoch + 800 ns niedrig) oder (800 ns hoch + 400 ns niedrig) Signal benötigen, um eine 0 oder eine 1 anzuzeigen.

Im Wesentlichen versuche ich also, ein Array von Daten zu nehmen und es direkt an einen GPIO mit etwa 2,5 MHz auszugeben. Ich habe den DMA noch nie zuvor verwendet, aber meines Wissens sollte er in der Lage sein, Daten direkt aus dem Speicher an einen GPIO auszugeben.

Kann jemand eine Anleitung geben, wie man den DMA dafür einrichtet, oder ob es bessere Möglichkeiten gibt, Daten auf einem GPIO mit einem konsistenten Takt auszugeben?

Antworten (3)

Sie sollten die Verwendung einer UART-, SPI- oder I2S-Schnittstelle in Betracht ziehen und ein Byte verwenden, um die Wellenform für ein Bit zu generieren. Der wichtige Punkt ist, dass solche Schnittstellen einen FIFO-Puffer haben, sodass die Aktivitäten der CPU nicht genau synchron mit dem Ausgangssignal sein müssen.

Ein Schüler von mir hat das erfolgreich auf einem LPC1114 gemacht.

Vielleicht können Sie DMA verwenden, um die serielle Schnittstelle zu speisen, aber Sie müssten die Daten auf ein Byte pro Bit "aufblähen".

Das Datenblatt bestätigt, dass das Umschalten von GPIO bei 2,5 MHz möglich ist

Schnelles I/O-Handling ermöglicht I/O-Toggeln bis zu 36 MHz

DMA-Schreibvorgänge auf GPIO sind möglich (Blick auf das Blockdiagramm des DMA-Abschnitts). Wenn Sie GPIO direkt in GPIO_data-Register schreiben könnten.

DMA kann aufgrund Ihrer Einschränkung im Arbeitszyklus für logisch niedrig und logisch hoch nicht verwendet werden. Ich würde vorschlagen, die Codierung in C zu versuchen und die GPIOs direkt anzusteuern (wechseln Sie zu Asm oder Inline, falls von der Toolchain unterstützt), wenn eine Geschwindigkeit von 1/400 ns = 2,5 MHz erforderlich ist und zusätzliche Zeit dazwischen erforderlich ist.
Bearbeiten: Um DMA gemäß dem folgenden Kommentar zu verwenden, damit der Prozessor frei sein kann, beträgt das Tastverhältnis immer noch 66,66% und 33,33% gemäß der Anforderung in OP. Aber die einzige Sache ist, dass die Rate auf 2,5 MHz erhöht wird. Ich muss noch die DMA-Konfiguration erkunden, um die Möglichkeit zu prüfen.Geben Sie hier die Bildbeschreibung ein

Eh, DC ist kein Problem, es sei denn, es gibt Verzögerungen oder Rückkehr zu Null zwischen den Bytes. Da das Signal ziemlich regelmäßig ist, können Sie 3 Ausgangsbits pro WS281X-Bit im Signal verwenden (100 für 0, 110 für 1).
Es wird nicht auf 7,5 MHz erhöht; Das Basissignal ist 800 kHz, also sind 2,5 MHz ungefähr richtig.
Danke für die nette Idee, die PWM mit digitalen Signalen zu erzeugen. Ich habe es auf 2,5 MHz korrigiert und fahre mit der Konfiguration fort

1.Stellen Sie bei einem STM32 die Taktgeschwindigkeit auf 40/80/120 MHz ein und verwenden Sie den SPI mit Ausgabe auf MOSI. Verwenden Sie den SPI- und DMA-Kanal. Der Puls liegt bei 400us. Bei 80 MHz ist der SPI-Teiler 32.

  1. Richten Sie den SPI so ein:

    hdma_spi1_tx.Instance = DMA1_Channel3;

    hdma_spi1_tx.Init.Direction = DMA_MEMORY_TO_PERIPH;

    hdma_spi1_tx.Init.PeriphInc = DMA_PINC_DISABLE;

    hdma_spi1_tx.Init.MemInc = DMA_MINC_ENABLE;

    hdma_spi1_tx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;

    hdma_spi1_tx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;

    hdma_spi1_tx.Init.Mode = DMA_NORMAL;

    hdma_spi1_tx.Init.Priority = DMA_PRIORITY_LOW;

3. Richten Sie den DMA-Port wie folgt ein:

DMA1_Channel3->CPAR = (uint32_t)&(SPI1->DR);

DMA1_Channel3->CMAR = (uint32_t) Pixel; // zum Senden an ws2812

DMA1_Kanal3->CCR |= DMA_CCR_DIR | DMA_CCR_MINC;

NVIC_SetPriority (DMA1_Channel2_3_IRQn, 0);

NVIC_EnableIRQ (DMA1_Channel2_3_IRQn);

4.Codieren Sie die Daten vor dem Senden korrekt. Bit 1 ist 110 und Bit 0: 100. Wenn Sie also 10 LEDs haben, sind WS2812 x 3 Bytes (24 Bits) x 3 Impulse = 90 Bytes

  1. Lassen Sie das erste und letzte Byte des an WS2812 zu sendenden Streams leer (0). Das erste Byte wird verwendet, um den Streifen zurückzusetzen.

6. Senden Sie Daten an den WS2812 mit dem DMA HAL_SPI_Transmit_DMA (&hspi1, Pixel, numBytes);

7. Warten Sie 1,25 ms x LEDs, bevor Sie erneut senden