A board support package for the LPC4088 Display Module.

Dependencies:   DM_HttpServer DM_USBHost

Dependents:   lpc4088_displaymodule_emwin lpc4088_displaymodule_demo_sphere sampleGUI sampleEmptyGUI ... more

Fork of DMSupport by EmbeddedArtists AB

GPDMA.h

Committer:
embeddedartists
Date:
2019-11-04
Revision:
42:bbfe299d4a0c
Parent:
38:420cdc281467

File content as of revision 42:bbfe299d4a0c:

/*
 *  Copyright 2015 Embedded Artists AB
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */

#ifndef GPDMA_H
#define GPDMA_H

#include "mbed.h"
#include "rtos.h"

/**
 * @brief GPDMA request connections
 */
#define GPDMA_CONN_MEMORY           ((0UL))
#define GPDMA_CONN_SDC              ((1UL))      /*!< SD card */

/**
 * @brief Macro defines for DMA channel control registers
 */
#define GPDMA_DMACCxControl_TransferSize(n) (((n & 0xFFF) << 0))  /*!< Transfer size*/
#define GPDMA_DMACCxControl_SBSize(n)       (((n & 0x07) << 12))  /*!< Source burst size*/
#define GPDMA_DMACCxControl_DBSize(n)       (((n & 0x07) << 15))  /*!< Destination burst size*/
#define GPDMA_DMACCxControl_SWidth(n)       (((n & 0x07) << 18))  /*!< Source transfer width*/
#define GPDMA_DMACCxControl_DWidth(n)       (((n & 0x07) << 21))  /*!< Destination transfer width*/
#define GPDMA_DMACCxControl_SI              ((1UL << 26))      /*!< Source increment*/
#define GPDMA_DMACCxControl_DI              ((1UL << 27))      /*!< Destination increment*/
#define GPDMA_DMACCxControl_SrcTransUseAHBMaster1   0
#define GPDMA_DMACCxControl_DestTransUseAHBMaster1  0
#define GPDMA_DMACCxControl_Prot1           ((1UL << 28))      /*!< Indicates that the access is in user mode or privileged mode*/
#define GPDMA_DMACCxControl_Prot2           ((1UL << 29))      /*!< Indicates that the access is bufferable or not bufferable*/
#define GPDMA_DMACCxControl_Prot3           ((1UL << 30))      /*!< Indicates that the access is cacheable or not cacheable*/
#define GPDMA_DMACCxControl_I               ((1UL << 31))      /*!< Terminal count interrupt enable bit */

/**
 * @brief GPDMA Burst size in Source and Destination definitions
 */
#define GPDMA_BSIZE_1   ((0UL))  /*!< Burst size = 1 */
#define GPDMA_BSIZE_4   ((1UL))  /*!< Burst size = 4 */
#define GPDMA_BSIZE_8   ((2UL))  /*!< Burst size = 8 */
#define GPDMA_BSIZE_16  ((3UL))  /*!< Burst size = 16 */
#define GPDMA_BSIZE_32  ((4UL))  /*!< Burst size = 32 */
#define GPDMA_BSIZE_64  ((5UL))  /*!< Burst size = 64 */
#define GPDMA_BSIZE_128 ((6UL))  /*!< Burst size = 128 */
#define GPDMA_BSIZE_256 ((7UL))  /*!< Burst size = 256 */

/**
 * @brief Width in Source transfer width and Destination transfer width definitions
 */
#define GPDMA_WIDTH_BYTE        ((0UL))  /*!< Width = 1 byte */
#define GPDMA_WIDTH_HALFWORD    ((1UL))  /*!< Width = 2 bytes */
#define GPDMA_WIDTH_WORD        ((2UL))  /*!< Width = 4 bytes */

/**
 * @brief Macro defines for DMA Configuration register
 */
#define GPDMA_DMACConfig_E              ((0x01))  /*!< DMA Controller enable*/
#define GPDMA_DMACConfig_M              ((0x02))  /*!< AHB Master endianness configuration*/
#define GPDMA_DMACConfig_BITMASK        ((0x03))

/**
 * @brief Macro defines for DMA Channel Configuration registers
 */
#define GPDMA_DMACCxConfig_E                    ((1UL << 0))      /*!< DMA control enable*/
#define GPDMA_DMACCxConfig_SrcPeripheral(n)     (((n & 0x1F) << 1))    /*!< Source peripheral*/
#define GPDMA_DMACCxConfig_DestPeripheral(n)    (((n & 0x1F) << 6))    /*!< Destination peripheral*/
#define GPDMA_DMACCxConfig_TransferType(n)      (((n & 0x7) << 11))    /*!< This value indicates the type of transfer*/
#define GPDMA_DMACCxConfig_IE                   ((1UL << 14))      /*!< Interrupt error mask*/
#define GPDMA_DMACCxConfig_ITC                  ((1UL << 15))      /*!< Terminal count interrupt mask*/
#define GPDMA_DMACCxConfig_L                    ((1UL << 16))      /*!< Lock*/
#define GPDMA_DMACCxConfig_A                    ((1UL << 17))      /*!< Active*/
#define GPDMA_DMACCxConfig_H                    ((1UL << 18))      /*!< Halt*/

/**
 * @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_Type;

/**
 * Wrapper for the General Purpose DMA controller.
 *
 * The GPDMA class allows multiple users of DMA to claim one or more
 * of the eight available DMA channels and to register handlers for the
 * interrupts. This centralized control is needed as there are eight
 * channels but only one DMA IRQ.
 *
 * By having to request a channel to use it is possible to avoid having
 * hardcoded DMA channel number in the code
 *
 * An example of use:
 *
 * @code
 * void handler() {
 *   _eventSuccess = LPC_GPDMA->IntTCStat & (1<<ch);
 *   LPC_GPDMA->IntTCClear = (1<<ch);
 * }
 *
 * void foo() {
 *    GPDMA* dma = &GPDMA::instance();
 *    dma->init();
 *
 *    DMAChannels ch = dma->acquireChannel(handler)
 *    if (ch == DMACh_Unavailable) {
 *      // handle error
 *    }
 *
 *    // prepare the channel data (see e.g. gpdma_transfer_from_mci() in MCIFileSystem)
 *    ...
 *
 *    // start the transfer
 *    dma->transfer(&cfg, ctrl_word, 0, GPDMA_CONN_SDC, GPDMA_CONN_MEMORY);
 *
 *    // wait for transfer to complete (e.g. by handler() setting a flag)
 *    ...
 *
 *    // return the channel now that it is no longer needed
 *    dma->releaseChannel(ch);
 * }
 * @endcode
 */
class GPDMA {
public:
    enum DMAChannels {
        DMACh0,   /* DMA channel 0 has the highest priority */
        DMACh1,
        DMACh2,
        DMACh3,
        DMACh4,
        DMACh5,
        DMACh6,
        DMACh7,   /* DMA channel 7 has the lowest priority */
        NumDMAChannels,
        DMACh_Unavailable = NumDMAChannels,
    };
    enum FlowControl {
        FlowControl_M2M_Ctrl_DMA,         /* Memory to memory - DMA control */
        FlowControl_M2P_Ctrl_DMA,         /* Memory to peripheral - DMA control */
        FlowControl_P2M_Ctrl_DMA,         /* Peripheral to memory - DMA control */
        FlowControl_P2P_Ctrl_DMA,         /* Source peripheral to destination peripheral - DMA control */
        FlowControl_P2P_Ctrl_DestPeriph,  /* Source peripheral to destination peripheral - destination peripheral control */
        FlowControl_M2P_Ctrl_Periph,      /* Memory to peripheral - peripheral control */
        FlowControl_P2M_Ctrl_Periph,      /* Peripheral to memory - peripheral control */
        FlowControl_P2P_Ctrl_SrcPeriph,   /* Source peripheral to destination peripheral - source peripheral control */
    };
    typedef struct {
        DMAChannels ChannelNum;
        uint32_t    TransferSize;  /* Length/Size of transfer */
        uint32_t    TransferWidth; /* Transfer width - used only for M2M */
        uint32_t    SrcAddr;       /* Physical Source Address, only for M2M and M2P */
        uint32_t    DstAddr;       /* Physical Destination Address, only for M2M and P2M */
        FlowControl TransferType;
    } GPDMA_Channel_CFG_T;

    /** Get the only instance of the GPDMA
     *
     *  @returns The Registry
     */
    static GPDMA& instance()
    {
        static GPDMA singleton;
        return singleton;
    }

    /** Initializes the GPDMA
     *
     *  Safe to call even with multiple DMA users
     */
    void init();

    /** Shuts down the GPDMA
     *
     *  Call will be ignored if there are any acquired channels
     */
    void deinit();

    /** Get a free GPDMA channel for one DMA connection
     *
     *  The function will start to look for the suggested channel.
     *  If it is in use then the next, higher, channel number will
     *  be tested. The default is set to use DMACh3 which has
     *  medium priority.
     *
     *  To acquire a channel with the highest available priority
     *  call this function with DMACh0 as parameter.
     *
     *  @param func       the interrupt callback function
     *  @param suggested  the first channel to look for
     *
     *  @returns
     *       DMACh0 to DMACh7 on success
     *       DMACh_Unavailable if there are no channels available
     */
    DMAChannels acquireChannel(void (*irqfunc)(void), DMAChannels suggested = DMACh3);

    /** Release a previously acquired channel
     *
     *  @param ch  the DMA channel to release
     */
    void releaseChannel(DMAChannels ch);

    /** Returns the raw registers for the GPDMA channel for direct manipulation
     *
     *  @param ch    the DMA channel
     *
     *  @returns
     *       The registers on success
     *       NULL if the channel is invalid
     */
    LPC_GPDMACH_TypeDef* getDirectRegisters(DMAChannels ch);

    // Internal use only. Called by the IRQ handler
    void processInterrupt();

    /** Does the actual DMA transfer
     *
     *  @param cfg           the DMA configuration
     *  @param CtrlWord      data for the DMA channel's CONTROL register
     *  @param LinkListItem  address to the linked list or 0 if not used
     *  @param SrcPeripheral source of the transfer (GPDMA_CONN_MEMORY or GPDMA_CONN_SDC)
     *  @param DstPeripheral destination of the transfer (GPDMA_CONN_MEMORY or GPDMA_CONN_SDC)
     *
     *  @returns
     *       True on success, false on failure
     */
    bool transfer(GPDMA_Channel_CFG_T* cfg,
                  uint32_t CtrlWord,
                  uint32_t LinkListItem,
                  uint8_t SrcPeripheral,
                  uint8_t DstPeripheral);

    void stopTransfer(DMAChannels ch);

private:
    typedef struct {
        bool inUse;
        void (*func)(void);
    } channelData_t;

    Mutex _mutex;
    channelData_t _chData[NumDMAChannels];
    int _usedChannels;
    bool _initialized;

    explicit GPDMA();
    // hide copy constructor
    GPDMA(const GPDMA&);
    // hide assign operator
    GPDMA& operator=(const GPDMA&);
    ~GPDMA();
};

#endif