//***************************************************************************** // //! Configures the dead timers for the PWM generators. //! //! This function configures the dead timers for all three PWM generators based //! on the dead time parameter. //! //! \return None. // //***************************************************************************** void PWMSetDeadBand(void) { // // Set the dead band times for all three PWM generators. // PWMDeadBandEnable(PWM0_BASE, PWM_GEN_0, g_sParameters.ucDeadTime, g_sParameters.ucDeadTime); PWMDeadBandEnable(PWM0_BASE, PWM_GEN_1, g_sParameters.ucDeadTime, g_sParameters.ucDeadTime); PWMDeadBandEnable(PWM0_BASE, PWM_GEN_2, g_sParameters.ucDeadTime, g_sParameters.ucDeadTime); // // Update the minimum PWM pulse width. // PWMSetMinPulseWidth(); }
//***************************************************************************** // // Configure the PWM0 block with dead-band generation. The example configures // the PWM0 block to generate a 25% duty cycle signal on PD0 with dead-band // generation. This will produce a complement of PD0 on PD1 (75% duty cycle). // The dead-band generator is set to have a 10us or 160 cycle delay // (160cycles / 16Mhz = 10us) on the rising and falling edges of the PD0 PWM // signal. // //***************************************************************************** int main(void) { // // Set the clocking to run directly from the external crystal/oscillator. // TODO: The SYSCTL_XTAL_ value must be changed to match the value of the // crystal on your board. // SysCtlClockSet(SYSCTL_SYSDIV_1 | SYSCTL_USE_OSC | SYSCTL_OSC_MAIN | SYSCTL_XTAL_16MHZ); // // Set the PWM clock to the system clock. // SysCtlPWMClockSet(SYSCTL_PWMDIV_1); // // Set up the serial console to use for displaying messages. This is just // for this example program and is not needed for PWM operation. // InitConsole(); // // Display the setup on the console. // UARTprintf("PWM ->\n"); UARTprintf(" Module: PWM0\n"); UARTprintf(" Pin(s): PD0 and PD1\n"); UARTprintf(" Features: Dead-band Generation\n"); UARTprintf(" Duty Cycle: 25%% on PD0 and 75%% on PD1\n"); UARTprintf(" Dead-band Length: 160 cycles on rising and falling edges\n\n"); UARTprintf("Generating PWM on PWM0 (PD0) -> "); // // The PWM peripheral must be enabled for use. // SysCtlPeripheralEnable(SYSCTL_PERIPH_PWM); // // For this example PWM0 is used with PortD Pins 0 and 1. The actual port // and pins used may be different on your part, consult the data sheet for // more information. GPIO port D needs to be enabled so these pins can be // used. // TODO: change this to whichever GPIO port you are using. // SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOD); // // Configure the GPIO pin muxing to select PWM functions for these pins. // This step selects which alternate function is available for these pins. // This is necessary if your part supports GPIO pin function muxing. // Consult the data sheet to see which functions are allocated per pin. // TODO: change this to select the port/pin you are using. // GPIOPinConfigure(GPIO_PD0_PWM0); GPIOPinConfigure(GPIO_PD1_PWM1); // // Configure the GPIO pad for PWM function on pins PD0 and PD1. Consult // the data sheet to see which functions are allocated per pin. // TODO: change this to select the port/pin you are using. // GPIOPinTypePWM(GPIO_PORTD_BASE, GPIO_PIN_0); GPIOPinTypePWM(GPIO_PORTD_BASE, GPIO_PIN_1); // // Configure the PWM0 to count up/down without synchronization. // Note: Enabling the dead-band generator automatically couples the 2 // outputs from the PWM block so we don't use the PWM synchronization. // PWMGenConfigure(PWM_BASE, PWM_GEN_0, PWM_GEN_MODE_UP_DOWN | PWM_GEN_MODE_NO_SYNC); // // Set the PWM period to 250Hz. To calculate the appropriate parameter // use the following equation: N = (1 / f) * SysClk. Where N is the // function parameter, f is the desired frequency, and SysClk is the // system clock frequency. // In this case you get: (1 / 250Hz) * 16MHz = 64000 cycles. Note that // the maximum period you can set is 2^16 - 1. // TODO: modify this calculation to use the clock frequency that you are // using. // PWMGenPeriodSet(PWM_BASE, PWM_GEN_0, 64000); // // Set PWM0 PD0 to a duty cycle of 25%. You set the duty cycle as a // function of the period. Since the period was set above, you can use the // PWMGenPeriodGet() function. For this example the PWM will be high for // 25% of the time or 16000 clock cycles (64000 / 4). // PWMPulseWidthSet(PWM_BASE, PWM_OUT_0, PWMGenPeriodGet(PWM_BASE, PWM_OUT_0) / 4); // // Enable the dead-band generation on the PWM0 output signal. PWM bit 0 // (PD0), will have a duty cycle of 25% (set above) and PWM bit 1 will have // a duty cycle of 75%. These signals will have a 10us gap between the // rising and falling edges. This means that before PWM bit 1 goes high, // PWM bit 0 has been low for at LEAST 160 cycles (or 10us) and the same // before PWM bit 0 goes high. The dead-band generator lets you specify // the width of the "dead-band" delay, in PWM clock cycles, before the PWM // signal goes high and after the PWM signal falls. For this example we // will use 160 cycles (or 10us) on both the rising and falling edges of // PD0. Reference the datasheet for more information on dead-band // generation. // PWMDeadBandEnable(PWM_BASE, PWM_GEN_0, 160, 160); // // Enable the PWM0 Bit 0 (PD0) and Bit 1 (PD1) output signals. // PWMOutputState(PWM_BASE, PWM_OUT_1_BIT | PWM_OUT_0_BIT, true); // // Enables the counter for a PWM generator block. // PWMGenEnable(PWM_BASE, PWM_GEN_0); // // Loop forever while the PWM signals are generated. // while(1) { // // Print out indication on the console that the program is running. // PrintRunningDots(); } }
//***************************************************************************** // //! 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))
void hardware_init(void) { //Set PWM clock at the same frequency as system clock SysCtlPWMClockSet(SYSCTL_PWMDIV_1); /* * Inverter system setup * period : Switching Frequency : 20Khz * cycle : Duty Cycle SPWM * deadband : Deadband */ inv.period = SysCtlClockGet()/20000; inv.deadband = 25*inv.period/100; inv.cycle = inv.period*500/1000; /* * Boost converter system setup * period: Switching frequency: 20kHz * cycle: Duty cycle * deadband: Deadband */ conv.period = inv.period; conv.deadband = inv.deadband; conv.cycle = conv.period*500/1000; /* * Setup SPWM on PWM0 GEN0 and GEN1 * PB6 : PWM0 GEN0 * PB7: PWM0 GEN1 */ SysCtlPeripheralEnable(SYSCTL_PERIPH_PWM0); SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOB); SysCtlPeripheralReset(SYSCTL_PERIPH_PWM0); SysCtlPeripheralReset(SYSCTL_PERIPH_GPIOB); GPIOPinConfigure(GPIO_PB6_M0PWM0); GPIOPinConfigure(GPIO_PB7_M0PWM1); GPIOPinTypePWM(GPIO_PORTB_BASE, (GPIO_PIN_6 | GPIO_PIN_7)); PWMGenConfigure(PWM0_BASE, PWM_GEN_0, (PWM_GEN_MODE_UP_DOWN | PWM_GEN_MODE_GEN_SYNC_LOCAL | PWM_GEN_MODE_FAULT_UNLATCHED | PWM_GEN_MODE_DB_NO_SYNC)); PWMGenPeriodSet(PWM0_BASE, PWM_GEN_0, inv.period-1); PWMPulseWidthSet(PWM0_BASE, PWM_OUT_0, inv.cycle); PWMDeadBandEnable(PWM0_BASE, PWM_GEN_0, 13, 0); PWMGenEnable(PWM0_BASE, PWM_GEN_0); PWMOutputState(PWM0_BASE, PWM_OUT_0_BIT|PWM_OUT_1_BIT, true); PWMSyncUpdate(PWM0_BASE, PWM_OUT_0_BIT|PWM_OUT_1_BIT); /* * Setup boost converter pwm on PWM1 * PA6: PWM1 GEN1 */ SysCtlPeripheralEnable(SYSCTL_PERIPH_PWM1); SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOA); SysCtlPeripheralReset(SYSCTL_PERIPH_PWM1); SysCtlPeripheralReset(SYSCTL_PERIPH_GPIOA); GPIOPinConfigure(GPIO_PA6_M1PWM2); //Map PWM1, P1 OP2 to PA6 GPIOPinTypePWM(GPIO_PORTA_BASE, GPIO_PIN_6); //Configure PA6 as PWM PWMGenConfigure(PWM1_BASE, PWM_GEN_1, (PWM_GEN_MODE_UP_DOWN | PWM_GEN_MODE_GEN_NO_SYNC| PWM_GEN_MODE_DB_NO_SYNC)); //Configure PWM1, G1 as Down counter with no sync of updates PWMGenPeriodSet(PWM1_BASE, PWM_GEN_1, conv.period-1); //Set Period of PWM1, G1 PWMPulseWidthSet(PWM1_BASE, PWM_OUT_2, conv.cycle); //Set phase shift PWMIntEnable(PWM1_BASE, PWM_INT_GEN_1); PWMGenIntTrigEnable(PWM1_BASE, PWM_GEN_1, PWM_TR_CNT_LOAD|PWM_INT_CNT_LOAD); IntPrioritySet(INT_PWM1_1, 0x02); PWMOutputState(PWM1_BASE, PWM_OUT_2_BIT, true); PWMGenEnable(PWM1_BASE, PWM_GEN_1); /* * Setup ISR for updating SPWM duty cycle */ uint32_t ui32TimIntSine = SysCtlClockGet()/200000; SysCtlPeripheralEnable(SYSCTL_PERIPH_TIMER2); SysCtlPeripheralReset(SYSCTL_PERIPH_TIMER2); TimerConfigure(TIMER2_BASE, TIMER_CFG_A_PERIODIC); TimerLoadSet(TIMER2_BASE, TIMER_A, ui32TimIntSine-1); TimerIntEnable(TIMER2_BASE, TIMER_TIMA_TIMEOUT); IntPrioritySet(INT_TIMER2A, 0x03); TimerEnable(TIMER2_BASE, TIMER_A); uint32_t ui32TimIntIcontrol = SysCtlClockGet()/40000; SysCtlPeripheralEnable(SYSCTL_PERIPH_TIMER1); SysCtlPeripheralReset(SYSCTL_PERIPH_TIMER1); TimerConfigure(TIMER1_BASE, TIMER_CFG_A_PERIODIC); TimerLoadSet(TIMER1_BASE, TIMER_A, ui32TimIntIcontrol-1); TimerIntEnable(TIMER1_BASE, TIMER_TIMA_TIMEOUT); IntPrioritySet(INT_TIMER1A, 0x01); TimerEnable(TIMER1_BASE, TIMER_A); /* * Setup PF1 as debug pin */ SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOF); // SysCtlPeripheralReset(SYSCTL_PERIPH_GPIOF); HWREG(0x40005520) = 0x4C4F434B; HWREG(0x40005524) |= 0x01; HWREG(0x40005520) = 0x00; GPIOPinTypeGPIOInput(GPIO_PORTF_BASE, GPIO_PIN_4); GPIOPadConfigSet(GPIO_PORTF_BASE,GPIO_PIN_4,GPIO_STRENGTH_2MA,GPIO_PIN_TYPE_STD_WPU); GPIOIntTypeSet(GPIO_PORTF_BASE, GPIO_PIN_4, GPIO_FALLING_EDGE); IntPrioritySet(INT_GPIOF,0x00); GPIOIntEnable(GPIO_PORTF_BASE, GPIO_PIN_4); GPIOPinTypeGPIOOutput(GPIO_PORTF_BASE, GPIO_PIN_1); /* * Setup ADC * Configuration currently in discussion * Interrupt at end might not be necessary */ SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOE); SysCtlPeripheralReset(SYSCTL_PERIPH_GPIOE); GPIOPinTypeADC(GPIO_PORTE_BASE, GPIO_PIN_2); GPIOPinTypeADC(GPIO_PORTE_BASE, GPIO_PIN_1); GPIOPinTypeADC(GPIO_PORTE_BASE, GPIO_PIN_0); SysCtlPeripheralEnable(SYSCTL_PERIPH_ADC0); SysCtlPeripheralReset(SYSCTL_PERIPH_ADC0); ADCHardwareOversampleConfigure(ADC0_BASE, 2); ADCSequenceDisable(ADC0_BASE, 2); ADCSequenceConfigure(ADC0_BASE, 2, ADC_TRIGGER_PWM1, 0x00); HWREG(0x4003801C) |= 0x1000; //Sec 13.4.2 Pt 3 ADCSequenceStepConfigure(ADC0_BASE, 2, 0, ADC_CTL_CH1); ADCSequenceStepConfigure(ADC0_BASE, 2, 1, ADC_CTL_CH2); ADCSequenceStepConfigure(ADC0_BASE, 2, 2, ADC_CTL_CH3|ADC_CTL_IE|ADC_CTL_END); ADCSequenceEnable(ADC0_BASE, 2); }