Libs for using Nucleo STM32F411 periphery

Introduction

Descruption: This lib uses the hardware peripherie from STM32F411 under serveral conditions. So you can use an quadraturencoder with different timers.

Requirement: Only tested with the nucleo F411. Include the mbed lib! Interfacing details are explained in the documentary of each class.

Overview

  1. timer modules
    1. Quadratur Encoder (Version 1.2 - C. Hoyer 12.8.2015)
  2. SPI modules
    1. AD5664 (Version 1.1 - C. Hoyer 23.7.2015)
  3. software modules
    1. Ringbuffer (Version 0.9 - C. Hoyer 18.8.2015)
    2. PID-Regler (Version 1.0 - C. Hoyer 17.9.2015)
Revision:
0:1acdcc576936
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/TIM/QUADRATURE.cpp	Mon Nov 28 17:27:43 2016 +0000
@@ -0,0 +1,226 @@
+#include "mbed.h"
+#include "QUADRATURE.h"
+#include "cmsis_nvic.h"
+
+//====================================================================================================================================
+//                                   Initialisieren und mappen der Kanäle, Timer etc
+//====================================================================================================================================
+QUADRATURE *QUADRATURE::instance;                                                       // Pointer zur Adresse der Instanz
+
+
+QUADRATURE::QUADRATURE(int tim, int mode, char _CI1_PORT, int _CI1_PIN, int CI1_POL,  char _CI2_PORT, int _CI2_PIN, int CI2_POL): CI1_PORT(_CI1_PORT), CI1_PIN(_CI1_PIN), CI2_PORT(_CI2_PORT), CI2_PIN(_CI2_PIN)
+{   
+  
+    TIMERCARRY = 0;                                                                     // bei neuem Objekt den entsprechenden Timercarry auf 0 setzen
+    instance = this;                                                                    // Instanz zuweisung zum neu generierten Objekt
+    extfct = false;                                                                     // Externe Funktion bei Timer Interrupt deaktiviert
+
+    //Konfiguration des Timers
+       switch(tim){                                                                     // Konfiguration jedes einzelnen Timers, durch Auswahl    
+                    case 1:                                                             // TIM1
+                        RCC->APB2ENR |= RCC_APB2ENR_TIM1EN;                             // Timer 1 aktivieren
+                        tipo = TIM1;                                                    // Pointer auf Timer1 zuweisen
+                        temp_ITM = TIM1_UP_TIM10_IRQn;                                  // NVIC Nummer für den Updateinterrupt Timer 1
+                        NVIC->ISER[0] &= ~(1 << TIM1_UP_TIM10_IRQn);                    // Interrupt Handler für den Timer 1 aktivieren
+                    break;
+                    
+                    case 2:                                                             // TIM2
+                        RCC->APB1ENR |= RCC_APB1ENR_TIM2EN;                             // Timer 2 aktivieren
+                        tipo = TIM2;                                                    // Pointer auf Timer2 zuweisen
+                        temp_ITM =  TIM2_IRQn;                                          // NVIC Nummer für den Updateinterrupt Timer 2
+                        NVIC->ISER[0] &= ~(1 << TIM2_IRQn);                             // Interrupt Handler für den Timer 2 aktivieren
+                    break;
+                    
+                    case 3:                                                             // TIM3
+                        RCC->APB1ENR |= RCC_APB1ENR_TIM3EN;                             // Timer 3 aktivieren
+                        tipo = TIM3;                                                    // Pointer auf Timer3 zuweisen
+                        temp_ITM =  TIM3_IRQn;                                          // NVIC Nummer für den Updateinterrupt Timer 3
+                        NVIC->ISER[0] &= ~(1 << TIM3_IRQn);                             // Interrupt Handler für den Timer 3 aktivieren
+                    break;   
+
+                    case 4:                                                             // TIM4
+                        RCC->APB1ENR |= RCC_APB1ENR_TIM4EN;                             // Timer 4 aktivieren 
+                        tipo = TIM4;                                                    // Pointer auf Timer4 zuweisen
+                        temp_ITM =  TIM4_IRQn;                                          // NVIC Nummer für den Updateinterrupt Timer 4
+                        NVIC->ISER[0] &= ~(1 << TIM4_IRQn);                             // Interrupt Handler für den Timer 4 aktivieren                        
+                    break;                
+
+                    case 5:                                                             // TIM5
+                        RCC->APB1ENR |= RCC_APB1ENR_TIM5EN;                             // Timer 5 aktivieren 
+                        tipo = TIM5;                                                    // Pointer auf Timer5 zuweisen
+                        temp_ITM =  TIM5_IRQn;                                          // NVIC Nummer für den Updateinterrupt Timer 5
+                        NVIC->ISER[1] &= ~(1 << (TIM5_IRQn-31));                        // Interrupt Handler für den Timer 5 aktivieren
+                    break;
+                    
+                    default:                                                            // keinen Timer ausgewählt und Fehlermeldung
+                        printf("\n \n \r \n  Falscher Timer ausgewahlt! \n \n \r");
+                        return;
+                }   
+                
+        tipo->SMCR  = mode;                                                             // Schreibt den aktuellen Modus in das SMCR Register (Slave Mode)
+        tipo->CCMR1 = 0xF1F1;                                                           // Mappen der Capture Inputs 1 und 2 auf Timer Input 1 und 2
+        tipo->CCMR2 = 0x0000;                                                           // Kein mappen der Capture Inputs 3 und 4
+        tipo->CCER  = 0x0011;                                                           // Capture Inputs 1 und 2 aktivieren 
+            
+        // Konfiguration der Pins      
+        setGPIO(CI1_PORT, CI1_PIN, tim);                                                // Setzt den Port Pin für CI1        
+        setGPIO(CI2_PORT, CI2_PIN, tim);                                                // Setzt den Port Pin für CI2
+        
+        // Konfiguration der Polarität 
+        if(CI1_POL ==  1){                                                              // Polarität für CI1 ändern auf fallende Flanke 
+                 tipo->CCER |= 0x0002;                                                   
+            } 
+        if(CI2_POL ==  1){                                                              // Polarität für CI2 ändern auf fallende Flanke 
+                 tipo->CCER |= 0x0020;                                                   
+            } 
+            
+        // Konfiguration der Interrupt Routine
+        NVIC_SetVector(temp_ITM, (uint32_t) &_UPDATE_HANDLER);                          // Adresse zum IRQ Handler des entsprechenden Timers
+        NVIC_SetPriority(temp_ITM, 0);                                                  // Festlegen der Priorität (Höchste, damit das nächste Increment mit gezählt wird)
+        tipo->DIER |= 0x0001;                                                           // Update Interrupt Einstellung im Timer aktivieren
+        
+                                                                         
+    }
+
+
+
+void QUADRATURE::setGPIO(char port, int pin, int tim){                                 // Funktion zum Mappen des Port Pins auf die Alternative Funktion für den Timer Eingang
+    
+     GPIOchoose(port);                                                                 // Wählt den passenden Pointer zum Port aus
+    
+     portpo->MODER  |= (1 <<((2*pin)+1));                                              // Alternative Funktion 0x10 mit Maske (2 Bit pro Pin) 
+     portpo->OTYPER |= (1 << pin);                                                     // Definition als Eingang 0x1 mit Open Drain 
+     
+         if(pin > 7){                                                                  // Ausgänge 8 bis 15 sind im höheren Register AFR[1]
+            if(tim < 3){                                                               // Für Timer 1 und Timer 2 (Alternatve Funktion 01)
+                 portpo->AFR[1] |= (1 << (4*(pin-8)));                                 // Alternative Funktion mit Maske für AF01
+            }
+            else{                                                                      // Für Timer 3, Timer 4 und Timer 5 (Alternative Funktion 10) 
+                 portpo->AFR[1] |= (1 << (4*(pin-8))+1);                               // Alternative Funktion mit Maske für AF02          
+            }   
+         }
+         else{                                                                         // Ausgänge 0 bis 7 sind im im unteren Register AFR[0]
+            if(tim < 3){                                                               // Für Timer 1 und Timer 2 (Alternatve Funktion 01)
+                 portpo->AFR[0] |= (1 << (4*pin));                                     // Alternative Funktion mit Maske für AF01
+            }
+            else{                                                                      // Für Timer 3, Timer 4 und Timer 5 (Alternative Funktion 10)  
+                 portpo->AFR[0] |= (1 << ((4*pin)+1));                                 // Alternative Funktion mit Maske für AF02          
+            }                       
+         }            
+    } 
+
+//====================================================================================================================================
+//                              Eventhandler für Timer und Externer Eingang
+//====================================================================================================================================
+
+void QUADRATURE::UPDATE_HANDLER(void){                                                  // Interrupt Service Routine für Update Events
+    
+            tipo->SR ^= 0x0001;                                                         // Flag löschen (Register xor mit Flag) 
+
+        if (getTIM() > 1){     
+                TIMERCARRY--;                                                           // Carryvariable -1 da Unterlauf
+         }
+         else{
+                TIMERCARRY++;                                                           // Carryvariable 1 da Überlauf
+             }  
+             
+        if(extfct == true){                                                             // Externe Funktion vorhanden?
+                    (*IRQ_HANDLER_EXTERN)();                                            // Aufruf der Externen Funktion
+            }               
+    }
+
+
+//====================================================================================================================================
+//                              Setter- und Getter-Funktionen
+//====================================================================================================================================
+
+void QUADRATURE::startTIM(){
+        NVIC_EnableIRQ(temp_ITM);                                                       // Enable den IRQ Handler
+        tipo->CR1 = 0x0001;                                                             // Starte Timer
+    }
+    
+void QUADRATURE::stopTIM(){
+        tipo->CR1 = 0x0000;                                                             // Stoppe Timer
+        NVIC_DisableIRQ(temp_ITM);                                                      // Disable den IRQ Handler
+    }
+        
+unsigned int QUADRATURE::getTIM(){
+        return   tipo->CNT;                                                             // Gibt aktuellen Timerwert zurück
+    }
+    
+signed short QUADRATURE::getCARRY(){
+        return   TIMERCARRY;                                                            // Gibt aktuellen Timercarry zurück
+    }
+        
+void QUADRATURE::setTIM(int pre, int arr){
+        tipo->PSC = pre;                                                                // Prescaler (Wert + 1)
+        tipo->ARR = arr;                                                                // Auto reload   
+    }
+
+void QUADRATURE::setUpRes(){
+        
+        GPIOchoose(CI1_PORT);                                                           // Wählt den passenden Pointer zum Port von CI1 aus  
+        portpo->PUPDR  |= (1 << ((2*CI1_PIN)));                                         // Setzt den Pull up für den entsprechenden Port Pin von CI1
+
+        GPIOchoose(CI2_PORT);                                                           // Wählt den passenden Pointer zum Port von CI2 aus  
+        portpo->PUPDR  |= (1 << ((2*CI2_PIN)));                                         // Setzt den Pull up für den entsprechenden Port Pin von CI2                
+    }
+        
+void QUADRATURE::setDownRes(){
+
+        GPIOchoose(CI1_PORT);                                                           // Wählt den passenden Pointer zum Port von CI1 aus    
+        portpo->PUPDR  |= (1 << ((2*CI1_PIN)+1));                                       // Setzt den Pull down für den entsprechenden Port Pin von CI1
+
+        GPIOchoose(CI2_PORT);                                                           // Wählt den passenden Pointer zum Port von CI2 aus 
+        portpo->PUPDR  |= (1 << ((2*CI2_PIN)+1));                                       // Setzt den Pull down für den entsprechenden Port Pin von CI2           
+    }
+    
+void QUADRATURE::setIRQ_METHODE(void (*IRQ_HANDLER_METHODE)(void)){                     // Adresse zur externen Funktion übergeben und Freigabe setzen
+          extfct = true;                                                                // Externe Funktion vorhanden. Freigabe setzen.
+          IRQ_HANDLER_EXTERN = IRQ_HANDLER_METHODE;                                     // Funktionspointer der Funktion übernehmen       
+    }
+
+
+//====================================================================================================================================
+//                             Hilfsfunktionen
+//====================================================================================================================================
+    
+void QUADRATURE::GPIOchoose(char port){ 
+  
+        switch(port){                                                                   // Konfiguration jedes Ports durch Auswahl
+                    case 'A':                                                           // Port A
+                        RCC->AHB1ENR |= RCC_AHB1ENR_GPIOAEN;                            // Port A aktivieren
+                        portpo = GPIOA;                                                 // Pointer auf Port A zuweisen
+                    break;
+                    
+                    case 'B':                                                           // Port B
+                        RCC->AHB1ENR |= RCC_AHB1ENR_GPIOBEN;                            // Port B aktivieren
+                        portpo = GPIOB;                                                 // Pointer auf Port B zuweisen
+                    break;
+                    
+                    case 'C':                                                           // Port C
+                        RCC->AHB1ENR |= RCC_AHB1ENR_GPIOCEN;                            // Port C aktivieren
+                        portpo = GPIOC;                                                 // Pointer auf Port C zuweisen
+                    break;   
+
+                    case 'D':                                                           // Port D
+                        RCC->AHB1ENR |= RCC_AHB1ENR_GPIODEN;                            // Port D aktivieren
+                        portpo = GPIOD;                                                 // Pointer auf Port D zuweisen
+                    break;                
+
+                    case 'E':                                                           // Port E
+                        RCC->AHB1ENR |= RCC_AHB1ENR_GPIOEEN;                            // Port E aktivieren
+                        portpo = GPIOE;                                                 // Pointer auf Port E zuweisen
+                    break;
+                    
+                    default:                                                            // kein Port ausgewählt und Fehlermeldung
+                        printf("\n \n \r \n  Falscher Port ausgewahlt! \n \n \r");
+                }     
+    }
+    
+void QUADRATURE::_UPDATE_HANDLER(void)                                                  // ISR Handler für die Instanz
+{
+    instance->UPDATE_HANDLER();                                                         // Zuordnung des Handlers zum Handler der Instanz
+    }
+
+