38-PWM_DMA-Library (STM32F4)

Mit dieser Library können 8 oder 16 GPIOs von einem Port zur PWM-Ausgabe benutzt werden.

Es wird ein Timer, ein DMA und ein GPIO-Port dafür benötigt. Ich habe im Beispiel Timer1 Port-E und DMA2 (Channel=6, Stream=5) benutzt. Es geht aber auch jede andere Kombination.

Vorsicht : Die DMA Ausgabe schreibt 8 bzw. 16 Bit an den Port…diese Pins dürfen nicht von was anderem belegt sein !

Im H-File kann eingestellt werden ob 8 Kanäle oder 16 benutzt werden sollen. Und wenn 8 Kanäle dann ob auf den Bits 0 bis 7 oder auf den Bits 8 bis 15.
(Ich habe 8Bit am Port-E Bit8 bis 15 benutzt weil die am Discovery-Board frei sind)

Im H-File muss (bzw. kann) auch die Auflösung vom PWM und die Clock-Frq vom Timer eingestellt werden. Daraus ergibt sich dann die PWM-Frequenz.

Beispielbild :

pwm

Voraussetzungen :

1
2
Benutzte Module der CooCox-IDE : GPIO, TIM, DMA
Benutzte Librarys : keine

Funktionen :

1
2
void UB_PWM_DMA_Init(void);                           // um den PWM per DMA zu initialisieren
void UB_PWM_DMA_SetPWM(uint8_t kanal, uint16_t wert); // zum einstellen eines PWM wertes

Beispiel :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
//--------------------------------------------------------------
// File     : main.c
// Datum    : 04.05.2013
// Version  : 1.0
// Autor    : UB
// EMail    : mc-4u(@)t-online.de
// Web      : www.mikrocontroller-4u.de
// CPU      : STM32F4
// IDE      : CooCox CoIDE 1.7.0
// Module   : CMSIS_BOOT, M4_CMSIS_CORE
// Funktion : Demo der PWM-DMA Library
// Hinweis  : Diese zwei Files muessen auf 8MHz stehen
//              "cmsis_boot/stm32f4xx.h"
//              "cmsis_boot/system_stm32f4xx.c"
//--------------------------------------------------------------
 
#include "main.h"
#include "stm32_ub_pwm_dma.h"
 
int main(void)
{
  SystemInit(); // Quarz Einstellungen aktivieren
 
  // init vom PWM per DMA
  UB_PWM_DMA_Init();
 
  // 8 PWM Werte einstellen
  UB_PWM_DMA_SetPWM(0,10); // Kanal0 auf 10%
  UB_PWM_DMA_SetPWM(1,25); // Kanal1 auf 25%
  UB_PWM_DMA_SetPWM(2,30); // Kanal2 auf 30%
  UB_PWM_DMA_SetPWM(3,40); // Kanal3 auf 40%
  UB_PWM_DMA_SetPWM(4,50); // Kanal4 auf 50%
  UB_PWM_DMA_SetPWM(5,60); // Kanal5 auf 60%
  UB_PWM_DMA_SetPWM(6,75); // Kanal6 auf 75%
  UB_PWM_DMA_SetPWM(7,90); // Kanal7 auf 90%
 
  while(1)
  {
 
  }
}

Hier die Library zum Download :

ub_stm32f4_pwm_dma_v100

Hier der komplette CooCox-Projektordner zum Download :

Demo_38_PWM_DMA

8 Antworten auf 38-PWM_DMA-Library (STM32F4)

  1. tueddel sagt:

    Hallo,

    ist es möglich per DMA den Inhalt eines Arrays Bitweise auf einen GPIO-Pin zu legen? Oder geht das wirklich nur Byteweise, auf quasi 8 IOs?

    Ich möchte gerne den Inhalt vom Array
    uint32_t data[10];
    Bitweise shiften und jeweils das unterste Bit (High/Low) auf den GPIO geben. Der Takt zur Ausgabe soll von einem Timer kommen. Aktuell hab ich das per Overflow Interrupt mit dem Timer gelöst. Aber das ist ganz schön Zeit aufwändig und bei meiner Anwendung kommts aufs Timing an… Oder aber ich muss die Taktrate deutlich reduzieren, damit mich Verzögerungen durch andere Interrupts nicht mehr stören. Daher meine Überlegung das komplett an den DMA abzuschieben, sofern das möglich ist.

    • admin_ub sagt:

      bei den DMA Einstellungen gehen nur 8bit, 16bit, 32bit. Event. wenn man nur ein GPIO-Pin als Ausgang deklariert…wäre aber “murks”. Wie schnell muss das ganze den sein und könnte man vor dem “senden” das ganze Array umkopieren so das es schon im richtigen Format vorliegt. Also eine Funktion die aus uint32_t data[10] ein bool bit_signal[320] macht ? damit wäre in der ISR nur drei Zeilen notwendig :

      GPIO = bit_signal[akt_pos];
      akt_pos++;
      if(akt_pos>=320) {
      // ende erreicht
      }

  2. Felix sagt:

    Hallo,

    erstmal ein großes Lob für die ganze Mühe. Die libs sind super!

    Ich benutze den PWM DMA Modus mit 1 kHz an PE0-PE7. Das ganze funktioniert auch wunderbar. Nun habe ich die GPIOs dieser Pins auf Open Drain ohne PullUp/PullDown gestellt, da ich externe PullUps an 5V habe:

    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
    GPIO_InitStructure.GPIO_OType = GPIO_OType_OD;
    GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;

    Das Ergebnis ist spannend:
    Die Frequenz sinkt auf 500 Hz. PWM funktionert weiterhin.
    Der High-Pegel beträgt jedoch nur 3.6V.

    Ohne externe PullUps liegt kein Signal am Ausgang.
    Open Drain scheint also aktiviert zu sein.

    Muss der GPIO auf “Alternate Function” gestellt werden?

    Gruß

    Felix

    • admin_ub sagt:

      nein “OUT” ist schon richtig. Welchen Widerstandswert hat dein PullUp und was hast du als “Last” an den Pin angeschlossen ? Sind deine “5V” auch gemessene 5V zu jedem Zeitpunkt ?

  3. Felix sagt:

    Die 5V sind wirklich konstant 5V ;-)
    PullUp 4,7k
    Keine Last (außer Oszi)
    Klappt an den normalen GPIOs auch wunderbar.

    Den geringeren High-Pegel könnte ich mir ja noch erklären (z. B. interner PullUp noch aktiv).
    Aber warum sinkt die Frequenz der PWM auf 500 Hz?

  4. Ncysys sagt:

    Hi Great Lib’s and sample code. They really help when learning a new micro.

    I found a small problem with the PWM_DMA running on the STMF4 discovery board. The discovery board only has PE7 to PE15 to output the PWM signals. So if you select #define PWM_DMA_USE_BIT8TO15 2 // 8 Kanäle (an Port Bit8 bis Bit15) and change the main code to UB_PWM_DMA_SetPWM(8,10) … UB_PWM_DMA_SetPWM(15,90), the discovery board does not output any signals. The code in stm32_ub_pwm_dma.c —void UB_PWM_DMA_SetPWM(uint8_t kanal, uint16_t wert) — #else will only support channels 0 to 7 and never 8 to 15.

    The solution for anyone wanting to get this example running quickly is to change the define in stm32_ub_pwm_dma.h to — #define PWM_DMA_USE_BIT0TO15 3 // 16 Kanäle (an Port Bit0 bis Bit15). or modify the code in stm32_ub_pwm_dma.c to support channels 0 to 7 or channels 8 to 15.

    • admin_ub sagt:

      thats not a bug…its a feature :-)
      the parameter number for the function “UB_PWM_DMA_SetPWM”
      is in 8bit Mode always 0…7. So if you use 8bit from Bit8 to Bit15 the first Channel (Bit8) is called by “UB_PWM_DMA_SetPWM(0,value);”
      Sounds crazy but this was the easiest way.
      In 16bit-Mode the nummers are from 0…15 to reach all 16 Channels.
      e.g. the sample code is running directly on a STM32F4-Discovery
      with output on PE8 to PE15 …CH0 = PE8…CH7 = PE15.

  5. Axel Opitz sagt:

    Hallo,
    es gelingt mir leider nur deine Routine mit Timer 1 oder Timer 8 zu realisieren.
    Mit Timer 4,(DMA1 Channel2 Stream6) oder Timer 2(DMA1, Channel3 Stream1) gelingt mir dies leider nicht. Würde mich freuen, wenn Du mir helfen könntest.


Wie hat Dir dieser Artikel gefallen?

1 Stern2 Sterne3 Sterne4 Sterne5 Sterne (Noch keine Bewertungen)
Loading...

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert