#include <stdio.h>
#include "OB90A64u1.h"
#include "dma.h"
#include "gpio.h"
#include "adc.h"

volatile uint32_t gDMA_Int = 0x00;

void PDMA_IRQHandler(void)
{
    if(OB_DMA0->CSR_b.FININTSTS == 1)
    {
        OB_DMA0->CSR_b.FININTSTS = 1;  // clear status
        gDMA_Int = gDMA_Int | 0x01;
    }
    if(OB_DMA1->CSR_b.FININTSTS == 1)
    {
        OB_DMA1->CSR_b.FININTSTS = 1;  // clear status
        gDMA_Int = gDMA_Int | 0x02;
    }
    if(OB_DMA2->CSR_b.FININTSTS == 1)
    {
        OB_DMA2->CSR_b.FININTSTS = 1;  // clear status
        gDMA_Int = gDMA_Int | 0x04;
    }
    if(OB_DMA3->CSR_b.FININTSTS == 1)
    {
        OB_DMA3->CSR_b.FININTSTS = 1;  // clear status
        gDMA_Int = gDMA_Int | 0x08;
    }
}

void DMA_Enable(OB_DMA_Type *pDMA)
{
    pDMA->CSR_b.ENB = 1;

}

void DMA_InterruptEnable(OB_DMA_Type *pDMA)
{
    pDMA->CSR_b.FININTENB = 1;
}

void DMA_DataLength(OB_DMA_Type *pDMA, uint32_t Length)
{
    pDMA->BLOCK = (Length - 1) | ((Length - 1) << 16);
}


//-------------------------------- 從memory抓資料到memory
void DMA_Open_M(OB_DMA_Type *pDMA,uint32_t Sourec_Addr, uint32_t Des_Addr, uint32_t DataLength)
{
    uint32_t Loop, Buff;
    uint32_t *pAddr;
    pAddr = (uint32_t *)Sourec_Addr;
    for(Loop = 0x00;Loop<DataLength;Loop++)
    {
        *pAddr = (0x12345678 + Loop);
        pAddr++;
    }

    pDMA->CSR = 0x00;
    //----------------ADC
    pDMA->CSR_b.SWIDTH = DMA_WIDTH_WORD;
    pDMA->CSR_b.DWIDTH = DMA_WIDTH_WORD;
    DMA_SourceAddr(pDMA, Sourec_Addr);        // 讀SFR的位置
    DMA_AddrInc(pDMA,DMA_ADDR_INC_SINGLE, DMA_ADDR_INC_SINGLE);   // Source 放完後RAM的位置加1(word). Destination 放完後RAM的位置加1(word)
    //-------------------------
    DMA_DestinationAddr(pDMA,Des_Addr );  // 放到RAM的位置
    DMA_DataLength(pDMA, DataLength);
    DMA_InterruptEnable(pDMA);
    DMA_Enable(pDMA);

    pAddr = (uint32_t *)Des_Addr;
    for(Loop = 0x00; Loop < DataLength; Loop++)
    {
        Buff = (0x12345678 + Loop);
        if( (*pAddr) != Buff)
        {
            printf("ERROR\r\n");
            while(1);
        }
        pAddr++;
    }
}

//-------------------------------- 從SFR抓資料到RAM ( ADC trigger)
void DMA_Open_ADC(OB_DMA_Type *pDMA,uint32_t Source_Addr, uint32_t Dest_Addr, uint32_t DataLength )
{
    pDMA->CSR = 0x00;
    //----------------ADC
    ADC_Open(OB_ADC, 0);
    OB_ADC->A0SC0 = 0x00;
    OB_ADC->SL0 = 1;
    OB_ADC->CONDMA0_b.DMAE = 1;
    DMA_TriggerEvent(pDMA, DMA_EVENT_ADC); // ADC TRIG
    //-------------------------------------------------------------
    pDMA->CSR_b.SWIDTH = DMA_WIDTH_WORD;
    pDMA->CSR_b.DWIDTH = DMA_WIDTH_WORD;
    DMA_SourceAddr(pDMA, Source_Addr);        // 讀SFR的位置
    DMA_AddrInc(pDMA,DMA_ADDR_INC_0, DMA_ADDR_INC_SINGLE);   // Source 讀固定位置, 所以位置加 0. Destination 放完後RAM的位置加1(word)
    //-------------------------
    DMA_DestinationAddr(pDMA,Dest_Addr );  // 放到RAM的位置

    DMA_DataLength(pDMA, DataLength);
    DMA_InterruptEnable(pDMA);
    DMA_Enable(pDMA);
    while(DataLength--)
    {
        OB_ADC->IESTC = 0xFFFFFFFF;
        OB_ADC->CON_b.START0 = 1; //
        while(1)
        {
            if(OB_ADC->IEST != 0x00)
                break;
        }
    }
}

//---------------------------------------Source----------------------------------------------------
void DMA_AddrInc(OB_DMA_Type *pDMA, uint32_t SourceAddrInc, uint32_t DestAddrInc)
{
    pDMA->CSR_b.SADDR = SourceAddrInc;
    pDMA->CSR_b.DADDR = DestAddrInc;
}


void DMA_DataWidth(OB_DMA_Type *pDMA,uint32_t SourecWidth, uint32_t DestWidth)
{
    pDMA->CSR_b.SWIDTH = SourecWidth;
    pDMA->CSR_b.DWIDTH = DestWidth;
}


void DMA_TriggerEvent(OB_DMA_Type *pDMA, uint32_t SourecEvent)
{
    if( (SourecEvent & 0x0100) == 0x0100)
        pDMA->CSR_b.SREQ =  SourecEvent & 0x00FF ;
    else
        pDMA->CSR_b.DREQ =  SourecEvent & 0x00FF ;
}

//-------------------------------------------------------------------------------------------
void DMA_SourceAddr(OB_DMA_Type *pDMA, uint32_t SourceAddr)
{
    pDMA->SRCADR = SourceAddr;
}

void DMA_DestinationAddr(OB_DMA_Type *pDMA, uint32_t DestinationAddr)
{
    pDMA->DESADR = DestinationAddr;
}

