//------------------------------------------------------------------------------ /// 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; }
//------------------------------------------------------------------------------ // Local functions //------------------------------------------------------------------------------ //------------------------------------------------------------------------------ /// This handler function must be called by the DMAC interrupt service routine. /// Identifies which event was activated and calls the associated function. //------------------------------------------------------------------------------ void DMAD_Handler() { unsigned int status; unsigned char channel; DmaTransfer *pTransfer; status = DMA_GetStatus(); // Check if the buffer transfer completed is set. if(status & AT91C_BTC) { // Scan each channel status. for(channel = 0; channel < DMA_CHANNEL_NUM; channel++) { if(!(status & (DMA_BTC << channel))){ continue; } dmad.transfers[channel].transferSize -= dmad.transfers[channel].bufSize; // if next buffer is to be the last buffer in the transfer, then clear the automatic mode bit. if(dmad.transfers[channel].transferSize <= dmad.transfers[channel].bufSize) { DMA_ClearAutoMode(channel); } // Transfer finished if(dmad.transfers[channel].transferSize == 0) { pTransfer = &(dmad.transfers[channel]); pTransfer->callback(); DMA_DisableIt(DMA_BTC << channel); DMA_DisableChannel(channel); } else { // Write the KEEPON field to clear the STALL states. DMA_KeeponChannel(channel); } } } }
//------------------------------------------------------------------------------ //./ 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 ); }
//------------------------------------------------------------------------------ /// 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; }
//------------------------------------------------------------------------------ // Local functions //------------------------------------------------------------------------------ //------------------------------------------------------------------------------ /// This handler function must be called by the DMAC interrupt service routine. /// Identifies which event was activated and calls the associated function. //------------------------------------------------------------------------------ extern void DMAC_IrqHandler( void ) { uint32_t dwStatus ; uint32_t dwChannel ; DmaTransfer *pTransfer ; dwStatus = DMA_GetStatus( DMAC ) ; // Check if the buffer transfer completed is set. if ( dwStatus & (DMAC_EBCISR_BTC0|DMAC_EBCISR_BTC1|DMAC_EBCISR_BTC2|DMAC_EBCISR_BTC3|DMAC_EBCISR_BTC4|DMAC_EBCISR_BTC5) ) { // Scan each dwChannel status. for ( dwChannel = 0 ; dwChannel < DMA_CHANNEL_NUM ; dwChannel++ ) { if ( !(dwStatus & (DMAC_EBCISR_BTC0 << dwChannel)) ) { continue ; } dmad.transfers[dwChannel].transferSize -= dmad.transfers[dwChannel].bufSize ; // if next buffer is to be the last buffer in the transfer, then clear the automatic mode bit. if ( dmad.transfers[dwChannel].transferSize <= dmad.transfers[dwChannel].bufSize ) { DMA_ClearAutoMode( DMAC, dwChannel ) ; } // Transfer finished if ( dmad.transfers[dwChannel].transferSize == 0 ) { pTransfer = &(dmad.transfers[dwChannel]) ; pTransfer->callback() ; DMA_DisableIt( DMAC, DMAC_EBCIDR_BTC0 << dwChannel ) ; DMA_DisableChannel( DMAC, dwChannel ) ; } else { // Write the KEEPON field to clear the STALL states. DMA_KeeponChannel( DMAC, dwChannel ) ; } } } }
//------------------------------------------------------------------------------ /// Initializes the DMA controller. /// \param channel Particular channel number /// \param defaultHandler Using the default dmad interrupt handler. //------------------------------------------------------------------------------ void DMAD_Initialize(U8 channel, U8 defaultHandler) { // U32 status; U32 flag; // status = DMA_GetChannelStatus(); // Read the channel handler status to ensure the channel is a free channel. // DEBUG_MSG("DMAD_Initialize channel: %x, Status: %x", channel, status); DMA_GetStatus(); // Clear any pending interrupts on the channel. DMA_DisableChannel(channel); // Disble the channel. flag = 0xffffff; DMA_DisableIt(flag); // Disable the interrupt DMA_Enable(); // Enable DMA. if(defaultHandler) { IRQ_PeriConf(21, 0, DMAD_Handler); IRQ_PeriEn(21); } dmad.transfers[channel].transferSize = 0; // Initialize transfer instance. }
//------------------------------------------------------------------------------ /// This handler function must be called by the DMAC interrupt service routine. /// Identifies which event was activated and calls the associated function. //------------------------------------------------------------------------------ void DMAD_Handler() { U32 status; U8 channel; DmaTransfer *pTransfer; status = DMA_GetStatus(); if(status & (0xFF)) // Check if the buffer transfer completed is set. { for(channel = 0; channel < 8; channel++) // Scan each channel status. { if(!(status & (0x1 << channel))) { continue; } dmad.transfers[channel].transferSize -= dmad.transfers[channel].bufSize; if(dmad.transfers[channel].transferSize <= dmad.transfers[channel].bufSize) // if next buffer is to be the last buffer in the transfer, then clear the automatic mode bit. { DMA_ClearAutoMode(channel); } if(dmad.transfers[channel].transferSize == 0) // Transfer finished { pTransfer = &(dmad.transfers[channel]); pTransfer->callback(); DMA_DisableIt(0x1 << channel); DMA_DisableChannel(channel); } else { DMA_KeeponChannel(channel); // Write the KEEPON field to clear the STALL states. } } } }