//------------------------------------------------------------------------------ /// Starts buffer transfer on the given channel /// \param channel Particular channel number. /// \param size Total transfer size in byte. /// \param callback Optional callback function. /// \param polling Polling channel status enable. //------------------------------------------------------------------------------ unsigned char DMAD_BufferTransfer(unsigned char channel, unsigned int size, DmaCallback callback, unsigned char polling) { DmaTransfer *pTransfer = &(dmad.transfers[channel]); // Check that no transfer is pending on the channel if (pTransfer-> transferSize > 0 ) { TRACE_ERROR("DAM transfer is already pending\n\r"); return DMAD_ERROR_BUSY; } pTransfer->status = DMAD_ERROR_BUSY; pTransfer->transferSize = size; pTransfer->callback = callback; if(!polling){ DMA_EnableIt(DMA_BTC << channel); } // Enable the channel. DMA_EnableChannel(channel); if(polling){ while ((DMA_GetChannelStatus() & (DMA_ENA << channel)) == (DMA_ENA << channel)); pTransfer->callback(); DMA_DisableChannel(channel); } return 0; }
//------------------------------------------------------------------------------ /// Initializes the DMA controller. /// \param dwChannel Particular dwChannel number /// \param defaultHandler Using the default dmad interrupt handler. //------------------------------------------------------------------------------ extern void DMAD_Initialize( uint32_t dwChannel, uint32_t defaultHandler ) { uint32_t dwStatus ; uint32_t dwFlag ; /* Enable peripheral clock */ PMC_EnablePeripheral( ID_DMAC ) ; /* Read the dwChannel handler status to ensure the channel is a free channel */ dwStatus = DMA_GetChannelStatus( DMAC ) ; TRACE_INFO( "DMAD_Initialize dwChannel %x \n\r", dwChannel ) ; assert( (dwStatus & (1 << dwChannel)) == 0 ) ; /* Clear any pending interrupts on the channel */ DMA_GetStatus( DMAC ) ; /* Disable the channel */ DMA_DisableChannel( DMAC, dwChannel ) ; /* Disable the interrupt */ dwFlag = 0x3FFFFF ; DMA_DisableIt( DMAC, dwFlag ) ; /* Enable DMA */ DMA_Enable( DMAC ) ; if ( defaultHandler ) { NVIC_EnableIRQ( DMAC_IRQn ) ; } // Initialize transfer instance. dmad.transfers[dwChannel].transferSize = 0; }
//------------------------------------------------------------------------------ //./ Configure the DMA Channels: 0 RX, 1 TX. //./ Channels are disabled after configure. //------------------------------------------------------------------------------ static void configureDmaChannels(void) { // Enable DMA Peripheral PERIPH_ENABLE(AT91C_ID_HDMA); // Enable DMA DMA_Enable(); // Free status DMA_DisableIt(0xFFFFFFFF); DMA_GetChannelStatus(); DMA_GetStatus(); DMA_DisableChannels((1 << DMA_CHANNEL_0) | (1 << DMA_CHANNEL_1)); // RX channel 0 DMA_SetConfiguration(DMA_CHANNEL_0, AT91C_HDMA_SRC_PER_2 | AT91C_HDMA_DST_PER_2 | AT91C_HDMA_SRC_H2SEL_HW | AT91C_HDMA_DST_H2SEL_SW | AT91C_HDMA_SOD_ENABLE | AT91C_HDMA_FIFOCFG_LARGESTBURST ); // TX channel 1 DMA_SetConfiguration(DMA_CHANNEL_1, AT91C_HDMA_SRC_PER_1 | AT91C_HDMA_DST_PER_1 | AT91C_HDMA_SRC_H2SEL_SW | AT91C_HDMA_DST_H2SEL_HW | AT91C_HDMA_SOD_ENABLE | AT91C_HDMA_FIFOCFG_LARGESTBURST ); }
//------------------------------------------------------------------------------ /// Starts buffer transfer on the given channel /// \param channel Particular channel number. /// \param size Total transfer size in byte. /// \param callback Optional callback function. /// \param polling Polling channel status enable. //------------------------------------------------------------------------------ U8 DMAD_BufferTransfer(U8 channel, U32 size, DmaCallback callback, U8 polling) { DmaTransfer *pTransfer = &(dmad.transfers[channel]); if (pTransfer-> transferSize > 0 ) // Check that no transfer is pending on the channel { DEBUG_MSG("DAM transfer is already pending"); return DMAD_ERROR_BUSY; } pTransfer->status = DMAD_ERROR_BUSY; pTransfer->transferSize = size; pTransfer->callback = callback; if(!polling) { DMA_EnableIt(0x1 << channel); } DMA_EnableChannel(channel); // Enable the channel. if(polling) { while ((DMA_GetChannelStatus() & (0x1 << channel)) == (0x1 << channel)); if (pTransfer->callback) { pTransfer->callback(); } pTransfer->transferSize = 0; DMA_DisableChannel(channel); } return 0; }
//------------------------------------------------------------------------------ /// Initializes the DMA controller. /// \param channel Particular channel number /// \param defaultHandler Using the default dmad interrupt handler. //------------------------------------------------------------------------------ void DMAD_Initialize(unsigned char channel, unsigned char defaultHandler) { unsigned int status; unsigned int flag; // Enable peripheral clock #if !defined(at91sam9rl64) AT91C_BASE_PMC->PMC_PCER = 1 << AT91C_ID_HDMA; #endif // Read the channel handler status to ensure the channel is a free channel. status = DMA_GetChannelStatus(); TRACE_INFO ("DMAD_Initialize channel %x \n\r", channel); SANITY_CHECK(!(status & (1 << channel))); // Clear any pending interrupts on the channel. DMA_GetStatus(); // Disble the channel. DMA_DisableChannel(channel); // Disable the interrupt flag = 0xffffff; DMA_DisableIt(flag); // Enable DMA. DMA_Enable(); if(defaultHandler) { IRQ_ConfigureIT(AT91C_ID_HDMA, 0, DMAD_Handler); IRQ_EnableIT(AT91C_ID_HDMA); } // Initialize transfer instance. dmad.transfers[channel].transferSize = 0; }
//------------------------------------------------------------------------------ /// Returns 1 if no transfer is currently pending on the given channel; /// otherwise, returns 0. /// \param channel Channel number. //------------------------------------------------------------------------------ //unsigned char DMAD_IsFinished(unsigned char channel) //{ // SANITY_CHECK(channel <= DMA_CHANNEL_NUM); // // if (dmad.transfers[channel].transferSize > 0) { // return 0; // } // else { // DMA_DisableChannel(channel); // return 1; // } //} unsigned char DMAD_IsFinished(unsigned char channel) { SANITY_CHECK(channel <= DMA_CHANNEL_NUM); if ( (DMA_GetChannelStatus() & (DMA_ENA << channel)) == (DMA_ENA << channel)) { return 0; } else { //DMA_DisableChannel(channel); return 1; } }
//------------------------------------------------------------------------------ /// Starts buffer transfer on the given dwChannel /// \param dwChannel Particular dwChannel number. /// \param size Total transfer size in byte. /// \param callback Optional callback function. /// \param polling Polling dwChannel status enable. //------------------------------------------------------------------------------ extern uint32_t DMAD_BufferTransfer( uint32_t dwChannel, uint32_t dwSize, DmaCallback callback, uint32_t dwPolling ) { DmaTransfer *pTransfer = &(dmad.transfers[dwChannel]) ; // Check that no transfer is pending on the dwChannel if ( pTransfer-> transferSize > 0 ) { TRACE_ERROR( "DAM transfer is already pending\n\r" ) ; return DMAD_ERROR_BUSY ; } pTransfer->status = DMAD_ERROR_BUSY ; pTransfer->transferSize = dwSize ; pTransfer->callback = callback ; if ( dwPolling == 0 ) { DMA_EnableIt( DMAC, DMA_BTC << dwChannel ) ; } // Enable the dwChannel. DMA_EnableChannel( DMAC, dwChannel ) ; if ( dwPolling != 0 ) { while ( (DMA_GetChannelStatus( DMAC ) & (DMAC_CHSR_ENA0 << dwChannel)) == (DMAC_CHSR_ENA0 << dwChannel)) ; if ( pTransfer->callback ) { pTransfer->callback() ; } pTransfer->transferSize = 0 ; DMA_DisableChannel( DMAC, dwChannel ) ; } return 0 ; }