Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Dependencies: DM_HttpServer DM_USBHost
Dependents: lpc4088_displaymodule_emwin lpc4088_displaymodule_demo_sphere sampleGUI sampleEmptyGUI ... more
Fork of DMSupport by
GPDMA.cpp
- Committer:
- alindvall
- Date:
- 2015-04-28
- Revision:
- 39:e1cb4dd9bfeb
- Parent:
- 38:420cdc281467
File content as of revision 39:e1cb4dd9bfeb:
/*
* 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.
*/
#include "mbed.h"
#include "DMBoard.h"
#include "GPDMA.h"
/******************************************************************************
* Defines and typedefs
*****************************************************************************/
#define GPDMACH(__x) ((LPC_GPDMACH_TypeDef*)(LPC_GPDMACH0_BASE + (0x20 * (__x))))
#define CH_MASK(__ch) (((1UL << (__ch)) & 0xFF))
#define GPDMA_ALL_CH_MASK (0xff)
/******************************************************************************
* Local variables
*****************************************************************************/
/******************************************************************************
* Private Class
*****************************************************************************/
/******************************************************************************
* DMA Interrupt Functon
*****************************************************************************/
static void mydmairq()
{
GPDMA::instance().processInterrupt();
}
/******************************************************************************
* Private Functions
*****************************************************************************/
/******************************************************************************
* Public Functions
*****************************************************************************/
GPDMA::GPDMA() : _usedChannels(0), _initialized(false)
{
for (int i = 0; i < NumDMAChannels; i++) {
_chData[i].inUse = false;
_chData[i].func = NULL;
}
/* Redirect all DMA IRQs to the local mydmairq() function */
NVIC_SetVector(DMA_IRQn, (uint32_t) mydmairq);
}
GPDMA::~GPDMA()
{
}
void GPDMA::init()
{
_mutex.lock();
if (!_initialized) {
/* Enable GPDMA master clock */
LPC_SC->PCONP |= (1<<29);
/* Reset all channel configuration register */
for (int i = 0; i < NumDMAChannels; i++) {
GPDMACH(i)->CConfig = 0;
}
/* Clear all DMA interrupt and error flag */
LPC_GPDMA->IntTCClear = 0xFF;
LPC_GPDMA->IntErrClr = 0xFF;
/* Reset all channel datas */
for (int i = 0; i < NumDMAChannels; i++) {
_chData[i].inUse = false;
_chData[i].func = NULL;
}
_initialized = true;
}
_mutex.unlock();
}
void GPDMA::deinit()
{
_mutex.lock();
if (_usedChannels == 0) {
/* Disable the real interrupt */
NVIC_DisableIRQ(DMA_IRQn);
/* Clear all DMA interrupt and error flag */
LPC_GPDMA->IntTCClear = 0xFF;
LPC_GPDMA->IntErrClr = 0xFF;
/* Disable GPDMA master clock */
LPC_SC->PCONP &= ~(1<<29);
_initialized = false;
}
_mutex.unlock();
}
GPDMA::DMAChannels GPDMA::acquireChannel(void (*irqfunc)(void), DMAChannels suggested)
{
DMAChannels result = DMACh_Unavailable;
_mutex.lock();
if (!_initialized) {
init();
}
for (int i = suggested; i < NumDMAChannels; i++) {
if ((!_chData[i].inUse) && ((LPC_GPDMA->EnbldChns & CH_MASK(i)) == 0)) {
_chData[i].inUse = true;
_chData[i].func = irqfunc;
result = (DMAChannels)i;
_usedChannels++;
break;
}
}
_mutex.unlock();
return result;
}
void GPDMA::releaseChannel(DMAChannels ch)
{
_mutex.lock();
if (ch < NumDMAChannels) {
stopTransfer(ch);
if (_chData[ch].inUse) {
_usedChannels--;
}
_chData[ch].inUse = false;
_chData[ch].func = NULL;
}
_mutex.unlock();
}
LPC_GPDMACH_TypeDef* GPDMA::getDirectRegisters(DMAChannels ch)
{
if (ch < NumDMAChannels) {
return GPDMACH(ch);
} else {
return NULL;
}
}
void GPDMA::processInterrupt()
{
/* check status of DMA channel interrupts */
uint32_t intstat = LPC_GPDMA->IntStat;
for (int i = 0; i < NumDMAChannels; i++) {
uint32_t mask = CH_MASK(i);
if (intstat & mask) {
if (_chData[i].func != NULL) {
/* Notify registered subscriber */
_chData[i].func();//GPDMACH(i), (tcstat&mask)!=0, (errstat&mask)!=0);
}
}
}
if ((LPC_GPDMA->EnbldChns & GPDMA_ALL_CH_MASK) == 0) {
/* No more enabled DMA channels, so turn of DMA IRQ */
//NVIC_DisableIRQ(DMA_IRQn);
}
}
bool GPDMA::transfer(GPDMA_Channel_CFG_T* cfg, uint32_t CtrlWord,
uint32_t LinkListItem, uint8_t SrcPeripheral,
uint8_t DstPeripheral)
{
if (LPC_GPDMA->EnbldChns & CH_MASK(cfg->ChannelNum)) {
/* This channel is enabled, return ERROR, need to release this channel first */
return false;
}
/* Get Channel pointer */
LPC_GPDMACH_TypeDef* pCh = GPDMACH(cfg->ChannelNum);
/* Reset the Interrupt status */
LPC_GPDMA->IntTCClear = CH_MASK(cfg->ChannelNum);
LPC_GPDMA->IntErrClr = CH_MASK(cfg->ChannelNum);
/* Clear configuration */
pCh->CControl = 0x00;
pCh->CConfig = 0x00;
/* Assign Linker List Item value */
pCh->CLLI = LinkListItem;
pCh->CSrcAddr = cfg->SrcAddr;
pCh->CDestAddr = cfg->DstAddr;
pCh->CControl = CtrlWord;
/* Enable DMA channels, little endian */
LPC_GPDMA->Config = GPDMA_DMACConfig_E;
while (!(LPC_GPDMA->Config & GPDMA_DMACConfig_E)) {}
/* Configure DMA Channel, enable Error Counter and Terminate counter */
pCh->CConfig = GPDMA_DMACCxConfig_IE
| GPDMA_DMACCxConfig_ITC
| GPDMA_DMACCxConfig_TransferType((uint32_t) cfg->TransferType)
| GPDMA_DMACCxConfig_SrcPeripheral(SrcPeripheral)
| GPDMA_DMACCxConfig_DestPeripheral(DstPeripheral);
/* Enable the interrupts */
NVIC_EnableIRQ(DMA_IRQn);
/* Start the Channel */
pCh->CConfig |= GPDMA_DMACCxConfig_E;
return true;
}
void GPDMA::stopTransfer(DMAChannels ch)
{
/* Disable channel */
GPDMACH(ch)->CConfig &= ~GPDMA_DMACCxConfig_E;
/* Clear pending interrupts */
LPC_GPDMA->IntTCClear = CH_MASK(ch);
LPC_GPDMA->IntErrClr = CH_MASK(ch);
}
