Variable speed drive (SPWM) for the STM32F302 Nucleo with the ihm07m1 motor control board

Dependencies:   mbed

Files at this revision

API Documentation at this revision

Comitter:
f3d
Date:
Sun Mar 08 13:51:54 2020 +0000
Commit message:
Variable speed drive for the STM32F302 Nucleo with the ihm07m1 motor control board

Changed in this revision

main.cpp Show annotated file Show diff for this revision Revisions of this file
mbed.bld Show annotated file Show diff for this revision Revisions of this file
diff -r 000000000000 -r 0e9094f7b28d main.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/main.cpp	Sun Mar 08 13:51:54 2020 +0000
@@ -0,0 +1,179 @@
+// This program allows the user to change the frequency of the three phase SPWM output
+// produced by TIM1.  The voltage ramps upwards with frequency.
+#include <stdint.h>
+#include "mbed.h"
+DigitalOut myled(LED1);
+/*
+PA8,9,10 are used to drive the PWM outputs.  They are also connected back to TIM_CH1,CH2,CH3 
+EN1,2,3 are pulled low and connected back to PC10,11,12
+PC13 = Blue button
+PB13 = User LED (I think - if not it is PA5)
+*/
+
+
+PwmOut PhA(PA_8);
+PwmOut PhB(PA_9);
+PwmOut PhC(PA_10);
+
+
+DigitalOut En1(PC_10);
+DigitalOut En2(PC_11);
+DigitalOut En3(PC_12);
+AnalogIn Pot(PB_1);
+Serial pc(USBTX, USBRX); // tx, rx useful for debugging
+volatile int CountA,CountB,CountC;
+
+#define FS 12000
+#define FC 72000000
+#define F_MOD_MIN 10
+#define F_MOD_MAX 100
+#define MAX_PWM_STEPS (FS/F_MOD_MIN)
+#define PI 3.141592f
+volatile int UpdatePending = 0;
+volatile uint32_t NSwitchesPerCycle;
+float AngleStep;
+float fm = 0; // modulation frequency
+float ami = 0; // Amplitude modulation index
+volatile uint16_t PWM_length;
+
+volatile uint16_t *PWM;
+volatile uint16_t PWMBuffer1[MAX_PWM_STEPS];
+volatile uint16_t PWMBuffer2[MAX_PWM_STEPS];
+
+
+void TimerISR(void)
+{
+    TIM1->CCR1 = PWM[CountA]; 
+    TIM1->CCR2 = PWM[CountB]; 
+    TIM1->CCR3 = PWM[CountC]; 
+    
+    CountB = (CountB + 1) % PWM_length;
+    CountC = (CountC + 1) % PWM_length;
+    TIM1->SR &= ~0x3f; // ack the interrupt    
+    CountA = (CountA + 1) % PWM_length;
+    if ( (CountA == 0) && UpdatePending )
+    {
+        if (PWM == PWMBuffer1) 
+            PWM = PWMBuffer2;
+        else        
+            PWM = PWMBuffer1;
+        CountA = 0;
+        CountB = PWM_length/3;
+        CountC = (2*PWM_length)/3;
+        PWM_length = NSwitchesPerCycle; 
+        UpdatePending = 0;
+    }
+
+}
+void initTimer1()
+{    
+    
+    TIM1->CR1 = 0; // make sure Counter is disabled before changing configuration
+    TIM1->CR2 = 0;
+    TIM1->PSC = 0; 
+    TIM1->ARR = (FC/FS)-1;
+    TIM1->CCR1 = 0; // 0% duty
+    TIM1->CCR2 = 0; // 0% duty
+    TIM1->CCR3 = 0; // 0% duty
+    // Enable timer outputs on channels 1,2,3
+    TIM1->CCER = (1 << 0) + (1 << 4) + (1 << 8);
+    TIM1->SR = 0;      // Clear flags.    
+    TIM1->CR1 |= 1; // enable counter
+
+    // Set up the interrupt handler
+    TIM1->DIER = 1; // Want update interrupt
+    NVIC_SetVector(TIM1_UP_TIM16_IRQn,(uint32_t) TimerISR);   
+    NVIC_EnableIRQ(TIM1_UP_TIM16_IRQn);
+    __enable_irq();   // enable interrupts */
+
+}
+void start()
+{
+    
+    TIM1->CCR1 = 0; // 0% duty
+    TIM1->CCR2 = 0; // 0% duty
+    TIM1->CCR3 = 0; // 0% duty
+    En1 = 1;
+    En2 = 1;
+    En3 = 1;
+    CountA = 0;
+    PWM_length = 6;
+    CountB = PWM_length / 3;
+    CountC = (2 *PWM_length) / 3;
+    for (int i=0;i<PWM_length;i++)
+    {
+        PWMBuffer1[i] = PWMBuffer2[i]= (FC/FS)/2; // set 50% duty for all values
+    }
+    PWM = PWMBuffer1;    
+}
+void updatePWM()
+{
+    float ami = Pot.read();
+    float fmi=ami; // maintain V/F = constant
+    uint16_t * UnusedPWMBuffer;
+    
+    if (PWM == PWMBuffer1) 
+    {
+        UnusedPWMBuffer = (uint16_t *)PWMBuffer2;
+    }
+    else
+    {
+        UnusedPWMBuffer = (uint16_t *)PWMBuffer1;
+    }
+    fm = fmi * F_MOD_MAX;
+    if (fm < F_MOD_MIN)
+    {
+        ami = 0;        
+        for (int i=0;i<PWM_length;i++)
+        {
+            UnusedPWMBuffer[i] = UnusedPWMBuffer[i]= (FC/FS)/2; // set 50% duty for all values
+        }
+        PWM = UnusedPWMBuffer;    
+        PWM_length = 6;
+    }
+    else
+    {
+        // Need to provide a voltage boost here to increase torque (motor stalls otherwise)
+        float amplitude = (1.5f*ami) * (FC/FS)/2; // Scale amplitude to ARR range
+        // The higher the frequency the greater the angle step size (similar to digital sampling
+        // The greatest number of steps occurs when we calculate a value for sine
+        
+        NSwitchesPerCycle = FS/fm;
+                
+        float AngleStep = 2.0f*PI / ((float)NSwitchesPerCycle);
+        
+        float Angle = 0;
+        
+        for (int i=0;i<NSwitchesPerCycle;i++)
+        {
+            float sine = (amplitude * sinf(Angle))+(FC/FS)/2;
+            if (sine > (FC/FS))
+                sine = (FC/FS);
+            if (sine < 0)
+                sine = 0;
+            UnusedPWMBuffer[i] = sine; // set 50% duty for all values
+            
+            Angle = Angle + AngleStep;
+        }
+        
+        UpdatePending = 1;
+        /* pc.printf("NSwitchesPerCycle = %d\r\n",NSwitchesPerCycle);
+        pc.printf("amplitude = %f\r\n",amplitude);
+        pc.printf("ARR = %d\r\n",TIM1->ARR);
+        pc.printf("---------------\r\n"); */
+    }
+    
+}
+int main() {
+    initTimer1();
+    start();
+    updatePWM();
+    while(1) {
+        wait(1); // wait for 200ms
+        myled = myled ^ 1; // Toggle the LED
+        updatePWM();
+        
+        
+
+    }
+}
diff -r 000000000000 -r 0e9094f7b28d mbed.bld
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed.bld	Sun Mar 08 13:51:54 2020 +0000
@@ -0,0 +1,1 @@
+https://os.mbed.com/users/mbed_official/code/mbed/builds/65be27845400
\ No newline at end of file