Forum: Mikrocontroller und Digitale Elektronik STM32F1 Brushless Motor Steuerung


von Kristoffer Ullsten (Gast)


Lesenswert?

Hallo,

ich versuch 2 Brushless Motoren mit STM32F1 zu steuern. Ich weiss nicht 
wie man 3, 120° Phasen versetzte PWMs mittels Timer1 erzeugt.

Hat jemand einen Beispiel Code für mich? Ich habe viel danach im 
Internet gesucht, bin am verzweifeln.

Danke!

von aSma>> (Gast)


Lesenswert?

Standart Peripheral Library in Ordner: TIM-->6Steps mit advanced timer 
1.

von Kristoffer Ullsten (Gast)


Lesenswert?

aSma>> schrieb:
> Standart Peripheral Library in Ordner: TIM-->6Steps mit advanced
> timer
> 1.

wow, im Ernte?

von Kristoffer Ullsten (Gast)


Angehängte Dateien:

Lesenswert?

offene Fragen:
1. Wofür sind die NVIC_Configuration und SysTick_Configuration im 
Beispiel?
2. Ein Pin wird als floating Eingang definiert. Was wird hier gemessen?
   Braucht man das überhaupt für die Steuerung der BLDCs?
3. ist Channel1N negierte Channel1 oder hat damit nix zu tun?
4. Wie gebe ich die PWM vor?
5. Wie ändere ich die Drehrichtung?

Danke ;)

von Matthias S. (Firma: matzetronics) (mschoeldgen)


Lesenswert?

Kristoffer Ullsten schrieb:
> 1. Wofür sind die NVIC_Configuration und SysTick_Configuration im
> Beispiel?

Steht im Quelltext. Der Systick erzeugt ein COM Event, um den Motor 
weiterzuschalten. Ohne die Konfiguration des NVIC wird kein Interrupt 
ausgelöst.

> 3. ist Channel1N negierte Channel1 oder hat damit nix zu tun?

Das ist der zu Channel 1 komplementäre Ausgang - lies im Reference 
Manual die Konfiguration der Advanced Timer und der CC Register.

> 4. Wie gebe ich die PWM vor?

Durch Schreiben der 3 CC Register. Wird im Beispiel nur in der Init 
benutzt, kann man aber mit im COM Interrupt erledigen.

> 5. Wie ändere ich die Drehrichtung?

Indem du in der COM ISR eine zweite Schiene einbaust, die die Steps 
enthält, aber bei der zwei Phasen vertauscht sind.

> 2. Ein Pin wird als floating Eingang definiert. Was wird hier gemessen?
Gemessen wird gar nichts. Ich denke, STM will den Eingang als Stop 
Eingang benutzen. Scheint aber noch nicht geschehen zu sein.

Alles in allem ist die Software nur ein Behelf. Die COM ISR würde 
sinnvoller mit einer kleinen Tabelle laufen, dann wäre auch die 
Drehrichtung vil leichter umkehrbar. Die zwanghafte Benutzung der Std. 
Peri. Lib ist hier nicht besonders hilfreich.

: Bearbeitet durch User
von Kristoffer Ullsten (Gast)


Lesenswert?

Matthias S. schrieb:
> Kristoffer Ullsten schrieb:
>> 1. Wofür sind die NVIC_Configuration und SysTick_Configuration im
>> Beispiel?
> Steht im Quelltext. Der Systick erzeugt ein COM Event, um den Motor
> weiterzuschalten. Ohne die Konfiguration des NVIC wird kein Interrupt
> ausgelöst.

Vielen Dank! ich verstehe langsam einiges. Das heißt ohne COM Event oder 
Info über Motor Drehlage ist es unmöglich, den Motor weiterzudrehen bzw. 
wieder ab Step1 zu betreiben?

>> 4. Wie gebe ich die PWM vor?
> Durch Schreiben der 3 CC Register. Wird im Beispiel nur in der Init
> benutzt, kann man aber mit im COM Interrupt erledigen.

Das heißt, müssen die 3 CC Register den gleichen Wert bzw. Pulsweite 
haben? Warum sind die CCR Werte verschieden im Beispiel.
1
uint16_t CCR1_Val = 32767;
2
uint16_t CCR2_Val = 24575;
3
uint16_t CCR3_Val = 16383;
4
uint16_t CCR4_Val = 8191;

Meine BLDC Motoren haben eingebaute 3 Hallsensoren und Shunts für 
Strommessung.

Ich habe überhaupt keine Erfahrung mit BLDC Motoren, daher muss ich 
folgende Noob Fragen stellen.

Was ist ein Com Event?
Welche Methoden gibts für die Steuerung von BLDC Motoren in Konbination 
mit Encoder.

Viele Dank.

von Matthias S. (Firma: matzetronics) (mschoeldgen)


Lesenswert?

Kristoffer Ullsten schrieb:
> Welche Methoden gibts für die Steuerung von BLDC Motoren in Konbination
> mit Encoder.

Wenn du Hallsensoren hast, wird die Sache viel einfacher als mit dem 
zwangsgeführten Motor aus dem Beispiel. Du konfigurierst 3 Pins als 
Interrupt Quelle und liest den Sektor bei Pegelwechsel aus dem Zustand 
der Sensoren. Damit schaltest du die Sektoren (Step1 - Step6 im 
Beispiel).
Wenn du die Sektornummer als Zeiger in eine Tabelle benutzt, ist die 
Kommutierung in nullkommanichts erledigt. Das kann z.B. so aussehen - 
von meinem alten Projekt für den VL Discovery
1
// from PMSMTables.h
2
// PHASES to position in TIM1_CCER register
3
4
#define UH 0x0004
5
#define UL 0x0001
6
7
#define VH 0x0040
8
#define VL 0x0010
9
10
#define WH 0x0400
11
#define WL 0x0100
12
13
#define LOSIDEMASK (UL | VL | WL)
14
#define HISIDEMASK (UH | VH | WH)
15
#define PHASEMASK (LOSIDEMASK | HISIDEMASK)
16
// tables organized for enabling bits in TIMx_CCER
17
const uint16_t blockCommutationTableForward[8] =
18
{
19
  0,               // illegal value
20
  WH | UL,              // UL, WH
21
  UH | VL,              // VL, UH
22
  WH | VL,              // VL, WH
23
  VH | WL,              // WL, VH
24
  VH | UL,              // UL, VH
25
  UH | WL,          // WL, UH
26
  0               // illegal value
27
};
28
const uint16_t blockCommutationTableReverse[8] =
29
{
30
      0,
31
      UH | VL,
32
      VH | WL,
33
      UH | WL,
34
      WH | UL,
35
      WH | VL,
36
      VH | UL,
37
      0
38
};
39
40
// from main.c
41
// set power to all of the CC Registers for block commutation
42
void BlockCommutationSetDuty(const uint16_t duty)
43
{
44
  // Set all compare registers to new duty cycle value.
45
  TIM_SetCompare1(TIM1, duty);
46
  TIM_SetCompare2(TIM1, duty);
47
  TIM_SetCompare3(TIM1, duty);
48
}
49
/* Block Commutate does the activation of OC outputs according to the  
50
 * supplied Hall Sensor Combination
51
 * fired through the Hall Interrupt
52
 */
53
void BlockCommutate(uint16_t hall)
54
{
55
 DisablePWMOutputs();
56
 if (fastFlags.desiredDirection == DIRECTION_REVERSE)
57
  {
58
   TIM1->CCER = blockCommutationTableReverse[hall] ;
59
  }
60
  else
61
  {
62
   TIM1->CCER = blockCommutationTableForward[hall] ;
63
  }
64
  EnablePWMOutputs();
65
}

: Bearbeitet durch User
von Kristoffer Ullsten (Gast)


Lesenswert?

ich habe die PWMs mit komplementären generiert, die PWMs schauen nicht 
phasenverschoben aus.

Wie verschiebe ich die denn um 120 grad. Danke!

von TestX (Gast)


Lesenswert?

Du arbeitest mit blockkommutierung...da werden die phasen nacheinander! 
angesteuert. Lies dir mal hier den Artikel zu BLDC Steuerungen durch!
Für hohe drehzahlen geht das problemlos...erst wenn der motor langsam 
drehen soll brauchst du eine feldorientierte Regelung..hierfür kannst du 
das Beispiel aber vergessen...das wird wesentlich komplexer

von Matthias S. (Firma: matzetronics) (mschoeldgen)


Lesenswert?

Kristoffer Ullsten schrieb:
> ich habe die PWMs mit komplementären generiert, die PWMs schauen nicht
> phasenverschoben aus.
>
> Wie verschiebe ich die denn um 120 grad. Danke!

Dafür sind doch die 6 Sektoren da. 360/6 = 60° und für jeweils 2 
Sektoren ist doch jede Wickung bestromt. Deswegen habe ich doch mal 
meinen Code für einfache Blockkommutierung gepostet. Der ist nicht 
vollständig, zeigt aber das Prinzip der Bestromung in Abhängigkeit von 
den Hallsensoren.

von Kristoffer Ullsten (Gast)


Lesenswert?

Hallo,

ist der Anfangszustand von 6 Steps unabhängig von Motordrehlage?

von Matthias S. (Firma: matzetronics) (mschoeldgen)


Lesenswert?

Kristoffer Ullsten schrieb:
> ist der Anfangszustand von 6 Steps unabhängig von Motordrehlage?

Nein. Der Sektor, in dem der Motor steht, wird ja durch deine 
Hallsensoren an den Controller gemeldet. Es ist also einer von 6 
möglichen Zuständen. Die Wicklungen werden dann so bestromt, das der 
Motor in den nächsten Sektor (vorwärts) oder in den vorigen Sektor 
(rückwärts) 'gezogen' wird.

Beim zwangsgeführten Beispiel von STM wird einfach mit einem Sektor 
angefangen, da eine Rückmeldung hier nicht erfolgt. Die Chancen sind 
also 1:5, das zufällig der Motor ohne Ruckeln anläuft.

Das PDF zur Atmel Application Note AVR447 erklärt dazu recht viel, unter 
anderem auch, wie aus einfacher Blockkommutierung dann Sinusmodulation 
wird, die den Motor laufruhiger macht und auch sehr gleichmässige 
Bewegung bei langsamen Drehzahlen ermöglicht:
http://www.atmel.com/images/doc8010.pdf
Ich lasse so mit u.a. dem VLDiscovery STM32F100RB sehr laufruhig und 
langsam einen Pioneer Direct Drive Plattenspieler Motor laufen - eine 
meiner Versuchsanordnungen für BLDC Antrieb.

von Kristoffer Ullsten (Gast)


Lesenswert?

Danke,

ich versuche grad folgende Zeile zu verstehen
1
 TIM1->CCER = blockCommutationTableReverse[hall]
.

Wie wird der Wert hall aus den Encoder Werten abgebildet. Mich würde 
interessieren, welchen Wert der hall bekommt, wenn Encoder Zustand 101 
ist, oder 100, 001.

Danke!

von Matthias S. (Firma: matzetronics) (mschoeldgen)


Lesenswert?

Kristoffer Ullsten schrieb:
> Mich würde
> interessieren, welchen Wert der hall bekommt, wenn Encoder Zustand 101
> ist, oder 100, 001.

Das ist genau die binäre Abbildung. Also '101' ist hall = 5, 001 
entspricht hall = 1 und 100 wäre hall = 4.
Ich habe die Hallsensor Eingänge auf PA0 bis PA2 gelegt und triggere 
beim Wechsel auf einem dieser Pins einen EXTI:
1
/* Setup Hall inputs */
2
RCC_APB2PeriphClockCmd(HALL_GPIO_CLK | RCC_APB2Periph_AFIO, ENABLE);
3
GPIO_InitStructure.GPIO_Pin = H1_GPIO_PIN | H2_GPIO_PIN | H3_GPIO_PIN;
4
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
5
GPIO_Init(HALL_GPIO_PORT, &GPIO_InitStructure);
6
/* Setup Hall Interrupt */
7
/* Connect EXTI0 Line to Hall1 GPIO Pin */
8
9
GPIO_EXTILineConfig(HALL_EXTI_PORT_SOURCE, HALL1_EXTI_PIN_SOURCE);
10
GPIO_EXTILineConfig(HALL_EXTI_PORT_SOURCE, HALL2_EXTI_PIN_SOURCE);
11
GPIO_EXTILineConfig(HALL_EXTI_PORT_SOURCE, HALL3_EXTI_PIN_SOURCE);
12
13
/* Configure Hall EXTI line */
14
15
EXTI_InitStructure.EXTI_Line = (HALL1_EXTI_LINE | HALL2_EXTI_LINE | HALL3_EXTI_LINE);
16
EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
17
EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising_Falling;
18
EXTI_InitStructure.EXTI_LineCmd = ENABLE;
19
EXTI_Init(&EXTI_InitStructure);
20
EXTI_ClearITPendingBit(HALL1_EXTI_LINE | HALL2_EXTI_LINE | HALL3_EXTI_LINE);
21
/* Enable and set EXTI0 Interrupt to the lowest priority */
22
NVIC_InitStructure.NVIC_IRQChannel = HALL1_EXTI_IRQn;
23
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x01;
24
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x01;
25
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
26
NVIC_Init(&NVIC_InitStructure);
27
NVIC_InitStructure.NVIC_IRQChannel = HALL2_EXTI_IRQn;
28
NVIC_Init(&NVIC_InitStructure);
29
NVIC_InitStructure.NVIC_IRQChannel = HALL3_EXTI_IRQn;
30
NVIC_Init(&NVIC_InitStructure);
Im Interrupt passiert dann:
1
/* return the number of the current hallsensors
2
 * which should be between 1 and 6
3
 * values of 0 or 7 mean an error and should set the ERR_HALLSENSOR bit in 'error'
4
 * this happens if more than 3 hallsensor errors have occured
5
 */
6
uint16_t GetHall(void) {
7
volatile uint8_t n = 0;
8
volatile uint16_t hall;
9
        hall = HALL_GPIO_PORT->IDR & HALLMASK;
10
        while(n<6){
11
          if (hall == (HALL_GPIO_PORT->IDR & HALLMASK)) {
12
            n++;
13
            }
14
          else {
15
            n = 0;
16
            hall = (HALL_GPIO_PORT->IDR & HALLMASK);
17
          }
18
        }
19
        if ( (hall < 1) | (hall > 6)) hallerrcount++;
20
         if (hallerrcount > 3 ) error |= ERR_HALLSENSORS;
21
         return hall;
22
}
23
24
void HallIRQ(void) {
25
  EXTI_ClearFlag(EXTI_Line0 | EXTI_Line1 | EXTI_Line2);
26
volatile uint16_t hall = GetHall();
27
    // spurious trap - this routine should only be fired if we have a
28
    // valid sensor change
29
if (lastHall != hall ) {
30
  LED_GPIO_PORT->BSRR = BLUE_LED_PIN;
31
//  rpms = TCD0.CNT;   // read measure
32
//  TCD0.CNT = 0 ;  // reset measure
33
        BlockCommutate(hall);
34
       }
35
}
36
/*
37
*  Hall Sensor 1 IRQ
38
*/
39
void EXTI0_IRQHandler(void)
40
{
41
  if(EXTI_GetITStatus(HALL1_EXTI_LINE) != RESET)
42
  {
43
    /* Clear the EXTI line pending bit */
44
    EXTI_ClearITPendingBit(HALL1_EXTI_LINE);
45
     HallIRQ();
46
  }
47
}
48
/*
49
*  Hall Sensor 2 IRQ
50
*/
51
void EXTI1_IRQHandler(void)
52
{
53
  if(EXTI_GetITStatus(HALL2_EXTI_LINE) != RESET)
54
  {
55
    /* Clear the EXTI line pending bit */
56
    EXTI_ClearITPendingBit(HALL2_EXTI_LINE);
57
    HallIRQ();
58
  }
59
}
60
/*
61
*  Hall Sensor 3 IRQ
62
*/
63
void EXTI2_IRQHandler(void)
64
{
65
  if(EXTI_GetITStatus(HALL3_EXTI_LINE) != RESET)
66
  {
67
    /* Clear the EXTI line pending bit */
68
    EXTI_ClearITPendingBit(HALL3_EXTI_LINE);
69
    HallIRQ();
70
   }
71
}
das ist alles abstrahiert, da ich die eigentliche Port Deklaration wie 
GPIOA usw. z.B. HALL_GPIO_PORT nenne, um schneller auf andere Ports 
umzutippen, falls das mal nötig sein sollte. Ich habe auch eine Menge 
hier weggelassen, wie z.B. lastHall und so, damit es nicht zu verwirrend 
wird.  Ausserdem sind da ein paar Plausibilitätschecks drin, weil es 
hier um etwas kritische Anwendungen geht.

: Bearbeitet durch User
von Kristoffer Ullsten (Gast)


Angehängte Dateien:

Lesenswert?

Vielen Dank. Ich habe den Code etwas geändert.
Hall Inputs bei mir PC10 bis PC12:
1
uint16_t HALLMASK = 7 << 9; // PC10 PC11 PC12
später nach Rechts um 9 Bits verschoben.
Beim Kompilieren gibts keine Fehlermeldung, nur der Motor dreht nicht.

Können Sie bitte den kompletten Code kurz schauen, ob es in Ordnung 
ausschaut.

Danke!

von Kristoffer Ullsten (Gast)


Lesenswert?

Beim GetHall weitere Rechtsbitverschiebung vergessen. Und ergänzt. Es 
funktioniert immer noch nicht. Leider habe ich kein Oszi
1
  hall = (GPIOC->IDR & HALLMASK) >> 9;
2
3
  while(n<6){
4
    if (hall == (GPIOC->IDR & HALLMASK) >> 9){
5
      n++;
6
    }
7
    else{
8
      n = 0;
9
      hall = (GPIOC->IDR & HALLMASK) >> 9;
10
    }
11
  }

von Matthias S. (Firma: matzetronics) (mschoeldgen)


Lesenswert?

Hier ist doppelt PinSource10 konfiguriert:
1
    GPIO_EXTILineConfig(GPIO_PortSourceGPIOC, GPIO_PinSource10);
2
3
    EXTI_InitStructure.EXTI_Line = EXTI_Line10;
4
    EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
5
    EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising_Falling;
6
    EXTI_InitStructure.EXTI_LineCmd = ENABLE;
7
    EXTI_Init(&EXTI_InitStructure);
8
9
    GPIO_EXTILineConfig(GPIO_PortSourceGPIOC, GPIO_PinSource10);
10
11
    EXTI_InitStructure.EXTI_Line = EXTI_Line11;
12
    EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
13
    EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising_Falling;
14
    EXTI_InitStructure.EXTI_LineCmd = ENABLE;
15
    EXTI_Init(&EXTI_InitStructure);
Ich würde mal eine serielle Ausgabe einbauen und mir Werte ausschreiben, 
wie z.B. hall oder das CCER Register.

von Kristoffer Ullsten (Gast)


Lesenswert?

Matthias S. schrieb:
> Hier ist doppelt PinSource10 konfiguriert:

Danke,
> Ich würde mal eine serielle Ausgabe einbauen und mir Werte ausschreiben,
> wie z.B. hall oder das CCER Register.

Danke!! Ich mach das gleich.. Der Encoder funktioniert jetzt ordentlich. 
:)

von Kristoffer Ullsten (Gast)


Lesenswert?

ich bekomme über GetHall() folgende Werte
Rechts: 264513264513264513264513264513264513264513264513264513
Links:  231546231546231546231546231546231546231546231546231546

Es funktioniert immer nicht :(

von Matthias S. (Firma: matzetronics) (mschoeldgen)


Lesenswert?

Kristoffer Ullsten schrieb:
> 264513

Das sieht doch gut aus. Wo ist denn jetzt das Problem?

Die Spulenbestromungsreihenfolge (hehehe) ist von Motor zu Motor 
unterschiedlich, wenn du jetzt also die Tabellen auf deine Maschine 
anpasst, klappt das.
Dazu bestromst du den Motor ganz wenig und prüfst ob der Motor immer in 
den nächsten Sektor ziehen will. Fehler in der Tabelle kriegst du über 
die Hallnummer ja sofort raus.

von Kristoffer Ullsten (Gast)


Lesenswert?

Matthias S. schrieb:
> azu bestromst du den Motor ganz wenig und prüfst ob der Motor immer in
> den näc

Matthias S. schrieb:
> Kristoffer Ullsten schrieb:
>> 264513
>
> Das sieht doch gut aus. Wo ist denn jetzt das Problem?
>
> Die Spulenbestromungsreihenfolge (hehehe) ist von Motor zu Motor
> unterschiedlich, wenn du jetzt also die Tabellen auf deine Maschine
> anpasst, klappt das.
> Dazu bestromst du den Motor ganz wenig und prüfst ob der Motor immer in
> den nächsten Sektor ziehen will. Fehler in der Tabelle kriegst du über
> die Hallnummer ja sofort raus.

wie denn?
na sag schon ;)

von Matthias S. (Firma: matzetronics) (mschoeldgen)


Lesenswert?

Kristoffer Ullsten schrieb:
> wie denn?
> na sag schon ;)

Du bist wohl ein Witzbold. Ich habe keine Ahnung von deinem Aufbau und 
von der derzeitigen Software. Hast du z.B. die Ports und die PWM 
initialisiert und eine Regelung der PWM Power eingebaut?
Ich kann dir nicht meinen kompletten Sourcecode posten - erstens ist der 
schweinelang und zweitens kommen dann noch mehr Fragen, weil dir 
anscheinend ein paar Grundlagen fehlen. Also lies in Ruhe mal AVR447 und 
evtl. auch AVR444. Auch Freescale hat interessante Artikel...

von Kristoffer Ullsten (Gast)


Angehängte Dateien:

Lesenswert?

bin beinah am verzweifeln. Es funktioniert immer nicht. Jedesmal beim 
Einschalten bricht die Quellspannung von 30V auf 18V zusammen und zieht 
dabei 2A. Ich weiss nicht wo der Fehler liegt.
1
void init_all(void){
2
    
3
    /* GPIOA GPIOB and GPIOC clock enable */
4
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
5
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
6
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE);
7
    /* USART3 clock enable */
8
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART3, ENABLE);
9
    /* Interrupt Pin Hall Sensors */
10
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);
11
    
12
    /* TIM1 clock enable APB2 = 56MHz */
13
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1, ENABLE);
14
    
15
    GPIO_InitTypeDef GPIO_InitStructure;
16
        
17
    /* GPIOA PA8 PA9 PA10  TIM1_CH1 TIM1_CH2 TIM1_CH3 */
18
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8 | GPIO_Pin_9 | GPIO_Pin_10;
19
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
20
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
21
    
22
    GPIO_Init(GPIOA, &GPIO_InitStructure);
23
    
24
    
25
    /* GPIOB PB13 PB14 PB15 TIM1_CH1N TIM1_CH2N TIM1_CH3N */
26
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13 | GPIO_Pin_14 | GPIO_Pin_15;
27
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
28
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
29
    
30
    GPIO_Init(GPIOB, &GPIO_InitStructure);
31
    
32
    /* BKIN pin PB12 Break Input Configuration */
33
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12;
34
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
35
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
36
    
37
    GPIO_Init(GPIOB, &GPIO_InitStructure);
38
    
39
 
40
    /* TIM1 clock enable APB2 = 56MHz */
41
    /* PWM_fr = TIM_CLK_fr / (Prescaler + 1) / (Period + 1)  TIM_CLK_fr = 84MHz */
42
    TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
43
    TIM_OCInitTypeDef  TIM_OCInitStructure;
44
    
45
    /* Initialize basic structures to default */
46
    TIM_TimeBaseStructInit(&TIM_TimeBaseStructure);
47
    TIM_OCStructInit(&TIM_OCInitStructure);
48
    
49
    TIM_TimeBaseStructure.TIM_Prescaler = 0;
50
    TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
51
    TIM_TimeBaseStructure.TIM_Period = TimerPeriod; //2800 - 1;
52
    TIM_TimeBaseStructure.TIM_ClockDivision = 0;
53
    TIM_TimeBaseStructure.TIM_RepetitionCounter = 0;
54
    
55
    TIM_TimeBaseInit(TIM1, &TIM_TimeBaseStructure);
56
    TIM_UpdateRequestConfig(TIM1, TIM_UpdateSource_Global);
57
    TIM_UpdateDisableConfig(TIM1,DISABLE);
58
    
59
    
60
    /* Channel 1, 2 and 3 Configuration in PWM mode */
61
    TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM2;
62
    TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
63
    TIM_OCInitStructure.TIM_OutputNState = TIM_OutputNState_Enable;
64
    TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
65
    TIM_OCInitStructure.TIM_OCNPolarity = TIM_OCNPolarity_High;
66
    TIM_OCInitStructure.TIM_OCIdleState = TIM_OCIdleState_Set;
67
    TIM_OCInitStructure.TIM_OCNIdleState = TIM_OCNIdleState_Set;
68
    
69
    TIM_OCInitStructure.TIM_Pulse = Channel1Pulse;
70
    TIM_OC1Init(TIM1, &TIM_OCInitStructure);
71
    
72
    TIM_OCInitStructure.TIM_Pulse = Channel1Pulse;
73
    TIM_OC2Init(TIM1, &TIM_OCInitStructure);
74
    
75
    TIM_OCInitStructure.TIM_Pulse = Channel1Pulse;
76
    TIM_OC3Init(TIM1, &TIM_OCInitStructure);
77
    
78
    TIM_BDTRInitTypeDef TIM_BDTRInitStructure;
79
    TIM_BDTRStructInit(&TIM_BDTRInitStructure);
80
    /* Automatic Output enable, Break, dead time and lock configuration*/
81
    TIM_BDTRInitStructure.TIM_OSSRState = TIM_OSSRState_Enable;
82
    TIM_BDTRInitStructure.TIM_OSSIState = TIM_OSSIState_Enable;
83
    TIM_BDTRInitStructure.TIM_LOCKLevel = TIM_LOCKLevel_OFF;
84
    TIM_BDTRInitStructure.TIM_DeadTime = 10;
85
    TIM_BDTRInitStructure.TIM_Break = TIM_Break_Disable;
86
    TIM_BDTRInitStructure.TIM_BreakPolarity = TIM_BreakPolarity_High;
87
    TIM_BDTRInitStructure.TIM_AutomaticOutput = TIM_AutomaticOutput_Enable;
88
    TIM_BDTRConfig(TIM1, &TIM_BDTRInitStructure);
89
90
91
    EXTI_InitTypeDef EXTI_InitStructure;
92
    NVIC_InitTypeDef NVIC_InitStructure;
93
    /* Hall Input Pin Config: PC10 PC11 PC12 */
94
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10 | GPIO_Pin_11 | GPIO_Pin_12;
95
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
96
    GPIO_Init(GPIOC, &GPIO_InitStructure);
97
    
98
    GPIO_EXTILineConfig(GPIO_PortSourceGPIOC, GPIO_PinSource10);
99
    
100
    EXTI_InitStructure.EXTI_Line = EXTI_Line10;
101
    EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
102
    EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising_Falling;
103
    EXTI_InitStructure.EXTI_LineCmd = ENABLE;
104
    EXTI_Init(&EXTI_InitStructure);
105
    
106
    GPIO_EXTILineConfig(GPIO_PortSourceGPIOC, GPIO_PinSource11);
107
    
108
    EXTI_InitStructure.EXTI_Line = EXTI_Line11;
109
    EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
110
    EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising_Falling;
111
    EXTI_InitStructure.EXTI_LineCmd = ENABLE;
112
    EXTI_Init(&EXTI_InitStructure);
113
    
114
    GPIO_EXTILineConfig(GPIO_PortSourceGPIOC, GPIO_PinSource12);
115
    
116
    EXTI_InitStructure.EXTI_Line = EXTI_Line12;
117
    EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
118
    EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising_Falling;
119
    EXTI_InitStructure.EXTI_LineCmd = ENABLE;
120
    EXTI_Init(&EXTI_InitStructure);
121
    
122
    
123
    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);
124
    
125
    NVIC_InitStructure.NVIC_IRQChannel = EXTI15_10_IRQn;
126
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
127
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x0F;
128
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x0F;
129
    NVIC_Init(&NVIC_InitStructure);
130
    
131
}
132
133
uint16_t HALLMASK = 7 << 10; // PC12 PC11 PC10
134
uint16_t GetHall(void){
135
    volatile uint16_t hall = (GPIOC->IDR & HALLMASK) >> 10;
136
    return hall;
137
}
138
139
volatile uint16_t lastHall = 0;
140
void HallIRQ(void){
141
    EXTI_ClearFlag(EXTI_Line10 | EXTI_Line11 | EXTI_Line12);
142
    volatile uint16_t hall = GetHall();        
143
    commutate(hall);
144
}
145
146
void commutate(uint16_t step){
147
    TIM_Cmd(TIM1, DISABLE);
148
    TIM_CtrlPWMOutputs(TIM1, DISABLE);
149
    
150
    switch(step){
151
        case 5:
152
            /*  Channel3 configuration */
153
            TIM_CCxCmd(TIM1, TIM_Channel_3, TIM_CCx_Disable);
154
            TIM_CCxNCmd(TIM1, TIM_Channel_3, TIM_CCxN_Disable);
155
            
156
            /*  Channel1 configuration */
157
            TIM_SelectOCxM(TIM1, TIM_Channel_1, TIM_OCMode_PWM1);
158
            TIM_CCxCmd(TIM1, TIM_Channel_1, TIM_CCx_Enable);
159
            TIM_CCxNCmd(TIM1, TIM_Channel_1, TIM_CCxN_Disable);
160
            
161
            /*  Channel2 configuration */
162
            TIM_SelectOCxM(TIM1, TIM_Channel_2, TIM_OCMode_PWM1 );
163
            TIM_CCxCmd(TIM1, TIM_Channel_2, TIM_CCx_Disable);
164
            TIM_CCxNCmd(TIM1, TIM_Channel_2, TIM_CCxN_Enable);
165
            break;
166
        case 4:
167
            /*  Channel2 configuration */
168
            TIM_SelectOCxM(TIM1, TIM_Channel_2, TIM_OCMode_PWM1);
169
            TIM_CCxCmd(TIM1, TIM_Channel_2, TIM_CCx_Disable);
170
            TIM_CCxNCmd(TIM1, TIM_Channel_2, TIM_CCxN_Enable);
171
            
172
            /*  Channel3 configuration */
173
            TIM_SelectOCxM(TIM1, TIM_Channel_3, TIM_OCMode_PWM1);
174
            TIM_CCxCmd(TIM1, TIM_Channel_3, TIM_CCx_Enable);
175
            TIM_CCxNCmd(TIM1, TIM_Channel_3, TIM_CCxN_Disable);
176
            
177
            /*  Channel1 configuration */
178
            TIM_CCxCmd(TIM1, TIM_Channel_1, TIM_CCx_Disable);
179
            TIM_CCxNCmd(TIM1, TIM_Channel_1, TIM_CCxN_Disable);
180
            break;
181
        case 6:
182
            /*  Channel3 configuration */
183
            TIM_SelectOCxM(TIM1, TIM_Channel_3, TIM_OCMode_PWM1);
184
            TIM_CCxCmd(TIM1, TIM_Channel_3, TIM_CCx_Enable);
185
            TIM_CCxNCmd(TIM1, TIM_Channel_3, TIM_CCxN_Disable);
186
            
187
            /*  Channel2 configuration */
188
            TIM_CCxCmd(TIM1, TIM_Channel_2, TIM_CCx_Disable);
189
            TIM_CCxNCmd(TIM1, TIM_Channel_2, TIM_CCxN_Disable);
190
            
191
            /*  Channel1 configuration */
192
            TIM_SelectOCxM(TIM1, TIM_Channel_1, TIM_OCMode_PWM1);
193
            TIM_CCxCmd(TIM1, TIM_Channel_1, TIM_CCx_Disable);
194
            TIM_CCxNCmd(TIM1, TIM_Channel_1, TIM_CCxN_Enable);
195
            break;
196
        case 2:
197
            /*  Channel3 configuration */
198
            TIM_CCxCmd(TIM1, TIM_Channel_3, TIM_CCx_Disable);
199
            TIM_CCxNCmd(TIM1, TIM_Channel_3, TIM_CCxN_Disable);
200
            
201
            /*  Channel1 configuration */
202
            TIM_SelectOCxM(TIM1, TIM_Channel_1, TIM_OCMode_PWM1);
203
            TIM_CCxCmd(TIM1, TIM_Channel_1, TIM_CCx_Disable);
204
            TIM_CCxNCmd(TIM1, TIM_Channel_1, TIM_CCxN_Enable);
205
            
206
            /*  Channel2 configuration */
207
            TIM_SelectOCxM(TIM1, TIM_Channel_2, TIM_OCMode_PWM1);
208
            TIM_CCxCmd(TIM1, TIM_Channel_2, TIM_CCx_Enable);
209
            TIM_CCxNCmd(TIM1, TIM_Channel_2, TIM_CCxN_Disable);
210
            break;
211
        case 3:
212
            /*  Channel3 configuration */
213
            TIM_SelectOCxM(TIM1, TIM_Channel_3, TIM_OCMode_PWM1);
214
            TIM_CCxCmd(TIM1, TIM_Channel_3, TIM_CCx_Disable);
215
            TIM_CCxNCmd(TIM1, TIM_Channel_3, TIM_CCxN_Enable);
216
            
217
            /*  Channel1 configuration */
218
            TIM_CCxCmd(TIM1, TIM_Channel_1, TIM_CCx_Disable);
219
            TIM_CCxNCmd(TIM1, TIM_Channel_1, TIM_CCxN_Disable);
220
            
221
            /*  Channel2 configuration */
222
            TIM_SelectOCxM(TIM1, TIM_Channel_2, TIM_OCMode_PWM1);
223
            TIM_CCxCmd(TIM1, TIM_Channel_2, TIM_CCx_Enable);
224
            TIM_CCxNCmd(TIM1, TIM_Channel_2, TIM_CCxN_Disable);
225
            break;
226
        case 1:
227
            /*  Channel1 configuration */
228
            TIM_SelectOCxM(TIM1, TIM_Channel_1, TIM_OCMode_PWM1);
229
            TIM_CCxCmd(TIM1, TIM_Channel_1, TIM_CCx_Enable);
230
            TIM_CCxNCmd(TIM1, TIM_Channel_2, TIM_CCxN_Disable);
231
            
232
            /*  Channel3 configuration */
233
            TIM_SelectOCxM(TIM1, TIM_Channel_3, TIM_OCMode_PWM1);
234
            TIM_CCxCmd(TIM1, TIM_Channel_3, TIM_CCx_Disable);
235
            TIM_CCxNCmd(TIM1, TIM_Channel_3, TIM_CCxN_Enable);
236
            
237
            /*  Channel2 configuration */
238
            TIM_CCxCmd(TIM1, TIM_Channel_2, TIM_CCx_Disable);
239
            TIM_CCxNCmd(TIM1, TIM_Channel_2, TIM_CCxN_Disable);
240
            break;
241
        default:
242
            break;
243
    }
244
    TIM_Cmd(TIM1, ENABLE);
245
    TIM_CtrlPWMOutputs(TIM1, ENABLE);
246
}

von Matthias S. (Firma: matzetronics) (mschoeldgen)


Lesenswert?

Kristoffer Ullsten schrieb:
> Jedesmal beim
> Einschalten bricht die Quellspannung von 30V auf 18V zusammen

Wie, du testest mit angeschlossenen Endstufen? Das solltest du vorerst 
lassen, sondern stattdessen erstmal nur die Hallsensoren anschliessen 
und schauen, was an den PWM Ausgängen passiert, wenn du den Motor 
langsam händisch drehst.
Ausserdem ist es sinnvoll, sich ein paar Debug Pins als Ausgang zu 
konfigurieren, um den Programmablauf zu untersuchen.
In der commutate() Routine hast du den Weg über switch case gewählt, 
statt über eine Tabelle, das macht das Konfigurieren unnötig 
unübersichtlich und langsam, aber gut, gehen sollte es auch.
Bei meinen ersten Versuchen (mit dem guten alten Mega) hatte ich mir auf 
ein Blatt Papier die Sensoren und die Spulen aufgemalt und dann 
untersucht, wie der Motor bestromt werden muss, damit er bei Zustand 1 
der Sensoren in den nächsten Sektor zieht, und das gleiche für alle 6 
Sektoren wiederholt. Als ich das so dann in die Tabelle eintrug, lief 
der kleine Kerl sofort wie gewünscht. Das gleiche habe ich dann für den 
Rückwärtslauf auch gemacht.

Gib dir über UART zu den Hallsensoren auch mal den Zustand des CCER 
Registers von Timer 1 aus (TIM1->CCER), dann siehst du, ob das 
Ansteuermuster auch funktioniert.

Hier ein paar ganz primitive Routinen zur Ausgabe von Bytes, Words und 
Longs auf UART:
1
const char hextable[16] = "0123456789ABCDEF";
2
// very simple output to hex
3
void printbyte(const uint8_t data)
4
{
5
  uart_put(hextable[data >> 4]);
6
  uart_put(hextable[data & 0x0f]);
7
}
8
void printword(const uint16_t data)
9
{
10
  printbyte(data >> 8);
11
  printbyte((uint8_t)data);
12
}
13
void printlong(const uint32_t data){
14
  printword((uint16_t)data >> 16);
15
  printword((uint16_t)data);
16
}

von Kristoffer Ullsten (Gast)


Lesenswert?

Matthias S. schrieb:
Danke für die Antwort. Ich hab den Motor zum Drehen gebracht einfach 
ohne PWM. Die untere 3 Eingänge PB13, PB14, PB15 vom Gate-Treiber sind 
invertiert worden.
1
void commutate(uint16_t step){
2
3
    switch(step){
4
        case 5:
5
            // 1
6
            GPIO_SetBits(GPIOA, GPIO_Pin_8);
7
            GPIO_SetBits(GPIOB, GPIO_Pin_13);
8
9
            GPIO_ResetBits(GPIOA, GPIO_Pin_9);
10
            GPIO_ResetBits(GPIOB, GPIO_Pin_14);
11
            
12
            GPIO_ResetBits(GPIOA, GPIO_Pin_10);
13
            GPIO_SetBits(GPIOB, GPIO_Pin_15);
14
            break;
15
        case 4:
16
            // 2
17
            GPIO_ResetBits(GPIOA, GPIO_Pin_8);
18
            GPIO_SetBits(GPIOB, GPIO_Pin_13);
19
20
            GPIO_ResetBits(GPIOA, GPIO_Pin_9);
21
            GPIO_ResetBits(GPIOB, GPIO_Pin_14);
22
            
23
            GPIO_SetBits(GPIOA, GPIO_Pin_10);
24
            GPIO_SetBits(GPIOB, GPIO_Pin_15);
25
            break;
26
        case 6:
27
            // 3
28
            GPIO_ResetBits(GPIOA, GPIO_Pin_8);
29
            GPIO_ResetBits(GPIOB, GPIO_Pin_13);
30
31
            GPIO_ResetBits(GPIOA, GPIO_Pin_9);
32
            GPIO_SetBits(GPIOB, GPIO_Pin_14);
33
            
34
            GPIO_SetBits(GPIOA, GPIO_Pin_10);
35
            GPIO_SetBits(GPIOB, GPIO_Pin_15);
36
            break;
37
        case 2:
38
           // 4
39
            GPIO_ResetBits(GPIOA, GPIO_Pin_8);
40
            GPIO_ResetBits(GPIOB, GPIO_Pin_13);
41
42
            GPIO_SetBits(GPIOA, GPIO_Pin_9);
43
            GPIO_SetBits(GPIOB, GPIO_Pin_14);
44
            
45
            GPIO_ResetBits(GPIOA, GPIO_Pin_10);
46
            GPIO_SetBits(GPIOB, GPIO_Pin_15);
47
            break;
48
        case 3:
49
            // 5
50
            GPIO_ResetBits(GPIOA, GPIO_Pin_8);
51
            GPIO_SetBits(GPIOB, GPIO_Pin_13);
52
53
            GPIO_SetBits(GPIOA, GPIO_Pin_9);
54
            GPIO_SetBits(GPIOB, GPIO_Pin_14);
55
            
56
            GPIO_ResetBits(GPIOA, GPIO_Pin_10);
57
            GPIO_ResetBits(GPIOB, GPIO_Pin_15);
58
            break;
59
        case 1:
60
            // 6
61
            GPIO_SetBits(GPIOA, GPIO_Pin_8);
62
            GPIO_SetBits(GPIOB, GPIO_Pin_13);
63
64
            GPIO_ResetBits(GPIOA, GPIO_Pin_9);
65
            GPIO_SetBits(GPIOB, GPIO_Pin_14);
66
            
67
            GPIO_ResetBits(GPIOA, GPIO_Pin_10);
68
            GPIO_ResetBits(GPIOB, GPIO_Pin_15);
69
            break;
70
        default:
71
            break;
72
    }
73
}

ich frag mich wie ich das jetzt mit PWM mache.
1
    /* Channel 1, 2 and 3 Configuration in PWM mode */
2
    TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM2;
3
    TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
4
    TIM_OCInitStructure.TIM_OutputNState = TIM_OutputNState_Enable;
5
    TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
6
    TIM_OCInitStructure.TIM_OCNPolarity = TIM_OCNPolarity_High;
7
    TIM_OCInitStructure.TIM_OCIdleState = TIM_OCIdleState_Set;
8
    TIM_OCInitStructure.TIM_OCNIdleState = TIM_OCNIdleState_Set;

von Matthias S. (Firma: matzetronics) (mschoeldgen)


Lesenswert?

Kristoffer Ullsten schrieb:
> ich frag mich wie ich das jetzt mit PWM mache.
>     /* Channel 1, 2 and 3 Configuration in PWM mode */
>     TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM2;
>     TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
>     TIM_OCInitStructure.TIM_OutputNState = TIM_OutputNState_Enable;
>     TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
>     TIM_OCInitStructure.TIM_OCNPolarity = TIM_OCNPolarity_High;
>     TIM_OCInitStructure.TIM_OCIdleState = TIM_OCIdleState_Set;
>     TIM_OCInitStructure.TIM_OCNIdleState = TIM_OCNIdleState_Set;

Sieht doch gar nicht falsch aus. Allerdings musst du die Struktur nun 
auch benutzen:
1
TIM_OC1Init(TIM1, &TIM_OCInitStructure);
2
TIM_OC2Init(TIM1, &TIM_OCInitStructure);
3
TIM_OC3Init(TIM1, &TIM_OCInitStructure);
Und nicht vergessen, die CC Register dann auch mit PWM Werten zu 
beschreiben. Timer 1 muss natürlich initialisiert sein, und die Pins auf 
AF konfiguriert werden. Siehe z.B. die Beispiele im STM32 VLDicovery 
Package.

: Bearbeitet durch User
von Kristoffer Ullsten (Gast)


Lesenswert?

Matthias S. schrieb:
> TIM_OutputNState

Matthias S. schrieb:
> Kristoffer Ullsten schrieb:
>> ich frag mich wie ich das jetzt mit PWM mache.
>>     /* Channel 1, 2 and 3 Configuration in PWM mode */
>>     TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM2;
>>     TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
>>     TIM_OCInitStructure.TIM_OutputNState = TIM_OutputNState_Enable;
>>     TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
>>     TIM_OCInitStructure.TIM_OCNPolarity = TIM_OCNPolarity_High;
>>     TIM_OCInitStructure.TIM_OCIdleState = TIM_OCIdleState_Set;
>>     TIM_OCInitStructure.TIM_OCNIdleState = TIM_OCNIdleState_Set;
>
> Sieht doch gar nicht falsch aus. Allerdings musst du die Struktur nun
> auch benutzen:TIM_OC1Init(TIM1, &TIM_OCInitStructure);
> TIM_OC2Init(TIM1, &TIM_OCInitStructure);
> TIM_OC3Init(TIM1, &TIM_OCInitStructure);
> Und nicht vergessen, die CC Register dann auch mit PWM Werten zu
> beschreiben. Timer 1 muss natürlich initialisiert sein, und die Pins auf
> AF konfiguriert werden. Siehe z.B. die Beispiele im STM32 VLDicovery
> Package.

Wie macht man dass die OCN Ausgänge nicht invertiert sind

von Matthias S. (Firma: matzetronics) (mschoeldgen)


Lesenswert?


: Bearbeitet durch User
von Kristoffer Ullsten (Gast)


Angehängte Dateien:

Lesenswert?

ich habe den Motor mit PWM 15% Tastverhältnis zum Drehen gebracht. Und 
zwar  vibriert er zu heftig und macht laute Geräusche. Ich denke, dass 
ich immer noch die Kommutierungsschritte nicht richtig hingekriegt habe. 
PWM Frequenz liegt auf 20kHz.

Ohne PWM direkt beispielsweise mit
1
void commutate(uint16_t step){
2
    switch(step){
3
        case 5:
4
            GPIO_SetBits(GPIOA, GPIO_Pin_8);
5
            GPIO_SetBits(GPIOB, GPIO_Pin_13);
6
7
            GPIO_ResetBits(GPIOA, GPIO_Pin_9);
8
            GPIO_ResetBits(GPIOB, GPIO_Pin_14);
9
            
10
            GPIO_ResetBits(GPIOA, GPIO_Pin_10);
11
            GPIO_SetBits(GPIOB, GPIO_Pin_15);
12
            break;
hat der Motor schön sauber gedreht. Ich weiss nicht wo der Fehler genau 
liegt.
1
    TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
2
    TIM_OCInitTypeDef  TIM_OCInitStructure;
3
    
4
    TIM_TimeBaseStructInit(&TIM_TimeBaseStructure);
5
    TIM_OCStructInit(&TIM_OCInitStructure);
6
    
7
    TIM_TimeBaseStructure.TIM_Prescaler = 0;
8
    TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
9
    TIM_TimeBaseStructure.TIM_Period = TimerPeriod; //2800 - 1;
10
    TIM_TimeBaseStructure.TIM_ClockDivision = 0;
11
    TIM_TimeBaseStructure.TIM_RepetitionCounter = 0;
12
    
13
    TIM_TimeBaseInit(TIM1, &TIM_TimeBaseStructure);    
14
    
15
    /* Channel 1, 2 and 3 Configuration in PWM mode */
16
    TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
17
    TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
18
    TIM_OCInitStructure.TIM_OutputNState = TIM_OutputNState_Enable;
19
    TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
20
    TIM_OCInitStructure.TIM_OCNPolarity = TIM_OCNPolarity_Low;
21
    TIM_OCInitStructure.TIM_OCIdleState = TIM_OCIdleState_Set;
22
    TIM_OCInitStructure.TIM_OCNIdleState = TIM_OCNIdleState_Set;
23
    
24
    TIM_OCInitStructure.TIM_Pulse = 0;
25
    TIM_OC1Init(TIM1, &TIM_OCInitStructure);
26
    
27
    TIM_OCInitStructure.TIM_Pulse = 0;
28
    TIM_OC2Init(TIM1, &TIM_OCInitStructure);
29
    
30
    TIM_OCInitStructure.TIM_Pulse = 0;
31
    TIM_OC3Init(TIM1, &TIM_OCInitStructure);
TIM_OCNPolarity ist auf TIM_OCNPolarity_Low, weil die 3 Low Eingänge 
invertiert sind.
1
uint16_t HALLMASK = 7 << 10; // PC12 PC11 PC10
2
uint16_t GetHall(void){
3
    volatile uint16_t hall = (GPIOC->IDR & HALLMASK) >> 10;
4
    return hall;
5
}
6
7
void HallIRQ(void){
8
    EXTI_ClearFlag(EXTI_Line10 | EXTI_Line11 | EXTI_Line12);
9
    volatile uint16_t hall = GetHall();        
10
    commutate(hall);
11
}

1
void commutate(uint16_t step){
2
    TIM_Cmd(TIM1, DISABLE);
3
    TIM_CtrlPWMOutputs(TIM1, DISABLE);
4
    
5
    switch(step){
6
        case 5:            
7
            /*  Channel1 configuration */
8
            TIM_SelectOCxM(TIM1, TIM_Channel_1, TIM_OCMode_PWM1);
9
            TIM_CCxCmd(TIM1, TIM_Channel_1, TIM_CCx_Enable);
10
            TIM_CCxNCmd(TIM1, TIM_Channel_1, TIM_CCxN_Enable);
11
            
12
            /*  Channel2 configuration */
13
            TIM_CCxCmd(TIM1, TIM_Channel_2, TIM_CCx_Disable);
14
            TIM_CCxNCmd(TIM1, TIM_Channel_2, TIM_CCxN_Disable);
15
            
16
            /*  Channel3 configuration */
17
            TIM_CCxCmd(TIM1, TIM_Channel_3, TIM_CCx_Disable);
18
            TIM_SelectOCxM(TIM1, TIM_Channel_3, TIM_ForcedAction_Active);
19
            TIM_CCxNCmd(TIM1, TIM_Channel_3, TIM_CCxN_Enable);
20
            break;
21
        case 4:
22
            /*  Channel1 configuration */
23
            TIM_CCxCmd(TIM1, TIM_Channel_1, TIM_CCx_Disable);
24
            TIM_SelectOCxM(TIM1, TIM_Channel_1, TIM_ForcedAction_Active);
25
            TIM_CCxNCmd(TIM1, TIM_Channel_1, TIM_CCxN_Enable);
26
27
            /*  Channel2 configuration */
28
            TIM_CCxCmd(TIM1, TIM_Channel_2, TIM_CCx_Disable);
29
            TIM_CCxNCmd(TIM1, TIM_Channel_2, TIM_CCxN_Disable);
30
            
31
            /*  Channel3 configuration */
32
            TIM_SelectOCxM(TIM1, TIM_Channel_3, TIM_OCMode_PWM1);
33
            TIM_CCxCmd(TIM1, TIM_Channel_3, TIM_CCx_Enable);
34
            TIM_CCxNCmd(TIM1, TIM_Channel_3, TIM_CCxN_Enable);
35
            break;
36
        case 6:
37
            /*  Channel1 configuration */
38
            TIM_CCxCmd(TIM1, TIM_Channel_1, TIM_CCx_Disable);
39
            TIM_CCxNCmd(TIM1, TIM_Channel_1, TIM_CCxN_Disable);
40
            
41
            /*  Channel2 configuration */
42
            TIM_CCxCmd(TIM1, TIM_Channel_2, TIM_CCx_Disable);
43
            TIM_SelectOCxM(TIM1, TIM_Channel_2, TIM_ForcedAction_Active);
44
            TIM_CCxNCmd(TIM1, TIM_Channel_2, TIM_CCxN_Enable);
45
            
46
            /*  Channel3 configuration */
47
            TIM_SelectOCxM(TIM1, TIM_Channel_3, TIM_OCMode_PWM1);
48
            TIM_CCxCmd(TIM1, TIM_Channel_3, TIM_CCx_Enable);
49
            TIM_CCxNCmd(TIM1, TIM_Channel_3, TIM_CCxN_Enable);
50
51
            break;
52
        case 2:
53
            /*  Channel1 configuration */
54
            TIM_CCxCmd(TIM1, TIM_Channel_1, TIM_CCx_Disable);
55
            TIM_CCxNCmd(TIM1, TIM_Channel_1, TIM_CCxN_Disable);
56
            
57
            /*  Channel2 configuration */
58
            TIM_SelectOCxM(TIM1, TIM_Channel_2, TIM_OCMode_PWM1);
59
            TIM_CCxCmd(TIM1, TIM_Channel_2, TIM_CCx_Enable);
60
            TIM_CCxNCmd(TIM1, TIM_Channel_2, TIM_CCxN_Enable);
61
                        
62
            /*  Channel3 configuration */
63
            TIM_CCxCmd(TIM1, TIM_Channel_3, TIM_CCx_Disable);
64
            TIM_SelectOCxM(TIM1, TIM_Channel_3, TIM_ForcedAction_Active);
65
            TIM_CCxNCmd(TIM1, TIM_Channel_3, TIM_CCxN_Enable);
66
            break;
67
        case 3:
68
            /*  Channel1 configuration */
69
            TIM_CCxCmd(TIM1, TIM_Channel_1, TIM_CCx_Disable);
70
            TIM_SelectOCxM(TIM1, TIM_Channel_1, TIM_ForcedAction_Active);
71
            TIM_CCxNCmd(TIM1, TIM_Channel_1, TIM_CCxN_Enable);
72
            
73
            /*  Channel2 configuration */
74
            TIM_SelectOCxM(TIM1, TIM_Channel_2, TIM_OCMode_PWM1);
75
            TIM_CCxCmd(TIM1, TIM_Channel_2, TIM_CCx_Enable);
76
            TIM_CCxNCmd(TIM1, TIM_Channel_2, TIM_CCxN_Enable);
77
78
            /*  Channel3 configuration */
79
            TIM_CCxCmd(TIM1, TIM_Channel_3, TIM_CCx_Disable);
80
            TIM_CCxNCmd(TIM1, TIM_Channel_3, TIM_CCxN_Disable);
81
            break;
82
        case 1:
83
            /*  Channel1 configuration */
84
            TIM_SelectOCxM(TIM1, TIM_Channel_1, TIM_OCMode_PWM1);
85
            TIM_CCxCmd(TIM1, TIM_Channel_1, TIM_CCx_Enable);
86
            TIM_CCxNCmd(TIM1, TIM_Channel_2, TIM_CCxN_Enable);
87
                        
88
            /*  Channel2 configuration */
89
            TIM_CCxCmd(TIM1, TIM_Channel_2, TIM_CCx_Disable);
90
            TIM_SelectOCxM(TIM1, TIM_Channel_2, TIM_ForcedAction_Active);
91
            TIM_CCxNCmd(TIM1, TIM_Channel_2, TIM_CCxN_Enable);
92
            
93
            /*  Channel3 configuration */
94
            TIM_CCxCmd(TIM1, TIM_Channel_3, TIM_CCx_Disable);
95
            TIM_CCxNCmd(TIM1, TIM_Channel_3, TIM_CCxN_Disable);
96
            break;
97
        default:
98
            break;
99
    }
100
    TIM_Cmd(TIM1, ENABLE);
101
    TIM_CtrlPWMOutputs(TIM1, ENABLE);
102
}

von Kristoffer Ullsten (Gast)


Angehängte Dateien:

Lesenswert?

hab soeben die Stränge am Oszi beobachtet, sieht etwas seltsam aus, kann 
mir jemand bitte erklären ob es in Ordnung ausschaut

von Matthias S. (Firma: matzetronics) (mschoeldgen)


Lesenswert?

Ich werde jetzt nicht die völlig bekloppte Methode mit deinen 
TIMCCxCMD() switch-case durchklappern. Da wirst du dich irgendwo 
vertippt haben.

Ich habe dir vor ein paar -zig Beiträgen die Sache mit den Tabellen 
vorgeschlagen, die recht idiotensicher und schnell an andere Motoren 
anpassbar ist.

von Kristoffer Ullsten (Gast)


Lesenswert?

Matthias S. schrieb:
> Ich werde jetzt nicht die völlig bekloppte Methode mit deinen
> TIMCCxCMD() switch-case durchklappern. Da wirst du dich irgendwo
> vertippt haben.
>
> Ich habe dir vor ein paar -zig Beiträgen die Sache mit den Tabellen
> vorgeschlagen, die recht idiotensicher und schnell an andere Motoren
> anpassbar ist.

Die Tabelle würde ich gern später verwenden. Mein Problem ist , wie 
setze ich einen bestimmten PWM Pin Pegel auf High ohne 
TIM_ForcedAction_Active zu benutzen.

Zwischen TIM1->CCER = 0x0002 und 0x0000 sehe ich keinen Unterschied am 
Oszi. Der Pin Level liegt immer auf Low.

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.