Test
Diff: MODDMA.h
- Revision:
- 0:c409efd8df78
- Child:
- 1:9700b9455cbf
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/MODDMA.h Tue Nov 23 14:50:39 2010 +0000 @@ -0,0 +1,508 @@ +/* + Copyright (c) 2010 Andy Kirkham + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. + + @file MODDMA.h + @purpose Adds DMA controller and multiple transfer configurations + @version 1.0 + @date Nov 2010 + @author Andy Kirkham +*/ + +#ifndef MODDMA_H +#define MODDMA_H + +/** @defgroup API The MODSERIAL API */ +/** @defgroup MISC Misc MODSERIAL functions */ +/** @defgroup INTERNALS MODSERIAL Internals */ + +#include "mbed.h" + +namespace AjK { + +/** + * @author Andy Kirkham + * @see http://mbed.org/cookbook/MODDMA + * @see example1.cpp + * @see API + * + * <b>MODDMA</b> defines a GPDMA controller and multiple DMA configurations that allow for DMA + * transfers from memory to memory, memory to peripheral or peripheral to memory. + * + * At the heart of the library is the MODDMA class the defines a single instance controller that + * manages all the GPDMA hardware registers and interrupts. The controller can accept multiple + * configurations that define the transfer. Each configuration specifies the src and dest information + * and other associated parts to maintain the transfer process. + * + * Standard example: + * @code + * #include "mbed.h" + * #include "MODDMA.h" + * + * DigitalOut led1(LED1); + * Serial pc(USBTX, USBRX); // tx, rx + * MODDMA dma; + * + * int main() { + * + * // Create a string buffer to send directly to a Uart/Serial + * char s[] = "***DMA*** ABCDEFGHIJKLMNOPQRSTUVWXYZ ***DMA***"; + * + * // Create a transfer configuarion + * MODDMA_Config *config = new MODDMA_Config; + * + * // Provide a "minimal" setup for demo purposes. + * config + * ->channelNum ( MODDMA::Channel_0 ) // The DMA channel to use. + * ->srcMemAddr ( (uint32_t) &s ) // A pointer to the buffer to send. + * ->transferSize ( sizeof(s) ) // The size of that buffer. + * ->transferType ( MODDMA::m2p ) // Buffer is memory, dest is peripheral + * ->dstConn ( MODDMA::UART0_Tx ) // Specifically, peripheral is Uart0 TX (USBTX, USBRX) + * ; // config end. + * + * // Pass the configuration to the MODDMA controller. + * dma.Setup( config ); + * + * // Enable the channel and begin transfer. + * dma.Enable( config->channelNum() ); + * + * while(1) { + * led1 = !led1; + * wait(0.25); + * } + * } + * @endcode + */ +class MODDMA_Config { +protected: + + // ***************************************** + // From GPDMA by NXP MCU SW Application Team + // ***************************************** + + uint32_t ChannelNum; //!< DMA channel number, should be in range from 0 to 7. + uint32_t TransferSize; //!< Length/Size of transfer + uint32_t TransferWidth; //!< Transfer width - used for TransferType is GPDMA_TRANSFERTYPE_m2m only + uint32_t SrcMemAddr; //!< Physical Src Addr, used in case TransferType is chosen as MODDMA::GPDMA_TRANSFERTYPE::m2m or MODDMA::GPDMA_TRANSFERTYPE::m2p + uint32_t DstMemAddr; //!< Physical Destination Address, used in case TransferType is chosen as MODDMA::GPDMA_TRANSFERTYPE::m2m or MODDMA::GPDMA_TRANSFERTYPE::p2m + uint32_t TransferType; //!< Transfer Type + uint32_t SrcConn; //!< Peripheral Source Connection type, used in case TransferType is chosen as + uint32_t DstConn; //!< Peripheral Destination Connection type, used in case TransferType is chosen as + uint32_t DMALLI; //!< Linker List Item structure data address if there's no Linker List, set as '0' + + // Mbed specifics. + +public: + + MODDMA_Config() { + isrIntTCStat = new FunctionPointer; + isrIntErrStat = new FunctionPointer; + ChannelNum = 0xFFFF; + TransferSize = 0; + TransferWidth = 0; + SrcMemAddr = 0; + DstMemAddr = 0; + TransferType = 0; + SrcConn = 0; + DstConn = 0; + DMALLI = 0; + } + + ~MODDMA_Config() { + delete(isrIntTCStat); + delete(isrIntErrStat); + } + + class MODDMA_Config * channelNum(uint32_t n) { ChannelNum = n & 0x7; return this; } + class MODDMA_Config * transferSize(uint32_t n) { TransferSize = n; return this; } + class MODDMA_Config * transferWidth(uint32_t n) { TransferWidth = n; return this; } + class MODDMA_Config * srcMemAddr(uint32_t n) { SrcMemAddr = n; return this; } + class MODDMA_Config * dstMemAddr(uint32_t n) { DstMemAddr = n; return this; } + class MODDMA_Config * transferType(uint32_t n) { TransferType = n; return this; } + class MODDMA_Config * srcConn(uint32_t n) { SrcConn = n; return this; } + class MODDMA_Config * dstConn(uint32_t n) { DstConn = n; return this; } + class MODDMA_Config * dmaLLI(uint32_t n) { DMALLI = n; return this; } + + uint32_t channelNum(void) { return ChannelNum; } + uint32_t transferSize(void) { return TransferSize; } + uint32_t transferWidth(void) { return TransferWidth; } + uint32_t srcMemAddr(void) { return SrcMemAddr; } + uint32_t dstMemAddr(void) { return DstMemAddr; } + uint32_t transferType(void) { return TransferType; } + uint32_t srcConn(void) { return SrcConn; } + uint32_t dstConn(void) { return DstConn; } + uint32_t dmaLLI(void) { return DMALLI; } + + FunctionPointer *isrIntTCStat; + FunctionPointer *isrIntErrStat; +}; + +/** + * @brief GPDMA Linker List Item structure type definition + */ + /* +typedef struct { + uint32_t SrcAddr; //!< Source Address + uint32_t DstAddr; //!< Destination address + uint32_t NextLLI; //!< Next LLI address, otherwise set to '0' + uint32_t Control; //!< GPDMA Control of this LLI +} GPDMA_LLI_t; +*/ + +/** + * @author Andy Kirkham + * @see http://mbed.org/cookbook/MODDMA_Config + * @see MODDMA + * @see API + * + * <b>MODDMA_Config</b> defines a configuration that can be passed to the MODDMA controller + * instance to perform a GPDMA data transfer. + * transfers from memory to memory, memory to peripheral or peripheral to memory. + */ +class MODDMA +{ +public: + + //! Channel definitions. + enum CHANNELS { + Channel_0 = 0 /*!< Channel 0 */ + , Channel_1 /*!< Channel 1 */ + , Channel_2 /*!< Channel 2 */ + , Channel_3 /*!< Channel 3 */ + , Channel_4 /*!< Channel 4 */ + , Channel_5 /*!< Channel 5 */ + , Channel_6 /*!< Channel 6 */ + , Channel_7 /*!< Channel 7 */ + }; + + //! Interrupt callback types. + enum IrqType_t { + TcIrq = 0 /*!< Terminal Count interrupt */ + , ErrIrq /*!< Error interrupt */ + }; + + //! Return status codes. + enum Status { + Ok = 0 /*!< Ok, suceeded */ + , Error = -1 /*!< General error */ + , ErrChInUse = -2 /*!< Specific error, channel in use */ + }; + + //! DMA Connection number definitions + enum GPDMA_CONNECTION { + SSP0_Tx = 0UL /*!< SSP0 Tx */ + , SSP0_Rx = 1UL /*!< SSP0 Rx */ + , SSP1_Tx = 2UL /*!< SSP1 Tx */ + , SSP1_Rx = 3UL /*!< SSP1 Rx */ + , ADC = 4UL /*!< ADC */ + , I2S_Channel_0 = 5UL /*!< I2S channel 0 */ + , I2S_Channel_1 = 6UL /*!< I2S channel 1 */ + , DAC = 7UL /*!< DAC */ + , UART0_Tx = 8UL /*!< UART0 Tx */ + , UART0_Rx = 9UL /*!< UART0 Rx */ + , UART1_Tx = 10UL /*!< UART1 Tx */ + , UART1_Rx = 11UL /*!< UART1 Rx */ + , UART2_Tx = 12UL /*!< UART2 Tx */ + , UART2_Rx = 13UL /*!< UART2 Rx */ + , UART3_Tx = 14UL /*!< UART3 Tx */ + , UART3_Rx = 15UL /*!< UART3 Rx */ + , MAT0_0 = 16UL /*!< MAT0.0 */ + , MAT0_1 = 17UL /*!< MAT0.1 */ + , MAT1_0 = 18UL /*!< MAT1.0 */ + , MAT1_1 = 19UL /*!< MAT1.1 */ + , MAT2_0 = 20UL /**< MAT2.0 */ + , MAT2_1 = 21UL /*!< MAT2.1 */ + , MAT3_0 = 22UL /*!< MAT3.0 */ + , MAT3_1 = 23UL /*!< MAT3.1 */ + }; + + //! GPDMA Transfer type definitions + enum GPDMA_TRANSFERTYPE { + m2m = 0UL /*!< Memory to memory - DMA control */ + , m2p = 1UL /*!< Memory to peripheral - DMA control */ + , p2m = 2UL /*!< Peripheral to memory - DMA control */ + , p2p = 3UL /*!< Src peripheral to dest peripheral - DMA control */ + }; + + //! Burst size in Source and Destination definitions */ + enum GPDMA_BSIZE { + _1 = 0UL /*!< Burst size = 1 */ + , _4 = 1UL /*!< Burst size = 4 */ + , _8 = 2UL /*!< Burst size = 8 */ + , _16 = 3UL /*!< Burst size = 16 */ + , _32 = 4UL /*!< Burst size = 32 */ + , _64 = 5UL /*!< Burst size = 64 */ + , _128 = 6UL /*!< Burst size = 128 */ + , _256 = 7UL /*!< Burst size = 256 */ + }; + + //! Width in Src transfer width and Dest transfer width definitions */ + enum GPDMA_WIDTH { + byte = 0UL /*!< Width = 1 byte */ + , halfword = 1UL /*!< Width = 2 bytes */ + , word = 2UL /*!< Width = 4 bytes */ + }; + + //! DMA Request Select Mode definitions. */ + enum GPDMA_REQSEL { + uart = 0UL /*!< UART TX/RX is selected */ + , timer = 1UL /*!< Timer match is selected */ + }; + + //! GPDMA Control register bits. + enum Config { + _E = 1 /*!< DMA Controller enable */ + , _M = 2 /*!< AHB Master endianness configuration */ + }; + + //! GPDMA Channel config register bits. + enum CConfig { + _CE = (1UL << 0) /*!< Channel enable */ + , _IE = (1UL << 14) /*!< Interrupt error mask */ + , _ITC = (1UL << 15) /*!< Terminal count interrupt mask */ + , _L = (1UL << 16) /*!< Lock */ + , _A = (1UL << 17) /*!< Active */ + , _H = (1UL << 18) /*!< Halt */ + }; + + /** + * The MODDMA constructor is used to initialise the DMA controller object. + */ + MODDMA() { init(true); } + + /** + * The MODDMA destructor. + */ + ~MODDMA() {} + + /** + * Used to setup the DMA controller to prepare for a data transfer. + * + * @param c A pointer to an instance of MODDMA_Config to setup. + */ + Status Setup(MODDMA_Config *c); + + /** + * Enable and begin data transfer. + * + * @param ChannelNumber Type CHANNELS, the channel number to enable + */ + void Enable(CHANNELS ChannelNumber); + + /** + * Enable and begin data transfer (overloaded function) + * + * @param ChannelNumber Type uin32_t, the channel number to enable + */ + void Enable(uint32_t ChannelNumber) { Enable((CHANNELS)(ChannelNumber & 0x7)); } + + /** + * Disable a channel and end data transfer. + * + * @param ChannelNumber Type CHANNELS, the channel number to enable + */ + void Disable(CHANNELS ChannelNumber); + + /** + * Disable a channel and end data transfer (overloaded function) + * + * @param ChannelNumber Type uin32_t, the channel number to disable + */ + void Disable(uint32_t ChannelNumber) { Disable((CHANNELS)(ChannelNumber & 0x7)); } + + /** + * Is the specified channel enabled? + * + * @param ChannelNumber Type CHANNELS, the channel number to test + * @return bool true if enabled, false otherwise. + */ + bool Enabled(CHANNELS ChannelNumber); + + /** + * Is the specified channel enabled? (overloaded function) + * + * @param ChannelNumber Type uin32_t, the channel number to test + * @return bool true if enabled, false otherwise. + */ + bool Enabled(uint32_t ChannelNumber) { Enabled((CHANNELS)(ChannelNumber & 0x7)); } + + __INLINE uint32_t IntStat(uint32_t n) { return (1UL << n) & 0xFF; } + __INLINE uint32_t IntTCStat_Ch(uint32_t n) { return (1UL << n) & 0xFF; } + __INLINE uint32_t IntTCClear_Ch(uint32_t n) { return (1UL << n) & 0xFF; } + __INLINE uint32_t IntErrStat_Ch(uint32_t n) { return (1UL << n) & 0xFF; } + __INLINE uint32_t IntErrClr_Ch(uint32_t n) { return (1UL << n) & 0xFF; } + __INLINE uint32_t RawIntErrStat_Ch(uint32_t n) { return (1UL << n) & 0xFF; } + __INLINE uint32_t EnbldChns_Ch(uint32_t n) { return (1UL << n) & 0xFF; } + __INLINE uint32_t SoftBReq_Src(uint32_t n) { return (1UL << n) & 0xFFFF; } + __INLINE uint32_t SoftSReq_Src(uint32_t n) { return (1UL << n) & 0xFFFF; } + __INLINE uint32_t SoftLBReq_Src(uint32_t n) { return (1UL << n) & 0xFFFF; } + __INLINE uint32_t SoftLSReq_Src(uint32_t n) { return (1UL << n) & 0xFFFF; } + __INLINE uint32_t Sync_Src(uint32_t n) { return (1UL << n) & 0xFFFF; } + __INLINE uint32_t ReqSel_Input(uint32_t n) { return (1UL << (n - 8)) & 0xFF; } + + + __INLINE uint32_t CxControl_TransferSize(uint32_t n) { return (n & 0xFFF) << 0; } + __INLINE uint32_t CxControl_SBSize(uint32_t n) { return (n & 0x7) << 12; } + __INLINE uint32_t CxControl_DBSize(uint32_t n) { return (n & 0x7) << 15; } + __INLINE uint32_t CxControl_SWidth(uint32_t n) { return (n & 0x7) << 18; } + __INLINE uint32_t CxControl_DWidth(uint32_t n) { return (n & 0x7) << 21; } + __INLINE uint32_t CxControl_SI() { return (1UL << 26); } + __INLINE uint32_t CxControl_DI() { return (1UL << 27); } + __INLINE uint32_t CxControl_Prot1() { return (1UL << 28); } + __INLINE uint32_t CxControl_Prot2() { return (1UL << 29); } + __INLINE uint32_t CxControl_Prot3() { return (1UL << 30); } + __INLINE uint32_t CxControl_I() { return (1UL << 31); } + __INLINE uint32_t CxControl_E() { return (1UL << 0); } + __INLINE uint32_t CxConfig_SrcPeripheral(uint32_t n) { return (n & 0x1F) << 1; } + __INLINE uint32_t CxConfig_DestPeripheral(uint32_t n) { return (n & 0x1F) << 6; } + __INLINE uint32_t CxConfig_TransferType(uint32_t n) { return (n & 0x7) << 11; } + __INLINE uint32_t CxConfig_IE() { return (1UL << 14); } + __INLINE uint32_t CxConfig_ITC() { return (1UL << 15); } + __INLINE uint32_t CxConfig_L() { return (1UL << 16); } + __INLINE uint32_t CxConfig_A() { return (1UL << 17); } + __INLINE uint32_t CxConfig_H() { return (1UL << 18); } + + /** + * A store for up to 8 (8 channels) of configurations. + * @see MODDMA_Config + */ + MODDMA_Config *setups[8]; + + /** + * Get a pointer to the current configuration the ISR is servicing. + * + * @return MODDMA_Config * A pointer to the setup the ISR is currently servicing. + */ + MODDMA_Config *getConfig(void) { return setups[IrqProcessingChannel]; } + + /** + * Set which channel the ISR is currently servicing. + * + * *** USED INTERNALLY. DO NOT CALL FROM USER PROGRAMS *** + * + * Must be public so the extern "C" ISR can use it. + */ + void setIrqProcessingChannel(CHANNELS n) { IrqProcessingChannel = n; } + + /** + * Gets which channel the ISR is currently servicing. + * + * @return CHANNELS The current channel the ISR is servicing. + */ + CHANNELS irqProcessingChannel(void) { return IrqProcessingChannel; } + + /** + * Gets which channel the ISR is currently servicing. + * + * @return uint32_t The current channel the ISR is servicing. + */ + uint32_t irqProcessingChannel(void) { return (uint32_t)(IrqProcessingChannel & 0x7); } + + /** + * Sets which type of IRQ the ISR is making a callback for. + * + * *** USED INTERNALLY. DO NOT CALL FROM USER PROGRAMS *** + * + * Must be public so the extern "C" ISR can use it. + */ + void setIrqType(IrqType_t n) { IrqType = n; } + + /** + * Get which type of IRQ the ISR is calling you about, + * terminal count or error. + */ + IrqType_t irqType(void) { return IrqType; } + + /** + * Clear the interrupt after handling. + * + * @param CHANNELS The channel the IQR occured on. + */ + void clearTcIrq(CHANNELS n) { LPC_GPDMA->DMACIntTCClear = (uint32_t)(1UL << n); } + + /** + * Clear the interrupt the ISR is currently handing.. + */ + void clearTcIrq(void) { clearTcIrq( IrqProcessingChannel ); } + + /** + * Clear the error interrupt after handling. + * + * @param CHANNELS The channel the IQR occured on. + */ + void clearErrIrq(CHANNELS n) { LPC_GPDMA->DMACIntTCClear = (uint32_t)(1UL << n); } + + /** + * Clear the error interrupt the ISR is currently handing. + */ + void clearErrIrq(void) { clearErrIrq( IrqProcessingChannel ); } + + /** + * Is the supplied channel currently active? + * + * @param CHANNELS The channel to inquire about. + * @return bool true if active, false otherwise. + */ + bool isActive(CHANNELS ChannelNumber); + + /** + * Halt the supplied channel. + * + * @param CHANNELS The channel to halt. + */ + void haltChannel(CHANNELS ChannelNumber); + + /** + * Wait for channel transfer to complete and then halt. + * + * @param CHANNELS The channel to wait for then halt. + */ + void haltAndWaitChannelComplete(CHANNELS n) { haltChannel(n); while (isActive(n)); } + + /** + * The MODDMA controllers terminal count interrupt callback. + */ + FunctionPointer isrIntTCStat; + + /** + * The MODDMA controllers error interrupt callback. + */ + FunctionPointer isrIntErrStat; + +protected: + + void init(bool isConstructorCalling, int Channels = 0xFF, int Tc = 0xFF, int Err = 0xFF); + + // Data LUTs. + uint32_t LUTPerAddr(int n); + uint8_t LUTPerBurst(int n); + uint8_t LUTPerWid(int n); + uint32_t Channel_p(int channel); + + CHANNELS IrqProcessingChannel; + + IrqType_t IrqType; +}; + +}; // namespace AjK ends. + +using namespace AjK; + +#endif