Forum: Compiler & IDEs STM32F4: PWM auf beliebigen Ports?


von Rainer R. (Firma: Reusch Elektronik) (reusch)


Lesenswert?

Hallo STM32-Fans! Hier die Beschreibung einer Situation, die vermutlich 
nur für mich als STM32-Einsteiger ein Problem darstellt. Gegeben ist:

Controller: STM32F407VG
Hardware: STM32F407-Discovery
IDE: CooCox 1.5.0
ARM GCC Toolchain: 4.6 2012q2
ST-Library: STM32F4xx_DSP_StdPeriph_Lib_V1.0.1

Es geht um das banale Thema PWM-Ausgabe auf einem Port. Das unten 
aufgeführte Listing funktioniert. Es verwendet den GPIOC-Pin 6, Timer 3 
und dessen Channel 1.
Wenn GPIOC-Pin 7 verwendet werden soll, muss Channel 2 gesetzt werden, 
damit es funktioniert. Die Wahl eines beliebigen Ports ist anscheinend 
nicht möglich. Die Doku zum Controller lässt jedoch anderes vermuten. 
Daher die Frage:

Ist die Ausgabe eines PWM-Signals an bestimmte Ports gebunden? Wenn ja, 
wo finde Informationen dazu?

Hier das Listing:

/**
  ************************************************************************ 
******
  * @file    Test_PWM_STM32F407VG/main.c
  * @author  Rainer Reusch, based on source from Andrew Markham
  * @version V1.0.0
  * @date    14-Sept-2012
  * @brief   Main program body
  ************************************************************************ 
******
  */

/* Includes 
------------------------------------------------------------------*/
#include "stm32f4xx_conf.h"
#include <stdio.h>

/* Definitions 
---------------------------------------------------------------*/
#define PWM_PORT GPIOC  // used port for PWM output
#define PWM_PIN 6 // used pin for PWM output
#define RCC_AHB1Periph_PWM_PORT RCC_AHB1Periph_GPIOC  // clock for used 
port

/* Private typedef 
-----------------------------------------------------------*/
GPIO_InitTypeDef  GPIO_InitStructure;
TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
TIM_OCInitTypeDef  TIM_OCInitStructure;

/* Private functions 
---------------------------------------------------------*/

/**
  * @brief  Configure the TIM3 Output Channels
  * @param  None
  * @retval None
  */
void TIM_ConfigDiscovery(void)
{
  GPIO_InitTypeDef GPIO_InitStructure;

  /* TIM3 clock enable */
  RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);

  /* GPIO clock enable */
  RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_PWM_PORT, ENABLE);

  /* GPIO Configuration: TIM3 CH1  */
  GPIO_InitStructure.GPIO_Pin = 1<<PWM_PIN;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
  GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
  GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP ;
  GPIO_Init(PWM_PORT, &GPIO_InitStructure);

  /* Connect TIM3 pins to AF2 */
  #if (PWM_PIN<8)
  PWM_PORT->AFR[0]=2<<(PWM_PIN<<2);  // Pin 0..7
  #else
  PWM_PORT->AFR[1]=2<<((PWM_PIN-8)<<2);  // Pin 8..15
  #endif
}

void PWM_Config(int period)
{
  uint16_t PrescalerValue = 0;

  /* Compute the prescaler value */
  PrescalerValue = 16;

  /* Time base configuration */
  TIM_TimeBaseStructure.TIM_Period = period;
  TIM_TimeBaseStructure.TIM_Prescaler = PrescalerValue;
  TIM_TimeBaseStructure.TIM_ClockDivision = 0;
  TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;

  TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure);

  /* PWM1 Mode configuration: Channel1 */
  TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
  TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
  TIM_OCInitStructure.TIM_Pulse = 0;
  TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;

  TIM_OC1Init(TIM3, &TIM_OCInitStructure);
  TIM_OC1PreloadConfig(TIM3, TIM_OCPreload_Enable);
  TIM_ARRPreloadConfig(TIM3, ENABLE);

  // TIM3 enable counter
  TIM_Cmd(TIM3, ENABLE);
}

/**
  * @brief  Main program
  * @param  None
  * @retval None
  */
int main(void)
{
  SCB->VTOR = SRAM_BASE; // Vector Table Relocation in Internal SRAM
  TIM_ConfigDiscovery();  // configure Timer
  PWM_Config(800);  // PWM Configuration

  TIM3->CCR1 = 100;  // set duty cycle
  while (1)
  {
  }
}

von r Inform (Gast)


Lesenswert?

> Wenn ja, wo finde Informationen dazu?

Wo, wenn nicht im Datenblatt oder RefMan?

von Toralf W. (willi)


Lesenswert?

Es gibt meistens noch einen alternativen Pin aber ansonsten ist die 
Ausgabe an einen bestimmten Pin gebunden -> RefMan

von Rainer R. (Firma: Reusch Elektronik) (reusch)


Lesenswert?

Die Bemerkung von Toralf und ein gefundener Hinweis im Reference Manual 
haben die Lösung gebracht. Die GPIOx->AFR Register bieten vom Konzept 
her zwar die Möglichkeit, eine PWM (oder eine andere Funktion) an jeden 
beliebigen GPIO-Pin zu legen, in der Praxis funktionieren jedoch nur 
wenige. Welche, das steht im Datenblatt zum Controller.

Für den im Beispiel verwendeten Timer 3 und dessen Channel 1 beim 
STM32F407VG können PA6, PB4 und PC6 für die PWM-Ausgabe verwendet 
werden.
Für andere Channels und andere Timer gelten andere Ports.

Fazit: Im Reference Manual steht nicht alles und der STM32 ist auch 
keine Wundertüte mit den endlosen Möglichkeiten!

von Hui (Gast)


Lesenswert?

Rainer Reusch schrieb:
> der STM32 ist auch
> keine Wundertüte mit den endlosen Möglichkeiten!

Die muss erst noch Erfunden werden.
Wer schon heute eine findet, lasst es mich wissen :-)

von Roland H. (batchman)


Lesenswert?

Rainer Reusch schrieb:
> Fazit: Im Reference Manual steht nicht alles und der STM32 ist auch
> keine Wundertüte mit den endlosen Möglichkeiten!

Wer hat denn dies als Wundertüte verkauft :-)

Wäre aber schon an einem STM32F4DIL interessiert.

PPS cross bars gibt's bei einigen PIC32. M. W. tendenziell eher bei den 
Chips, welche wenig Pins haben. Die mit vielen Pins haben m. W. dann 
wiederum eher keine Crossbar.

Der genannte stm32f407 hat ca. 15 Timer und reichlich Rechenpower, da 
kann eine SW PWM in einer ISR an jeden Pin gebunden werden.

von Rainer R. (Firma: Reusch Elektronik) (reusch)


Lesenswert?

Eine Software-PWM ist und bleibt eine Notlösung. Auch wenn man viel 
Rechenpower hat, wird man die meistens besser zu nutzen wissen.

> Wäre aber schon an einem STM32F4DIL interessiert.

Das ist zumindest schon mal angedacht. Wenn, dann allerdings wohl "nur" 
mit dem STM32F405RGT6. Der hat 64 Pins.

Für mein nächsten Projekt ist dieser vermutlich zu klein. Deshalb ist 
die Motivation, ein Modul für den Dual-In-Line-Sockel zu entwickeln, 
z.Zt. nicht sehr ausgeprägt. Es sei denn, so ein Modul stößt auf 
allgemeines Interesse. Wer will, kann mir über die E-Mail-Adresse 
stm32f4dil@reworld.eu sein Interesse bekunden (bitte nur Ernst 
gemeinte). Sollte es das Modul dann tatsächlich mal geben, würde ich die 
Interessenten informieren.

von Marco (Gast)


Lesenswert?

Wo hat ihr im "RM0090 Reference manual" eingentlich diese Mapping 
gefunden? Ich kann das nicht finden ..... :-(
Danke
-Marco

von holger (Gast)


Lesenswert?


von Marco (Gast)


Lesenswert?

Merci!

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.