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
Diff: MODDMA_cache.cpp
- Revision:
- 0:2381a319fc35
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/MODDMA_cache.cpp Fri Aug 02 02:23:36 2013 +0000 @@ -0,0 +1,606 @@ +#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); +}