📄 pwm.c
字号:
/***********************************************************************
* *
* File: pwm.c *
* *
* Purpose: Provides an API to play audio through the PWM with FIFO *
* SOPC Builder Component *
* *
* Author: N. Knight *
* Altera Corporation *
* Aug 2005 *
**********************************************************************/
#define PWM_DEBUG 0
#include <stdio.h>
#include "system.h"
#include "pwm.h"
#include "io.h"
#include "alt_types.h"
/***********************************************************************
* Function: PWM_SetSamplingRate *
* *
* Purpose: Sets the sampling period of the PWM hardware. The period *
* of the PWM should be the same as the sampling rate of the *
* audio being played. This function calculates the proper *
* modulus of the PWM period counter based on the sample rate *
* and the period counter's clock rate *
* *
* Input: Sample rate of current set of audio samples *
* Base address of PWM peripheral *
* Output: Writes period value to PWM hardware *
**********************************************************************/
void PWM_SetSamplingRate( alt_u32 new_sample_rate, alt_u32 pwm_base_addr )
{
static alt_u32 current_sample_rate = 0;
alt_u32 pwm_period = 0;
/* Only need to change it if it's different.*/
if ( new_sample_rate != current_sample_rate )
{
current_sample_rate = new_sample_rate;
pwm_period = ( PWM_CLOCK_RATE / current_sample_rate );
/* Write sampling period to the PWM peripheral */
IOWR_16DIRECT( pwm_base_addr, PWM_PERIOD_OFFSET, pwm_period );
}
return;
}
/***********************************************************************
* Function: PWM_PlaySamples *
* *
* Purpose: Scales and writes a sample stream to the PWM fifo. If *
* there isnt room in the FIFO, we return -1 to indicate we *
* couldn't accept the samples at this time *
* *
* Input: Pointers to left and right channel audio sample buffers *
* Number of samples currently in buffer ready for output *
* Sample rate of audio *
* PWM FIFO size *
* PWM Base address *
* Output: Writes playable samples to PWM FIFO hardware *
* Returns: Result code: 0 = Success, -1 = No room in FIFO *
**********************************************************************/
int PWM_PlaySamples( int *left, int *right, alt_u32 num_samples,
alt_u32 sample_rate, alt_u32 fifo_size,
alt_u32 pwm_base_addr )
{
alt_u32 free_fifo_space;
alt_u32 i;
int ret_code = 0;
signed int sample_l;
signed int sample_r;
alt_u32 sample_period;
alt_u32 composite_sample;
/* Find out how much space is available in the pwm fifo */
free_fifo_space = ( fifo_size - IORD_16DIRECT( pwm_base_addr, PWM_FIFO_USED_OFFSET ) );
/* If there's enough room for the samples we have, scale 'em and stuff 'em */
if( free_fifo_space >= num_samples )
{
sample_period = ( PWM_CLOCK_RATE / sample_rate );
for( i = 0; i < num_samples; i++ )
{
/* Left channel */
sample_l = PWM_ScaleSample( left[i], sample_period );
/* Right channel */
sample_r = PWM_ScaleSample( right[i], sample_period );
/*
* Combine the left and right samples into one word and send
* them to the PWM
* */
composite_sample = ( (sample_l << 16) | sample_r );
IOWR_32DIRECT( pwm_base_addr, PWM_DATA_OFFSET, ( alt_u32 )composite_sample );
}
/* Woohoo! we were successful, so return 0 */
ret_code = SUCCESS;
}
else
{
/* If there wasnt room, return -1 */
ret_code = FAIL;
}
return ret_code;
}
/***********************************************************************
* Function: PWM_ScaleSample *
* *
* Purpose: Takes a 24-bit signed sample and scales it to be playable *
* by the PWM. Scaling is dependant upon the sampling period *
* of the PWM *
* *
* Input: 24-bit signed sample value *
* Current sampling period of the PWM *
* Output: Properly scaled sample value *
**********************************************************************/
int PWM_ScaleSample( int sample, int sampling_period )
{
/*
* This sample scaling method for the PWM seems to give the best sound
* quality and volume consistency over varying sampling periods. It does
* however employ a mult and a div, which could hurt performance.
*/
sample = ( ( sample >> 4 ) + 0x7fff );
sample = ( ( sample * sampling_period ) / 0x0ffff );
# if 0
/*
* This sample scaling method is fast, but has poorish audio quality
*/
if(sample <= -0x10000000L)
sample = 0;
else if(sample >= 0x10000000L)
sample = 0xfff;
else
sample = ((sample >> 17) & 0xfff) ^0x00000800L;
# endif
return( sample );
}
/***********************************************************************
* Function: PWM_Start *
* *
* Purpose: Starts the playing of samples *
* *
* Input: PWM base address *
* Output: Writes register value to PWM hardware *
**********************************************************************/
void PWM_Start( alt_u32 pwm_base_addr )
{
// Play audio
IOWR_16DIRECT( pwm_base_addr, PWM_CONTROL_OFFSET, PWM_GO );
}
/***********************************************************************
* Function: PWM_Stop *
* *
* Purpose: Stops the playing of samples *
* *
* Input: PWM base address *
* Output: Writes register value to PWM hardware *
**********************************************************************/
void PWM_Stop( alt_u32 pwm_base_addr )
{
// shut off audio
IOWR_16DIRECT( pwm_base_addr, PWM_CONTROL_OFFSET, PWM_STOP );
}
/***********************************************************************
* Function: PWM_ResetPWM *
* *
* Purpose: Stops the playing of samples and resets the PWM hardware *
* *
* Input: PWM base address *
* Output: Writes register values to PWM hardware *
**********************************************************************/
void PWM_ResetPWM( alt_u32 pwm_base_addr )
{
// reset the PWM, then return it to stopped state
IOWR_16DIRECT( pwm_base_addr, PWM_CONTROL_OFFSET, PWM_RESET );
IOWR_16DIRECT( pwm_base_addr, PWM_CONTROL_OFFSET, PWM_STOP );
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -