Mirror with some correction

Dependencies:   mbed FastIO FastPWM USBDevice

SimpleDMA/SimpleDMA_LPC1768.cpp

Committer:
arnoz
Date:
2021-10-01
Revision:
116:7a67265d7c19
Parent:
45:c42166b2878c

File content as of revision 116:7a67265d7c19:

#ifdef TARGET_LPC1768

#include "SimpleDMA.h"

SimpleDMA *SimpleDMA::irq_owner[8] = {NULL};
LPC_GPDMACH_TypeDef *LPC_GPDMACH[8] = {LPC_GPDMACH0, LPC_GPDMACH1, LPC_GPDMACH2, LPC_GPDMACH3, LPC_GPDMACH4, LPC_GPDMACH5, LPC_GPDMACH6, LPC_GPDMACH7};
uint32_t getTransferType(SimpleDMA_Trigger trig, uint32_t source, uint32_t destination);

SimpleDMA::SimpleDMA(int channel) {
    this->channel(channel);
    
    //Power up
    LPC_SC->PCONP |= 1<<29;
    LPC_GPDMA->DMACConfig = 1;
    trigger(Trigger_ALWAYS);
    
    NVIC_SetVector(DMA_IRQn, (uint32_t)&irq_handler0);
    NVIC_EnableIRQ(DMA_IRQn);          
}

int SimpleDMA::start(uint32_t length) {
    if (auto_channel)
        _channel = getFreeChannel();
    else
        while(isBusy());
    
    uint32_t control = (source_inc << 26) | (destination_inc << 27) | (1UL << 31);
    switch (source_size) {
        case 16:
            control |= (1<<18) | (length >> 1);
            break;
        case 32:
            control |= (2<<18) | (length >> 2);  
            break;
        default:
            control |= length;
    }
    switch (destination_size) {
        case 16:
            control |= (1<<21);
            break;
        case 32:
            control |= (2<<21);  
            break;
    } 
    
    LPC_GPDMACH[_channel]->DMACCSrcAddr = _source;
    LPC_GPDMACH[_channel]->DMACCDestAddr = _destination;
    LPC_GPDMACH[_channel]->DMACCLLI = 0;
    LPC_GPDMACH[_channel]->DMACCControl = control;     //Enable interrupt also
    
    irq_owner[_channel] = this;
    
    if (_trigger != Trigger_ALWAYS) {      
        if (_trigger & 16) 
            LPC_SC->DMAREQSEL |= 1 << (_trigger - 24);
        else
            LPC_SC->DMAREQSEL &= ~(1 << (_trigger - 24));
        
        LPC_GPDMACH[_channel]->DMACCConfig = ((_trigger & 15) << 1) + ((_trigger & 15) << 6) + (getTransferType(_trigger, _source, _destination) << 11) +  (1<<15) +1;        //Both parts of the transfer get triggered at same time
    } else 
        LPC_GPDMACH[_channel]->DMACCConfig = (getTransferType(_trigger, _source, _destination) << 11) + 1 + (1<<15);               //Enable channel
    
    return 0;
}

bool SimpleDMA::isBusy( int channel ) {
    if (channel == -1)
        channel = _channel;
    return (LPC_GPDMA->DMACEnbldChns & (1<<channel));
}

void SimpleDMA::irq_handler0(void) {
    while(LPC_GPDMA->DMACIntTCStat != 0) {
        
    uint32_t intloc = 31 - __CLZ(LPC_GPDMA->DMACIntTCStat & 0xFF);
    if (irq_owner[intloc]!=NULL)
        irq_owner[intloc]->irq_handler();
    }
}

void SimpleDMA::irq_handler(void) {
    LPC_GPDMA->DMACIntTCClear = 1<<_channel;
    _callback.call();
}

static inline bool isMemory(uint32_t addr)
{
    return (addr >> 28) == 0 || (addr >> 28) == 1 || ((addr >= 0x2007C000) && (addr < (0x2007C000 + 0x8000)));
}

uint32_t getTransferType(SimpleDMA_Trigger trig, uint32_t source, uint32_t destination) {
    //If it is always, simply put it on memory-to-memory
    if (trig == Trigger_ALWAYS)
        return 0;
    else if (isMemory(source)) {       //if source is RAM/Flash
        if (isMemory(destination))        //if destination is RAM/flash
            return 3;                                                               //Return p2p for m2m with a trigger (since I have no idea wtf you are trying to do)
        else
            return 1;                                                               //Source is memory, destination is peripheral, so m2p
        }
    else {
        if (isMemory(destination))
            return 2;                                                               //Source is peripheral, destination is memory
        else
            return 3;                                                               //Both source and destination are peripherals
        }
        
}
#endif