Pinscape fork (KL25Z)

Dependents:   Pinscape_Controller_V2_arnoz Pinscape_Controller_V2

Fork of FastPWM by Erik -

Files at this revision

API Documentation at this revision

Comitter:
mjr
Date:
Fri Mar 24 05:39:58 2017 +0000
Parent:
34:8b826bfff900
Parent:
33:e880dcb178f4
Commit message:
Merge branch

Changed in this revision

--- a/Device/FastPWM_KSDK.cpp	Fri Mar 24 05:32:57 2017 +0000
+++ b/Device/FastPWM_KSDK.cpp	Fri Mar 24 05:39:58 2017 +0000
@@ -1,7 +1,7 @@
 #if defined(TARGET_KPSDK_MCUS)
 
 #include "FastPWM.h"
-#include "fsl_clock_manager.h"
+#include "fsl_ftm.h"
 
 
 #define PWM_CNV              (*(((fastpwm_struct*)fast_obj)->CnV))  
@@ -15,18 +15,16 @@
 } fastpwm_struct;
 
 static uint32_t pwm_prescaler;
+static FTM_Type *const ftm_addrs[] = FTM_BASE_PTRS;
 
 void FastPWM::initFastPWM( void ) {
     fast_obj = new fastpwm_struct;
     bits = 16;
-    
-    uint32_t pwm_base_clock;
-    CLOCK_SYS_GetFreq(kBusClock, &pwm_base_clock);
-    pwm_prescaler = SystemCoreClock / pwm_base_clock;
+
+    pwm_prescaler = SystemCoreClock / CLOCK_GetFreq(kCLOCK_BusClk);;
 
-    uint32_t ftms[] = FTM_BASE_ADDRS;
-    unsigned int ch_n = (_pwm.pwm_name & 0xFF);
-    FTM_Type *ftm = (FTM_Type *)ftms[_pwm.pwm_name >> TPM_SHIFT];
+    unsigned int ch_n = (_pwm.pwm_name & 0xF);
+    FTM_Type *ftm = ftm_addrs[_pwm.pwm_name >> TPM_SHIFT];
     
     ((fastpwm_struct*)fast_obj)->CnV = &ftm->CONTROLS[ch_n].CnV;
     ((fastpwm_struct*)fast_obj)->MOD = &ftm->MOD;
@@ -35,6 +33,10 @@
 
 void FastPWM::pulsewidth_ticks( uint32_t ticks ) {
     PWM_CNV = ticks;
+    
+    //Temporary work around until I figure out which settings mbed screwed up in this update
+    FTM_Type *ftm = ftm_addrs[_pwm.pwm_name >> TPM_SHIFT];
+    FTM_SetSoftwareTrigger(ftm, true);
 }
 
 void FastPWM::period_ticks( uint32_t ticks ) {
--- a/Device/FastPWM_LPC1768.cpp	Fri Mar 24 05:32:57 2017 +0000
+++ b/Device/FastPWM_LPC1768.cpp	Fri Mar 24 05:39:58 2017 +0000
@@ -1,4 +1,4 @@
-#ifdef TARGET_LPC1768
+#ifdef TARGET_LPC176X
 
 #include "FastPWM.h"
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Device/FastPWM_LPC_SCT.cpp	Fri Mar 24 05:39:58 2017 +0000
@@ -0,0 +1,63 @@
+//For targets which use the SCT
+#if defined(TARGET_LPC81X) || defined(TARGET_LPC82X)
+
+#ifdef TARGET_LPC82X
+#define CTRL_U CTRL
+#endif
+
+#include "FastPWM.h"
+
+void FastPWM::initFastPWM( void ) {
+    //Mbed uses the timer as a single unified 32-bit timer, who are we to argue with this, and it is easier
+    bits = 32;
+    
+    #ifdef TARGET_LPC82X
+    //The mbed lib uses the PWM peripheral slightly different, which is irritating. This sets it bck to the LPC81X
+        _pwm.pwm->EVENT[_pwm.pwm_ch + 1].CTRL  = (1 << 12) | (_pwm.pwm_ch + 1);     // Event_n on Match_n 
+        _pwm.pwm->EVENT[_pwm.pwm_ch + 1].STATE = 0xFFFFFFFF;                        // All states  
+        _pwm.pwm->OUT[_pwm.pwm_ch].SET = (1 << 0);                                  // All PWM channels are SET on Event_0 
+        _pwm.pwm->OUT[_pwm.pwm_ch].CLR = (1 << (_pwm.pwm_ch + 1));                  // PWM ch is CLRed on Event_(ch+1) 
+    #endif
+    
+    //With 32-bit we fix prescaler to 1
+    _pwm.pwm->CTRL_U |= (1 << 2) | (1 << 3);
+    _pwm.pwm->CTRL_U &= ~(0x7F << 5);
+    _pwm.pwm->CTRL_U &= ~(1 << 2);
+
+}
+
+void FastPWM::pulsewidth_ticks( uint32_t ticks ) {
+    #ifdef TARGET_LPC81X
+    _pwm.pwm->MATCHREL[_pwm.pwm_ch + 1].U = ticks;
+    #else
+    _pwm.pwm->MATCHREL[_pwm.pwm_ch + 1] = ticks;
+    #endif
+}
+
+void FastPWM::period_ticks( uint32_t ticks ) {
+    #ifdef TARGET_LPC81X
+    _pwm.pwm->MATCHREL[0].U = ticks;
+    #else
+    _pwm.pwm->MATCHREL[0] = ticks;
+    #endif
+}
+
+uint32_t FastPWM::getPeriod( void ) {
+    #ifdef TARGET_LPC81X
+    return _pwm.pwm->MATCHREL[0].U;
+    #else
+    return _pwm.pwm->MATCHREL[0];
+    #endif
+}
+
+//Maybe implemented later, but needing to change the prescaler for a 32-bit
+//timer used in PWM mode is kinda unlikely.
+//If you really need to do it, rejoice, you can make it run so slow a period is over 40,000 year
+uint32_t FastPWM::setPrescaler(uint32_t reqScale) {
+    //Disable dynamic prescaling
+    dynamicPrescaler = false;
+    
+    return 1;
+}
+
+#endif
\ No newline at end of file
--- a/Device/FastPWM_STM_TIM.cpp	Fri Mar 24 05:32:57 2017 +0000
+++ b/Device/FastPWM_STM_TIM.cpp	Fri Mar 24 05:39:58 2017 +0000
@@ -6,14 +6,38 @@
 
 typedef __IO uint32_t* CHANNEL_P_T;
 
-#define PWM_CHANNEL     (**(CHANNEL_P_T*)fast_obj)
-#define PWM_TIMER       ((TIM_TypeDef*)_pwm.pwm)
+typedef struct  {
+    CHANNEL_P_T channel;
+    uint32_t clk_prescaler;
+} fastpwm_struct;
 
-extern CHANNEL_P_T getChannel(TIM_TypeDef* pwm, PinName pin);
+#define PWM_CHANNEL         ((((fastpwm_struct*)fast_obj)->channel)) 
+#define PWM_CLK_PRESCALER   ((((fastpwm_struct*)fast_obj)->clk_prescaler))
+#define PWM_TIMER           ((TIM_TypeDef*)_pwm.pwm)
+
+#if defined(TARGET_STM32F0) || defined (TARGET_STM32F1) || defined (TARGET_STM32L1)
+extern __IO uint32_t* getChannel(TIM_TypeDef* pwm, PinName pin);
+#endif
 
 void FastPWM::initFastPWM( void ) {
-    fast_obj = new (CHANNEL_P_T);
-    *(CHANNEL_P_T*)fast_obj = getChannel(PWM_TIMER, _pwm.pin);
+    fast_obj = new fastpwm_struct;
+    #if defined(TARGET_STM32F0) || defined (TARGET_STM32F1) || defined (TARGET_STM32L1)
+    PWM_CHANNEL = getChannel(PWM_TIMER, _pwm.pin);
+    #else
+    PWM_CHANNEL = (&PWM_TIMER->CCR1 + _pwm.channel - 1); 
+    #endif
+    
+    // Depending on the timer and the internal bus it is connected to, each STM timer
+    // can have a fixed prescaler from the clock, especially the faster devices.
+    // In order not to have to hardcode this in, we use knowledge that mbed lib sets
+    // default period to 20ms to reverse engineer the prescaler from this. 
+    uint32_t current_hz = SystemCoreClock / (PWM_TIMER->PSC + 1) / (PWM_TIMER->ARR+1);
+    PWM_CLK_PRESCALER = (current_hz + 1) / 50;  //50Hz is magic number it should be, +1 is to handle possible rounding errors in mbed setup
+    
+    //Sanity check in case a target does something different
+    if ( (PWM_CLK_PRESCALER == 0 ) || (PWM_CLK_PRESCALER > 16)) {
+        PWM_CLK_PRESCALER = 1;
+    }
     
     //Enable PWM period syncing for glitch free result
     PWM_TIMER->CR1 |= TIM_CR1_ARPE;
@@ -22,7 +46,7 @@
 }
 
 void FastPWM::pulsewidth_ticks( uint32_t ticks ) {
-    PWM_CHANNEL = ticks;    
+    *PWM_CHANNEL = ticks;    
 }
 
 void FastPWM::period_ticks( uint32_t ticks ) {
@@ -34,15 +58,18 @@
 }
 
 uint32_t FastPWM::setPrescaler(uint32_t reqScale) {
-    if (reqScale == 0)
+    if (reqScale == 0) {
         //Return prescaler
-        return PWM_TIMER->PSC + 1;
-    if (reqScale > (uint32_t)(1<<16))
-        reqScale = 1<<16;
+        return (PWM_TIMER->PSC + 1) * PWM_CLK_PRESCALER;
+    }
+    if (reqScale > (uint32_t)(PWM_CLK_PRESCALER<<16)) {
+        reqScale = PWM_CLK_PRESCALER<<16;
+    }
     //Else set prescaler, we have to substract one from reqScale since a 0 in PCVAL is prescaler of 1
-    PWM_TIMER->PSC = reqScale - 1;
+    //Take into account PWM_CLK_PRESCALER, we need to make sure reqScale is always rounded up
+    PWM_TIMER->PSC = (reqScale + PWM_CLK_PRESCALER - 1)/PWM_CLK_PRESCALER - 1;
 
-    return reqScale;
+    return setPrescaler(0);
 }
 
 #endif
\ No newline at end of file
--- a/Device/FastPWM_STM_TIM_PinOut.cpp	Fri Mar 24 05:32:57 2017 +0000
+++ b/Device/FastPWM_STM_TIM_PinOut.cpp	Fri Mar 24 05:39:58 2017 +0000
@@ -1,6 +1,6 @@
 #include "mbed.h"
 
-#ifdef TARGET_NUCLEO_F030R8
+#if defined (TARGET_NUCLEO_F030R8) || (TARGET_DISCO_F051R8)
 __IO uint32_t* getChannel(TIM_TypeDef* pwm, PinName pin) {
     switch (pin) {
         // Channels 1
@@ -23,30 +23,7 @@
 }
 #endif
 
-#if defined TARGET_NUCLEO_F401RE || defined TARGET_NUCLEO_F411RE
-__IO uint32_t* getChannel(TIM_TypeDef* pwm, PinName pin) {
-    switch (pin) {
-        // Channels 1 : PWMx/1
-        case PA_0: case PA_5: case PA_6: case PA_8: case PA_15: case PB_4: case PB_6: case PC_6: case PA_7: case PB_13:
-            return &pwm->CCR1;
-        
-        // Channels 2 : PWMx/2
-        case PA_1: case PA_9: case PB_3: case PB_5: case PB_7: case PC_7: case PB_0: case PB_14:
-            return &pwm->CCR2;
-            
-        // Channels 3 : PWMx/3
-        case PA_2: case PA_10: case PB_8: case PB_10: case PC_8: case PB_1: case PB_15:
-            return &pwm->CCR3;
- 
-        // Channels 4 : PWMx/4
-        case PA_3: case PA_11: case PB_9: case PC_9: 
-            return &pwm->CCR4;
-    }
-    return NULL;
-}
-#endif
-
-#if defined TARGET_NUCLEO_F103RB
+#if defined (TARGET_NUCLEO_F103RB) || (TARGET_DISCO_F100RB)
 __IO uint32_t* getChannel(TIM_TypeDef* pwm, PinName pin) {
     switch (pin) {
         // Channels 1 : PWMx/1
@@ -69,31 +46,6 @@
 }
 #endif
 
-#ifdef TARGET_NUCLEO_F334R8
-__IO uint32_t* getChannel(TIM_TypeDef* pwm, PinName pin) {
-    switch (pin) {
-         // Channels 1
-        case PA_2: case PA_6: case PA_7: case PA_8: case PA_12: case PB_4: case PB_5: case PB_8: case PB_9: case PB_14: case PC_0: case PC_6:
-        case PA_1: case PA_13: case PB_6: case PB_13: case PC_13:
-            return &pwm->CCR1;
- 
-        // Channels 2
-        case PA_3: case PA_4: case PA_9: case PB_15: case PC_1: case PC_7:
-            return &pwm->CCR2;
-            
-        // Channels 3
-        case PA_10: case PB_0: case PC_2: case PC_8:
-        case PF_0:
-            return &pwm->CCR3;
- 
-        // Channels 4
-        case PA_11: case PB_1: case PB_7: case PC_3: case PC_9:
-            return &pwm->CCR4;
-    }
-    return NULL;
-}
-#endif
-
 #if defined TARGET_NUCLEO_F072RB
 __IO uint32_t* getChannel(TIM_TypeDef* pwm, PinName pin) {
     switch (pin) {
@@ -117,4 +69,34 @@
     }
     return NULL;
 }
-#endif
\ No newline at end of file
+#endif
+
+
+
+#if defined (TARGET_NUCLEO_L152RE)
+__IO uint32_t* getChannel(TIM_TypeDef* pwm, PinName pin) {
+    switch (pin) {
+        // Channels 1 : PWMx/1
+        case PA_6:  case PB_4: case PB_12: case PB_13: case PC_6:
+            return &pwm->CCR1;
+        
+        // Channels 2 : PWMx/2
+        case PA_1: case PA_7: case PB_3: case PB_5: case PB_14: case PB_7: case PC_7:
+            return &pwm->CCR2;
+            
+        // Channels 3 : PWMx/3
+        case PA_2: case PB_0: case PB_8: case PB_10: case PC_8:
+            return &pwm->CCR3;
+ 
+        // Channels 4 : PWMx/4
+        case PA_3: case PB_1:case PB_9: case PB_11: case PC_9: 
+            return &pwm->CCR4;
+        default:
+            /* NOP */
+            break;
+    }
+    return NULL;
+}
+#endif
+
+ 
\ No newline at end of file