📄 sound.c
字号:
//
// Set the FIFO trigger limit
//
I2SRxFIFOLimitSet (I2S0_BASE, 4);
//
// Enable the I2S Rx controller.
//
I2SRxEnable(I2S0_BASE);
//
// Disable all DMA attributes.
//
uDMAChannelAttributeDisable(UDMA_CHANNEL_I2S0RX, UDMA_ATTR_ALL);
}
//
// Enable the I2S interrupt on the NVIC
//
IntEnable(INT_I2S0);
}
//*****************************************************************************
//
//! Handles the I2S sound interrupt.
//!
//! This function services the I2S interrupt and will call the callback function
//! provided with the buffer that was given to the SoundBufferPlay() or
//! SoundBufferRead() functions to handle emptying or filling the buffers and
//! starting up DMA transfers again. It is solely the responsibility of the
//! callback functions to continuing sending or receiving data to or from the
//! audio codec.
//!
//! \return None.
//
//*****************************************************************************
void
SoundIntHandler(void)
{
unsigned long ulStatus;
unsigned long *pulTemp;
//
// Get the interrupt status and clear any pending interrupts.
//
ulStatus = I2SIntStatus(I2S0_BASE, 1);
//
// Clear out any interrupts.
//
I2SIntClear(I2S0_BASE, ulStatus);
//
// Handle the RX channel interrupt
//
if(HWREGBITW(&g_ulDMAFlags, FLAG_RX_PENDING))
{
//
// If the RX DMA is done, then start another one using the same
// RX buffer. This keeps the RX running continuously.
//
if(uDMAChannelModeGet(UDMA_CHANNEL_I2S0RX | UDMA_PRI_SELECT) ==
UDMA_MODE_STOP)
{
//
// Save a temp pointer so that the current pointer can be set to
// zero before calling the callback.
//
pulTemp = g_sInBuffers[0].pulData;
//
// If at the mid point the refill the first half of the buffer.
//
if(g_sInBuffers[0].pfnBufferCallback)
{
g_sInBuffers[0].pulData = 0;
g_sInBuffers[0].pfnBufferCallback(pulTemp, BUFFER_EVENT_FULL);
}
}
else if(uDMAChannelModeGet(UDMA_CHANNEL_I2S0RX | UDMA_ALT_SELECT) ==
UDMA_MODE_STOP)
{
//
// Save a temp pointer so that the current pointer can be set to
// zero before calling the callback.
//
pulTemp = g_sInBuffers[1].pulData;
//
// If at the mid point the refill the first half of the buffer.
//
if(g_sInBuffers[1].pfnBufferCallback)
{
g_sInBuffers[1].pulData = 0;
g_sInBuffers[1].pfnBufferCallback(pulTemp, BUFFER_EVENT_FULL);
}
}
//
// If there are no more scheduled buffers then there are no more
// pending DMA transfers.
//
if((g_sInBuffers[0].pulData == 0) && (g_sInBuffers[1].pulData == 0))
{
HWREGBITW(&g_ulDMAFlags, FLAG_RX_PENDING) = 0;
}
}
//
// Handle the TX channel interrupt
//
if(HWREGBITW(&g_ulDMAFlags, FLAG_TX_PENDING))
{
//
// If the TX DMA is done, then call the callback if present.
//
if(uDMAChannelModeGet(UDMA_CHANNEL_I2S0TX | UDMA_PRI_SELECT) ==
UDMA_MODE_STOP)
{
//
// Save a temp pointer so that the current pointer can be set to
// zero before calling the callback.
//
pulTemp = g_sOutBuffers[0].pulData;
//
// If at the mid point then refill the first half of the buffer.
//
if((g_sOutBuffers[0].pfnBufferCallback) &&
(g_sOutBuffers[0].pulData != 0))
{
g_sOutBuffers[0].pulData = 0;
g_sOutBuffers[0].pfnBufferCallback(pulTemp, BUFFER_EVENT_FREE);
}
}
//
// If the TX DMA is done, then call the callback if present.
//
if(uDMAChannelModeGet(UDMA_CHANNEL_I2S0TX | UDMA_ALT_SELECT) ==
UDMA_MODE_STOP)
{
//
// Save a temp pointer so that the current pointer can be set to
// zero before calling the callback.
//
pulTemp = g_sOutBuffers[1].pulData;
//
// If at the mid point then refill the first half of the buffer.
//
if((g_sOutBuffers[1].pfnBufferCallback) &&
(g_sOutBuffers[1].pulData != 0))
{
g_sOutBuffers[1].pulData = 0;
g_sOutBuffers[1].pfnBufferCallback(pulTemp, BUFFER_EVENT_FREE);
}
}
//
// If no more buffers are pending then clear the flag.
//
if((g_sOutBuffers[0].pulData == 0) && (g_sOutBuffers[1].pulData == 0))
{
HWREGBITW(&g_ulDMAFlags, FLAG_TX_PENDING) = 0;
}
}
}
//*****************************************************************************
//
//! Starts playback of a song.
//!
//! \param pusSong is a pointer to the song data structure.
//! \param ulLength is the length of the song data structure in bytes.
//!
//! This function starts the playback of a song or sound effect. If a song
//! or sound effect is already being played, its playback is canceled and the
//! new song is started.
//!
//! \return None.
//
//*****************************************************************************
void
SoundPlay(const unsigned short *pusSong, unsigned long ulLength)
{
//
// Set the format of the audio stream.
//
SoundSetFormat(48000, 16, 2);
//
// Save the music buffer.
//
g_ulMusicCount = 0;
g_ulMusicSize = ulLength * 2;
g_pusMusic = pusSong;
g_ulPlaying = 0;
g_sOutBuffers[0].pulData = 0;
g_sOutBuffers[1].pulData = 0;
if(SoundNextTone() != 0)
{
SoundBufferPlay(g_pulTxBuf, g_ulSize, BufferCallback);
SoundBufferPlay(g_pulTxBuf, g_ulSize, BufferCallback);
}
}
//*****************************************************************************
//
//! Configures the I2S peripheral for the given audio data format.
//!
//! \param ulSampleRate is the sample rate of the audio to be played in
//! samples per second.
//! \param usBitsPerSample is the number of bits in each audio sample.
//! \param usChannels is the number of audio channels, 1 for mono, 2 for stereo.
//!
//! This function configures the I2S peripheral in preparation for playing
//! and recording audio data of a particular format.
//!
//! \return None.
//
//*****************************************************************************
void
SoundSetFormat(unsigned long ulSampleRate, unsigned short usBitsPerSample,
unsigned short usChannels)
{
unsigned long ulFormat;
unsigned long ulDMASetting;
//
// Save these values for use when configuring I2S.
//
g_usChannels = usChannels;
g_usBitsPerSample = usBitsPerSample;
I2SMasterClockSelect(I2S0_BASE, 0);
//
// Always use have the controller be an I2S Master.
//
ulFormat = I2S_CONFIG_FORMAT_I2S | I2S_CONFIG_CLK_MASTER;
//
// Mono or Stereo formats.
//
if(g_usChannels == 1)
{
if(g_usBitsPerSample == 8)
{
ulFormat |= I2S_CONFIG_WIRE_SIZE_8 | I2S_CONFIG_MODE_MONO |
I2S_CONFIG_SAMPLE_SIZE_8;
}
else if(g_usBitsPerSample == 16)
{
ulFormat |= I2S_CONFIG_WIRE_SIZE_16 | I2S_CONFIG_MODE_MONO |
I2S_CONFIG_SAMPLE_SIZE_16;
}
else if(g_usBitsPerSample == 24)
{
ulFormat |= I2S_CONFIG_WIRE_SIZE_24 | I2S_CONFIG_MODE_MONO |
I2S_CONFIG_SAMPLE_SIZE_24;
}
else
{
ulFormat |= I2S_CONFIG_WIRE_SIZE_32 | I2S_CONFIG_MODE_MONO |
I2S_CONFIG_SAMPLE_SIZE_32;
}
}
else
{
if(g_usBitsPerSample == 8)
{
ulFormat |= I2S_CONFIG_WIRE_SIZE_8 | I2S_CONFIG_MODE_COMPACT_8 |
I2S_CONFIG_SAMPLE_SIZE_8;
}
else if(g_usBitsPerSample == 16)
{
ulFormat |= I2S_CONFIG_WIRE_SIZE_16 | I2S_CONFIG_MODE_COMPACT_16 |
I2S_CONFIG_SAMPLE_SIZE_16;
}
else if(g_usBitsPerSample == 24)
{
ulFormat |= I2S_CONFIG_WIRE_SIZE_24 | I2S_CONFIG_MODE_DUAL |
I2S_CONFIG_SAMPLE_SIZE_24;
}
else
{
ulFormat |= I2S_CONFIG_WIRE_SIZE_32 | I2S_CONFIG_MODE_DUAL |
I2S_CONFIG_SAMPLE_SIZE_32;
}
}
//
// Configure the I2S TX and RX format.
//
I2STxConfigSet(I2S0_BASE, ulFormat);
ulFormat = (ulFormat & ~I2S_CONFIG_FORMAT_MASK) | I2S_CONFIG_FORMAT_LEFT_JUST;
I2SRxConfigSet(I2S0_BASE, ulFormat);
//
// Internally both are masters but the pins may not be driven out.
//
I2SMasterClockSelect(I2S0_BASE, I2S_TX_MCLK_INT | I2S_RX_MCLK_INT);
//
// Set the MCLK rate and save it for conversion back to sample rate.
// The multiply by 8 is due to a 4X oversample rate plus a factor of two
// since the data is always stereo on the I2S interface.
//
g_ulSampleRate = SysCtlI2SMClkSet(0, ulSampleRate * usBitsPerSample * 8);
//
// Convert the MCLK rate to sample rate.
//
g_ulSampleRate = g_ulSampleRate/(usBitsPerSample * 8);
//
// Configure the I2S TX DMA channel to use high priority burst transfer.
//
uDMAChannelAttributeEnable(UDMA_CHANNEL_I2S0TX,
(UDMA_ATTR_USEBURST |
UDMA_ATTR_HIGH_PRIORITY));
//
// Set the DMA channel configuration.
//
if(g_usChannels == 1)
{
//
// Handle Mono formats.
//
if(g_usBitsPerSample == 8)
{
//
// The transfer size is 8 bits from the TX buffer to the TX FIFO.
//
ulDMASetting = UDMA_SIZE_8 | UDMA_SRC_INC_8 |
UDMA_DST_INC_NONE | UDMA_ARB_2;
}
else
{
//
// The transfer size is 16 bits from the TX buffer to the TX FIFO.
//
ulDMASetting = UDMA_SIZE_16 | UDMA_SRC_INC_16 |
UDMA_DST_INC_NONE | UDMA_ARB_2;
}
}
else
{
//
// Handle Stereo formats.
//
if(g_usBitsPerSample == 8)
{
//
// The transfer size is 16 bits(stereo 8 bits) from the TX buffer
// to the TX FIFO.
//
ulDMASetting = UDMA_SIZE_16 | UDMA_SRC_INC_16 |
UDMA_DST_INC_NONE | UDMA_ARB_2;
}
else
{
//
// The transfer size is 32 bits(stereo 16 bits) from the TX buffer
// to the TX FIFO.
//
ulDMASetting = UDMA_SIZE_32 | UDMA_SRC_INC_32 |
UDMA_DST_INC_NONE | UDMA_ARB_2;
}
}
//
// Configure the DMA settings for this channel.
//
uDMAChannelControlSet(UDMA_CHANNEL_I2S0TX | UDMA_PRI_SELECT, ulDMASetting);
uDMAChannelControlSet(UDMA_CHANNEL_I2S0TX | UDMA_ALT_SELECT, ulDMASetting);
}
//*****************************************************************************
//
//! Returns the current sample rate.
//!
//! This function returns the sample rate that was set by a call to
//! SoundSetFormat(). This is needed to retrieve the exact sample rate that is
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -