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

📄 ad1836.cpp

📁 vdk audio driver example
💻 CPP
📖 第 1 页 / 共 2 页
字号:
		// Map DMA2 to Sport0 TX
		*pDMA2_PERIPHERAL_MAP = 0x2000;

		m_writeBuffers = 0;
		m_writeFlags = mode;
	}

	return 0;
}

int AD1836::Close (const VDK::DispatchUnion &inUnion)
{
	// Retrieve the open mode from the device handle
	unsigned mode = reinterpret_cast<unsigned>(*inUnion.OpenClose_t.dataH);

	if (mode != (mode & (m_readFlags | m_writeFlags)))
		return -1;

	VDK::DispatchUnion outUnion;
	outUnion.ReadWrite_t.dataH    = inUnion.OpenClose_t.dataH;
	outUnion.ReadWrite_t.timeout  = 0;
	outUnion.ReadWrite_t.dataSize = 0;
	outUnion.ReadWrite_t.data     = NULL;

	if (mode & READ_MODE)
	{
		SyncRead(outUnion); // wait for any current read to complete
		m_readFlags = 0;
	}

	if (mode & WRITE_MODE)
	{
		SyncWrite(outUnion); // wait for any current write to complete
		m_writeFlags = 0;
	}

	*inUnion.OpenClose_t.dataH = 0;
	
	return 0;
}


//
// This function implements pipelined 'read' behaviour for the AD1836 device.
//
// On entry, the m_readBuffers member variable will always contain either
// zero or one. One means that a pipelined read (started by the previous call)
// is in progress, so we will block until it completes. Zero means that no
// transfer is in progress, so we will simply start the new transfer and return.
//
// Note that although m_readBuffers may be set to 2 immediately prior to
// blocking on the device flag, it will always have been decremented (in 
// Actvate()) before the device flag is posted, so that m_readBuffers will
// always be 0 or 1 when we leave this function.
//
int AD1836::SyncRead(const VDK::DispatchUnion &inUnion)
{
	// Retrieve the open mode from the device handle
	unsigned mode = reinterpret_cast<unsigned>(*inUnion.ReadWrite_t.dataH);

	if (0 == (mode & READ_MODE))  // must be open for reading
		return -1;

	// Store the SyncRead arguments in instance variables
	m_vReadNextBuffStart = (short *)inUnion.ReadWrite_t.data;
	m_vReadNextBuffCount = inUnion.ReadWrite_t.dataSize / m_sampleBytes;

	// TBD. We should flush and invalidate the data cache over the range of
	// the data buffer here, as DMA bypasses the cache. Until this is added,
	// the driver will not be safe to use with data caching enabled.
	
	// Disable interrupts
	VDK::PushCriticalRegion();

	// If m_readBuffers was non-zero on entry then input is
	// already underway into the previous buffer...
	if (0 != m_readBuffers) // m_readBuffers == 1
	{
		// ...in which case we have to block until it completes.
		
		// If the buffer size is zero then it's a dummy write which
		// just blocks until the current write finishes, hence we
		// don't count it as a pending buffer.
		if (0 != inUnion.ReadWrite_t.dataSize)
		{
			m_readBuffers = 2;
 			
 			// Set up globals for the ISR to swap in the
 			// new buffer
 			c_nextRxAddr  = m_vReadNextBuffStart;
 			c_nextRxCount = m_vReadNextBuffCount;
 		}
			
		// Block on the device flag (this re-enables interrupts)			
		VDK::PendDeviceFlag(m_DevFlagRead, inUnion.ReadWrite_t.timeout);
	}
	else // m_readBuffers is zero
	{
		// ...otherwise we need to start the transfer by setting up DMA1
		// If the buffer size is zero then we don't do anything
		if (0 != inUnion.ReadWrite_t.dataSize)
		{
			// Setup the first DMA transfer in the sequence
			m_readBuffers = 1;
			*pDMA1_START_ADDR = m_vReadNextBuffStart; // Start address of data buffer
			*pDMA1_X_COUNT = m_vReadNextBuffCount;    // DMA inner loop count
			*pDMA1_X_MODIFY	= m_sampleBytes;          // Inner loop address increment 
	
			// Enable DMA for input, with 16-bit transfers and interrupt on completion
			*pDMA1_CONFIG = WNR | WDSIZE_16 | DI_EN | DMAEN;
			
			// enable Sport0 RX
			*pSPORT0_RCR1 |= RSPEN;
		}
		
		// Re-enable interrupts
		VDK::PopCriticalRegion();
	}
	
	// Now reap the result of the previous operation
	int result = m_vReadCurrBuffCount * m_sampleBytes;
	
	// and move the "next" transfer details to the "current" variables
	m_vReadCurrBuffCount = m_vReadNextBuffCount;
	m_vReadCurrBuffStart = m_vReadNextBuffStart;
	m_vReadNextBuffCount = 0;
	m_vReadNextBuffStart = NULL;

	return result;
}


//
// This function implements pipelined 'write' behaviour for the AD1836 device.
//
// On entry, the m_writeBuffers member variable will always contain either
// zero or one. One means that a pipelined write (started by the previous call)
// is in progress, so we will block until it completes. Zero means that no
// transfer is in progress, so we will simply start the new transfer and return.
//
// Note that although m_writeBuffers may be set to 2 immediately prior to
// blocking on the device flag, it will always have been decremented (in 
// Actvate()) before the device flag is posted, so that m_writeBuffers will
// always be 0 or 1 when we leave this function.
//
int AD1836::SyncWrite(const VDK::DispatchUnion &inUnion)
{
	// Retrieve the open mode from the device handle
	unsigned mode = reinterpret_cast<unsigned>(*inUnion.ReadWrite_t.dataH);

	if (0 == (mode & WRITE_MODE))  // must be open for reading
		return -1;

	// Store the SyncWrite arguments in instance variables
	m_vWriteNextBuffStart = (short *)inUnion.ReadWrite_t.data;
	m_vWriteNextBuffCount = inUnion.ReadWrite_t.dataSize / m_sampleBytes;

	// TBD. We should flush and invalidate the data cache over the range of
	// the data buffer here, as DMA bypasses the cache. Until this is added,
	// the driver will not be safe to use with data caching enabled.

	// Disable interrupts
	VDK::PushCriticalRegion();

	// If m_writeBuffers is non-zero then output is
	// currently underway from the previous buffer...
	if (0 != m_writeBuffers) // m_writeBuffers == 1
	{
		// ...in which case we have to block until it completes.
		
		// If the buffer size is zero then it's a dummy write which
		// just blocks until the current write finishes, hence we
		// don't count it as a pending buffer.
		if (0 != inUnion.ReadWrite_t.dataSize)
		{
			m_writeBuffers = 2;
 			
 			// Set up globals for the ISR to swap in the
 			// new buffer
 			c_nextTxAddr  = m_vWriteNextBuffStart;
 			c_nextTxCount = m_vWriteNextBuffCount;
 		}

		// Block on the device flag (this re-enables interrupts)			
		VDK::PendDeviceFlag(m_DevFlagWrite, inUnion.ReadWrite_t.timeout);
	}
	else // m_writeBuffers is zero
	{
		// ...otherwise we need to start the transfer by setting up DMA2

		// If the buffer size is zero then we don't do anything
		if (0 != inUnion.ReadWrite_t.dataSize)
		{
			// Setup the first DMA transfer in the sequence
			m_writeBuffers = 1;
			*pDMA2_START_ADDR = m_vWriteNextBuffStart; // Start address of data buffer
			*pDMA2_X_COUNT = m_vWriteNextBuffCount;    // DMA inner loop count
			*pDMA2_X_MODIFY	= m_sampleBytes;           // Inner loop address increment
	
			// Enable DMA for output, with 16-bit transfers and interrupt on completion
			*pDMA2_CONFIG = WDSIZE_16 | DI_EN | DMAEN;
			
			// enable Sport0 TX
			*pSPORT0_TCR1 |= TSPEN;
		}
		
		// Re-enable interrupts
		VDK::PopCriticalRegion();
	}

	// Now reap the result of the previous operation
	int result = m_vWriteCurrBuffCount * m_sampleBytes;
	
	// and move the "next" transfer details to the "current" variables
	m_vWriteCurrBuffCount = m_vWriteNextBuffCount;
	m_vWriteCurrBuffStart = m_vWriteNextBuffStart;
	m_vWriteNextBuffCount = 0;
	m_vWriteNextBuffStart = NULL;

	return result;
}


//
// There is no IOCtl functionality at present for this device.
// In future it may support updates to the codec control registers.
//
int AD1836::IOCtl    (const VDK::DispatchUnion &inUnion)
{
	return 0;
}


//
// This function is invoked (initiated by the ISR) whenever the serial
// port Rx or Tx DMA reaches the end of one of its current buffer.
//
// Activate()'s job is to:
// - start the next DMA transfer if there is a buffer queued, else
//   turn off the serial port
// - unblock waiting threads
//
// First we have to determine which of the serial port interrupt
// sources are active. We do this by looking at the dma1_irq_status
// and dma2_irq_status variables, which hold the contents of the
// dma irq status registers at the time of the most recent IVG9
// interrupt (and prior to the interrupts being cleared.
//
void AD1836::Activate (const VDK::DispatchUnion &inUnion)
{
	// Check DMA1 status (serial port 0 Rx)
	if (DMA_DONE & c_vDma1IrqStatus[m_devNo]) // input buffer is full
	{
		if (2 == m_readBuffers) // then there is another buffer waiting
		{
			// The next DMA transfer has been started by the ISR
			m_readBuffers = 1;
		}
		else
		{			
			// No more buffers, disable Sport0 RX
			*pDMA1_CONFIG = WNR | WDSIZE_16 | DI_EN;  // disable DMA1	
			*pSPORT0_RCR1 &= ~RSPEN;                  // disable Sport0
			m_readBuffers = 0;
		}

		// Post Rx device flag
		VDK::PostDeviceFlag(m_DevFlagRead);
	}

	// Check DMA2 status (serial port 0 Tx)
	if (DMA_DONE & c_vDma2IrqStatus[m_devNo]) // output buffer has emptied
	{
		if (2 == m_writeBuffers) // then there is another buffer waiting
		{
			// The next DMA transfer has been started by the ISR
			m_writeBuffers = 1;
		}
		else
		{			
			// No more buffers, disable Sport0 TX
			*pDMA2_CONFIG = WDSIZE_16 | DI_EN;  // disable DMA1	
			*pSPORT0_TCR1 &= ~TSPEN;            // disable Sport0
			m_writeBuffers = 0;
		}

		// Post Tx device flag
		VDK::PostDeviceFlag(m_DevFlagWrite);
	}
}

#endif /* VDK_INCLUDE_IO_ */

/* ========================================================================== */

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -