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
- timer modules
- Quadratur Encoder (Version 1.2 - C. Hoyer 12.8.2015)
- SPI modules
- AD5664 (Version 1.1 - C. Hoyer 23.7.2015)
- software modules
- Ringbuffer (Version 0.9 - C. Hoyer 18.8.2015)
- PID-Regler (Version 1.0 - C. Hoyer 17.9.2015)
Diff: TIM/QUADRATURE.cpp
- 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 + } + +