bool pwmInit(drv_pwm_config_t *init) { int i = 0; const uint8_t *setup; // this is pretty hacky shit, but it will do for now. array of 4 config maps, [ multiPWM multiPPM airPWM airPPM ] if (init->airplane) i = 2; // switch to air hardware config if (init->usePPM) i++; // next index is for PPM setup = hardwareMaps[i]; for (i = 0; i < MAX_PORTS; i++) { uint8_t port = setup[i] & 0x0F; uint8_t mask = setup[i] & 0xF0; if (setup[i] == 0xFF) // terminator break; // skip UART ports for GPS if (init->useUART && (port == PWM3 || port == PWM4)) continue; // skip ADC for powerMeter if configured if (init->adcChannel && (init->adcChannel == port)) continue; // hacks to allow current functionality if (mask & (TYPE_IP | TYPE_IW) && !init->enableInput) mask = 0; if (init->useServos && !init->airplane) { // remap PWM9+10 as servos (but not in airplane mode LOL) if (port == PWM9 || port == PWM10) mask = TYPE_S; } if (init->extraServos && !init->airplane) { // remap PWM5..8 as servos when used in extended servo mode if (port >= PWM5 && port <= PWM8) mask = TYPE_S; } if (mask & TYPE_IP) { pwmInConfig(port, ppmCallback, 0); numInputs = 8; } else if (mask & TYPE_IW) { pwmInConfig(port, pwmCallback, numInputs); numInputs++; } else if (mask & TYPE_M) { motors[numMotors++] = pwmOutConfig(port, 1000000 / init->motorPwmRate, PULSE_1MS); } else if (mask & TYPE_S) { servos[numServos++] = pwmOutConfig(port, 1000000 / init->servoPwmRate, PULSE_1MS); } } return false; }
pwmIOConfiguration_t *pwmInit(drv_pwm_config_t *init) { #ifndef SKIP_RX_PWM_PPM int channelIndex = 0; #endif memset(&pwmIOConfiguration, 0, sizeof(pwmIOConfiguration)); // this is pretty hacky shit, but it will do for now. array of 4 config maps, [ multiPWM multiPPM airPWM airPPM ] int i = 0; if (init->airplane) i = 2; // switch to air hardware config if (init->usePPM || init->useSerialRx) i++; // next index is for PPM const uint16_t *setup = hardwareMaps[i]; for (i = 0; i < USABLE_TIMER_CHANNEL_COUNT && setup[i] != 0xFFFF; i++) { uint8_t timerIndex = setup[i] & 0x00FF; uint8_t type = (setup[i] & 0xFF00) >> 8; const timerHardware_t *timerHardwarePtr = &timerHardware[timerIndex]; #ifdef OLIMEXINO_UNCUT_LED2_E_JUMPER // PWM2 is connected to LED2 on the board and cannot be connected unless you cut LED2_E if (timerIndex == PWM2) continue; #endif #ifdef STM32F10X // skip UART2 ports if (init->useUART2 && (timerIndex == PWM3 || timerIndex == PWM4)) continue; #endif #if defined(STM32F303xC) && defined(USE_USART3) // skip UART3 ports (PB10/PB11) if (init->useUART3 && IO_GPIOBYTAG(timerHardwarePtr->tag) == UART3_GPIO && (IO_PINBYTAG(timerHardwarePtr->tag) == UART3_TX_PIN || IO_PINBYTAG(timerHardwarePtr->tag) == UART3_RX_PIN)) continue; #endif #ifdef SOFTSERIAL_1_TIMER if (init->useSoftSerial && timerHardwarePtr->tim == SOFTSERIAL_1_TIMER) continue; #endif #ifdef SOFTSERIAL_2_TIMER if (init->useSoftSerial && timerHardwarePtr->tim == SOFTSERIAL_2_TIMER) continue; #endif #ifdef LED_STRIP_TIMER // skip LED Strip output if (init->useLEDStrip) { if (timerHardwarePtr->tim == LED_STRIP_TIMER) continue; #if defined(STM32F303xC) && defined(WS2811_GPIO) && defined(WS2811_PIN_SOURCE) if (IO_GPIOBYTAG(timerHardwarePtr->tag) == WS2811_GPIO && IO_GPIO_PinSource(IOGetByTag(timerHardwarePtr->tag)) == WS2811_PIN_SOURCE) continue; #endif } #endif #ifdef VBAT_ADC_GPIO if (init->useVbat && IO_GPIOBYTAG(timerHardwarePtr->tag) == VBAT_ADC_GPIO && IO_PINBYTAG(timerHardwarePtr->tag) == VBAT_ADC_GPIO_PIN) { continue; } #endif #ifdef RSSI_ADC_GPIO if (init->useRSSIADC && IO_GPIOBYTAG(timerHardwarePtr->tag) == RSSI_ADC_GPIO && IO_PINBYTAG(timerHardwarePtr->tag) == RSSI_ADC_GPIO_PIN) { continue; } #endif #ifdef CURRENT_METER_ADC_GPIO if (init->useCurrentMeterADC && IO_GPIOBYTAG(timerHardwarePtr->tag) == CURRENT_METER_ADC_GPIO && IO_PINBYTAG(timerHardwarePtr->tag) == CURRENT_METER_ADC_GPIO_PIN) { continue; } #endif #ifdef SONAR if (init->sonarGPIOConfig && IO_GPIOBYTAG(timerHardwarePtr->tag) == init->sonarGPIOConfig->gpio && ( IO_PINBYTAG(timerHardwarePtr->tag) == init->sonarGPIOConfig->triggerPin || IO_PINBYTAG(timerHardwarePtr->tag) == init->sonarGPIOConfig->echoPin ) ) { continue; } #endif // hacks to allow current functionality if (type == MAP_TO_PWM_INPUT && !init->useParallelPWM) continue; if (type == MAP_TO_PPM_INPUT && !init->usePPM) continue; #ifdef USE_SERVOS if (init->useServos && !init->airplane) { #if defined(NAZE) // remap PWM9+10 as servos if ((timerIndex == PWM9 || timerIndex == PWM10) && timerHardwarePtr->tim == TIM1) type = MAP_TO_SERVO_OUTPUT; #endif #if defined(COLIBRI_RACE) || defined(LUX_RACE) // remap PWM1+2 as servos if ((timerIndex == PWM6 || timerIndex == PWM7 || timerIndex == PWM8 || timerIndex == PWM9) && timerHardwarePtr->tim == TIM2) type = MAP_TO_SERVO_OUTPUT; #endif #if defined(CC3D) // remap 10 as servo if (timerIndex == PWM10 && timerHardwarePtr->tim == TIM1) type = MAP_TO_SERVO_OUTPUT; #endif #if defined(SPARKY) // remap PWM1+2 as servos if ((timerIndex == PWM1 || timerIndex == PWM2) && timerHardwarePtr->tim == TIM15) type = MAP_TO_SERVO_OUTPUT; #endif #if defined(SPRACINGF3) // remap PWM15+16 as servos if ((timerIndex == PWM15 || timerIndex == PWM16) && timerHardwarePtr->tim == TIM15) type = MAP_TO_SERVO_OUTPUT; #endif #if (defined(STM32F3DISCOVERY) && !defined(CHEBUZZF3)) // remap PWM 5+6 or 9+10 as servos - softserial pin pairs require timer ports that use the same timer if (init->useSoftSerial) { if (timerIndex == PWM5 || timerIndex == PWM6) type = MAP_TO_SERVO_OUTPUT; } else { if (timerIndex == PWM9 || timerIndex == PWM10) type = MAP_TO_SERVO_OUTPUT; } #endif #if defined(MOTOLAB) // remap PWM 7+8 as servos if (timerIndex == PWM7 || timerIndex == PWM8) type = MAP_TO_SERVO_OUTPUT; #endif } if (init->useChannelForwarding && !init->airplane) { #if defined(NAZE) && defined(LED_STRIP_TIMER) // if LED strip is active, PWM5-8 are unavailable, so map AUX1+AUX2 to PWM13+PWM14 if (init->useLEDStrip) { if (timerIndex >= PWM13 && timerIndex <= PWM14) { type = MAP_TO_SERVO_OUTPUT; } } else #endif // remap PWM5..8 as servos when used in extended servo mode if (timerIndex >= PWM5 && timerIndex <= PWM8) type = MAP_TO_SERVO_OUTPUT; } #endif #ifdef CC3D // This part of code is unnecessary and can be removed - timer clash is resolved by forcing configuration with the same // timer tick rate - PWM_TIMER_MHZ /* if (init->useParallelPWM) { // Skip PWM inputs that conflict with timers used outputs. if ((type == MAP_TO_SERVO_OUTPUT || type == MAP_TO_MOTOR_OUTPUT) && (timerHardwarePtr->tim == TIM2 || timerHardwarePtr->tim == TIM3)) { continue; } if (type == MAP_TO_PWM_INPUT && timerHardwarePtr->tim == TIM4) { continue; } } */ #endif if (type == MAP_TO_PPM_INPUT) { #ifndef SKIP_RX_PWM_PPM #ifdef CC3D_PPM1 if (init->useOneshot || isMotorBrushed(init->motorPwmRate)) { ppmAvoidPWMTimerClash(timerHardwarePtr, TIM4); } #endif #ifdef SPARKY if (init->useOneshot || isMotorBrushed(init->motorPwmRate)) { ppmAvoidPWMTimerClash(timerHardwarePtr, TIM2); } #endif ppmInConfig(timerHardwarePtr); pwmIOConfiguration.ioConfigurations[pwmIOConfiguration.ioCount].flags = PWM_PF_PPM; pwmIOConfiguration.ppmInputCount++; #endif } else if (type == MAP_TO_PWM_INPUT) { #ifndef SKIP_RX_PWM_PPM pwmInConfig(timerHardwarePtr, channelIndex); pwmIOConfiguration.ioConfigurations[pwmIOConfiguration.ioCount].flags = PWM_PF_PWM; pwmIOConfiguration.pwmInputCount++; channelIndex++; #endif } else if (type == MAP_TO_MOTOR_OUTPUT) { #if defined(CC3D) && !defined(CC3D_PPM1) if (init->useOneshot || isMotorBrushed(init->motorPwmRate)) { // Skip it if it would cause PPM capture timer to be reconfigured or manually overflowed if (timerHardwarePtr->tim == TIM2) continue; } #endif if (init->useOneshot) { pwmOneshotMotorConfig(timerHardwarePtr, pwmIOConfiguration.motorCount); pwmIOConfiguration.ioConfigurations[pwmIOConfiguration.ioCount].flags = PWM_PF_MOTOR | PWM_PF_OUTPUT_PROTOCOL_ONESHOT|PWM_PF_OUTPUT_PROTOCOL_PWM; } else if (isMotorBrushed(init->motorPwmRate)) { pwmBrushedMotorConfig(timerHardwarePtr, pwmIOConfiguration.motorCount, init->motorPwmRate, init->idlePulse); pwmIOConfiguration.ioConfigurations[pwmIOConfiguration.ioCount].flags = PWM_PF_MOTOR | PWM_PF_MOTOR_MODE_BRUSHED | PWM_PF_OUTPUT_PROTOCOL_PWM; } else { pwmBrushlessMotorConfig(timerHardwarePtr, pwmIOConfiguration.motorCount, init->motorPwmRate, init->idlePulse); pwmIOConfiguration.ioConfigurations[pwmIOConfiguration.ioCount].flags = PWM_PF_MOTOR | PWM_PF_OUTPUT_PROTOCOL_PWM ; } pwmIOConfiguration.ioConfigurations[pwmIOConfiguration.ioCount].index = pwmIOConfiguration.motorCount; pwmIOConfiguration.ioConfigurations[pwmIOConfiguration.ioCount].timerHardware = timerHardwarePtr; pwmIOConfiguration.motorCount++; } else if (type == MAP_TO_SERVO_OUTPUT) { #ifdef USE_SERVOS pwmServoConfig(timerHardwarePtr, pwmIOConfiguration.servoCount, init->servoPwmRate, init->servoCenterPulse); pwmIOConfiguration.ioConfigurations[pwmIOConfiguration.ioCount].flags = PWM_PF_SERVO | PWM_PF_OUTPUT_PROTOCOL_PWM; pwmIOConfiguration.ioConfigurations[pwmIOConfiguration.ioCount].index = pwmIOConfiguration.servoCount; pwmIOConfiguration.ioConfigurations[pwmIOConfiguration.ioCount].timerHardware = timerHardwarePtr; pwmIOConfiguration.servoCount++; #endif } else { continue; } pwmIOConfiguration.ioCount++; } return &pwmIOConfiguration; }
pwmOutputConfiguration_t *pwmInit(drv_pwm_config_t *init) { int i = 0; const uint16_t *setup; int channelIndex = 0; static pwmOutputConfiguration_t pwmOutputConfiguration; memset(&pwmOutputConfiguration, 0, sizeof(pwmOutputConfiguration)); // this is pretty hacky shit, but it will do for now. array of 4 config maps, [ multiPWM multiPPM airPWM airPPM ] if (init->airplane) i = 2; // switch to air hardware config if (init->usePPM || init->useSerialRx) i++; // next index is for PPM setup = hardwareMaps[i]; for (i = 0; i < USABLE_TIMER_CHANNEL_COUNT && setup[i] != 0xFFFF; i++) { uint8_t timerIndex = setup[i] & 0x00FF; uint8_t type = (setup[i] & 0xFF00) >> 8; const timerHardware_t *timerHardwarePtr = &timerHardware[timerIndex]; #ifdef OLIMEXINO_UNCUT_LED2_E_JUMPER // PWM2 is connected to LED2 on the board and cannot be connected unless you cut LED2_E if (timerIndex == PWM2) continue; #endif #ifdef STM32F10X // skip UART2 ports if (init->useUART2 && (timerIndex == PWM3 || timerIndex == PWM4)) continue; #endif #ifdef SOFTSERIAL_1_TIMER if (init->useSoftSerial && timerHardwarePtr->tim == SOFTSERIAL_1_TIMER) continue; #endif #ifdef SOFTSERIAL_2_TIMER if (init->useSoftSerial && timerHardwarePtr->tim == SOFTSERIAL_2_TIMER) continue; #endif #ifdef LED_STRIP_TIMER // skip LED Strip output if (init->useLEDStrip) { if (timerHardwarePtr->tim == LED_STRIP_TIMER) continue; #if defined(STM32F303xC) && defined(WS2811_GPIO) && defined(WS2811_PIN_SOURCE) if (timerHardwarePtr->gpio == WS2811_GPIO && timerHardwarePtr->gpioPinSource == WS2811_PIN_SOURCE) continue; #endif } #endif #ifdef VBAT_ADC_GPIO if (init->useVbat && timerHardwarePtr->gpio == VBAT_ADC_GPIO && timerHardwarePtr->pin == VBAT_ADC_GPIO_PIN) { continue; } #endif #ifdef RSSI_ADC_GPIO if (init->useRSSIADC && timerHardwarePtr->gpio == RSSI_ADC_GPIO && timerHardwarePtr->pin == RSSI_ADC_GPIO_PIN) { continue; } #endif #ifdef CURRENT_METER_ADC_GPIO if (init->useCurrentMeterADC && timerHardwarePtr->gpio == CURRENT_METER_ADC_GPIO && timerHardwarePtr->pin == CURRENT_METER_ADC_GPIO_PIN) { continue; } #endif // hacks to allow current functionality if (type == MAP_TO_PWM_INPUT && !init->useParallelPWM) continue; if (type == MAP_TO_PPM_INPUT && !init->usePPM) continue; #ifdef USE_SERVOS if (init->useServos && !init->airplane) { #if defined(NAZE) // remap PWM9+10 as servos if ((timerIndex == PWM9 || timerIndex == PWM10) && timerHardwarePtr->tim == TIM1) type = MAP_TO_SERVO_OUTPUT; #endif #if defined(SPARKY) // remap PWM1+2 as servos if ((timerIndex == PWM1 || timerIndex == PWM2) && timerHardwarePtr->tim == TIM15) type = MAP_TO_SERVO_OUTPUT; #endif #if defined(SPRACINGF3) // remap PWM15+16 as servos if ((timerIndex == PWM15 || timerIndex == PWM16) && timerHardwarePtr->tim == TIM15) type = MAP_TO_SERVO_OUTPUT; #endif #if defined(NAZE32PRO) || (defined(STM32F3DISCOVERY) && !defined(CHEBUZZF3)) // remap PWM 5+6 or 9+10 as servos - softserial pin pairs require timer ports that use the same timer if (init->useSoftSerial) { if (timerIndex == PWM5 || timerIndex == PWM6) type = MAP_TO_SERVO_OUTPUT; } else { if (timerIndex == PWM9 || timerIndex == PWM10) type = MAP_TO_SERVO_OUTPUT; } #endif } if (init->extraServos && !init->airplane) { #if defined(NAZE) && defined(LED_STRIP_TIMER) // if LED strip is active, PWM5-8 are unavailable, so map AUX1+AUX2 to PWM13+PWM14 if (init->useLEDStrip) { if (timerIndex >= PWM13 && timerIndex <= PWM14) { type = MAP_TO_SERVO_OUTPUT; } } else #endif // remap PWM5..8 as servos when used in extended servo mode if (timerIndex >= PWM5 && timerIndex <= PWM8) type = MAP_TO_SERVO_OUTPUT; } #endif #ifdef CC3D if (init->useParallelPWM) { // Skip PWM inputs that conflict with timers used outputs. if ((type == MAP_TO_SERVO_OUTPUT || type == MAP_TO_MOTOR_OUTPUT) && (timerHardwarePtr->tim == TIM2 || timerHardwarePtr->tim == TIM3)) { continue; } if (type == MAP_TO_PWM_INPUT && timerHardwarePtr->tim == TIM4) { continue; } } #endif if (type == MAP_TO_PPM_INPUT) { #ifdef CC3D if (init->useOneshot) { ppmAvoidPWMTimerClash(timerHardwarePtr, TIM4); } #endif #ifdef SPARKY if (init->useOneshot) { ppmAvoidPWMTimerClash(timerHardwarePtr, TIM2); } #endif ppmInConfig(timerHardwarePtr); } else if (type == MAP_TO_PWM_INPUT) { pwmInConfig(timerHardwarePtr, channelIndex); channelIndex++; } else if (type == MAP_TO_MOTOR_OUTPUT) { if (init->useOneshot) { pwmOneshotMotorConfig(timerHardwarePtr, pwmOutputConfiguration.motorCount, init->idlePulse); } else if (init->motorPwmRate > 500) { pwmBrushedMotorConfig(timerHardwarePtr, pwmOutputConfiguration.motorCount, init->motorPwmRate, init->idlePulse); } else { pwmBrushlessMotorConfig(timerHardwarePtr, pwmOutputConfiguration.motorCount, init->motorPwmRate, init->idlePulse); } pwmOutputConfiguration.motorCount++; } else if (type == MAP_TO_SERVO_OUTPUT) { #ifdef USE_SERVOS pwmServoConfig(timerHardwarePtr, pwmOutputConfiguration.servoCount, init->servoPwmRate, init->servoCenterPulse); pwmOutputConfiguration.servoCount++; #endif } } return &pwmOutputConfiguration; }
void pwmInit(drv_pwm_config_t *init) { int i = 0; const uint16_t *setup; int channelIndex = 0; int servoIndex = 0; int motorIndex = 0; // this is pretty hacky shit, but it will do for now. array of 4 config maps, [ multiPWM multiPPM airPWM airPPM ] if (init->airplane) i = 2; // switch to air hardware config if (init->usePPM) i++; // next index is for PPM setup = hardwareMaps[i]; for (i = 0; i < USABLE_TIMER_CHANNEL_COUNT; i++) { uint8_t timerIndex = setup[i] & 0x00FF; uint8_t type = (setup[i] & 0xFF00) >> 8; if (setup[i] == 0xFFFF) // terminator break; #ifdef OLIMEXINO_UNCUT_LED2_E_JUMPER // PWM2 is connected to LED2 on the board and cannot be connected unless you cut LED2_E if (timerIndex == PWM2) continue; #endif #ifdef STM32F10X_MD // skip UART2 ports if (init->useUART2 && (timerIndex == PWM3 || timerIndex == PWM4)) continue; #endif #ifdef STM32F10X_MD // skip softSerial ports if (init->useSoftSerial && (timerIndex == PWM5 || timerIndex == PWM6 || timerIndex == PWM7 || timerIndex == PWM8)) continue; #endif #ifdef CHEBUZZF3 // skip softSerial ports // PWM4 can no-longer be used since it uses the same timer as PWM5 and PWM6 if (init->useSoftSerial && (timerIndex == PWM4 || timerIndex == PWM5 || timerIndex == PWM6 || timerIndex == PWM7 || timerIndex == PWM8)) continue; #endif #if defined(STM32F3DISCOVERY) && !defined(CHEBUZZF3) // skip softSerial ports if (init->useSoftSerial && (timerIndex == PWM9 || timerIndex == PWM10 || timerIndex == PWM11 || timerIndex == PWM12)) continue; #endif #if defined(STM32F10X_MD) #define LED_STRIP_PWM PWM4 #endif #if defined(STM32F303xC) && !(defined(CHEBUZZF3) || defined(NAZE32PRO)) #define LED_STRIP_PWM PWM2 #endif #if defined(CHEBUZZF3) #define LED_STRIP_PWM PWM2 #endif #if defined(NAZE32PRO) #define LED_STRIP_PWM PWM13 #endif #ifdef LED_STRIP_PWM // skip LED Strip output if (init->useLEDStrip && timerIndex == LED_STRIP_PWM) continue; #endif #ifdef STM32F10X_MD // skip ADC for RSSI if (init->useRSSIADC && timerIndex == PWM2) continue; #endif // hacks to allow current functionality if (type == TYPE_IW && !init->useParallelPWM) type = 0; if (type == TYPE_IP && !init->usePPM) type = 0; if (init->useServos && !init->airplane) { #if defined(STM32F10X_MD) || defined(CHEBUZZF3) // remap PWM9+10 as servos if (timerIndex == PWM9 || timerIndex == PWM10) type = TYPE_S; #endif #if (defined(STM32F303xC) || defined(STM32F3DISCOVERY)) && !defined(CHEBUZZF3) // remap PWM 5+6 or 9+10 as servos - softserial pin pairs require timer ports that use the same timer if (init->useSoftSerial) { if (timerIndex == PWM5 || timerIndex == PWM6) type = TYPE_S; } else { if (timerIndex == PWM9 || timerIndex == PWM10) type = TYPE_S; } #endif } if (init->extraServos && !init->airplane) { // remap PWM5..8 as servos when used in extended servo mode if (timerIndex >= PWM5 && timerIndex <= PWM8) type = TYPE_S; } if (type == TYPE_IP) { ppmInConfig(timerIndex); } else if (type == TYPE_IW) { pwmInConfig(timerIndex, channelIndex); channelIndex++; } else if (type == TYPE_M) { if (init->motorPwmRate > 500) { pwmBrushedMotorConfig(&timerHardware[timerIndex], motorIndex, init->motorPwmRate, init->idlePulse); } else { pwmBrushlessMotorConfig(&timerHardware[timerIndex], motorIndex, init->motorPwmRate, init->idlePulse); } motorIndex++; } else if (type == TYPE_S) { pwmServoConfig(&timerHardware[timerIndex], servoIndex, init->servoPwmRate, init->servoCenterPulse); servoIndex++; } } }
pwmOutputConfiguration_t *pwmInit(drv_pwm_config_t *init) { const uint16_t *setup; #ifndef SKIP_RX_PWM_PPM int channelIndex = 0; #endif memset(&pwmOutputConfiguration, 0, sizeof(pwmOutputConfiguration)); // this is pretty hacky shit, but it will do for now. array of 4 config maps, [ multiPWM multiPPM airPWM airPPM ] int i = 0; if (init->airplane) i = 2; // switch to air hardware config if (init->usePPM || init->useSerialRx) i++; // next index is for PPM #ifdef CC3D setup = init->useBuzzerP6 ? hardwareMapsBP6[i] : hardwareMaps[i]; #else setup = hardwareMaps[i]; #endif for (i = 0; i < USABLE_TIMER_CHANNEL_COUNT && setup[i] != 0xFFFF; i++) { uint8_t timerIndex = setup[i] & 0x00FF; uint8_t type = (setup[i] & 0xFF00) >> 8; const timerHardware_t *timerHardwarePtr = &timerHardware[timerIndex]; #ifdef OLIMEXINO_UNCUT_LED2_E_JUMPER // PWM2 is connected to LED2 on the board and cannot be connected unless you cut LED2_E if (timerIndex == PWM2) continue; #endif #ifdef STM32F10X // skip UART2 ports if (init->useUART2 && (timerIndex == PWM3 || timerIndex == PWM4)) continue; #endif #if defined(STM32F303xC) && defined(USE_UART3) // skip UART3 ports (PB10/PB11) if (init->useUART3 && (timerHardwarePtr->tag == IO_TAG(UART3_TX_PIN) || timerHardwarePtr->tag == IO_TAG(UART3_RX_PIN))) continue; #endif #ifdef SOFTSERIAL_1_TIMER if (init->useSoftSerial && timerHardwarePtr->tim == SOFTSERIAL_1_TIMER) continue; #endif #ifdef SOFTSERIAL_2_TIMER if (init->useSoftSerial && timerHardwarePtr->tim == SOFTSERIAL_2_TIMER) continue; #endif #ifdef WS2811_TIMER // skip LED Strip output if (init->useLEDStrip) { if (timerHardwarePtr->tim == WS2811_TIMER) continue; #if defined(STM32F303xC) && defined(WS2811_PIN) if (timerHardwarePtr->tag == IO_TAG(WS2811_PIN)) continue; #endif } #endif #ifdef VBAT_ADC_PIN if (init->useVbat && timerHardwarePtr->tag == IO_TAG(VBAT_ADC_PIN)) { continue; } #endif #ifdef RSSI_ADC_GPIO if (init->useRSSIADC && timerHardwarePtr->tag == IO_TAG(RSSI_ADC_PIN)) { continue; } #endif #ifdef CURRENT_METER_ADC_GPIO if (init->useCurrentMeterADC && timerHardwarePtr->tag == IO_TAG(CURRENT_METER_ADC_PIN)) { continue; } #endif #ifdef SONAR if (init->useSonar && ( timerHardwarePtr->tag == init->sonarIOConfig.triggerTag || timerHardwarePtr->tag == init->sonarIOConfig.echoTag )) { continue; } #endif // hacks to allow current functionality if (type == MAP_TO_PWM_INPUT && !init->useParallelPWM) continue; if (type == MAP_TO_PPM_INPUT && !init->usePPM) continue; #ifdef USE_SERVOS if (init->useServos && !init->airplane) { #if defined(NAZE) // remap PWM9+10 as servos if ((timerIndex == PWM9 || timerIndex == PWM10) && timerHardwarePtr->tim == TIM1) type = MAP_TO_SERVO_OUTPUT; #endif #if defined(DOGE) // remap outputs 1+2 (PWM2+3) as servos if ((timerIndex == PWM2 || timerIndex == PWM3) && timerHardwarePtr->tim == TIM4) type = MAP_TO_SERVO_OUTPUT; #endif #if defined(COLIBRI_RACE) || defined(LUX_RACE) // remap PWM1+2 as servos if ((timerIndex == PWM6 || timerIndex == PWM7 || timerIndex == PWM8 || timerIndex == PWM9) && timerHardwarePtr->tim == TIM2) type = MAP_TO_SERVO_OUTPUT; #endif #if defined(CC3D) // remap PWM9+10 as servos if ((timerIndex == PWM9 || timerIndex == PWM10) && timerHardwarePtr->tim == TIM1) type = MAP_TO_SERVO_OUTPUT; #endif #if defined(SPARKY) // remap PWM1+2 as servos if ((timerIndex == PWM1 || timerIndex == PWM2) && timerHardwarePtr->tim == TIM15) type = MAP_TO_SERVO_OUTPUT; #endif #if defined(SPRACINGF3) // remap PWM15+16 as servos if ((timerIndex == PWM15 || timerIndex == PWM16) && timerHardwarePtr->tim == TIM15) type = MAP_TO_SERVO_OUTPUT; #endif #if defined(SPRACINGF3MINI) || defined(OMNIBUS) // remap PWM6+7 as servos if ((timerIndex == PWM6 || timerIndex == PWM7) && timerHardwarePtr->tim == TIM15) type = MAP_TO_SERVO_OUTPUT; #endif #if (defined(STM32F3DISCOVERY) && !defined(CHEBUZZF3)) // remap PWM 5+6 or 9+10 as servos - softserial pin pairs require timer ports that use the same timer if (init->useSoftSerial) { if (timerIndex == PWM5 || timerIndex == PWM6) type = MAP_TO_SERVO_OUTPUT; } else { if (timerIndex == PWM9 || timerIndex == PWM10) type = MAP_TO_SERVO_OUTPUT; } #endif #if defined(MOTOLAB) // remap PWM 7+8 as servos if (timerIndex == PWM7 || timerIndex == PWM8) type = MAP_TO_SERVO_OUTPUT; #endif #if defined(SINGULARITY) // remap PWM6+7 as servos if (timerIndex == PWM6 || timerIndex == PWM7) type = MAP_TO_SERVO_OUTPUT; #endif } if (init->useChannelForwarding && !init->airplane) { #if defined(NAZE) && defined(WS2811_TIMER) // if LED strip is active, PWM5-8 are unavailable, so map AUX1+AUX2 to PWM13+PWM14 if (init->useLEDStrip) { if (timerIndex >= PWM13 && timerIndex <= PWM14) { type = MAP_TO_SERVO_OUTPUT; } } else #endif #if defined(SPRACINGF3) || defined(NAZE) // remap PWM5..8 as servos when used in extended servo mode if (timerIndex >= PWM5 && timerIndex <= PWM8) type = MAP_TO_SERVO_OUTPUT; #endif } #endif // USE_SERVOS #ifdef CC3D if (init->useParallelPWM) { // Skip PWM inputs that conflict with timers used outputs. if ((type == MAP_TO_SERVO_OUTPUT || type == MAP_TO_MOTOR_OUTPUT) && (timerHardwarePtr->tim == TIM2 || timerHardwarePtr->tim == TIM3)) { continue; } if (type == MAP_TO_PWM_INPUT && timerHardwarePtr->tim == TIM4) { continue; } } #endif if (type == MAP_TO_PPM_INPUT) { #ifndef SKIP_RX_PWM_PPM #if defined(SPARKY) || defined(ALIENFLIGHTF3) if (!(init->pwmProtocolType == PWM_TYPE_CONVENTIONAL)) { ppmAvoidPWMTimerClash(timerHardwarePtr, TIM2, init->pwmProtocolType); } #endif ppmInConfig(timerHardwarePtr); #endif } else if (type == MAP_TO_PWM_INPUT) { #ifndef SKIP_RX_PWM_PPM pwmInConfig(timerHardwarePtr, channelIndex); channelIndex++; #endif } else if (type == MAP_TO_MOTOR_OUTPUT) { #ifdef CC3D if (!(init->pwmProtocolType == PWM_TYPE_CONVENTIONAL)) { // Skip it if it would cause PPM capture timer to be reconfigured or manually overflowed if (timerHardwarePtr->tim == TIM2) continue; } #endif if (init->useFastPwm) { pwmFastPwmMotorConfig(timerHardwarePtr, pwmOutputConfiguration.motorCount, init->motorPwmRate, init->idlePulse, init->pwmProtocolType); pwmOutputConfiguration.portConfigurations[pwmOutputConfiguration.outputCount].flags = PWM_PF_MOTOR | PWM_PF_OUTPUT_PROTOCOL_PWM | PWM_PF_OUTPUT_PROTOCOL_ONESHOT; } else if (init->pwmProtocolType == PWM_TYPE_BRUSHED) { pwmBrushedMotorConfig(timerHardwarePtr, pwmOutputConfiguration.motorCount, init->motorPwmRate); pwmOutputConfiguration.portConfigurations[pwmOutputConfiguration.outputCount].flags = PWM_PF_MOTOR | PWM_PF_OUTPUT_PROTOCOL_PWM | PWM_PF_MOTOR_MODE_BRUSHED; } else { pwmBrushlessMotorConfig(timerHardwarePtr, pwmOutputConfiguration.motorCount, init->motorPwmRate, init->idlePulse); pwmOutputConfiguration.portConfigurations[pwmOutputConfiguration.outputCount].flags = PWM_PF_MOTOR | PWM_PF_OUTPUT_PROTOCOL_PWM; } pwmOutputConfiguration.portConfigurations[pwmOutputConfiguration.outputCount].index = pwmOutputConfiguration.motorCount; pwmOutputConfiguration.portConfigurations[pwmOutputConfiguration.outputCount].timerHardware = timerHardwarePtr; pwmOutputConfiguration.motorCount++; pwmOutputConfiguration.outputCount++; } else if (type == MAP_TO_SERVO_OUTPUT) { #ifdef USE_SERVOS pwmOutputConfiguration.portConfigurations[pwmOutputConfiguration.outputCount].index = pwmOutputConfiguration.servoCount; pwmServoConfig(timerHardwarePtr, pwmOutputConfiguration.servoCount, init->servoPwmRate, init->servoCenterPulse); pwmOutputConfiguration.portConfigurations[pwmOutputConfiguration.outputCount].flags = PWM_PF_SERVO | PWM_PF_OUTPUT_PROTOCOL_PWM; pwmOutputConfiguration.servoCount++; pwmOutputConfiguration.outputCount++; #endif } } return &pwmOutputConfiguration; }
pwmIOConfiguration_t *pwmInit(drv_pwm_config_t *init) { int i = 0; const uint16_t *setup; int channelIndex = 0; memset(&pwmIOConfiguration, 0, sizeof(pwmIOConfiguration)); // this is pretty hacky shit, but it will do for now. array of 4 config maps, [ multiPWM multiPPM airPWM airPPM ] PWM mappings are used for RX_MSP. if (init->airplane) i = 2; // switch to air hardware config if (init->usePPM || init->useSerialRx) i++; // next index is for PPM setup = hardwareMaps[i]; for (i = 0; i < USABLE_TIMER_CHANNEL_COUNT && setup[i] != 0xFFFF; i++) { uint8_t timerIndex = setup[i] & 0x00FF; uint8_t type = (setup[i] & 0xFF00) >> 8; const timerHardware_t *timerHardwarePtr = &timerHardware[timerIndex]; // skip UART ports #ifdef USE_UART2 if (init->useUART2 && timerHardwarePtr->gpio == UART2_GPIO && (timerHardwarePtr->pin == UART2_TX_PIN || timerHardwarePtr->pin == UART2_RX_PIN)) continue; #endif #ifdef USE_UART3 if (init->useUART3 && timerHardwarePtr->gpio == UART3_GPIO && (timerHardwarePtr->pin == UART3_TX_PIN || timerHardwarePtr->pin == UART3_RX_PIN)) continue; #endif #ifdef USE_UART4 if (init->useUART4 && timerHardwarePtr->gpio == UART4_GPIO && (timerHardwarePtr->pin == UART4_TX_PIN || timerHardwarePtr->pin == UART4_RX_PIN)) continue; #endif #ifdef USE_UART5 if (init->useUART5 && ( (timerHardwarePtr->gpio == UART5_GPIO_TX && timerHardwarePtr->pin == UART5_TX_PIN) || (timerHardwarePtr->gpio == UART5_GPIO_RX && timerHardwarePtr->pin == UART5_RX_PIN) ) ) continue; #endif #if defined(STM32F10X) && defined(USE_I2C) // skip I2C ports if device 1 is selected if (I2C_DEVICE == I2CDEV_1 && timerHardwarePtr->gpio == GPIOB && (timerHardwarePtr->pin == Pin_6 || timerHardwarePtr->pin == Pin_7)) continue; #endif #ifdef SOFTSERIAL_1_TIMER if (init->useSoftSerial && timerHardwarePtr->tim == SOFTSERIAL_1_TIMER) continue; #endif #ifdef SOFTSERIAL_2_TIMER if (init->useSoftSerial && timerHardwarePtr->tim == SOFTSERIAL_2_TIMER) continue; #endif #ifdef LED_STRIP_TIMER // skip LED Strip output if (init->useLEDStrip) { if (timerHardwarePtr->tim == LED_STRIP_TIMER) continue; #if defined(STM32F303xC) && defined(WS2811_GPIO) && defined(WS2811_PIN_SOURCE) if (timerHardwarePtr->gpio == WS2811_GPIO && timerHardwarePtr->gpioPinSource == WS2811_PIN_SOURCE) continue; #endif } #endif #ifdef VBAT_ADC_GPIO if (init->useVbat && timerHardwarePtr->gpio == VBAT_ADC_GPIO && timerHardwarePtr->pin == VBAT_ADC_GPIO_PIN) { continue; } #endif #ifdef RSSI_ADC_GPIO if (init->useRSSIADC && timerHardwarePtr->gpio == RSSI_ADC_GPIO && timerHardwarePtr->pin == RSSI_ADC_GPIO_PIN) { continue; } #endif #ifdef AMPERAGE_METER_ADC_GPIO if (init->useCurrentMeterADC && timerHardwarePtr->gpio == AMPERAGE_METER_ADC_GPIO && timerHardwarePtr->pin == AMPERAGE_METER_ADC_GPIO_PIN) { continue; } #endif #ifdef SONAR if (init->sonarGPIOConfig && ( (timerHardwarePtr->gpio == init->sonarGPIOConfig->triggerGPIO && timerHardwarePtr->pin == init->sonarGPIOConfig->triggerPin) || (timerHardwarePtr->gpio == init->sonarGPIOConfig->echoGPIO && timerHardwarePtr->pin == init->sonarGPIOConfig->echoPin) ) ) { continue; } #endif // hacks to allow current functionality #if defined(SPRACINGF3MINI) // remap PWM1, 6-9 as PWM input when parallel PWM is used (for AUX1 and RC1-4, respectively) if (init->useParallelPWM && (timerIndex == PWM6 || timerIndex == PWM7 || timerIndex == PWM8 || timerIndex == PWM9 || timerIndex == PWM1)) { type = MAP_TO_PWM_INPUT; } #endif if (type == MAP_TO_PWM_INPUT && !init->useParallelPWM) continue; if (type == MAP_TO_PPM_INPUT && !init->usePPM) continue; #ifdef USE_SERVOS if (init->useServos && !init->airplane) { #if defined(NAZE) if ((timerIndex == PWM9 || timerIndex == PWM10) && timerHardwarePtr->tim == TIM1) type = MAP_TO_SERVO_OUTPUT; #endif #if defined(COLIBRI_RACE) || defined(LUX_RACE) if ((timerIndex == PWM6 || timerIndex == PWM7 || timerIndex == PWM8 || timerIndex == PWM9) && timerHardwarePtr->tim == TIM2) type = MAP_TO_SERVO_OUTPUT; #endif #if defined(CC3D) if (timerIndex == PWM10 && timerHardwarePtr->tim == TIM1) type = MAP_TO_SERVO_OUTPUT; #endif #if defined(SPARKY) if ((timerIndex == PWM1 || timerIndex == PWM2) && timerHardwarePtr->tim == TIM15) type = MAP_TO_SERVO_OUTPUT; #endif #if defined(SPRACINGF3) if ((timerIndex == PWM15 || timerIndex == PWM16) && timerHardwarePtr->tim == TIM15) type = MAP_TO_SERVO_OUTPUT; #endif #if defined(SPRACINGF3MINI) if ((timerIndex == PWM6 || timerIndex == PWM7) && timerHardwarePtr->tim == TIM15) type = MAP_TO_SERVO_OUTPUT; #endif #if defined(SPRACINGF3NEO) if (((timerIndex == PWM7 || timerIndex == PWM8) && timerHardwarePtr->tim == TIM8) || ((timerIndex == PWM9 || timerIndex == PWM10) && timerHardwarePtr->tim == TIM2)) { type = MAP_TO_SERVO_OUTPUT; } #endif #if defined(RCEXPLORERF3) if (timerIndex == PWM2) { type = MAP_TO_SERVO_OUTPUT; } #endif #if defined(SPRACINGF3EVO) if ((timerIndex == PWM6 || timerIndex == PWM7 || timerIndex == PWM8 || timerIndex == PWM9) && timerHardwarePtr->tim == TIM3) { type = MAP_TO_SERVO_OUTPUT; } #endif #if defined(NAZE32PRO) || (defined(STM32F3DISCOVERY) && !defined(CHEBUZZF3)) // remap PWM 5+6 or 9+10 as servos - softserial pin pairs require timer ports that use the same timer if (init->useSoftSerial) { if (timerIndex == PWM5 || timerIndex == PWM6) type = MAP_TO_SERVO_OUTPUT; } else { if (timerIndex == PWM9 || timerIndex == PWM10) type = MAP_TO_SERVO_OUTPUT; } #endif #if defined(MOTOLAB) // remap PWM 7+8 as servos if (timerIndex == PWM7 || timerIndex == PWM8) type = MAP_TO_SERVO_OUTPUT; #endif } if (init->useChannelForwarding && !init->airplane) { #if defined(NAZE) && defined(LED_STRIP_TIMER) // if LED strip is active, PWM5-8 are unavailable, so map AUX1+AUX2 to PWM13+PWM14 if (init->useLEDStrip) { if (timerIndex >= PWM13 && timerIndex <= PWM14) { type = MAP_TO_SERVO_OUTPUT; } } else #endif #if defined(SPRACINGF3) || defined(NAZE) // remap PWM5..8 as servos when used in extended servo mode if (timerIndex >= PWM5 && timerIndex <= PWM8) type = MAP_TO_SERVO_OUTPUT; #endif #if defined(SPRACINGF3EVO) if ((timerIndex == PWM6 || timerIndex == PWM7 || timerIndex == PWM8 || timerIndex == PWM9) && timerHardwarePtr->tim == TIM3) { type = MAP_TO_SERVO_OUTPUT; } #endif #if defined(SPRACINGF3MINI) if (((timerIndex == PWM6 || timerIndex == PWM7) && timerHardwarePtr->tim == TIM15) || ((timerIndex == PWM8 || timerIndex == PWM9 || timerIndex == PWM10 || timerIndex == PWM11) && timerHardwarePtr->tim == TIM2)) { type = MAP_TO_SERVO_OUTPUT; } #endif #if defined(SPRACINGF3NEO) if (((timerIndex == PWM7 || timerIndex == PWM8) && timerHardwarePtr->tim == TIM8) || ((timerIndex == PWM9 || timerIndex == PWM10) && timerHardwarePtr->tim == TIM2)) { type = MAP_TO_SERVO_OUTPUT; } #endif } #endif // USE_SERVOS #ifdef CC3D if (init->useParallelPWM) { // Skip PWM inputs that conflict with timers used outputs. if ((type == MAP_TO_SERVO_OUTPUT || type == MAP_TO_MOTOR_OUTPUT) && (timerHardwarePtr->tim == TIM2 || timerHardwarePtr->tim == TIM3)) { continue; } if (type == MAP_TO_PWM_INPUT && timerHardwarePtr->tim == TIM4) { continue; } } #endif if (type == MAP_TO_PPM_INPUT) { #if defined(SPARKY) || defined(ALIENFLIGHTF3) if (init->useOneshot || isMotorBrushed(init->motorPwmRate)) { ppmAvoidPWMTimerClash(timerHardwarePtr, TIM2); } #endif ppmInConfig(timerHardwarePtr); pwmIOConfiguration.ioConfigurations[pwmIOConfiguration.ioCount].flags = PWM_PF_PPM; pwmIOConfiguration.ppmInputCount++; } else if (type == MAP_TO_PWM_INPUT) { pwmInConfig(timerHardwarePtr, channelIndex); pwmIOConfiguration.ioConfigurations[pwmIOConfiguration.ioCount].flags = PWM_PF_PWM; pwmIOConfiguration.pwmInputCount++; channelIndex++; } else if (type == MAP_TO_MOTOR_OUTPUT) { #ifdef CC3D if (init->useOneshot || isMotorBrushed(init->motorPwmRate)){ // Skip it if it would cause PPM capture timer to be reconfigured or manually overflowed if (timerHardwarePtr->tim == TIM2) continue; } #endif if (init->useOneshot) { pwmOneshotMotorConfig(timerHardwarePtr, pwmIOConfiguration.motorCount); pwmIOConfiguration.ioConfigurations[pwmIOConfiguration.ioCount].flags = PWM_PF_MOTOR | PWM_PF_OUTPUT_PROTOCOL_ONESHOT|PWM_PF_OUTPUT_PROTOCOL_PWM; } else if (isMotorBrushed(init->motorPwmRate)) { pwmBrushedMotorConfig(timerHardwarePtr, pwmIOConfiguration.motorCount, init->motorPwmRate, init->idlePulse); pwmIOConfiguration.ioConfigurations[pwmIOConfiguration.ioCount].flags = PWM_PF_MOTOR | PWM_PF_MOTOR_MODE_BRUSHED | PWM_PF_OUTPUT_PROTOCOL_PWM; } else { pwmBrushlessMotorConfig(timerHardwarePtr, pwmIOConfiguration.motorCount, init->motorPwmRate, init->idlePulse); pwmIOConfiguration.ioConfigurations[pwmIOConfiguration.ioCount].flags = PWM_PF_MOTOR | PWM_PF_OUTPUT_PROTOCOL_PWM ; } pwmIOConfiguration.ioConfigurations[pwmIOConfiguration.ioCount].index = pwmIOConfiguration.motorCount; pwmIOConfiguration.ioConfigurations[pwmIOConfiguration.ioCount].timerHardware = timerHardwarePtr; pwmIOConfiguration.motorCount++; } else if (type == MAP_TO_SERVO_OUTPUT) { #ifdef USE_SERVOS pwmServoConfig(timerHardwarePtr, pwmIOConfiguration.servoCount, init->servoPwmRate, init->servoCenterPulse); pwmIOConfiguration.ioConfigurations[pwmIOConfiguration.ioCount].flags = PWM_PF_SERVO | PWM_PF_OUTPUT_PROTOCOL_PWM; pwmIOConfiguration.ioConfigurations[pwmIOConfiguration.ioCount].index = pwmIOConfiguration.servoCount; pwmIOConfiguration.ioConfigurations[pwmIOConfiguration.ioCount].timerHardware = timerHardwarePtr; pwmIOConfiguration.servoCount++; #endif } else { continue; } pwmIOConfiguration.ioCount++; } return &pwmIOConfiguration; }
bool pwmInit(drv_pwm_config_t *init) { int i = 0; const uint8_t *setup; // to avoid importing cfg/mcfg failsafeThreshold = init->failsafeThreshold; // this is pretty hacky shit, but it will do for now. array of 4 config maps, [ multiPWM multiPPM airPWM airPPM ] if (init->airplane) i = 2; // switch to air hardware config if (init->usePPM) i++; // next index is for PPM setup = hardwareMaps[i]; for (i = 0; i < MAX_PORTS; i++) { uint8_t port = setup[i] & 0x0F; uint8_t mask = setup[i] & 0xF0; if (setup[i] == 0xFF) // terminator break; #ifdef OLIMEXINO_UNCUT_LED2_E_JUMPER // PWM2 is connected to LED2 on the board and cannot be connected unless you cut LED2_E if (port == PWM2) continue; #endif // skip UART ports for GPS if (init->useUART && (port == PWM3 || port == PWM4)) continue; // skip softSerial ports if (init->useSoftSerial && (port == PWM5 || port == PWM6 || port == PWM7 || port == PWM8)) continue; // skip ADC for powerMeter if configured if (init->adcChannel && (init->adcChannel == port)) continue; // hacks to allow current functionality if (mask & (TYPE_IP | TYPE_IW) && !init->enableInput) mask = 0; if (init->useServos && !init->airplane) { // remap PWM9+10 as servos (but not in airplane mode LOL) if (port == PWM9 || port == PWM10) mask = TYPE_S; } if (init->extraServos && !init->airplane) { // remap PWM5..8 as servos when used in extended servo mode if (port >= PWM5 && port <= PWM8) mask = TYPE_S; } if (mask & TYPE_IP) { pwmInConfig(port, ppmCallback, 0); numInputs = 8; } else if (mask & TYPE_IW) { pwmInConfig(port, pwmCallback, numInputs); numInputs++; } else if (mask & TYPE_M) { motors[numMotors++] = pwmOutConfig(port, 1000000 / init->motorPwmRate, init->idlePulse > 0 ? init->idlePulse : PULSE_1MS); } else if (mask & TYPE_S) { servos[numServos++] = pwmOutConfig(port, 1000000 / init->servoPwmRate, PULSE_1MS); } } return false; }
bool pwmInit(drv_pwm_config_t *init) { int i = 0; const uint8_t *setup; uint16_t period; // to avoid importing cfg/mcfg failsafeThreshold = init->failsafeThreshold; // pwm filtering on input pwmFilter = init->pwmFilter; syncPWM = init->syncPWM; // this is pretty hacky shit, but it will do for now. array of 4 config maps, [ multiPWM multiPPM airPWM airPPM ] if (init->airplane) i = 2; // switch to air hardware config if (init->usePPM) i++; // next index is for PPM setup = hardwareMaps[i]; for (i = 0; i < MAX_PORTS; i++) { uint8_t port = setup[i] & 0x0F; uint8_t mask = setup[i] & 0xF0; if (setup[i] == 0xFF) // terminator break; // skip UART ports for GPS if (init->useUART && (port == PWM3 || port == PWM4)) continue; // skip softSerial ports if (init->useSoftSerial && (port == PWM5 || port == PWM6 || port == PWM7 || port == PWM8)) continue; // skip ADC for powerMeter if configured if (init->adcChannel && (init->adcChannel == port)) continue; // hacks to allow current functionality if ((mask & (TYPE_IP | TYPE_IW)) && !init->enableInput) mask = 0; if (init->useServos && !init->airplane) { // remap PWM9+10 as servos (but not in airplane mode LOL) if (port == PWM9 || port == PWM10) mask = TYPE_S; } if (init->extraServos && !init->airplane) { // remap PWM5..8 as servos when used in extended servo mode. // condition for airplane because airPPM already has these as servos if (port >= PWM5 && port <= PWM8) mask = TYPE_S; } if (mask & TYPE_IP) { pwmInConfig(port, ppmCallback, 0); numInputs = 8; } else if (mask & TYPE_IW) { pwmInConfig(port, pwmCallback, numInputs); numInputs++; } else if (mask & TYPE_M) { uint32_t hz, mhz; if (init->motorPwmRate > 500 || init->fastPWM) mhz = PWM_TIMER_8_MHZ; else mhz = PWM_TIMER_MHZ; hz = mhz * 1000000; if (init->syncPWM) period = 8000 * mhz; // 8ms period in syncPWM mode, cycletime should be smaller than this else if (init->fastPWM) period = hz / 4000; else period = hz / init->motorPwmRate; motors[numMotors++] = pwmOutConfig(port, mhz, period, init->idlePulse); } else if (mask & TYPE_S) { servos[numServos++] = pwmOutConfig(port, PWM_TIMER_MHZ, 1000000 / init->servoPwmRate, init->servoCenterPulse); } } // determine motor writer function pwmWritePtr = pwmWriteStandard; if (init->motorPwmRate > 500) pwmWritePtr = pwmWriteBrushed; else if (init->syncPWM) pwmWritePtr = pwmWriteSyncPwm; // set return values in init struct init->numServos = numServos; return false; }
pwmIOConfiguration_t *pwmInit(drv_pwm_config_t *init) { #if defined(USE_RX_PWM) || defined(USE_RX_PPM) int channelIndex = 0; #endif memset(&pwmIOConfiguration, 0, sizeof(pwmIOConfiguration)); // this is pretty hacky shit, but it will do for now. array of 4 config maps, [ multiPWM multiPPM airPWM airPPM ] int i = 0; if (init->airplane) i = 2; // switch to air hardware config if (init->usePPM || init->useSerialRx) i++; // next index is for PPM const uint16_t *setup = hardwareMaps[i]; for (i = 0; i < USABLE_TIMER_CHANNEL_COUNT && setup[i] != 0xFFFF; i++) { uint8_t timerIndex = setup[i] & 0x00FF; uint8_t type = (setup[i] & 0xFF00) >> 8; const timerHardware_t *timerHardwarePtr = &timerHardware[timerIndex]; #ifdef OLIMEXINO_UNCUT_LED2_E_JUMPER // PWM2 is connected to LED2 on the board and cannot be connected unless you cut LED2_E if (timerIndex == PWM2) { addBootlogEvent6(BOOT_EVENT_TIMER_CH_SKIPPED, BOOT_EVENT_FLAGS_WARNING, i, pwmIOConfiguration.motorCount, pwmIOConfiguration.servoCount, 3); continue; } #endif #ifdef STM32F10X // skip UART2 ports if (init->useUART2 && (timerHardwarePtr->tag == IO_TAG(PA2) || timerHardwarePtr->tag == IO_TAG(PA3))) { addBootlogEvent6(BOOT_EVENT_TIMER_CH_SKIPPED, BOOT_EVENT_FLAGS_WARNING, i, pwmIOConfiguration.motorCount, pwmIOConfiguration.servoCount, 3); continue; } #endif #if defined(STM32F303xC) && defined(USE_UART3) // skip UART3 ports (PB10/PB11) if (init->useUART3 && (timerHardwarePtr->tag == IO_TAG(UART3_TX_PIN) || timerHardwarePtr->tag == IO_TAG(UART3_RX_PIN))) { addBootlogEvent6(BOOT_EVENT_TIMER_CH_SKIPPED, BOOT_EVENT_FLAGS_WARNING, i, pwmIOConfiguration.motorCount, pwmIOConfiguration.servoCount, 3); continue; } #endif #if defined(UART6_TX_PIN) || defined(UART6_RX_PIN) if (init->useUART6 && (timerHardwarePtr->tag == IO_TAG(UART6_TX_PIN) || timerHardwarePtr->tag == IO_TAG(UART6_RX_PIN))) { addBootlogEvent6(BOOT_EVENT_TIMER_CH_SKIPPED, BOOT_EVENT_FLAGS_WARNING, i, pwmIOConfiguration.motorCount, pwmIOConfiguration.servoCount, 3); continue; } #endif #ifdef SOFTSERIAL_1_TIMER if (init->useSoftSerial && timerHardwarePtr->tim == SOFTSERIAL_1_TIMER) { addBootlogEvent6(BOOT_EVENT_TIMER_CH_SKIPPED, BOOT_EVENT_FLAGS_WARNING, i, pwmIOConfiguration.motorCount, pwmIOConfiguration.servoCount, 3); continue; } #endif #ifdef SOFTSERIAL_2_TIMER if (init->useSoftSerial && timerHardwarePtr->tim == SOFTSERIAL_2_TIMER) { addBootlogEvent6(BOOT_EVENT_TIMER_CH_SKIPPED, BOOT_EVENT_FLAGS_WARNING, i, pwmIOConfiguration.motorCount, pwmIOConfiguration.servoCount, 3); continue; } #endif #ifdef WS2811_TIMER // skip LED Strip output if (init->useLEDStrip) { if (timerHardwarePtr->tim == WS2811_TIMER) { addBootlogEvent6(BOOT_EVENT_TIMER_CH_SKIPPED, BOOT_EVENT_FLAGS_WARNING, i, pwmIOConfiguration.motorCount, pwmIOConfiguration.servoCount, 3); continue; } #if defined(STM32F303xC) && defined(WS2811_PIN) if (timerHardwarePtr->tag == IO_TAG(WS2811_PIN)) { addBootlogEvent6(BOOT_EVENT_TIMER_CH_SKIPPED, BOOT_EVENT_FLAGS_WARNING, i, pwmIOConfiguration.motorCount, pwmIOConfiguration.servoCount, 3); continue; } #endif } #endif #ifdef VBAT_ADC_PIN if (init->useVbat && timerHardwarePtr->tag == IO_TAG(VBAT_ADC_PIN)) { addBootlogEvent6(BOOT_EVENT_TIMER_CH_SKIPPED, BOOT_EVENT_FLAGS_WARNING, i, pwmIOConfiguration.motorCount, pwmIOConfiguration.servoCount, 3); continue; } #endif #ifdef RSSI_ADC_PIN if (init->useRSSIADC && timerHardwarePtr->tag == IO_TAG(RSSI_ADC_PIN)) { addBootlogEvent6(BOOT_EVENT_TIMER_CH_SKIPPED, BOOT_EVENT_FLAGS_WARNING, i, pwmIOConfiguration.motorCount, pwmIOConfiguration.servoCount, 3); continue; } #endif #ifdef CURRENT_METER_ADC_PIN if (init->useCurrentMeterADC && timerHardwarePtr->tag == IO_TAG(CURRENT_METER_ADC_PIN)) { addBootlogEvent6(BOOT_EVENT_TIMER_CH_SKIPPED, BOOT_EVENT_FLAGS_WARNING, i, pwmIOConfiguration.motorCount, pwmIOConfiguration.servoCount, 3); continue; } #endif #ifdef SONAR if (init->useSonar && ( timerHardwarePtr->tag == init->sonarIOConfig.triggerTag || timerHardwarePtr->tag == init->sonarIOConfig.echoTag )) { addBootlogEvent6(BOOT_EVENT_TIMER_CH_SKIPPED, BOOT_EVENT_FLAGS_WARNING, i, pwmIOConfiguration.motorCount, pwmIOConfiguration.servoCount, 3); continue; } #endif // hacks to allow current functionality if (type == MAP_TO_PWM_INPUT && !init->useParallelPWM) continue; if (type == MAP_TO_PPM_INPUT && !init->usePPM) continue; #ifdef USE_SERVOS if (init->useServos && !init->airplane) { #if defined(NAZE) // remap PWM9+10 as servos if ((timerIndex == PWM9 || timerIndex == PWM10) && timerHardwarePtr->tim == TIM1) type = MAP_TO_SERVO_OUTPUT; #endif #if defined(DOGE) // remap outputs 1+2 (PWM2+3) as servos if ((timerIndex == PWM2 || timerIndex == PWM3) && timerHardwarePtr->tim == TIM4) type = MAP_TO_SERVO_OUTPUT; #endif #if defined(COLIBRI_RACE) || defined(LUX_RACE) // remap PWM1+2 as servos if ((timerIndex == PWM6 || timerIndex == PWM7 || timerIndex == PWM8 || timerIndex == PWM9) && timerHardwarePtr->tim == TIM2) type = MAP_TO_SERVO_OUTPUT; #endif #if defined(CC3D) // remap PWM9+10 as servos if ((timerIndex == PWM9 || timerIndex == PWM10) && timerHardwarePtr->tim == TIM1) type = MAP_TO_SERVO_OUTPUT; #endif #if defined(SPARKY) // remap PWM1+2 as servos if ((timerIndex == PWM1 || timerIndex == PWM2) && timerHardwarePtr->tim == TIM15) type = MAP_TO_SERVO_OUTPUT; #endif #if defined(SPRACINGF3) // remap PWM15+16 as servos if ((timerIndex == PWM15 || timerIndex == PWM16) && timerHardwarePtr->tim == TIM15) type = MAP_TO_SERVO_OUTPUT; #endif #if defined(FALCORE) // remap PWM5+6 as servos if ((timerIndex == PWM5 || timerIndex == PWM6) && timerHardwarePtr->tim == TIM3) type = MAP_TO_SERVO_OUTPUT; #endif #if defined(SPRACINGF3MINI) // remap PWM6+7 as servos if ((timerIndex == PWM6 || timerIndex == PWM7) && timerHardwarePtr->tim == TIM15) type = MAP_TO_SERVO_OUTPUT; #endif #if defined(OMNIBUS) // remap PWM2 (OUT1) as servo if (timerIndex == PWM2 && timerHardwarePtr->tim == TIM8) type = MAP_TO_SERVO_OUTPUT; #endif #if defined(OMNIBUSF4) // remap PWM12 (OUT6) as servo if (timerIndex == PWM12) type = MAP_TO_SERVO_OUTPUT; #endif #if defined(RCEXPLORERF3) if (timerIndex == PWM2) { type = MAP_TO_SERVO_OUTPUT; } #endif #if defined(SPRACINGF3EVO) if ((timerIndex == PWM8 || timerIndex == PWM9) && timerHardwarePtr->tim == TIM3) { type = MAP_TO_SERVO_OUTPUT; } #endif #if (defined(STM32F3DISCOVERY) && !defined(CHEBUZZF3)) // remap PWM 5+6 or 9+10 as servos - softserial pin pairs require timer ports that use the same timer if (init->useSoftSerial) { if (timerIndex == PWM5 || timerIndex == PWM6) type = MAP_TO_SERVO_OUTPUT; } else { if (timerIndex == PWM9 || timerIndex == PWM10) type = MAP_TO_SERVO_OUTPUT; } #endif #if defined(MOTOLAB) // remap PWM 7+8 as servos if (timerIndex == PWM7 || timerIndex == PWM8) type = MAP_TO_SERVO_OUTPUT; #endif #if defined(SINGULARITY) // remap PWM6+7 as servos if (timerIndex == PWM6 || timerIndex == PWM7) type = MAP_TO_SERVO_OUTPUT; #endif #if defined(AIRBOTF4) // remap PWM11+PWM12 as servos on multirotor mixers that use servos (i.e. Tri) if (timerIndex == PWM11 || timerIndex == PWM12) type = MAP_TO_SERVO_OUTPUT; #endif } if (init->useChannelForwarding && !init->airplane) { #if defined(NAZE) && defined(WS2811_TIMER) // if LED strip is active, PWM5-8 are unavailable, so map AUX1+AUX2 to PWM13+PWM14 if (init->useLEDStrip) { if (timerIndex >= PWM13 && timerIndex <= PWM14) { type = MAP_TO_SERVO_OUTPUT; } } else #endif #if defined(SPRACINGF3) || defined(NAZE) // remap PWM5..8 as servos when used in extended servo mode if (timerIndex >= PWM5 && timerIndex <= PWM8) type = MAP_TO_SERVO_OUTPUT; #endif #if defined(SPRACINGF3EVO) if ((timerIndex == PWM6 || timerIndex == PWM7 || timerIndex == PWM8 || timerIndex == PWM9) && timerHardwarePtr->tim == TIM3) { type = MAP_TO_SERVO_OUTPUT; } #endif #if defined(SPRACINGF3MINI) if (((timerIndex == PWM6 || timerIndex == PWM7) && timerHardwarePtr->tim == TIM15) || ((timerIndex == PWM8 || timerIndex == PWM9 || timerIndex == PWM10 || timerIndex == PWM11) && timerHardwarePtr->tim == TIM2)) { type = MAP_TO_SERVO_OUTPUT; } #endif } #endif // USE_SERVOS #ifdef CC3D // This part of code is unnecessary and can be removed - timer clash is resolved by forcing configuration with the same // timer tick rate - PWM_TIMER_MHZ /* if (init->useParallelPWM) { // Skip PWM inputs that conflict with timers used outputs. if ((type == MAP_TO_SERVO_OUTPUT || type == MAP_TO_MOTOR_OUTPUT) && (timerHardwarePtr->tim == TIM2 || timerHardwarePtr->tim == TIM3)) { continue; } if (type == MAP_TO_PWM_INPUT && timerHardwarePtr->tim == TIM4) { continue; } } */ #endif if (type == MAP_TO_PPM_INPUT) { #if defined(USE_RX_PPM) #ifdef CC3D_PPM1 if (init->useFastPwm || init->pwmProtocolType == PWM_TYPE_BRUSHED) { ppmAvoidPWMTimerClash(timerHardwarePtr, TIM4); } #endif #if defined(SPARKY) || defined(ALIENFLIGHTF3) if (init->useFastPwm || init->pwmProtocolType == PWM_TYPE_BRUSHED) { ppmAvoidPWMTimerClash(timerHardwarePtr, TIM2); } #endif ppmInConfig(timerHardwarePtr); pwmIOConfiguration.ioConfigurations[pwmIOConfiguration.ioCount].flags = PWM_PF_PPM; pwmIOConfiguration.ppmInputCount++; addBootlogEvent6(BOOT_EVENT_TIMER_CH_MAPPED, BOOT_EVENT_FLAGS_NONE, i, pwmIOConfiguration.motorCount, pwmIOConfiguration.servoCount, 0); #endif } else if (type == MAP_TO_PWM_INPUT) { #if defined(USE_RX_PWM) pwmInConfig(timerHardwarePtr, channelIndex); pwmIOConfiguration.ioConfigurations[pwmIOConfiguration.ioCount].flags = PWM_PF_PWM; pwmIOConfiguration.pwmInputCount++; channelIndex++; addBootlogEvent6(BOOT_EVENT_TIMER_CH_MAPPED, BOOT_EVENT_FLAGS_NONE, i, pwmIOConfiguration.motorCount, pwmIOConfiguration.servoCount, 1); #endif } else if (type == MAP_TO_MOTOR_OUTPUT) { /* Check if we already configured maximum supported number of motors and skip the rest */ if (pwmIOConfiguration.motorCount >= MAX_MOTORS) { addBootlogEvent6(BOOT_EVENT_TIMER_CH_SKIPPED, BOOT_EVENT_FLAGS_WARNING, i, pwmIOConfiguration.motorCount, pwmIOConfiguration.servoCount, 1); continue; } #if defined(CC3D) && !defined(CC3D_PPM1) if (init->useFastPwm || init->pwmProtocolType == PWM_TYPE_BRUSHED) { // Skip it if it would cause PPM capture timer to be reconfigured or manually overflowed if (timerHardwarePtr->tim == TIM2) { addBootlogEvent6(BOOT_EVENT_TIMER_CH_SKIPPED, BOOT_EVENT_FLAGS_WARNING, i, pwmIOConfiguration.motorCount, pwmIOConfiguration.servoCount, 3); continue; } } #endif pwmMotorConfig(timerHardwarePtr, pwmIOConfiguration.motorCount, init->motorPwmRate, init->idlePulse, init->pwmProtocolType, init->enablePWMOutput); if (init->useFastPwm) { pwmIOConfiguration.ioConfigurations[pwmIOConfiguration.ioCount].flags = PWM_PF_MOTOR | PWM_PF_OUTPUT_PROTOCOL_FASTPWM | PWM_PF_OUTPUT_PROTOCOL_PWM; } else if (init->pwmProtocolType == PWM_TYPE_BRUSHED) { pwmIOConfiguration.ioConfigurations[pwmIOConfiguration.ioCount].flags = PWM_PF_MOTOR | PWM_PF_MOTOR_MODE_BRUSHED | PWM_PF_OUTPUT_PROTOCOL_PWM; } else { pwmIOConfiguration.ioConfigurations[pwmIOConfiguration.ioCount].flags = PWM_PF_MOTOR | PWM_PF_OUTPUT_PROTOCOL_PWM ; } pwmIOConfiguration.ioConfigurations[pwmIOConfiguration.ioCount].index = pwmIOConfiguration.motorCount; pwmIOConfiguration.ioConfigurations[pwmIOConfiguration.ioCount].timerHardware = timerHardwarePtr; pwmIOConfiguration.motorCount++; addBootlogEvent6(BOOT_EVENT_TIMER_CH_MAPPED, BOOT_EVENT_FLAGS_NONE, i, pwmIOConfiguration.motorCount, pwmIOConfiguration.servoCount, 2); } else if (type == MAP_TO_SERVO_OUTPUT) { if (pwmIOConfiguration.servoCount >= MAX_SERVOS) { addBootlogEvent6(BOOT_EVENT_TIMER_CH_SKIPPED, BOOT_EVENT_FLAGS_WARNING, i, pwmIOConfiguration.motorCount, pwmIOConfiguration.servoCount, 2); continue; } #ifdef USE_SERVOS pwmServoConfig(timerHardwarePtr, pwmIOConfiguration.servoCount, init->servoPwmRate, init->servoCenterPulse, init->enablePWMOutput); pwmIOConfiguration.ioConfigurations[pwmIOConfiguration.ioCount].flags = PWM_PF_SERVO | PWM_PF_OUTPUT_PROTOCOL_PWM; pwmIOConfiguration.ioConfigurations[pwmIOConfiguration.ioCount].index = pwmIOConfiguration.servoCount; pwmIOConfiguration.ioConfigurations[pwmIOConfiguration.ioCount].timerHardware = timerHardwarePtr; pwmIOConfiguration.servoCount++; addBootlogEvent6(BOOT_EVENT_TIMER_CH_MAPPED, BOOT_EVENT_FLAGS_NONE, i, pwmIOConfiguration.motorCount, pwmIOConfiguration.servoCount, 3); #endif } else { continue; } pwmIOConfiguration.ioCount++; } return &pwmIOConfiguration; }
bool pwmInit(drv_pwm_config_t *init) { uint8_t i = 0; const uint8_t *setup; // this is pretty hacky shit, but it will do for now. array of 4 config maps, [ multiPWM multiPPM airPWM airPPM ] if (init->airplane) i = 2; // switch to air hardware config if (init->usePPM) i++; // next index is for PPM setup = hardwareMaps[i]; for (i = 0; i < MAX_PORTS; i++) { uint8_t port = setup[i] & 0x0F; uint8_t mask = setup[i] & 0xF0; // Mask = TYPE_IP, TYPE_IW, TYPE_M, TYPE_S if (setup[i] == 0xFF) break; // terminator if (init->useUART && (port == PWM3 || port == PWM4)) // skip UART ports for GPS continue; // Jump to beginning of for loop again if (init->adcChannel && (init->adcChannel == port)) // skip ADC for powerMeter if configured continue; if (init->useRC5 && port == PWM5) // skip RC5 ports for MONO_LED continue; if (init->useRC6 && port == PWM6) // skip RC6 ports for MONO_LED continue; if (init->usePWM56 && (port == PWM13 || port == PWM14))// skip PWM5 ports for SONAR they are pwm13/14 in other nomenclature continue; if (init->useRC78 && (port == PWM7 || port == PWM8)) // skip RC78 ports for SONAR continue; if ((mask & (TYPE_IP | TYPE_IW)) && !init->enablePWMInput)// hacks to allow current functionality mask = 0; if (!init->airplane) { if (init->useServos && (port == PWM9 || port == PWM10)) mask = TYPE_S; // remap PWM9+10 as servos (but not in airplane mode LOL) if (init->extraServos && port >= PWM5 && port <= PWM8) mask = TYPE_S; // remap PWM5..8 as servos when used in extended servo mode } switch(mask) { case TYPE_IP: // PPM input pwmInConfig(port, ppmCallback, 0); numInputs = 8; // ONLY 8 here with that auxchannelstuff? break; case TYPE_IW: // Single PWM input pwmInConfig(port, pwmCallback, numInputs); numInputs++; break; case TYPE_M: // Motor motors[numMotors++] = pwmOutConfig(port, 1000000 / init->motorPwmRate, PULSE_1MS); break; case TYPE_S: // Servo servos[numServos++] = pwmOutConfig(port, 1000000 / init->servoPwmRate, PULSE_1MS); break; } } return false; }