test codes to test DMA features

Dependencies:   mDMA mbed

main.cpp

Committer:
steniu01
Date:
2015-03-09
Revision:
0:9b2f77afaacd
Child:
1:5b946b818a29

File content as of revision 0:9b2f77afaacd:

/**
M2M : read content from a files using CPU, test the time; read content from a file using DMA. Compare the content
M2P : demenstrate while DMA-UART working, LED swtich is also working 
P2M : demenstrate m2m, m2p, p2m, could work together ; keep sending 
P2P
 
Do we need constructor?
Select which ever free or which ever not declared?
How to put comments?


Done 1. make init struct generic -- Done
2. make trigger type generic .-- Done
3. support pass method callback -- no solution 
4. read_adc -- Done
5. PC app to received data from uart
6. start ADC transfer rate
7. trigger on Timer 
8. Add assert --- Done
9. Destructor - Done 
10. add space/ comments  
*/

// disassembler memcpy
#include "mbed.h"
#include "dma.h"

#define test_attach 1
#define test_m2m 0
#define test_m2m_int 0
#define test_m2p 0
#define test_p2m 0
#define test_p2p 0
#define test_all 0
#define test_adc 0
#define test_LLI 0


LocalFileSystem local("local");

DigitalOut myled1(LED1);
DigitalOut myled2(LED2);
DigitalOut myled3(LED3);
DigitalOut myled4(LED4);

// Use Timer to measure the execution time
Timer t;

RawSerial pc (USBTX, USBRX);

// Callbacks for DMA interrupts
void led_switchon_m2m(void);
void led_switchon_m2p (void);
void led_switchon_p2m (void);
void led_switchon_p2p (void);
void led_show (void);
void IRQ_err (void);


void ADC_init();
void old_ADC_init();
void burst_ADC_init();
uint32_t ADC_read(uint8_t channel);


volatile bool m2p_finishFlag = 0; 

class mynumber {
    public:
        int num;
        mynumber(){
            num = 0;
        }
        void print_mynumber(void){
            pc.printf("my number is %d", num);
        }
    
};

mynumber mynumber1;

void test_mynumber (){
     static_cast<mynumber*>(&mynumber1)->print_mynumber();
}


template<typename T>
void led_test_call (T *object, void (T::*member)(void)){
    void (T::*m)(void);
    T* o = static_cast<T*>(object);
    memcpy((char*)&m, (char*)&member, sizeof(m));
    (o->*m)();
}

mynumber mynumber2;

void irq_handler(void)
{
    led_test_call<mynumber> (&mynumber2, &mynumber::print_mynumber);
}



int main(void)
{
char src[] =        
                                    "Hello world Copy the logical and implementation_tsmc28hpm directories in to the Skadi home directo \r\n" \
                                    "Thank you for the demonstration. I understand now. I have come to terms with the fact that I misunderstood how \r\n" \
                                    "memory is laid out. I thought that each individual address was capable of storing an entire word, not just a byte \r\n" \
                                    "(for instance address 0x12345678 could hold a value of 0xffffffff and then 0x12345679 could hold a completely  \r\n" \
                                    "different value 0x00000000). Now I realize that 0x12345678 holds only one byte of a word and the next word\r\n"\
                                    "The logic for your memcpy is correct and your interviewer didn't ask you to change it  or add a restriction.\r\n" 
                                    "Hello world Copy the logical and implementation_tsmc28hpm directories in to the Skadi home directo \r\n" \
                                    "Thank you for the demonstration. I understand now. I have come to terms with the fact that I misunderstood how \r\n" \
                                    "memory is laid out. I thought that each individual address was capable of storing an entire word, not just a byte \r\n" \
                                    "(for instance address 0x12345678 could hold a value of 0xffffffff and then 0x12345679 could hold a completely  \r\n" \
                                    "different value 0x00000000). Now I realize that 0x12345678 holds only one byte of a word and the next word \r\n" \
                                    "The logic for your memcpy is correct and your interviewer didn't ask you to change it or add a restriction.  \r\n" \
                                    "different value 0x00000000). Now I realize that 0x12345678 holds only one byte of a word and the next word\r\n" \
                                    "The logic for your memcpy is correct and your interviewer didn't ask you to change it or add a restriction.\r\n"\
                                    "Hello world Copy the logical and implementation_tsmc28hpm directories in to the Skadi home directo \r\n"\
                                    "Thank you for the demonstration. I understand now. I have come to terms with the fact that I misunderstood how \r\n" \
                                    "memory is laid out. I thought that each individual address was capable of storing an entire word, not just a byte \r\n" \
                                    "(for instance address 0x12345678 could hold a value of 0xffffffff and then 0x12345679 could hold a completely  \r\n" \
                                    "different value 0x00000000). Now I realize that 0x12345678 holds only one byte of a word and the next word \r\n" \
                                    "The logic for your memcpy is correct and your interviewer didn't ask you to change it or add a restriction.  \r\n" \
                                  "Thank you for the demonstration. I understand now. I have come to terms with the fact that I misunderstood how \r\n" \
                                    "Hello world Copy the logical and implementation_tsmc28hpm directories in to the Skadi home directo \r\n" \
                                    "Thank you for the demonstration. I understand now. I have come to terms with the fact that I misunderstood how \r\n" \
                                    "memory is laid out. I thought that each individual address was capable of storing an entire word, not just a byte \r\n" \
                                    "(for instance address 0x12345678 could hold a value of 0xffffffff and then 0x12345679 could hold a completely  \r\n" \
                                    "different value 0x00000000). Now I realize that 0x12345678 holds only one byte of a word and the next word \r\n" \
                                    "The logic for your memcpy is correct and your interviewer didn't ask you to change it or add a restriction.  \r\n" \
                                  "Thank you for the demonstration. I understand now. I have come to terms with the fact that I misunderstood how\r\n" \
                                    "memory is laid out. I thought that each individual address was capable of storing an entire word, not just a byte \r\n" \
                                    "(for instance address 0x12345678 could hold a value of 0xffffffff and then 0x12345679 could hold a completely \r\n" \
                                    "different value 0x00000000). Now I realize that 0x12345678 holds only one byte of a word and the next word \r\n" \
                                    "The logic for your memcpy is correct and your interviewer didn't ask you to change it or add a restriction. \r\n" \
                                    "memory is laid out. I thought that each individual address was capable of storing an entire word, not just a byte \r\n" \
                                    "(for instance address 0x12345678 could hold a value of 0xffffffff and then 0x12345679 could hold a completely  \r\n" \
                                    "different value 0x00000000). Now I realize that 0x12345678 holds only one byte of a word and the next word \r\n" \
                                    "The logic for your memcpy is correct and your interviewer didn't ask you to change it or add a restriction. \r\n" \
                                    "Thank you for the demonstration. I understand now. I have come to terms with the fact that I misunderstood how \r\n" \
                                    "Thank you for the demonstration. I understand now. I have come to terms with the fact that I misunderstood how \r\n" \
                                    "memory is laid out. I thought that each individual address was capable of storing an entire word, not just a byte \r\n" \
                                    "algorithm. Memory operates on words rather than bytes. In a 32-bit system, a word is typically 4 bytes, it\r\n"\
                                    "akes the same amount of time to read/write 1 byte as it does to read/write 1 word. The second loop is to   \r\n"\
                                    "Hello world Copy the logical and implementation_tsmc28hpm directories in to the Skadi home directory\r\n"\
                                    "1.pick what kind of geek you want to be there are different kinds of geeks such as sci fi and fantasy geek\r\n"\
                                    "#book geek manga geek and many more just be who you really are\r\n"\
                                    "2. Read lots of books. Some good geeky books include The Lord Of The Rings, Harry Potter, The Hunger Games,\r\n"\
                                    "I Robot and The Zombie Survival Guide. These can be found in your local library.\r\n"\
                                    "3.Be smart. Try to get an A in every subject except for PE.\r\n"\
                                    "4.Read geeky comics and graphic novels. You don't have to read superhero comics if you want to be geeky.\r\n"\
                                    "You can read Science Fiction, Fantasy, Horror or Comedy.\r\n"\
                                    "5.Watch geeky movies such as Shaun of The Dead, Star Trek, Doctor who, Revenge Of the Nerds, and Star Wars.\r\n"\
                                    "6.Know all things Star Trek. Captain Kirk's background, the fact that spock is a vulcan, and the vulcan salute are all things that a geek must know\r\n"\
                                    "7.Watch geeky series such as Doctor Who, Merlin and The Big Bang Theory.\r\n"\
                                    "8.Be good with computers. Learn a programming language and read books about computers.\r\n"\
                                    "9.Have geeky friends and a geeky hangout such as the book shop, the tabletop game shop, the comic shop and the computer shop.\r\n"\
                                    "10.A geek knows everything\"thinkgeek.com\". Thinkgeek is a website which holds everything a geek could want. A geek has an account on thinkgeek and has thinkgeek points.\r\n"\
                                    "11.A GEEK DOES NOT PLAY ROCK PAPER SCISSORS. A geek plays the famous game invented by Sheldon Cooper: rock-paper-scissors-lizard-Spock.\r\n"\
                                    "12.Buy some shirts from thinkgeek.com and wear Adidas slides.\r\n";
                        
                                    
int src_int[1786];              


    
#if test_attach

        
    pc.printf("start to test mehtod attach function now!\r\n");
        
    char src2[] = "this  is for test_attach test";
    wait(2);                
    size_t size = sizeof (src2);
    char *dst1  = (char *) malloc(size);
    memset (dst1, '\0', size);
    
    mynumber1.num = 3;  
    DMA dma1 (-1); // choose whichever free channel
    dma1.source (src2,1, 8); // set source as incremental. Not need to set the transfer width as MBED dma will do it for you.
    dma1.destination (dst1, 1, 8);
    dma1.attach_TC(test_mynumber);
    
      
    dma1.start(size);
    dma1.wait();
    pc.printf("finish");
    
#endif
    
#if test_m2m
    /* test the DMA M2M, copy data from src to dest, and then print out the dest mem data */

    pc.printf("start to test DMA M2M test now!\r\n");   
     // wait(1);                
    size_t size = sizeof(src);
    char *dst1  = (char *) malloc(size);
        
    char *dst2  = (char *) malloc(size);
    memset(dst1, '\0', size+1);
    memset(dst2, '\0', size+1);
    t.start();
    memcpy(dst1,src,size);
    t.stop();
    printf("The source size is %d\r\n", size);
    printf("The time CPU took was %f seconds\r\n", t.read());
    t.reset();

        
    DMA dma1(-1); // choose whichever free channel
    dma1.source(src,1, 8); // set source as incremental. Not need to set the transfer width as MBED dma will do it for you.
    dma1.destination(dst2, 1, 8);
    
    dma1.attach_TC(led_switchon_m2m);
    dma1.attach_Err(IRQ_err);
    t.start();
    dma1.start(size);
    dma1.wait();
    t.stop();
        
    pc.printf("The time DMA took was %f seconds\r\n", t.read());
    wait(5);
    pc.printf("dst text: %s \r\n", dst2);
    t.reset();
    if (strcmp(dst2, dst1) != 0)
    {
        pc.printf("error! \r\n");
        for (int i = 0; i < size +1; i++)
            if(dst1[i] != dst2[i])
                printf ("In the %d charator, dst1 is %c and dst2 is %c \r\n", i+1, dst1[i], dst2[i]);
    }
    else
        pc.printf("correct! \r\n");
#endif

#if test_m2m_int
    pc.printf("start to test DMA M2M test now!\r\n");
    // wait(1);     
    for (int i = 0; i < sizeof(src_int)/4; i++)
    src_int[i]=i; 
    size_t size = sizeof(src_int)/4;
    int *dst1  = (int *) malloc(sizeof(src_int)/4);
    int *dst2  = (int *) malloc(sizeof(src_int)/4);
    memset(dst1, '\0', size);
    memset(dst2, '\0', size);
    t.start();
    memcpy(dst1,src_int,size);
    t.stop();
    printf("The source size is %d\r\n", size);
    printf("The time CPU took was %f seconds\r\n", t.read());
    t.reset();

        
    DMA dma1(1); // choose whichever free channel
    dma1.source(src_int,1); // set source as incremental. Not need to set the transfer width as MBED dma will do it for you.
    dma1.destination(dst2, 1);
    
 // dma1.attach_TC(led_switchon_m2m);
//  dma1.attach_Err(IRQ_err);
    t.start();
    dma1.start(size);
    dma1.wait();
    t.stop();
        
    pc.printf("The time DMA took was %f seconds\r\n", t.read());
    wait(5);
    for (int i=0; i<sizeof(src_int)/4;i++)
    pc.printf("dst text: %d \r\n", dst2[i]);
    t.reset();
    if (memcmp(dst2, src_int, sizeof(src_int)/4) != 0)
        pc.printf("error! \r\n");
    else
        pc.printf("correct! \r\n");     
#endif      
        
#if test_LLI
        
    pc.printf ("start to test LLI now\r\n");

    wait(2);
    
    char src_dma[] = "This is to test the scatter-gather support \r\n";
    char src_LLI[] = "this is from linked item \r\n";
    LPC_UART0->FCR  |=  1<<3 ; //Enable UART DMA mode
    LPC_UART0->LCR &= ~(1<<3); // No parity bit generated 
        
    DMA dmaLLI(2);
    dmaLLI.destination(&(LPC_UART0->THR),0, sizeof(char)*8);    
    dmaLLI.source(src_dma,1, sizeof(char)*8);
    dmaLLI.TriggerDestination(_UART0_TX);
    dmaLLI.attach_TC(led_switchon_m2p);//  m2p_finishFlag will be set when FINISH interrupt generated
    dmaLLI.attach_Err(IRQ_err);

    dmaLLI.next((uint32_t)src_LLI, (uint32_t)&(LPC_UART0->THR), sizeof(src_LLI));
    // dmaLLI.next((uint32_t)src_LLI, (uint32_t)dst_LLI, 7);
    //  DMA dmaLLI2(3);
    //  dmaLLI2.next((uint32_t)src_LLI, (uint32_t)dst_LLI, 7);
    dmaLLI.start(sizeof(src_dma));
    dmaLLI.wait();
    while(1);
#endif  
        
        
        
#if test_m2p
    /*Test m2P, send the memory data to UART;*/ 
    pc.printf ("start to test m2p now\r\n");
        
    t.start();  
    pc.printf(src);
    t.stop();
    wait(1);
    printf("The time CPU took was %f seconds\r\n", t.read());
    wait(1);
    t.reset();
            
    LPC_UART0->FCR  |=  1<<3 ; //Enable UART DMA mode
    LPC_UART0->LCR &= ~(1<<3); // No parity bit genrated 
        
    DMA dma2(2);
    dma2.destination(&(LPC_UART0->THR),0, sizeof(char)*8);
    dma2.source(src,1, sizeof(char)*8);
    dma2.TriggerDestination(_UART0_TX);
    dma2.attach_TC(led_switchon_m2p);//  m2p_finishFlag will be set when FINISH interrupt generated
    dma2.attach_Err (IRQ_err);
    
    t.start();
    dma2.start(sizeof(src));
    dma2.wait();
    t.stop();
    printf("The time DMA took was %f seconds\r\n", t.read());
    printf("The transfer size is %d \r\n", sizeof(src));
    wait(2);
        
    pc.printf ("Now demonstrate CPU and DMA could work together\r\n");
    wait(1);
    m2p_finishFlag = 0;
    dma2.start(sizeof(src));
    // Demonstrate CPU and DMA could work together, led2 keep blinking while DMA is transferring data 
    
    while (!m2p_finishFlag){
        myled2 = !myled2;
        wait (0.2);
    }


    // Demonstrate Err interrupt callback also works
    // Dedicately read data from the unallocated memory range to generate error 
    wait (1);
    pc.printf ("Now demonstrate error interrupt callback also works\r\n");
    wait(2);
    dma2.attach_Err (IRQ_err);
    dma2.start((sizeof(src)+4)); 
    dma2.wait();
        
#endif

#if test_p2m
    
    pc.printf("start to test DMA P2M now!\r\n");
    wait(2);
    volatile unsigned int data = 0;
    unsigned int data2 = 0;
    volatile int *dst3  = (int *) malloc(4);
    old_ADC_init();

    NVIC_DisableIRQ(ADC_IRQn); // If ADC DMA is used, the ADC interrupt must be disabled    
    
    DMA dma3(3);
    dma3.destination(dst3, 0, 32); // Some sample codes show it should be half-word as only low 16bit contains the data. 
                                                                //  But I think it should be 32 as the reigster is 32-bit width 
    dma3.source(&(LPC_ADC->ADDR4),0, 32);
    dma3.TriggerSource(_ADC);
    dma3.attach_TC(led_switchon_p2m);
        
    while (1)
    {
      //  LPC_ADC->ADCR |= 1 << 24;// start the conversion now
        dma3.start(1);
        data= float(dst3[0]>>4 & 0xfff); // Only bit4-bit16 contains the valid ADC data
        data2 = ADC_read(4); // read ADC channel 4
        pc.printf("The ADC data of DMA is: %d\r\n", data);
        pc.printf("The ADC data of CPU is: %d\r\n", data2);
        wait (1);
    }
            
    pc.printf("\nFinish!\r\n");
#endif
    

        
        
#if test_p2p
    
    wait(2);
    volatile unsigned int data = 0;
    unsigned int data2 = 0;
    volatile unsigned int  raw_data = 0; 
    volatile int *dst3  = (int *) malloc(4);
    old_ADC_init();
    NVIC_DisableIRQ(ADC_IRQn); // If ADC DMA is used, the ADC interrupt must be disabled    
    
    LPC_UART0->FCR  |=  1<<3 ; //Enable UART DMA mode
    LPC_UART0->LCR &= ~(1<<3); // No parity bit genrated 
    
    DMA dma4(4);
    dma4.source(&(LPC_ADC->ADDR4),0, 32);
    dma4.destination(&(LPC_UART0->THR),0,8); 
   // dma4.destination(dst3, 0, 32);        
    dma4.TriggerSource(_ADC);
    dma4.TriggerDestination(_UART0_TX);
    dma4.attach_TC(led_switchon_p2p);

    while (1)
    {
        LPC_ADC->ADCR |= 1 << 24;// start the conversion now
        dma4.start(1);
    
    /*      
            data= float(dst3[0]>>4 & 0xfff); // Only bit4-bit16 contains the valid ADC data
              raw_data= (unsigned int )dst3[0] &0x7fffffff;
              pc.printf("The ADC data of raw data is: %d\r\n", raw_data);
              pc.printf("The ADC data of DMA is: %d\r\n", data);
        */  
          wait (3);
    }
            

    pc.printf("\nFinish!\r\n");
#endif
        
        


#if test_all
        
    DMA dma1 (1) ; 
    DMA dma2 (2);
    DMA dma3 (3);
        
    size_t size1 = sizeof (src);
    char *dst1  = (char *) malloc(size1);
    dma1.source (src,1); // set source as incremental. Not need to set the transfer width as MBED dma will do it for you.
    dma1.destination (dst1, 1);
    dma1.attach_TC(led_switchon_m2m) ;
    dma1.attach_Err (IRQ_err);
    


   // char src2[] = "This message was transmitted via UART DMA from memor";
        
    size_t size2 = sizeof (src);
    pc.printf("the size is %d",size2);
    wait(1);
    LPC_UART0->FCR  |=  1<<3 ; //Enable UART DMA mode
    LPC_UART0->LCR &= ~(1<<3); // No parity bit genrated 
    dma2.destination(&(LPC_UART0->THR),0, sizeof(char)*8);
    dma2.source(src,1, sizeof(char)*8);
    dma2.TriggerDestination(_UART0_TX);
    dma2.attach_TC(led_switchon_m2p);//  m2p_finishFlag will be set when FINISH interrupt generated
    dma2.attach_Err (IRQ_err);

 
    volatile unsigned int data = 0;
    volatile int *dst3  = (int *) malloc(128);
    ADC_init();
    NVIC_DisableIRQ(ADC_IRQn); // If ADC DMA is used, the ADC interrupt must be disabled    
    dma3.destination(dst3, 1, 32); // Some sample codes show it should be half-word as only low 16bit contains the data. 
                                                                //  But I think it should be 32 as the reigster is 32-bit width 
    dma3.source(&(LPC_ADC->ADDR0),0, 32);
    dma3.TriggerSource(_ADC);
    dma3.attach_TC(led_switchon_p2m);
    dma3.attach_Err (IRQ_err);
  

    dma1.start(size1);
    dma2.start(size2);
    dma3.start(32);

#endif

    while (1);
    return 0;
}


void ADC_init()
{
   // ensure power is turned on
    LPC_SC->PCONP |= (1 << 12);
    
    // set PCLK of ADC to 1
    LPC_SC->PCLKSEL0 &= ~(0x3 << 24);
    LPC_SC->PCLKSEL0 |= 1<<24;
    
    // select PIN 14, ADC 0.0
    LPC_PINCON->PINSEL1 &= (uint32_t) ~(0x3 << 14);
    LPC_PINCON->PINSEL1 |= 0x1 << 14;
    
    // PIN14 no pull-up, no pull-down 
    LPC_PINCON->PINMODE2 |= 0x2 << 28;
    
    // ADC conversion not start yet
    LPC_ADC->ADCR &= ~ (1 << 24);
    
    // the global DONE flat in ADDR must be disabled to generate an interrupt 
    LPC_ADC->ADINTEN &= ~(1<<8); 
    LPC_ADC->ADINTEN = 0x1;
     
    LPC_ADC->ADCR = (uint32_t)  ((1 << 21)  // ADC is operational  
                                  | (1 << 8) // APB clock is divided by 1
                                  | 0x01); // Select AD0.0 to be sampled and converted 
    

     LPC_ADC->ADCR |= 1 << 16 ; // BURST mode

}
    
void led_switchon_m2m(void)
{
    myled1=1;
}

void led_switchon_m2p(void)
{
    m2p_finishFlag = 1;
    myled2=1;
}

void led_switchon_p2m(void)
{
    myled3=1;
}

void led_switchon_p2p(void)
{
    myled4=1;
}

void IRQ_err (void)
{
    t.stop();
    pc.printf("The time DMA took was %f seconds\r\n", t.read());
    myled1 = 0;
    myled2 = 0;
    myled3 = 0;
    myled4 = 0;
    wait (0.5);   
    pc.printf ("\r\n");
    pc.printf ("Error Interrupt happens\r\n");
}


static inline int div_round_up(int x, int y)
{
    return (x + (y - 1)) / y;
}
void old_ADC_init()
{
    // ensure power is turned on
    LPC_SC->PCONP |= (1 << 12);

    /* p19 pin is set to ADC input.*/
    LPC_PINCON->PINSEL3 |= 0x30000000;
    /* no pull-up, no pull-down */
    LPC_PINCON->PINMODE3 |= 0x20000000;

    // set PCLK of ADC to 1
    LPC_SC->PCLKSEL0 &= ~(0x3 << 24);
    LPC_SC->PCLKSEL0 |= (0x1 << 24);
    uint32_t PCLK = SystemCoreClock;

    // calculate minimum clock divider
    // clkdiv = divider - 1
    uint32_t MAX_ADC_CLK = 13000000;
    uint32_t clkdiv = div_round_up(PCLK, MAX_ADC_CLK) - 1;
    
      
     LPC_ADC->ADCR &=  ~(1 << 0) // SEL: 0 = no channels selected  
                       & ~ (1 << 16) // No BURST mode
                       & ~(1 << 17)     // CLKS: not applicable
                       & ~(1 << 24); // ADC conversion not start yet
                                            
        
    LPC_ADC->ADINTEN = 1 <<8; 
    // Set the generic software-controlled ADC settings
    LPC_ADC->ADCR |= ( 24 << 8) // CLKDIV: PCLK max ~= 25MHz, /25 to give safe 1MHz at fastest         
                     | (1 << 21) ; // PDN: 1 = operational
   

    // Select the  channel 4 
    LPC_ADC->ADCR |= 1 << 4;
    // Start conversionf
    LPC_ADC->ADCR |= 1 << 24;
}

void burst_ADC_init()
{
    // ensure power is turned on
    LPC_SC->PCONP |= (1 << 12);

    /* p19 pin is set to ADC input.*/
    LPC_PINCON->PINSEL3 |= 0x30000000;
    /* no pull-up, no pull-down */
    LPC_PINCON->PINMODE3 |= 0x20000000;

    // set PCLK of ADC to 1
    LPC_SC->PCLKSEL0 &= ~(0x3 << 24);
    LPC_SC->PCLKSEL0 |= (0x1 << 24);
    uint32_t PCLK = SystemCoreClock;

    // calculate minimum clock divider
    // clkdiv = divider - 1
    uint32_t MAX_ADC_CLK = 13000000;
    uint32_t clkdiv = div_round_up(40000, MAX_ADC_CLK) - 1;
    
      
    LPC_ADC->ADCR &=  ~(1 << 0) // SEL: 0 = no channels selected  
                      & ~(1 << 17)     // CLKS: not applicable
                      & ~(1 << 24); // ADC conversion not start yet
                                            
    // ADGINTEN must be set to 0 in burst mode 
     LPC_ADC->ADINTEN &= ~(1<<8); 
    // Set the generic software-controlled ADC settings
    LPC_ADC->ADCR |= (clkdiv << 8)      // CLKDIV: PCLK max ~= 25MHz, /25 to give safe 1MHz at fastest  
                     | (1 << 16)  // Burst mode
                     | (1 << 21) ; // PDN: 1 = operational
   

    // Select the  channel 4 
    LPC_ADC->ADCR |= 1 << 4;
    // Start conversion
    LPC_ADC->ADCR |= 1 << 24;
}


uint32_t ADC_read(uint8_t channel)
{
    // Select the appropriate channel and start conversion
    LPC_ADC->ADCR &= ~0xFF;
    LPC_ADC->ADCR |= 1 << channel;
    LPC_ADC->ADCR |= 1 << 24;
    // Repeatedly get the sample data until DONE bit
    unsigned int data;

    do {
        data = LPC_ADC->ADGDR;
    } while ((data & ((unsigned int)1 << 31)) == 0);
    // Stop conversion
    LPC_ADC->ADCR &= ~(1 << 24);
    return (data >> 4) & 0xfff; // 12 bit
    }