steven niu
/
test_mDMA
test codes to test DMA features
Diff: main.cpp
- Revision:
- 0:9b2f77afaacd
- Child:
- 1:5b946b818a29
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/main.cpp Mon Mar 09 21:47:50 2015 +0000 @@ -0,0 +1,655 @@ +/** +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 + }