📄 ad1836.cpp
字号:
// 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 + -