How to read 6 analog inputs through ADC continuously and print them to the console screen

cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

How to read 6 analog inputs through ADC continuously and print them to the console screen

3,254 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by Getdan35 on Thu Nov 14 06:28:19 MST 2013
/*
===============================================================================
Name        : main.c
Author      : $(author)
Version     :
Copyright   : $(copyright)
Description : main definition
===============================================================================
*/

#ifdef __USE_CMSIS
#include "LPC17xx.h"
#endif
#include <cr_section_macros.h>
#include <stdio.h>

/* A/D Converter 0 (ADC0) */
#define AD0_BASE_ADDR  0x40034000
#define AD0CR          (*(volatile unsigned long *)(AD0_BASE_ADDR + 0x00))
#define AD0GDR         (*(volatile unsigned long *)(AD0_BASE_ADDR + 0x04))
#define AD0INTEN       (*(volatile unsigned long *)(AD0_BASE_ADDR + 0x0C))
#define AD0DR0         (*(volatile unsigned long *)(AD0_BASE_ADDR + 0x10))
#define AD0DR1         (*(volatile unsigned long *)(AD0_BASE_ADDR + 0x14))
#define AD0DR2         (*(volatile unsigned long *)(AD0_BASE_ADDR + 0x18))
#define AD0DR3         (*(volatile unsigned long *)(AD0_BASE_ADDR + 0x1C))
#define AD0DR4         (*(volatile unsigned long *)(AD0_BASE_ADDR + 0x20))
#define AD0DR5         (*(volatile unsigned long *)(AD0_BASE_ADDR + 0x24))
#define AD0DR6         (*(volatile unsigned long *)(AD0_BASE_ADDR + 0x28))
#define AD0DR7         (*(volatile unsigned long *)(AD0_BASE_ADDR + 0x2C))
#define AD0STAT        (*(volatile unsigned long *)(AD0_BASE_ADDR + 0x30))
#define ADTRIM         (*(volatile unsigned long *)(AD0_BASE_ADDR + 0x34))

int ADC_Val1, ADC_Val2;
double v1,v2;

// TODO: insert other definitions and declarations here
void initADC()
{
LPC_SC->PCONP |= (1<<12); //Turn on ADC power and clock
LPC_PINCON->PINSEL1 |= (1<<14); //P0.23 is connected to AD0.0
LPC_PINCON->PINSEL1 |= (1<<16); //P0.24 is connected to AD0.1
LPC_PINCON->PINSEL1 |= (1<<18); //P0.25 is connected to AD0.2
LPC_PINCON->PINSEL1 |= (1<<20); //P0.26 is connected to AD0.3
LPC_PINCON->PINSEL3 |= (3<<28); //P1.30 is connected to AD0.4
LPC_PINCON->PINSEL3 |= (3<<30); //P1.31 is connected to AD0.5
LPC_PINCON->PINSEL0 |= (2<<6);  //P0.3 is connected to AD0.6
LPC_PINCON->PINSEL0 |= (2<<4);  //P0.2 is connected to AD0.7

AD0CR |= (1<<0); // select operating mode
AD0CR |= (1<<21);// set to 1 so converter is operational

}
int readADC()
{
AD0CR |= (1<<24);//START CONVERSION
while((AD0CR & (1<<31)==0));//WAIT FOR END OF CONVERSION
return ((AD0GDR>>4)&0xfff);//SHIFT TO RIGHT 4 BITS GLOBAL REGISTER
}


int main(void) {

    // TODO: insert code here
printf("ADC TEST");
initADC();
    volatile static int i = 0 ; // Force the counter to be placed into memory


    while(1)
{
ADC_Val1=readADC();
v1 = (3.13/4096)*ADC_Val1;
printf("ADC0: %.2lf\n", v1);
}
    return 0 ;
}
Can read one input ok but not sure how to go about reading 6 at same time?

Please help
Labels (1)
0 Kudos
16 Replies

2,279 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by Pacman on Wed Nov 27 10:27:07 MST 2013
To be honest, I've never used the UART/USART on the LPC. I have other things I need to work on, before I can look at the UART/USART. This is mainly because I do not have a serial port on my computer.

What I would suggest is that you start a new thread, and use the [color=#060][[/color][color=#060]code][/color] ... [color=#060][[/color][color=#060]/code][/color] tags in order to make your post readable.
0 Kudos

2,279 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by Getdan35 on Wed Nov 27 06:16:05 MST 2013
Hi Pacman

I have a uart example working with a terminal receiving dummy data im sending, I can only see 2 examples in lpc175x_6x/Examples and i find them hard to follow. Is there any examples that show a adc-uart example. Converting data through the adc then sending it through the uart to the terminal window displaying the data. Any help will be much appreciated. This is just basically printing test to the terminal over and over.

while (1)
{
UARTSend (3,"Test\r\n",6);

if ( UART3Count != 0 )
{
LPC_UART3->IER = IER_THRE | IER_RLS;/* Disable RBR */
UARTSend(3, (uint8_t *)UART3Buffer, UART3Count );
UART3Count = 0;
LPC_UART3->IER = IER_THRE | IER_RLS | IER_RBR;/* Re-enable RBR */
}
}


Im wondering where do i read the adc inputs and then send. Even a tip to read and send one would be great.
0 Kudos

2,279 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by Pacman on Wed Nov 27 01:19:49 MST 2013
I think you'll find around 9 UART examples in the lpc175x_6x/Examples directory.
Try out the different examples. The interrupt example might be a good choice.
When you've built one of those examples, you should be able to set up your PC with a terminal and receive some data.
After that, you can modify the example, or you can apply the UART code to your ADC project.
0 Kudos

2,279 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by Getdan35 on Mon Nov 25 08:26:33 MST 2013
Thanks for the reply Pacman you explained it very well, now i need to use this data from the ADC to send it through the Uart and display it on a terminal.

Any good examples out there?
0 Kudos

2,279 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by Pacman on Fri Nov 22 03:28:57 MST 2013

Quote:
What do these do
LPC_PINCON->PINSEL1 |= (1 << 14); //P0.23 is connected to AD0.0
LPC_PINCON->PINMODE1 |= (1 << 15);//Set PINMODE of AD0.0 as no pull-up/down resistors
LPC_PINCON->PINSEL1 |= (1 << 16); //P0.24 is connected to AD0.1
LPC_PINCON->PINMODE1 |= (1 << 17);
LPC_PINCON->PINSEL1 |= (1 << 18); //P0.25 is connected to AD0.2
LPC_PINCON->PINMODE1 |= (1 << 19);


Can you give me an example of how these work as i dont think they are really explained well in lpc17xx guide.
Not sure how to set the Pinmodes?



I'll go into detail about these; not because it's complicated, but because I'd like you to get a good foundation from the beginning.

In UM10360, the entire Chapter 8 (starting on page 104) is about setting up the pin functions (connection, mode, etc.)
In section 8.3, we find table 75. It's a list of possible values for the PINSEL values. Each PINSEL register is 32 bits wide and two bits are used per pin, thus a PINSEL register can hold information for up to 16 pins.
In section 8.4, we find table 76, this table lists possible values for each pin in the PINMODE registers.
Table 77 explains how to put a pin in Open Drain mode.

Now go to section 8.5.1 (page 108). You'll find table 79, which lists detailed information about PINSEL0.
In the heading, we see "PINSEL0", "Function when 00", "Function when 01", "Function when 10", "Function when 11" and "Reset value".
-But you don't find P0_23 and friends there. You'll have to scroll down to the next table, table 80, which is detailed information about PINSEL1.
We'll find that pin P0_23 is configured using bits 14 and 15. By default, this pin is set to function 00 (see Reset value), so in order to make it work as an ADC pin, we'll have to change its function...
[list]
  [*]Function 00 is GPIO Port 0.23 (aka GPIO0[23])
  [*]Function 01 is AD0.0 (aka AD0[0])
  [*]Function 10 is I2SRX_CLK (this is used if you want to send data to an audio DAC)
  [*]Function 11 is CAP3.0 (timer capture pin)
[/list]
As we're interested in the ADC functionality, we want to set the pin to use Function 01.

Remember the following procedure, you're going to use it many times:
[color=#00f]Now open the file lpc175x_6x/Core/Device/NXP/LPC17xx/Include/LPC17xx.h[/color]

[color=#00f]Search for the word "PINSEL"
You will find a structure called LPC_PINCON_TypeDef. It contains PINSEL0, PINSEL1, PINSEL2, etc...
It also contains PINMODE0, PINMODE1, PINMODE2, etc...  - and PINMODE_OD0, etc...
Now search for LPC_PINCON_TypeDef. You'll of course find the same structure, but search for the next occurrence, and you will find a line that looks like this:[/color]
[color=#00f]#define LPC_PINCON            ((LPC_PINCON_TypeDef    *) LPC_PINCON_BASE   )[/color]


[color=#00f]This sets up LPC_PINCON to point to a LPC_PINCON_TypeDef structure at address LPC_PINCON_BASE.
It creates a convenient way to access the PINCON registers.[/color]

[color=#00f]Now open the file lpc175x_6x/Drivers/include/lpc17xx_pinsel.h
Scroll through the file and notice the #define names. We'll use those names, in order to make our source-code readable.[/color]

OK, let's set the value of our PINSEL1 register...
Imagine that you might have set up other pin functions already. You do not want to ruin those settings, so instead of writing the full 32-bit value, you first read the value, modify it and write it back.
This can be done using logical AND and logical OR:
LPC_PINCON->PINSEL1 = (LPC_PINCON->PINSEL1 & ~(3 << (PINSEL_PIN_7 << 1))) | (PINSEL_FUNC_1 << (PINSEL_PIN_7 << 1));


Now that looks a bit messy, so we'll now make a few #define lines ourselves, to make configuring a little neater.
#define PINFUNC(p,f)((f) << ((p) << 1))
#define PINMODE(p,m)PINFUNC((p),(m))
#define CONMASK(r,p)(LPC_PINCON->r & ~PINFUNC(p,3))


LPC_PINCON->PINSEL1 = CONMASK(PINSEL1, PINSEL_PIN_7) | PINFUNC(PINSEL_PIN_7, PINSEL_FUNC_1);


Now, in UM10360, find section 8.5.10, table 88...
This is the detailed information on the PINMODE1 register. Again, we'll find our P0_23MODE is configured using bits 14 and 15 and the default mode is 00. We'll follow the reference and look at P0.00 to find out what the different modes are.
We don't want a pull-up or a pull-down enabled, nor do we want repeater mode, so we'll use mode 10.
Let's look in lpc17xx_pinsel.h again and see what the name for that mode is, search for PINMODE...

...alright, it seems we've found the desired pinmode there.
You can use the #defines from above in order to set the mode correctly:
LPC_PINCON->PINMODE1 = CONMASK(PINMODE1, PINSEL_PIN_7) | PINMODE(PINSEL_PIN_7, desiredmode);

-where 'desiredmode' is one of the modes you've found in the lpc17xx_pinsel.h header file.

If we wanted to change the Open Drain configuration of the pin, we could do it this way:
LPC_PINCON->PINMODE_OD1 |= (PINSEL_PINMODE_OPENDRAIN << PINSEL_PIN_7);

-But it appears it's not necessary, since we just tristated the pin anyway - so we don't want to change that.
0 Kudos

2,279 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by Getdan35 on Thu Nov 21 06:02:25 MST 2013
Im working with the LPC1769FBD100 on the  LPCXpesso board. I see your in europe also good man. I got it reading all 6 pins but have half of them are 0.2 volts out of the actual reading. Tried to post my code yesterday but it was blocked by the spam filter, dont know why? I have that UM10360 manual downloaded and its what i've being using. My next step to try send this data using a uart. Any good examples out there,

Daniel
0 Kudos

2,279 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by Pacman on Thu Nov 21 00:06:19 MST 2013
Those lines configure your pins.
Each pin can be configured to do one of several functions.

If you haven't done so yet, please download the manual for your microcontroller.
Here are some examples:
[list]
  [*] For LPC177x and LPC178x: UM10470.
  [*] For LPC175x and LPC176x: UM10360.
[/list]
The User's Manual contains all the information you need for the microcontroller.

Now, in order to be able to help you any further, you'll need to let me know which microcontroller you are working with.
0 Kudos

2,278 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by Pacman on Wed Nov 20 23:01:45 MST 2013
Click my name, and you'll see my location.
A good time to catch me online is probably difficult, but I check for forum posts, sometimes every day, but sometimes I may not be online for a week or two.
0 Kudos

2,278 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by Getdan35 on Wed Nov 20 10:55:36 MST 2013
What do these do
LPC_PINCON->PINSEL1 |= (1 << 14); //P0.23 is connected to AD0.0
LPC_PINCON->PINMODE1 |= (1 << 15);//Set PINMODE of AD0.0 as no pull-up/down resistors
LPC_PINCON->PINSEL1 |= (1 << 16); //P0.24 is connected to AD0.1
LPC_PINCON->PINMODE1 |= (1 << 17);
LPC_PINCON->PINSEL1 |= (1 << 18); //P0.25 is connected to AD0.2
LPC_PINCON->PINMODE1 |= (1 << 19);

Can you give me an example of how these work as i dont think they are really explained well in lpc17xx guide.
Not sure how to set the Pinmodes?
0 Kudos

2,278 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by Getdan35 on Wed Nov 20 07:32:18 MST 2013
Hey Pacman, where about are you and when would be a good time to catch you online?
0 Kudos

2,278 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by Pacman on Tue Nov 19 09:43:29 MST 2013
First of all, I'd like to mention, just in case you don't know it already, that there is a User's Manual for the LPC177x and LPC178x.
It is called UM10470 and can be found right here.

Next: Please make sure you have the LPC178x_7x libraries from NXP, they can be downloaded from here. Look inside the folder, especially in the "Examples" folder and the "Drivers" folder. It is very helpful.


Quote: Getdan35

while((LPC_ADC->ADDR0 & (1<<31)) == 0);        change to ADDR1 AND SO ON UP TO ADDR5 reads AD0.0 up to AD0.5
return ((LPC_ADC->ADDR0 >> 4) & 0xFFF);        change to ADDR1 AND SO ON UP TO ADDR5
LPC_ADC->ADCR |= (1 << 2); //WILL SELECT BIT ADO.2 AND TURN IT ON and this is done up to (1 << 5)



OK, here you are switching channels, which I believe is the correct way.
-But it seems you are not doing it correctly.
If you look at the source code for ADC_ChannelCmd (lpc177x_8x/Drivers/source/lpc177x_8x_adc.c), you will see how NXP is doing it.

In short:
[list]
  [*]To disable a channel, you have to stop the channel first.
  [*]Then you disable the channel.
  [*]After that, you enable your new channel.
  [*]Finally you start the new channel.
[/list]

Try this sequence:
LPC_ADC->CR &= ~ADC_CR_START_MASK;/* stop whichever channel is running */
LPC_ADC->CR &= ~0xff;/* disable all channels */
LPC_ADC->CR |= (1 << (channel & 7));/* enable the new channel */
LPC_ADC->CR |= ADC_CR_START_MODE_SEL(ADC_START_NOW);



Quote:
I have not done C in years so im very rusty at it. I'm not even sure what you mean by code tags.



OK. I'll explain... In this forum, you can use code-tags to mark that your code-snippets are to be formatted in a special way.
Here is an example:
[color=#060][[/color][color=#060]code][/color]int main(int argc, const char *argv[])
{
printf("Hello World!\n");
return(0);
}[color=#060][[/color][color=#060]/code][/color]
...results in...
int main(int argc, const char *argv[])
{
printf("Hello World!\n");
return(0);
}

...So it's much easier to read.


Quote:
Your help is very much appreciated Pacman.


Thank you. I hope that it results in that you get everything to work the way you want it to.


Quote:
Im not sure what to do in the while loop to read each input one after the other.


You might want to use the 4-step sequence above, and then increment 'channel'.


Quote:
For example when i set a pinsel1 pin do i have to unset it before i read next pin.


Nope. Your program would be quite huge if you had to.


Quote:
Ive tried even just to read 2 inputs one after the other but it get stuck in while loop after reading AD0.0.


Uhm, yes, I've heard of similar situations. I think it's related to not stopping the channel before moving on to the next one.


Quote:
Maybe you could add me on skype and we can share screens if your not to busy.


Sorry, can't do skype. The computers here are not supported by skype...


Quote:
What does Pinmode actually do?


It configures your pins to do the precise function that you specify.
Each pin can be configured to do one out of many functions.
By default, a pin is configured as a GPIO pin, which is very useful for many things.
But some pins can be configured to work as a UART/USART RxD pin (so it can be used for receiving data via for instance RS232), some can be configured for TxD (UART transmit data), some can be configured for I2C operations, some for I2S, etc.
In this case, you've chosen to configure your pins for the ADC. Please note, that when they're configured for ADC, they are no longer 5V tolerant.
0 Kudos

2,278 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by Getdan35 on Tue Nov 19 06:13:26 MST 2013
Hey Pacman

I can only switch between the different inputs by changing

while((LPC_ADC->ADDR0 & (1<<31)) == 0);        change to ADDR1 AND SO ON UP TO ADDR5 reads AD0.0 up to AD0.5
return ((LPC_ADC->ADDR0 >> 4) & 0xFFF);        change to ADDR1 AND SO ON UP TO ADDR5
LPC_ADC->ADCR |= (1 << 2); //WILL SELECT BIT ADO.2 AND TURN IT ON and this is done up to (1 << 5)
LPC_PINCON->PINSEL1 |= (1<<14);
LPC_PINCON->PINSEL1 |= (1<<14); //P0.23 is connected to AD0.0
LPC_PINCON->PINSEL1 |= (1<<16); //P0.24 is connected to AD0.1
LPC_PINCON->PINSEL1 |= (1<<18); //P0.25 is connected to AD0.2 // to read AD0.2 I SELECT THIS PINSEL1
LPC_PINCON->PINSEL1 |= (1<<20); //P0.26 is connected to AD0.3
LPC_PINCON->PINSEL3 |= (3<<28); //P1.30 is connected to AD0.4
LPC_PINCON->PINSEL3 |= (3<<30); //P1.31 is connected to AD0.5

I basically have it set up to read one input but i just edit the code to read different inputs individually and it reads them fine. I have not done C in years so im very rusty at it. I'm not even sure what you mean by code tags(((. Sorry. Your help is very much appreciated Pacman.
Im not sure what to do in the while loop to read each input one after the other. For example when i set a pinsel1 pin do i have to unset it before i read next pin. Ive tried even just to read 2 inputs one after the other but it get stuck in while loop after reading AD0.0. Maybe you could add me on skype and we can share screens if your not to busy. Getdan1 is my name there. What does Pinmode actually do?
0 Kudos

2,278 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by Pacman on Mon Nov 18 10:43:30 MST 2013
Please use [color=#009][[/color][color=#009]code][/color] ... [color=#009][[/color][color=#009]/code][/color] tags.


Quote: Getdan35
Ive attached code that works fine but only reads one input but i can switch between any input from ADO.O TO ADO.5



Can you give an example on how you 'switch' between those inputs ?
0 Kudos

2,278 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by Getdan35 on Mon Nov 18 08:39:45 MST 2013
Thanks for the reply Pacman, i dont want to use channels or interrupts. I just want to switch between registers, like ADDR0 to ADDR5, READ first register which is attached to AD0.0 and print result to console. Ive attached code that works fine but only reads one input but i can switch between any input from ADO.O TO ADO.5 and it will print the correct value but now i just want it to read all registers in a loop and print them to console.

#include "LPC17xx.h"


int ADC_Val1, ADC_Val2; //ADC_Val3; ADC_Val4; ADC_Val5; ADC_Val6;
double v1,v2; //v3;v4;v5;v6;
void initADC()
{
//A/D Converter is powered on
LPC_SC->PCONP |= 1<<12;

//set P0.23 as AD0.0
LPC_PINCON->PINSEL1 |= (1<<14); //P0.23 is connected to AD0.0
LPC_PINCON->PINSEL1 |= (1<<16); //P0.24 is connected to AD0.1

//Set PINMODE of AD0.0 as no pull-up/down resistors
//LPC_PINCON->PINMODE1 |= (2 << 14);
//select AD0.0, CLKDIV = 4+1 => 25MHz/5 = 5MHz < 13MHz, power on
LPC_ADC->ADCR |= (1 << 0) | (1 << 21);
}

int readADC()
{
//start conversion
LPC_ADC->ADCR |= (1 << 24);

//wait for conversion to finish by checking ADGDR.31
while((LPC_ADC->ADDR0 & (1<<31)) == 0);

//return conversion result
return ((LPC_ADC->ADDR0 >> 4) & 0xFFF);
}

// Enter an infinite loop, just incrementing a counter

volatile static int i = 0 ;
int main(void)
{
printf("ADC CHANNEL TEST");
initADC();
while(1)
{
ADC_Val1=readADC();
v1 = (3.13/4096.0)*ADC_Val1;
printf("\nADC0: %.2lf", v1);
}

return 0 ;
}
0 Kudos

2,278 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by Pacman on Fri Nov 15 14:15:29 MST 2013
I'll try and answer your questions with questions amd suggestions, rather than solutions, in order to train you in finding the problems.


Quote: Getdan35
Can read one input ok but not sure how to go about reading 6 at same time?



Please wrap your code in [color=#030][[/color][color=#030]code][/color] / [color=#030][[/color][color=#030]/code][/color] tags.
(two include files are missing)

I see that you....
#include "lpc17xx.h"

...But you don't use anything from it. If you did, your code-snippet would be very short, and it would perhaps be portable to other devices as well.
Hint: Look for LPC_ADC_TypeDef.
while(!(val & ADC_DR_DONE_FLAG))
{
val = LPC_ADC->ADDR0;
}
val = ADC_DR_RESULT(val);


It's a very good idea to use the #defines from your libraries (you don't have to use the libraries, just the definitions).
#include "lpc17xx_adc.h"

If you do that, people who want to help you, do not have to decode your #defines and check that they are correct.

-But if you can use the libraries, I definitely recommend using the ADC_Init(...) function they provide. Your code-snippet can be very, very short if you do.

You might want to take a look at "lpc17xx_adc.c"; there are a lot of useful functions and this file tells you more or less how to use them.

If you want to read ADC values from multiple ADC pins, try switching between the pins.
See ADC_ChannelCmd for an example on how to switch channels correctly. (stop channel, disable channel, enable channel)

Buggy debug-code can be some of the most frustrating things to work with, and these bugs are often not spoken of.
[color=#00f]If no matter what you try and nothing seems to help, try checking that your debug-code actually works.[/color]
Actually its even better to verify that your debug-code works, before you start looking for bugs.

If you do any calculations like these...
v1 = (3.13/4096)*ADC_Val1;

...I'd recommend that you multiply first, then divide later, perhaps avoid using floats and doubles completely, so you only use them when they are really necessary.

What's the result of (1 / 100) * 300 ?
What's the result of ((1 * 300) / 100) ?
What's the result of (3.13 / 4096) ?
What's the result of (ADC_VAL1 * 3130) /  4096 ?
0 Kudos

2,278 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by Getdan35 on Thu Nov 14 06:29:46 MST 2013
If your out there EX zero i need your help
0 Kudos