DSP program for the Surfboard hardware (PCB to be open sourced) http://www.avbotz.com/ourauv/electrical/signal-processing/
Dependencies: MODDMA SimpleIOMacros mbed-dsp mbed
MODDMA_cache.cpp
- Committer:
- avbotz
- Date:
- 2013-08-02
- Revision:
- 0:2381a319fc35
File content as of revision 0:2381a319fc35:
#include "MODDMA_cache.h" // Exists so the IRQ handler can access MODDMA object. MODDMA_Cache* moddma_p; // Setup the DMA controller and then cache some values. they will be used in Reset(). // does not work; these values do not change. we aren't caching the right ones. MODDMA_Cache::MODDMA_Cache() { moddma_p = this; init(); } // A copy of Kirkham's setup function. This caches most values as they are set. uint32_t MODDMA_Cache::Setup(MODDMA_Config* config) { LPC_GPDMACH_TypeDef *pChannel = (LPC_GPDMACH_TypeDef *)Channel_p( config->channelNum() ); setups[config->channelNum() & 0x7] = config; // Reset the Interrupt status LPC_GPDMA->DMACIntTCClear = DMACIntTCClear = IntTCClear_Ch( config->channelNum() ); LPC_GPDMA->DMACIntErrClr = DMACIntErrClr = IntErrClr_Ch ( config->channelNum() ); // Clear DMA configure pChannel->DMACCControl = 0x00; pChannel->DMACCConfig = 0x00; // Assign Linker List Item value pChannel->DMACCLLI = DMACCLLI = config->dmaLLI(); // Set value to Channel Control Registers switch (config->transferType()) { // Memory to memory case m2m: // Assign physical source and destination address pChannel->DMACCSrcAddr = config->srcMemAddr(); pChannel->DMACCDestAddr = config->dstMemAddr(); pChannel->DMACCControl = CxControl_TransferSize(config->transferSize()) | CxControl_SBSize(_32) | CxControl_DBSize(_32) | CxControl_SWidth(config->transferWidth()) | CxControl_DWidth(config->transferWidth()) | CxControl_SI() | CxControl_DI() | CxControl_I(); break; // Memory to peripheral case m2p: // Assign physical source pChannel->DMACCSrcAddr = DMACCSrcAddr = config->srcMemAddr(); // Assign peripheral destination address pChannel->DMACCDestAddr = DMACCDestAddr = (uint32_t)LUTPerAddr(config->dstConn()); pChannel->DMACCControl = DMACCControl = CxControl_TransferSize((uint32_t)config->transferSize()) | CxControl_SBSize((uint32_t)LUTPerBurst(config->dstConn())) | CxControl_DBSize((uint32_t)LUTPerBurst(config->dstConn())) | CxControl_SWidth((uint32_t)LUTPerWid(config->dstConn())) | CxControl_DWidth((uint32_t)LUTPerWid(config->dstConn())) | CxControl_SI() | CxControl_I(); break; // Peripheral to memory case p2m: // Assign peripheral source address pChannel->DMACCSrcAddr = DMACCSrcAddr = (uint32_t)LUTPerAddr(config->srcConn()); // Assign memory destination address pChannel->DMACCDestAddr = DMACCDestAddr = config->dstMemAddr(); pChannel->DMACCControl = DMACCControl = CxControl_TransferSize((uint32_t)config->transferSize()) | CxControl_SBSize((uint32_t)LUTPerBurst(config->srcConn())) | CxControl_DBSize((uint32_t)LUTPerBurst(config->srcConn())) | CxControl_SWidth((uint32_t)LUTPerWid(config->srcConn())) | CxControl_DWidth((uint32_t)LUTPerWid(config->srcConn())) | CxControl_DI() | CxControl_I(); break; // Peripheral to peripheral case p2p: // Assign peripheral source address pChannel->DMACCSrcAddr = (uint32_t)LUTPerAddr(config->srcConn()); // Assign peripheral destination address pChannel->DMACCDestAddr = (uint32_t)LUTPerAddr(config->dstConn()); pChannel->DMACCControl = CxControl_TransferSize((uint32_t)config->transferSize()) | CxControl_SBSize((uint32_t)LUTPerBurst(config->srcConn())) | CxControl_DBSize((uint32_t)LUTPerBurst(config->dstConn())) | CxControl_SWidth((uint32_t)LUTPerWid(config->srcConn())) | CxControl_DWidth((uint32_t)LUTPerWid(config->dstConn())) | CxControl_I(); break; // GPIO to memory case g2m: // Assign GPIO source address pChannel->DMACCSrcAddr = config->srcMemAddr(); // Assign memory destination address pChannel->DMACCDestAddr = config->dstMemAddr(); pChannel->DMACCControl = CxControl_TransferSize((uint32_t)config->transferSize()) | CxControl_SBSize((uint32_t)LUTPerBurst(config->srcConn())) | CxControl_DBSize((uint32_t)LUTPerBurst(config->srcConn())) | CxControl_SWidth((uint32_t)LUTPerWid(config->srcConn())) | CxControl_DWidth((uint32_t)LUTPerWid(config->srcConn())) | CxControl_DI() | CxControl_I(); break; // Memory to GPIO case m2g: // Assign physical source pChannel->DMACCSrcAddr = config->srcMemAddr(); // Assign peripheral destination address pChannel->DMACCDestAddr = config->dstMemAddr(); pChannel->DMACCControl = CxControl_TransferSize((uint32_t)config->transferSize()) | CxControl_SBSize((uint32_t)LUTPerBurst(config->dstConn())) | CxControl_DBSize((uint32_t)LUTPerBurst(config->dstConn())) | CxControl_SWidth((uint32_t)LUTPerWid(config->dstConn())) | CxControl_DWidth((uint32_t)LUTPerWid(config->dstConn())) | CxControl_SI() | CxControl_I(); break; // Do not support any more transfer type, return ERROR default: return 0; } // Re-Configure DMA Request Select for source peripheral if (config->srcConn() > 15) { DMAREQSEL = LPC_SC->DMAREQSEL |= (1 << (config->srcConn() - 16)); } else { DMAREQSEL = LPC_SC->DMAREQSEL &= ~(1 << (config->srcConn() - 8)); } // Re-Configure DMA Request Select for destination peripheral if (config->dstConn() > 15) { DMAREQSEL = LPC_SC->DMAREQSEL |= (1 << (config->dstConn() - 16)); } else { DMAREQSEL = LPC_SC->DMAREQSEL &= ~(1 << (config->dstConn() - 8)); } // Enable DMA channels, little endian LPC_GPDMA->DMACConfig = _E; while (!(LPC_GPDMA->DMACConfig & _E)); // Calculate absolute value for Connection number uint32_t tmp1 = config->srcConn(); tmp1 = ((tmp1 > 15) ? (tmp1 - 8) : tmp1); uint32_t tmp2 = config->dstConn(); tmp2 = ((tmp2 > 15) ? (tmp2 - 8) : tmp2); if (config->dmacSync()) { uint32_t tmp3 = config->dmacSync(); tmp3 = ((tmp3 > 15) ? (tmp3 - 8) : tmp3); LPC_GPDMA->DMACSync |= DMACSync = Sync_Src( tmp3 ); } uint32_t tfer_type = (uint32_t)config->transferType(); if (tfer_type == g2m || tfer_type == m2g) { tfer_type -= 2; // Adjust psuedo transferType to a real transferType. } // Configure DMA Channel, enable Error Counter and Terminate counter pChannel->DMACCConfig = DMACCConfig = CxConfig_IE() | CxConfig_ITC() | CxConfig_TransferType(tfer_type) | CxConfig_SrcPeripheral(tmp1) | CxConfig_DestPeripheral(tmp2); return pChannel->DMACCControl; } /* uint32_t MODDMA_Cache::Setup(MODDMA_Config* config) { moddma_p = this; //uint32_t ret = ((MODDMA*)this)->Setup(config); uint32_t ret = MODDMA::Setup(config); LPC_GPDMACH_TypeDef *pChannel = (LPC_GPDMACH_TypeDef*)Channel_p(config->channelNum()); DMACCSrcAddr = pChannel->DMACCSrcAddr; DMACCDestAddr = pChannel->DMACCDestAddr; DMACCLLI = pChannel->DMACCLLI; //DMACCControl = pChannel->DMACCControl; switch (config->transferType()) { case p2m: DMACCControl = CxControl_TransferSize((uint32_t)config->transferSize()) | CxControl_SBSize((uint32_t)LUTPerBurst(config->srcConn())) | CxControl_DBSize((uint32_t)LUTPerBurst(config->srcConn())) | CxControl_SWidth((uint32_t)LUTPerWid(config->srcConn())) | CxControl_DWidth((uint32_t)LUTPerWid(config->srcConn())) | CxControl_DI() | CxControl_I(); break; case m2p: DMACCControl = CxControl_TransferSize((uint32_t)config->transferSize()) | CxControl_SBSize((uint32_t)LUTPerBurst(config->dstConn())) | CxControl_DBSize((uint32_t)LUTPerBurst(config->dstConn())) | CxControl_SWidth((uint32_t)LUTPerWid(config->dstConn())) | CxControl_DWidth((uint32_t)LUTPerWid(config->dstConn())) | CxControl_SI() | CxControl_I(); break; default: return 5000; // oh no, your mbed blew up! } uint32_t tmp1 = config->srcConn(); tmp1 = ((tmp1 > 15) ? (tmp1 - 8) : tmp1); uint32_t tmp2 = config->dstConn(); tmp2 = ((tmp2 > 15) ? (tmp2 - 8) : tmp2); if (config->dmacSync()) { uint32_t tmp3 = config->dmacSync(); tmp3 = ((tmp3 > 15) ? (tmp3 - 8) : tmp3); LPC_GPDMA->DMACSync |= Sync_Src( tmp3 ); } uint32_t tfer_type = (uint32_t)config->transferType(); if (tfer_type == g2m || tfer_type == m2g) { tfer_type -= 2; // Adjust psuedo transferType to a real transferType. } // Configure DMA Channel, enable Error Counter and Terminate counter DMACCConfig = CxConfig_IE() | CxConfig_ITC() | CxConfig_TransferType(tfer_type) | CxConfig_SrcPeripheral(tmp1) | CxConfig_DestPeripheral(tmp2); DMACSync = LPC_GPDMA->DMACSync; return ret; }*/ // This is modified from MODDMA::Setup(). Values that don't change between DMA operations will be cached to make it faster. // Everything commented or deleted here wasn't necessary to restart DMA. /*void MODDMA_Cache::Reset(MODDMA_Config* config) { LPC_GPDMACH_TypeDef *pChannel = (LPC_GPDMACH_TypeDef*)Channel_p(config->channelNum()); //LPC_GPDMA->DMACIntTCClear = IntTCClear_Ch( config->channelNum() ); //LPC_GPDMA->DMACIntErrClr = IntErrClr_Ch ( config->channelNum() ); //pChannel->DMACCLLI = DMACCLLI; pChannel->DMACCConfig = DMACCConfig;// //LPC_GPDMA->DMACSync = DMACSync; //setups[config->channelNum() & 0x7] = config; // Reset the Interrupt status LPC_GPDMA->DMACIntTCClear = IntTCClear_Ch( config->channelNum() );// LPC_GPDMA->DMACIntErrClr = IntErrClr_Ch ( config->channelNum() ); // BIGASS SWITCH WENT HERE pChannel->DMACCControl = DMACCControl; if (config->transferType() == p2m) { pChannel->DMACCSrcAddr = DMACCSrcAddr; pChannel->DMACCDestAddr = config->dstMemAddr();// } // Enable DMA channels, little endian pChannel->DMACCConfig |= _E; return; } */ /* void MODDMA_Cache::Reset(MODDMA_Config* config) { LPC_GPDMACH_TypeDef *pChannel = (LPC_GPDMACH_TypeDef*)Channel_p(config->channelNum()); LPC_GPDMA->DMACIntTCClear = IntTCClear_Ch( config->channelNum() ); LPC_GPDMA->DMACIntErrClr = IntErrClr_Ch ( config->channelNum() ); pChannel->DMACCLLI = DMACCLLI; pChannel->DMACCConfig = DMACCConfig;// LPC_GPDMA->DMACSync = DMACSync; setups[config->channelNum() & 0x7] = config; // Reset the Interrupt status LPC_GPDMA->DMACIntTCClear = IntTCClear_Ch( config->channelNum() );// LPC_GPDMA->DMACIntErrClr = IntErrClr_Ch ( config->channelNum() ); // BIGASS SWITCH WENT HERE pChannel->DMACCControl = DMACCControl; if (config->transferType() == p2m) { pChannel->DMACCSrcAddr = DMACCSrcAddr; pChannel->DMACCDestAddr = config->dstMemAddr();// } // Enable DMA channels, little endian //pChannel->DMACCConfig |= _E; LPC_GPDMA->DMACConfig = _E; return; }*/ /* These notes based on the LPC17xx family datasheet: DMACIntTCClear Interrupt terminal count clear clear interrupt request from <http://dreamrunner.org/wiki/public_html/Embedded%20System/kernel/DMA.html> "When the value in the current count register goes from 0 to -1, a terminal count (TC) signal is generated, which signifies the completion of the DMA transfer sequence." "DMA controllers require reprogramming when a DMA channel reaches TC." DMACIntErrClr Write 1 to request that some error flags be cleared DMACCControl* contain tons of information: transfer size, burst size, transfer width, etc Updated by DMA controller when the linked list is followed. So may not change in our application? DMACCConfig Contains Enable, src type, dest type, transfer type, error mask (to find/mask out the error bit), terminal count irq mask, active (whether there is data), and halt (to stop transfer) DMACCLLI address of next linked list item. If zero, this is the last item in the list and the transfer is complete after this list item is done. DMACCSrcAddr* User sets the starting address. DMA updates w/ current read address as it goes. DMACCDestAddr* same idea as SrcAddr, but for the data destination DMAREQSEL Datasheet calls it "DMAReqSel" for some reason. I'm not too clear on what this is. Lets you pick whether you want UART or Timer DMA for DMA inputs 8-15. *Changes very quickly while the transfer in progress, so don't bother reading at that time */ void MODDMA_Cache::Reset(MODDMA_Config *config) { /*Setup(config); return;*/ LPC_GPDMACH_TypeDef *pChannel = (LPC_GPDMACH_TypeDef *)Channel_p( config->channelNum() ); setups[config->channelNum() & 0x7] = config; // Reset the Interrupt status LPC_GPDMA->DMACIntTCClear = IntTCClear_Ch( config->channelNum() ); LPC_GPDMA->DMACIntErrClr = IntErrClr_Ch ( config->channelNum() ); // Clear DMA configure pChannel->DMACCControl = 0x00; pChannel->DMACCConfig = 0x00; // Assign Linker List Item value pChannel->DMACCLLI = config->dmaLLI(); // Set value to Channel Control Registers switch (config->transferType()) { // Memory to memory case m2m: // Assign physical source and destination address pChannel->DMACCSrcAddr = config->srcMemAddr(); pChannel->DMACCDestAddr = config->dstMemAddr(); pChannel->DMACCControl = CxControl_TransferSize(config->transferSize()) | CxControl_SBSize(_32) | CxControl_DBSize(_32) | CxControl_SWidth(config->transferWidth()) | CxControl_DWidth(config->transferWidth()) | CxControl_SI() | CxControl_DI() | CxControl_I(); break; // Memory to peripheral case m2p: // Assign physical source pChannel->DMACCSrcAddr = config->srcMemAddr(); // Assign peripheral destination address pChannel->DMACCDestAddr = (uint32_t)LUTPerAddr(config->dstConn()); pChannel->DMACCControl = /*DMACCControl;*/CxControl_TransferSize((uint32_t)config->transferSize()) | CxControl_SBSize((uint32_t)LUTPerBurst(config->dstConn())) | CxControl_DBSize((uint32_t)LUTPerBurst(config->dstConn())) | CxControl_SWidth((uint32_t)LUTPerWid(config->dstConn())) | CxControl_DWidth((uint32_t)LUTPerWid(config->dstConn())) | CxControl_SI() | CxControl_I(); break; // Peripheral to memory case p2m: // Assign peripheral source address pChannel->DMACCSrcAddr = (uint32_t)LUTPerAddr(config->srcConn()); // Assign memory destination address pChannel->DMACCDestAddr = config->dstMemAddr(); pChannel->DMACCControl = /*DMACCControl;*/CxControl_TransferSize((uint32_t)config->transferSize()) | CxControl_SBSize((uint32_t)LUTPerBurst(config->srcConn())) | CxControl_DBSize((uint32_t)LUTPerBurst(config->srcConn())) | CxControl_SWidth((uint32_t)LUTPerWid(config->srcConn())) | CxControl_DWidth((uint32_t)LUTPerWid(config->srcConn())) | CxControl_DI() | CxControl_I(); break; // Peripheral to peripheral case p2p: // Assign peripheral source address pChannel->DMACCSrcAddr = (uint32_t)LUTPerAddr(config->srcConn()); // Assign peripheral destination address pChannel->DMACCDestAddr = (uint32_t)LUTPerAddr(config->dstConn()); pChannel->DMACCControl = CxControl_TransferSize((uint32_t)config->transferSize()) | CxControl_SBSize((uint32_t)LUTPerBurst(config->srcConn())) | CxControl_DBSize((uint32_t)LUTPerBurst(config->dstConn())) | CxControl_SWidth((uint32_t)LUTPerWid(config->srcConn())) | CxControl_DWidth((uint32_t)LUTPerWid(config->dstConn())) | CxControl_I(); break; // GPIO to memory case g2m: // Assign GPIO source address pChannel->DMACCSrcAddr = config->srcMemAddr(); // Assign memory destination address pChannel->DMACCDestAddr = config->dstMemAddr(); pChannel->DMACCControl = CxControl_TransferSize((uint32_t)config->transferSize()) | CxControl_SBSize((uint32_t)LUTPerBurst(config->srcConn())) | CxControl_DBSize((uint32_t)LUTPerBurst(config->srcConn())) | CxControl_SWidth((uint32_t)LUTPerWid(config->srcConn())) | CxControl_DWidth((uint32_t)LUTPerWid(config->srcConn())) | CxControl_DI() | CxControl_I(); break; // Memory to GPIO case m2g: // Assign physical source pChannel->DMACCSrcAddr = config->srcMemAddr(); // Assign peripheral destination address pChannel->DMACCDestAddr = config->dstMemAddr(); pChannel->DMACCControl = CxControl_TransferSize((uint32_t)config->transferSize()) | CxControl_SBSize((uint32_t)LUTPerBurst(config->dstConn())) | CxControl_DBSize((uint32_t)LUTPerBurst(config->dstConn())) | CxControl_SWidth((uint32_t)LUTPerWid(config->dstConn())) | CxControl_DWidth((uint32_t)LUTPerWid(config->dstConn())) | CxControl_SI() | CxControl_I(); break; // Do not support any more transfer type, return ERROR default: return;// 0; } // Re-Configure DMA Request Select for source peripheral if (config->srcConn() > 15) { LPC_SC->DMAREQSEL |= (1 << (config->srcConn() - 16)); } else { LPC_SC->DMAREQSEL &= ~(1 << (config->srcConn() - 8)); } // Re-Configure DMA Request Select for destination peripheral if (config->dstConn() > 15) { LPC_SC->DMAREQSEL |= (1 << (config->dstConn() - 16)); } else { LPC_SC->DMAREQSEL &= ~(1 << (config->dstConn() - 8)); } // Enable DMA channels, little endian LPC_GPDMA->DMACConfig = _E; pChannel->DMACCConfig |= _E; // copied from MODDMA::Enable() while (!(LPC_GPDMA->DMACConfig & _E)); // Calculate absolute value for Connection number uint32_t tmp1 = config->srcConn(); tmp1 = ((tmp1 > 15) ? (tmp1 - 8) : tmp1); uint32_t tmp2 = config->dstConn(); tmp2 = ((tmp2 > 15) ? (tmp2 - 8) : tmp2); if (config->dmacSync()) { uint32_t tmp3 = config->dmacSync(); tmp3 = ((tmp3 > 15) ? (tmp3 - 8) : tmp3); LPC_GPDMA->DMACSync |= Sync_Src( tmp3 ); } uint32_t tfer_type = (uint32_t)config->transferType(); if (tfer_type == g2m || tfer_type == m2g) { tfer_type -= 2; // Adjust psuedo transferType to a real transferType. } // Configure DMA Channel, enable Error Counter and Terminate counter pChannel->DMACCConfig = /*DMACCConfig;*/CxConfig_IE() | CxConfig_ITC() | CxConfig_TransferType(tfer_type) | CxConfig_SrcPeripheral(tmp1) | CxConfig_DestPeripheral(tmp2); return;// pChannel->DMACCControl; } extern "C" void MODDMA_Cache_IRQHandler() { p6_TOGGLE; /*if (moddma_p == (class MODDMA *)NULL) { if (oldDMAHandler) { ((MODDMA_FN)oldDMAHandler)(); return; } else { error("Interrupt without instance"); } }*/ // SEE UNROLLED VERSION BELOW. They are equivalent. for (int channel_number = 0; channel_number < 2; channel_number++) { uint32_t channel_mask = (1UL << channel_number); // Since we only have one if statement inside anyway, I took this out //if (LPC_GPDMA->DMACIntStat & channel_mask) //{ if (LPC_GPDMA->DMACIntTCStat & channel_mask) { moddma_p->setups[channel_number]->isrIntTCStat->call(); LPC_GPDMA->DMACIntTCClear = channel_mask; } //if (LPC_GPDMA->DMACIntErrStat & channel_mask) //{ // removed for speed //moddma_p->setups[channel_number]->isrIntErrStat->call(); LPC_GPDMA->DMACIntErrClr = channel_mask; //} //} } /* // This is some nasty code uint32_t channel_mask; channel_mask = (1UL << 0); // Since we only have one if statement inside anyway, I took this out //if (LPC_GPDMA->DMACIntStat & channel_mask) //{ if (LPC_GPDMA->DMACIntTCStat & channel_mask) { moddma_p->setups[0]->isrIntTCStat->call(); LPC_GPDMA->DMACIntTCClear = channel_mask; } //if (LPC_GPDMA->DMACIntErrStat & channel_mask) //{ // removed for speed //moddma_p->setups[channel_number]->isrIntErrStat->call(); LPC_GPDMA->DMACIntErrClr = channel_mask; //} //} channel_mask = (1UL << 1); // Since we only have one if statement inside anyway, I took this out //if (LPC_GPDMA->DMACIntStat & channel_mask) //{ if (LPC_GPDMA->DMACIntTCStat & channel_mask) { moddma_p->setups[1]->isrIntTCStat->call(); LPC_GPDMA->DMACIntTCClear = channel_mask; } //if (LPC_GPDMA->DMACIntErrStat & channel_mask) //{ // removed for speed //moddma_p->setups[channel_number]->isrIntErrStat->call(); LPC_GPDMA->DMACIntErrClr = channel_mask; //} //}*/ p6_TOGGLE; } void MODDMA_Cache::init() { NVIC_SetVector(DMA_IRQn, (uint32_t)MODDMA_Cache_IRQHandler); NVIC_EnableIRQ(DMA_IRQn); }