⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 pwm.c

📁 在SOPC平台上
💻 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 + -