//***************************************************************************** // // The interrupt handler for the for PWM0 interrupts. // //***************************************************************************** void PWM0IntHandler(void) { // // Clear the PWM0 LOAD interrupt flag. This flag gets set when the PWM // counter gets reloaded. // PWMGenIntClear(PWM_BASE, PWM_GEN_0, PWM_INT_CNT_LOAD); // // If the duty cycle is less or equal to 75% then add 0.1% to the duty // cycle. Else, reset the duty cycle to 0.1% cycles. Note that 64 is // 0.01% of the period (64000 cycles). // if((PWMPulseWidthGet(PWM_BASE, PWM_OUT_0) + 64) <= ((PWMGenPeriodGet(PWM_BASE, PWM_GEN_0) * 3) / 4)) { PWMPulseWidthSet(PWM_BASE, PWM_OUT_0, PWMPulseWidthGet(PWM_BASE, PWM_OUT_0) + 64); } else { PWMPulseWidthSet(PWM_BASE, PWM_OUT_0, 64); } }
void PWMGen1Handler() { PWMGenIntClear(PWM0_BASE, PWM_GEN_1, PWM_INT_CNT_LOAD); if (!camera_DBSelected) { camera_DBSelected = 1; uDMAChannelTransferSet(UDMA_CHANNEL_ADC3 | UDMA_ALT_SELECT, UDMA_MODE_PINGPONG, (void*) (ADC0_BASE + ADC_O_SSFIFO3), camera_DoubleBuffer[camera_DBSelected], CAMERA_SAMPLES); // switch camera input to near camera ADCSequenceStepConfigure(ADC0_BASE, 3, 0, ADC_CTL_CH1 | ADC_CTL_IE | ADC_CTL_END); current_Camera = FAR; } if (camera_DBSelected) { camera_DBSelected = 0; uDMAChannelTransferSet(UDMA_CHANNEL_ADC3 | UDMA_PRI_SELECT, UDMA_MODE_PINGPONG, (void*) (ADC0_BASE + ADC_O_SSFIFO3), camera_DoubleBuffer[camera_DBSelected], CAMERA_SAMPLES); // switch camera input to far camera ADCSequenceStepConfigure(ADC0_BASE, 3, 0, ADC_CTL_CH0 | ADC_CTL_IE | ADC_CTL_END); current_Camera = NEAR; } }
// Upon the PWM rising edge, the current system time is measured, a counter is incremented // and the number of pulses generated to that point is checked. void transponder_pulse_isr(void) { PWMGenIntClear(PWM0_BASE, PWM_GEN_2, PWM_INT_CNT_LOAD); if(g_transponder_pulse_count >= 0) g_transponder_times[g_transponder_pulse_count] = stopwatch_get_time_us(&g_transponder_stopwatch); //TODO: consider if the response hasnt occured g_transponder_pulse_count++; stopwatch_start(&g_transponder_stopwatch); if (g_transponder_pulse_count >= g_num_pulses) PWMGenDisable(PWM0_BASE, PWM_GEN_2); }
// Save as the first airspeed pulse gen ISR as above, however // The PWM module is disabled after 3 pulses are generated void airspeed_pulse_isr_gpio_test_b(void) { PWMGenIntClear(PWM0_BASE, PWM_GEN_0, PWM_INT_CNT_LOAD); if(g_airspeed_pulse_count >= 1) // Proccess last latency measurement g_airspeed_times[g_airspeed_pulse_count] = stopwatch_get_time_us(&g_airspeed_stopwatch); // Increment the pulse count if output is currently enabled and disable output // if two pulses have been generated g_airspeed_pulse_count += 1 - test_b_output_toggle(); stopwatch_start(&g_airspeed_stopwatch); if (g_airspeed_pulse_count >= MAX_NUM_PULSES) PWMGenDisable(PWM0_BASE, PWM_GEN_0); }
// Upon the PWM rising edge, the current system time is measured, a counter is incremented // and the number of pulses generated to that point is checked. void airspeed_pulse_isr(void) { PWMGenIntClear(PWM0_BASE, PWM_GEN_0, PWM_INT_CNT_LOAD); //GPIOPinWrite(GPIO_PORTC_BASE, (1<<2), (1<<2)); // debug if(g_airspeed_pulse_count >= 0) // Proccess last latency measurement g_airspeed_times[g_airspeed_pulse_count] = stopwatch_get_time_us(&g_airspeed_stopwatch); g_airspeed_pulse_count++; stopwatch_start(&g_airspeed_stopwatch); if (g_airspeed_pulse_count >= g_num_pulses) PWMGenDisable(PWM0_BASE, PWM_GEN_0); //GPIOPinWrite(GPIO_PORTC_BASE, (1<<2), ~(1<<2)); // debug }
//***************************************************************************** // //! Handles the PWM1 interrupt. //! //! This function responds to the PWM1 interrupt, updating the duty cycle of //! the output waveform in order to produce sound. It is the application's //! responsibility to ensure that this function is called in response to the //! PWM1 interrupt, typically by installing it in the vector table as the //! handler for the PWM1 interrupt. //! //! \return None. // //***************************************************************************** void ClassDPWMHandler(void) { long lStep, lNibble, lDutyCycle; // // Clear the PWM interrupt. // PWMGenIntClear(PWM_BASE, PWM_GEN_1, PWM_INT_CNT_ZERO); // // See if the startup ramp is in progress. // if(HWREGBITW(&g_ulClassDFlags, CLASSD_FLAG_STARTUP)) { // // Decrement the ramp count. // g_ulClassDStep--; // // Increase the pulse width of the two outputs by one clock. // PWMDeadBandEnable(PWM_BASE, PWM_GEN_1, 0, g_ulClassDStep); PWMPulseWidthSet(PWM_BASE, PWM_OUT_2, (g_ulClassDPeriod - g_ulClassDStep) / 2); // // See if this was the last step of the ramp. // if(g_ulClassDStep == 0) { // // Indicate that the startup ramp has completed. // HWREGBITW(&g_ulClassDFlags, CLASSD_FLAG_STARTUP) = 0; } // // There is nothing further to be done. // return; } // // See if the shutdown ramp is in progress. // if(HWREGBITW(&g_ulClassDFlags, CLASSD_FLAG_SHUTDOWN)) { // // See if this was the last step of the ramp. // if(g_ulClassDStep == (g_ulClassDPeriod - 2)) { // // Disable the PWM2 and PWM3 output signals. // PWMOutputState(PWM_BASE, PWM_OUT_2_BIT | PWM_OUT_3_BIT, false); // // Clear the Class-D audio flags. // g_ulClassDFlags = 0; // // Disable the PWM interrupt. // IntDisable(INT_PWM1); } else { // // Increment the ramp count. // g_ulClassDStep++; // // Decrease the pulse width of the two outputs by one clock. // PWMDeadBandEnable(PWM_BASE, PWM_GEN_1, 0, g_ulClassDStep); PWMPulseWidthSet(PWM_BASE, PWM_OUT_2, (g_ulClassDPeriod - g_ulClassDStep) / 2); } // // There is nothing further to be done. // return; } // // Compute the value of the PCM sample based on the blended average of the // previous and current samples. It should be noted that linear // interpolation does not produce the best results with audio (it produces // a significant amount of harmonic aliasing) but it is fast. // lDutyCycle = (((g_pusClassDSamples[0] * (8 - (g_ulClassDStep & 7))) + (g_pusClassDSamples[1] * (g_ulClassDStep & 7))) / 8); // // Adjust the magnitude of the sample based on the current volume. Since a // multiplicative volume control is implemented, the volume value will // result in nearly linear volume adjustment if it is squared. // lDutyCycle = (((lDutyCycle - 32768) * g_lClassDVolume * g_lClassDVolume) / 65536) + 32768; // // Set the PWM duty cycle based on this PCM sample. // lDutyCycle = (g_ulClassDPeriod * lDutyCycle) / 65536; if(lDutyCycle > (g_ulClassDPeriod - 2)) { lDutyCycle = g_ulClassDPeriod - 2; } if(lDutyCycle < 2) { lDutyCycle = 2; } PWMPulseWidthSet(PWM_BASE, PWM_OUT_2, lDutyCycle); // // Increment the audio step. // g_ulClassDStep++; // // See if the next sample has been reached. // if((g_ulClassDStep & 7) == 0) { // // Copy the current sample to the previous sample. // g_pusClassDSamples[0] = g_pusClassDSamples[1]; // // See if there is more input data. // if(g_ulClassDLength == 0) { // // All input data has been played, so start a shutdown to avoid a // pop. // g_ulClassDFlags = 0; HWREGBITW(&g_ulClassDFlags, CLASSD_FLAG_SHUTDOWN) = 1; g_ulClassDStep = 0; } // // See if an ADPCM stream is being played. // else if(HWREGBITW(&g_ulClassDFlags, CLASSD_FLAG_ADPCM)) { // // See which nibble should be decoded. // if((g_ulClassDStep & 8) == 0) { // // Extract the lower nibble from the current byte, and skip to // the next byte. // lNibble = *g_pucClassDBuffer++; // // Decrement the count of bytes to be decoded. // g_ulClassDLength--; } else { // // Extract the upper nibble from the current byte. // lNibble = *g_pucClassDBuffer >> 4; } // // Compute the sample delta based on the current nibble and step // size. // lStep = ((((2 * (lNibble & 7)) + 1) * g_pusADPCMStep[g_lClassDADPCMStepIndex]) / 16); // // Add or subtract the delta to the previous sample value, clipping // if necessary. // if(lNibble & 8) { lStep = g_pusClassDSamples[0] - lStep; if(lStep < 0) { lStep = 0; } } else { lStep = g_pusClassDSamples[0] + lStep; if(lStep > 65535) { lStep = 65535; } } // // Store the generated sample. // g_pusClassDSamples[1] = lStep; // // Adjust the step size index based on the current nibble, clipping // the value if required. // g_lClassDADPCMStepIndex += g_pcADPCMIndex[lNibble & 7]; if(g_lClassDADPCMStepIndex < 0) { g_lClassDADPCMStepIndex = 0; } if(g_lClassDADPCMStepIndex > 88) { g_lClassDADPCMStepIndex = 88; } } // // See if a 8-bit PCM stream is being played. // else if(HWREGBITW(&g_ulClassDFlags, CLASSD_FLAG_PCM))
//-------------------------------- extern "C" void OnPWM1Gen1Interrupt(void) { PWMGenIntClear(PWM1_BASE, PWM_GEN_1, PWM_INT_CNT_LOAD); if (g_pTheStepper) { g_pTheStepper->OnInterrupt(); } }
//***************************************************************************** // //! Handles the PWM interrupt. //! //! This function is called as a result of the interrupt generated by the PWM //! module when the counter reaches zero. If an updated PWM frequency or duty //! cycle is available, they will be updated in the hardware by this function. //! //! \return None. // //***************************************************************************** void PWM0IntHandler(void) { // // Clear the PWM interrupt. This is done twice since the clear will be // ignored by hardware if it occurs on the same cycle as another interrupt // event; the second clear takes care of the case wehre the first gets // ignored. // PWMGenIntClear(PWM0_BASE, PWM_GEN_0, PWM_INT_CNT_ZERO); PWMGenIntClear(PWM0_BASE, PWM_GEN_0, PWM_INT_CNT_ZERO); // // Increment the count of PWM periods. // g_ulPWMPeriodCount++; // // See if it is time for a new PWM duty cycle, based on the correct number // of PWM periods passing and the availability of new duty cycle values. // if((g_ulPWMPeriodCount > g_sParameters.ucUpdateRate) && (HWREGBITW(&g_ulPWMFlags, PWM_FLAG_NEW_DUTY_CYCLE) == 1)) { // // See if the PWM frequency needs to be updated. // if(HWREGBITW(&g_ulPWMFlags, PWM_FLAG_NEW_FREQUENCY) == 1) { // // Set the new PWM period in each of the PWM generators. // PWMGenPeriodSet(PWM0_BASE, PWM_GEN_0, g_ulPWMClock); PWMGenPeriodSet(PWM0_BASE, PWM_GEN_1, g_ulPWMClock); PWMGenPeriodSet(PWM0_BASE, PWM_GEN_2, g_ulPWMClock); // // Indicate that the PWM frequency has been updated. // HWREGBITW(&g_ulPWMFlags, PWM_FLAG_NEW_FREQUENCY) = 0; } // // Update the duty cycle. // PWMUpdateDutyCycle(); // // Clear the duty cycle update flag. // HWREGBITW(&g_ulPWMFlags, PWM_FLAG_NEW_DUTY_CYCLE) = 0; } // // If the required number of PWM periods have expired, request an update of // the duty cycle computations. // if(g_ulPWMPeriodCount >= (g_sParameters.ucUpdateRate + 1)) { if(g_sParameters.ucModulationType == MOD_TYPE_SINE) { // // Trigger the waveform update software interrupt. // HWREG(NVIC_SW_TRIG) = INT_PWM0_1 - 16; } else { // // Reduce the PWM period count based on the number of updates that // would have occurred if the motor drive was running. // PWMReducePeriodCount((PWMGetPeriodCount() / (g_sParameters.ucUpdateRate + 1)) * (g_sParameters.ucUpdateRate + 1)); } } // // Increment the millisecond counter. By adding 1000 for each PWM // interrupt, it will take one millisecond for the counter to reach the PWM // frequency. // g_ulPWMMillisecondCount += 1000; // // See if a millisecond has expired. // if(g_ulPWMMillisecondCount >= g_ulPWMFrequency) { // // Trigger the millisecond software interrupt. // HWREG(NVIC_SW_TRIG) = INT_PWM0_2 - 16; // // Decrement the millisecond counter by the PWM frequency, which // corresponds to one millisecond. // g_ulPWMMillisecondCount -= g_ulPWMFrequency; // // Run the precharge state machine. // Note: The minimum precharge define (in pwm_ctrl.h) must account // for all states in this simple state machine. // if(HWREGBITW(&g_ulPWMFlags, PWM_FLAG_NEW_PRECHARGE) == 1) { HWREGBITW(&g_ulPWMFlags, PWM_FLAG_NEW_PRECHARGE) = 0; HWREGBITW(&g_ulPWMFlags, PWM_FLAG_SET_OUTPUT_A) = 1; } else if(HWREGBITW(&g_ulPWMFlags, PWM_FLAG_SET_OUTPUT_A) == 1) { HWREGBITW(&g_ulPWMFlags, PWM_FLAG_SET_OUTPUT_A) = 0; HWREGBITW(&g_ulPWMFlags, PWM_FLAG_SET_OUTPUT_B) = 1; PWMOutputState(PWM0_BASE, PWM_OUT_1_BIT, true); } else if(HWREGBITW(&g_ulPWMFlags, PWM_FLAG_SET_OUTPUT_B) == 1) { HWREGBITW(&g_ulPWMFlags, PWM_FLAG_SET_OUTPUT_B) = 0; HWREGBITW(&g_ulPWMFlags, PWM_FLAG_SET_OUTPUT_C) = 1; PWMOutputState(PWM0_BASE, PWM_OUT_3_BIT, true); } else if(HWREGBITW(&g_ulPWMFlags, PWM_FLAG_SET_OUTPUT_C) == 1) { HWREGBITW(&g_ulPWMFlags, PWM_FLAG_SET_OUTPUT_C) = 0; PWMOutputState(PWM0_BASE, PWM_OUT_5_BIT, true); } } }
//***************************************************************************** // //! Initializes the PWM control routines. //! //! This function initializes the PWM module and the control routines, //! preparing them to produce PWM waveforms to drive the power module. //! //! \return None. // //***************************************************************************** void PWMInit(void) { // // Make the PWM pins be peripheral function. // GPIOPinTypePWM(PIN_PHASEA_LOW_PORT, PIN_PHASEA_LOW_PIN | PIN_PHASEA_HIGH_PIN); GPIOPinTypePWM(PIN_PHASEB_LOW_PORT, PIN_PHASEB_LOW_PIN | PIN_PHASEB_HIGH_PIN); GPIOPinTypePWM(PIN_PHASEC_LOW_PORT, PIN_PHASEC_LOW_PIN | PIN_PHASEC_HIGH_PIN); // // Configure the three PWM generators for up/down counting mode, // synchronous updates, and to stop at zero on debug events. // PWMGenConfigure(PWM0_BASE, PWM_GEN_0, (PWM_GEN_MODE_UP_DOWN | PWM_GEN_MODE_SYNC | PWM_GEN_MODE_DBG_STOP)); PWMGenConfigure(PWM0_BASE, PWM_GEN_1, (PWM_GEN_MODE_UP_DOWN | PWM_GEN_MODE_SYNC | PWM_GEN_MODE_DBG_STOP)); PWMGenConfigure(PWM0_BASE, PWM_GEN_2, (PWM_GEN_MODE_UP_DOWN | PWM_GEN_MODE_SYNC | PWM_GEN_MODE_DBG_STOP)); // // Set the initial duty cycles to 50%. // g_ulPWMDutyCycleA = 32768; g_ulPWMDutyCycleB = 32768; g_ulPWMDutyCycleC = 32768; // // Configure the PWM period, duty cycle, and dead band. The initial period // is 1 KHz (for triggering the ADC), which will be increased when the // motor starts running. // PWMClearDeadBand(); PWMSetFrequency(); PWMGenPeriodSet(PWM0_BASE, PWM_GEN_0, PWM_CLOCK / 1000); PWMGenPeriodSet(PWM0_BASE, PWM_GEN_1, PWM_CLOCK / 1000); PWMGenPeriodSet(PWM0_BASE, PWM_GEN_2, PWM_CLOCK / 1000); PWMUpdateDutyCycle(); // // Enable the PWM generators. // PWMGenEnable(PWM0_BASE, PWM_GEN_0); PWMGenEnable(PWM0_BASE, PWM_GEN_1); PWMGenEnable(PWM0_BASE, PWM_GEN_2); // // Synchronize the time base of the generators. // PWMSyncTimeBase(PWM0_BASE, PWM_GEN_0_BIT | PWM_GEN_1_BIT | PWM_GEN_2_BIT); // // Configure an interrupt on the zero event of the first generator, and an // ADC trigger on the load event of the first generator. // PWMGenIntClear(PWM0_BASE, PWM_GEN_0, PWM_INT_CNT_ZERO); PWMGenIntTrigEnable(PWM0_BASE, PWM_GEN_0, PWM_INT_CNT_ZERO | PWM_TR_CNT_LOAD); PWMGenIntTrigEnable(PWM0_BASE, PWM_GEN_1, 0); PWMGenIntTrigEnable(PWM0_BASE, PWM_GEN_2, 0); PWMIntEnable(PWM0_BASE, PWM_INT_GEN_0); IntEnable(INT_PWM0_0); IntEnable(INT_PWM0_1); IntEnable(INT_PWM0_2); // // Set all six PWM outputs to go to the inactive state when a fault event // occurs (which includes debug events). // PWMOutputFault(PWM0_BASE, (PWM_OUT_0_BIT | PWM_OUT_1_BIT | PWM_OUT_2_BIT | PWM_OUT_3_BIT | PWM_OUT_4_BIT | PWM_OUT_5_BIT), true); // // Disable all six PWM outputs. // PWMOutputState(PWM0_BASE, (PWM_OUT_0_BIT | PWM_OUT_1_BIT | PWM_OUT_2_BIT | PWM_OUT_3_BIT | PWM_OUT_4_BIT | PWM_OUT_5_BIT), false); // // Ensure that all outputs are not-inverted. // PWMOutputInvert(PWM0_BASE, (PWM_OUT_0_BIT | PWM_OUT_1_BIT | PWM_OUT_2_BIT | PWM_OUT_3_BIT | PWM_OUT_4_BIT | PWM_OUT_5_BIT), false); }