Author Topic: HELP ATSAMD21 ADC bare code  (Read 9423 times)

0 Members and 1 Guest are viewing this topic.

Offline OliverKTopic starter

  • Contributor
  • Posts: 19
  • Country: nl
  • student electrical engineering
HELP ATSAMD21 ADC bare code
« on: June 07, 2017, 02:52:21 pm »
For a school project i need to read out different sensors, with the ADC pins on the Atsamd21j18a (explained pro user board). The sensor needs to be connected to PA03 (AIN1), 12 bit ADC and adc prescaler is 64 (with using a 8m osc as clock source). I have written a code, but is cant read out a result. So my question is does anybody know what i doing wrong in my code???? I used asf but get a lot of problems with it.

With the help of the following links i have written my code:

https://www.eevblog.com/forum/microcontrollers/dac-sam-d21-bare-code-driver/

http://community.atmel.com/forum/samd21-adc-interrupt-routine

http://www.avrfreaks.net/forum/adc-conversion-asf-sam-d10-xplained-board-doesnt-work

https://github.com/Molorius/ATSAMD21-ADC/blob/master/ATSAMD21_ADC.h

I put an extra function in configOSC8M(); in there with should be the same as this part in te ADCinit(); function ->
GCLK->CLKCTRL.reg = GCLK_CLKCTRL_ID(DAC_GCLK_ID) |   GCLK_CLKCTRL_CLKEN | GCLK_CLKCTRL_GEN(0);

i tried using both but im still not getting a result?

https://github.com/ataradov/mcu-starter-projects/tree/master/samd21, i used this project as a starter (because it had adc.h include files in the project).
« Last Edit: June 07, 2017, 04:21:56 pm by OliverK »
 

Offline ataradov

  • Super Contributor
  • ***
  • Posts: 11260
  • Country: us
    • Personal site
Re: HELP ATSAMD21 ADC bare code
« Reply #1 on: June 07, 2017, 04:54:59 pm »
You never actually call ADC_readValue() in your code. Forget about interrupts for now, and make the code work with polling first.

My GitHub has plenty of sample code. This is exactly what you are looking for https://github.com/ataradov/dgw/blob/master/embedded/adc.c
Alex
 
The following users thanked this post: blueskull, OliverK

Offline OliverKTopic starter

  • Contributor
  • Posts: 19
  • Country: nl
  • student electrical engineering
Re: HELP ATSAMD21 ADC bare code
« Reply #2 on: June 15, 2017, 02:31:29 pm »
sorry for my late comment but:

ADC->CALIB.reg = ADC_CALIB_BIAS_CAL(NVM_READ_CAL(ADC_BIASCAL)) |
ADC_CALIB_LINEARITY_CAL(NVM_READ_CAL(ADC_LINEARITY));

in your code i found this, the file doesnt reqonise ADC_BIASCAL and ADC LINEARITY is it possible to commment this out
 

Offline ataradov

  • Super Contributor
  • ***
  • Posts: 11260
  • Country: us
    • Personal site
Re: HELP ATSAMD21 ADC bare code
« Reply #3 on: June 15, 2017, 03:16:44 pm »
You can remove them, but then calibration will be off. I don't know if it matters to you or not.
Alex
 

Offline OliverKTopic starter

  • Contributor
  • Posts: 19
  • Country: nl
  • student electrical engineering
Re: HELP ATSAMD21 ADC bare code
« Reply #4 on: June 15, 2017, 04:04:42 pm »
Yes i want callibation, but i get errrors that those variables arnt delcleard. Did do declear them somewear?

When i leave them out i dont get the wrigth adc values, with gain of 1 and i use pa02 (ain0) as positive pin and GND and ground as negitive pin, with a 12 bit adc, and INTVCC1 as vref (1.65 volts)

when i put a voltage of 1 volts on the pin it reads 260, i use the seriele terminal to read out the value of the adc

Code: [Select]
#include <stdlib.h>
#include <stdint.h>
#include <stdbool.h>
#include <string.h>
#include "samd21.h"
#include "hal_gpio.h"

#include "math.h"
//
// void reverse(char *str, int len);
// void ftoa(float n, char *res, int afterpoint);
// int intToStr(int x, char str[], int d);

//-----------------------------------------------------------------------------
#define PERIOD_FAST     100
#define PERIOD_SLOW     500

HAL_GPIO_PIN(LED,      B, 30)
HAL_GPIO_PIN(BUTTON,   A, 15)
HAL_GPIO_PIN(UART_TX,  A, 22)
HAL_GPIO_PIN(UART_RX,  A, 23)

//-----------------------------------------------------------------------------

//-----------------------------------------------------------------------------
static void uart_init(uint32_t baud)
{
uint64_t br = (uint64_t)65536 * (F_CPU - 16 * baud) / F_CPU;

HAL_GPIO_UART_TX_out();
HAL_GPIO_UART_TX_pmuxen(PORT_PMUX_PMUXE_C_Val);
HAL_GPIO_UART_RX_in();
HAL_GPIO_UART_RX_pmuxen(PORT_PMUX_PMUXE_C_Val);

PM->APBCMASK.reg |= PM_APBCMASK_SERCOM3;

GCLK->CLKCTRL.reg = GCLK_CLKCTRL_ID(SERCOM3_GCLK_ID_CORE) |
GCLK_CLKCTRL_CLKEN | GCLK_CLKCTRL_GEN(0);

SERCOM3->USART.CTRLA.reg =
SERCOM_USART_CTRLA_DORD | SERCOM_USART_CTRLA_MODE_USART_INT_CLK |
SERCOM_USART_CTRLA_RXPO(1/*PAD1*/) | SERCOM_USART_CTRLA_TXPO(0/*PAD0*/);

SERCOM3->USART.CTRLB.reg = SERCOM_USART_CTRLB_RXEN | SERCOM_USART_CTRLB_TXEN |
SERCOM_USART_CTRLB_CHSIZE(0/*8 bits*/);

SERCOM3->USART.BAUD.reg = (uint16_t)br;

SERCOM3->USART.CTRLA.reg |= SERCOM_USART_CTRLA_ENABLE;
}

//-----------------------------------------------------------------------------
static void uart_putc(char c)
{
while (!(SERCOM3->USART.INTFLAG.reg & SERCOM_USART_INTFLAG_DRE));
SERCOM3->USART.DATA.reg = c;
}

//-----------------------------------------------------------------------------
static void uart_puts(char *s)
{
while (*s)
uart_putc(*s++);
}

//-----------------------------------------------------------------------------
static void sys_init(void)
{
// Switch to 8MHz clock (disable prescaler)
SYSCTRL->OSC8M.bit.PRESC = 0;

// Enable interrupts
asm volatile ("cpsie i");
}

void adc_init(void);
int adc_read(void);
//-----------------------------------------------------------------------------
int main(void)
{
uint32_t cnt = 0;
bool fast = false;

sys_init();
timer_init();

uart_init(115200);
adc_init();
uint16_t value123 = adc_read();
char str[16];
itoa(value123, str, 10);
uart_puts(str);

while (1)
{
}
return 0;
}

/*- Definitions -------------------------------------------------------------*/
HAL_GPIO_PIN(ADC,      A, 2)

/*- Implementations ---------------------------------------------------------*/

//-----------------------------------------------------------------------------
void adc_init(void)
{
HAL_GPIO_ADC_in();
HAL_GPIO_ADC_pmuxen(HAL_GPIO_PMUX_B);

PM->APBCMASK.reg |= PM_APBCMASK_ADC;

GCLK->CLKCTRL.reg = GCLK_CLKCTRL_ID(ADC_GCLK_ID) |
GCLK_CLKCTRL_CLKEN | GCLK_CLKCTRL_GEN(0);

ADC->CTRLA.reg = ADC_CTRLA_SWRST;
while (ADC->CTRLA.reg & ADC_CTRLA_SWRST);

ADC->REFCTRL.reg = ADC_REFCTRL_REFSEL_INTVCC1 | ADC_REFCTRL_REFCOMP;

ADC->CTRLB.reg = ADC_CTRLB_RESSEL_12BIT | ADC_CTRLB_PRESCALER_DIV32;
ADC->AVGCTRL.reg = ADC_AVGCTRL_SAMPLENUM_128;

ADC->INPUTCTRL.reg = ADC_INPUTCTRL_MUXPOS_PIN0 | ADC_INPUTCTRL_MUXNEG_GND |
ADC_INPUTCTRL_GAIN_1X;

ADC->CALIB.reg = ADC_CALIB_BIAS_CAL(NVM_READ_CAL(ADC_BIASCAL)) |
ADC_CALIB_LINEARITY_CAL(NVM_READ_CAL(ADC_LINEARITY));

ADC->CTRLA.reg = ADC_CTRLA_ENABLE;
}

HAL_GPIO_PIN(X, B, 17)

//-----------------------------------------------------------------------------
int adc_read(void)
{
HAL_GPIO_X_out();
HAL_GPIO_X_set();

ADC->SWTRIG.reg = ADC_SWTRIG_START;
while (0 == (ADC->INTFLAG.reg & ADC_INTFLAG_RESRDY));

HAL_GPIO_X_clr();

return ADC->RESULT.reg;
}

 

Offline ataradov

  • Super Contributor
  • ***
  • Posts: 11260
  • Country: us
    • Personal site
Re: HELP ATSAMD21 ADC bare code
« Reply #5 on: June 15, 2017, 04:31:28 pm »
Here is a file that declares them. But you can just read the datasheet, and make declarations yourself. The goal is to read calibration parameters from the calibration area.
Alex
 

Offline OliverKTopic starter

  • Contributor
  • Posts: 19
  • Country: nl
  • student electrical engineering
Re: HELP ATSAMD21 ADC bare code
« Reply #6 on: June 15, 2017, 05:44:54 pm »
Yeah now its seems to work, but the 12 bit ADC still doesnt give me the orrect value, but in 16 bit mode it does.
When i apply 1,55 V to PA02 the 12 bit adc (with and without sampling on)  give an adc value between thr 700 and 800, so i devided this bij 4096 and multiply that with 1,65 i get 0.3 V, but when i do in 16 bit mode i get 62175 / 65536 * 1.65 = 1,56 volt. What im looking for.

An other question is i want to calibrate the ADC, first i apply 0 volt to that adc input and want to load somewear for the offset, next i want to apply a voltage to determane the gain. with thes values i want to do a better adc calaculation.

In asf there is a good example of this (look below). But in your code where do i store there value to?



Code: [Select]
const uint16_t expected_value
= ((ADC_12BIT_FULL_SCALE_VALUE + 1) * ADC_CALIBRATION_IN_VOLTAGE) / (ADC_CALIBRATION_REF_VOLTAGE);

/* Captured value for gain correction */
static uint16_t captured_value;

if (correction_measures_done == false) {

printf("\n*ADC offset correction:\n");
printf("Set PA2 pin to 0 Volt(GND).\n");
printf("Press any key to trigger measurement.\n");

getchar();

/* Capture ADC result for 0 Volt */

offset_correction = adc_start_read_result();

adc_get_config_defaults(&conf_adc);

printf("ADC Offset measurement in progress...\n");

gain_corr = ((ADC_12BIT_FULL_SCALE_VALUE + 1) * 1) / 1;

/* Enable offset correction */
conf_adc.correction.correction_enable = true;
conf_adc.correction.gain_correction = gain_corr;
conf_adc.correction.offset_correction = offset_correction;

adc_init(&adc_instance, ADC, &conf_adc);

adc_enable(&adc_instance);
printf("ADC Offset measurement complete.\n");

printf("*ADC Gain correction\n");
printf("Set PA2 pin to 1.55 Volt");
printf("Press a key to trigger measurement.\n");

getchar();

/* Capture ADC result for 1.55 Volts */
captured_value = adc_start_read_result();

correction_measures_done = true;
}

/* Enable offset & gain correction */
adc_get_config_defaults(&conf_adc);
printf("ADC Gain correction in progress...\n");

gain_corr = (2048L * expected_value) / captured_value;

conf_adc.correction.correction_enable = true;
conf_adc.correction.gain_correction = gain_corr;
conf_adc.correction.offset_correction = offset_correction;

adc_init(&adc_instance, ADC, &conf_adc);

adc_enable(&adc_instance);
 

Offline ataradov

  • Super Contributor
  • ***
  • Posts: 11260
  • Country: us
    • Personal site
Re: HELP ATSAMD21 ADC bare code
« Reply #7 on: June 15, 2017, 05:51:33 pm »
You put them exactly where you just read the factory calibration settings.

What are your exact settings for both 12-bit and 16-bit mode?
Alex
 

Offline OliverKTopic starter

  • Contributor
  • Posts: 19
  • Country: nl
  • student electrical engineering
Re: HELP ATSAMD21 ADC bare code
« Reply #8 on: June 15, 2017, 06:40:41 pm »
i only changed the: ADC_CTRLB_RESSEL_16BIT to ADC_CTRLB_RESSEL_12BIT, one time i commented out ADC->AVGCTRL.reg = ADC_AVGCTRL_SAMPLENUM_128; but it didnt help really (in the 12 bit mode)


Code: [Select]
void adc_init(void)
{
HAL_GPIO_ADC_in();
HAL_GPIO_ADC_pmuxen(HAL_GPIO_PMUX_B);

PM->APBCMASK.reg |= PM_APBCMASK_ADC;

GCLK->CLKCTRL.reg = GCLK_CLKCTRL_ID(ADC_GCLK_ID) |
GCLK_CLKCTRL_CLKEN | GCLK_CLKCTRL_GEN(0);

ADC->CTRLA.reg = ADC_CTRLA_SWRST;
while (ADC->CTRLA.reg & ADC_CTRLA_SWRST);

ADC->REFCTRL.reg = ADC_REFCTRL_REFSEL_INTVCC1 | ADC_REFCTRL_REFCOMP;

ADC->CTRLB.reg = ADC_CTRLB_RESSEL_16BIT | ADC_CTRLB_PRESCALER_DIV32;
ADC->AVGCTRL.reg = ADC_AVGCTRL_SAMPLENUM_128;

ADC->INPUTCTRL.reg = ADC_INPUTCTRL_MUXPOS_PIN0 | ADC_INPUTCTRL_MUXNEG_GND |
ADC_INPUTCTRL_GAIN_1X;

ADC->CALIB.reg = ADC_CALIB_BIAS_CAL(NVM_READ_CAL(ADC_BIASCAL)) |
ADC_CALIB_LINEARITY_CAL(NVM_READ_CAL(ADC_LINEARITY));

ADC->CTRLA.reg = ADC_CTRLA_ENABLE;
}
 

Offline ataradov

  • Super Contributor
  • ***
  • Posts: 11260
  • Country: us
    • Personal site
Re: HELP ATSAMD21 ADC bare code
« Reply #9 on: June 15, 2017, 07:52:02 pm »
I'm not sure what exactly going on, but when you enable averaging, there is some automatic division happens as well.

So I would just play with different averaging numbers, just to see if there is any difference in the result.
Alex
 
The following users thanked this post: OliverK

Offline OliverKTopic starter

  • Contributor
  • Posts: 19
  • Country: nl
  • student electrical engineering
Re: HELP ATSAMD21 ADC bare code
« Reply #10 on: June 17, 2017, 12:50:25 pm »
Its seems to work now if i do lower sampleing setting.

I was working on calibrations of the ADC, i wrote s simle function that calibrates and read the new voltage. The values get printed in the seriele monitor. The offset en the captured value get printed, but the result value keeps printing 0, dont really understand why? look at pitcher

Code: [Select]
void configure_ADC(void)
{
uart_puts("\n wanted value at 1,55 V =");
// expected value at a given voltage, this example is 1,55V
const uint16_t expectedvalue = ((ADC_16BIT_FULL_SCALE_VALUE + 1) * ADC_CALIBRATION_IN_VOLTAGE) / (ADC_CALIBRATION_REF_VOLTAGE);
itoa(expectedvalue, str, 10);
uart_puts(str);

if (mesuments_done == false)
{
uart_puts("\r\n Starting calibration\r\n");
uart_puts("\n Apply 0V to pin PA02 (AIN0) to determine OFFSET value");

while(button_pressed == false) // wait unit user pressed the button
{
if (HAL_GPIO_BUTTON_read())
cnt = 0;
else if (cnt < 5001)
cnt++;

if (5000 == cnt)
{
button_pressed = true;
}
}

button_pressed = false;

Offset_correction = adc_read();

uart_puts("\n Measured offset == \t");
itoa(Offset_correction, str, 10);
uart_puts(str);

uart_puts("\nApply 1.55V to pin PA02 (AIN0) to determine gain correction\n");

while(button_pressed == false) // wait unit user pressed the button
{
if (HAL_GPIO_BUTTON_read())
cnt = 0;
else if (cnt < 5001)
cnt++;

if (5000 == cnt)
{
button_pressed = true;
}
}
button_pressed = false;
uart_puts("\n");

capturedvalue = adc_read() - Offset_correction;

itoa(capturedvalue, str, 10);
uart_puts(str);

if (capturedvalue > expectedvalue ) // gain lager then > 1
{
gain_correctionf = expectedvalue / capturedvalue ;
gain_correctionf = gain_correctionf *  10000; // to go from float to interger so 0.9999 would be 9999.9
gain_correctionI = gain_correctionf; // so gain_correctionI would be 9999

}
else
{
gain_correctionf = capturedvalue / expectedvalue ;
gain_correctionf = gain_correctionf * 10000; //
gain_correctionI = gain_correctionf;
}
uart_puts("\n Captured Value after Calibration \t");

mesuments_done = true;
}

Result_value = ((adc_read() - Offset_correction) * gain_correctionI ) / 10000;

itoa(Result_value, str, 16);

uart_puts(str);
}

In main i got this

Code: [Select]
>:D uart_puts("\r\nValue before adc configurations\r\n");
uint16_t result_waarde = adc_read();
itoa(result_waarde, str, 10);
uart_puts(str);

configure_ADC();


U said that it was possible to to put these value into the ADC_BIAS_CAL and ADC_LINERY_CAL. But how to i do that ?
« Last Edit: June 17, 2017, 12:52:50 pm by OliverK »
 

Offline ataradov

  • Super Contributor
  • ***
  • Posts: 11260
  • Country: us
    • Personal site
Re: HELP ATSAMD21 ADC bare code
« Reply #11 on: June 17, 2017, 05:38:15 pm »
Section "33.6.10 Offset and Gain Correction" of the datasheet describes how to do that. You will have to convert your gain and offset values to a range that ADC can work with and write then into corresponding registers.

Of you can just continue to do that in the software, allowing for more flexibility.
Alex
 

Offline OliverKTopic starter

  • Contributor
  • Posts: 19
  • Country: nl
  • student electrical engineering
Re: HELP ATSAMD21 ADC bare code
« Reply #12 on: June 19, 2017, 07:34:41 pm »
Oke thanks for your responce, if i want to do it my way: Do you know why i cant print the result (see previous attacht code)? its the line with result_value, it just prints 0. i defined result_value as a uint_16t so it should work?

 
Quote
  if (capturedvalue > expectedvalue ) // gain lager then > 1
  {
   gain_correctionf = expectedvalue / capturedvalue ;
   gain_correctionf = gain_correctionf *  10000; // to go from float to interger so 0.9999 would be 9999.9
   gain_correctionI = gain_correctionf; // so gain_correctionI would be 9999
  }
  else
  {
   gain_correctionf = capturedvalue / expectedvalue ;
   gain_correctionf = gain_correctionf * 10000; //
   gain_correctionI = gain_correctionf;
  }
  uart_puts("\n Captured Value after Calibration \t");
  mesuments_done = true;
 }
 Result_value = ((adc_read() - Offset_correction) * gain_correctionI ) / 10000;
 itoa(Result_value, str, 16);
 uart_puts(str);
 

Offline ataradov

  • Super Contributor
  • ***
  • Posts: 11260
  • Country: us
    • Personal site
Re: HELP ATSAMD21 ADC bare code
« Reply #13 on: June 19, 2017, 08:09:58 pm »
Start by printing adc_read().

I also don't understand that calibration logic, but that's something to figure out later.
Alex
 

Offline OliverKTopic starter

  • Contributor
  • Posts: 19
  • Country: nl
  • student electrical engineering
Re: HELP ATSAMD21 ADC bare code
« Reply #14 on: June 21, 2017, 03:26:02 pm »
the print of ADC read works:

Code: [Select]
uint16_t result_waarde = adc_read();
itoa(result_waarde, str, 10);
uart_puts(str);

THis is what i want to do:

1. First i calaclulate the voltage that i need to have at a given point (in my case 1,55 volt so is 61565 in dec with 16 bit adc)

Quote
   uart_puts("\n wanted value at 1,55 V =");
   // expected value at a given voltage, this example is 1,55V
   const uint16_t expectedvalue = ((ADC_16BIT_FULL_SCALE_VALUE + 1) * ADC_CALIBRATION_IN_VOLTAGE) / (ADC_CALIBRATION_REF_VOLTAGE);
   
   itoa(expectedvalue, str, 10);
   uart_puts(str);

2. then apply 0V to the adc pin, if i have done that i press the butten, en that value that the adc measures is the offset value.

Code: [Select]
uart_puts("\n Apply 0V to pin PA02 (AIN0) to determine OFFSET value");  // not printing this line

while(button_pressed == false) // wait unit user pressed the button
{
if (HAL_GPIO_BUTTON_read())
cnt = 0;
else if (cnt < 5001)
cnt++;

if (5000 == cnt)
{
button_pressed = true;
}
}

button_pressed = false;

Offset_correction = adc_read();

uart_puts("\n Measured offset == \t");
itoa(Offset_correction, str, 10);
uart_puts(str);

3 then i calculate the gain correction. I do this by beginning to this by taking a new adc measument and subsituting the offset-correction of it. this value i called captued value. The next thing is that i the captured value is lager of smaller then my expected value (actualy i should also look if their equal but for now it doesnt matter). If the captured value is greater then my expected value, i dived the expectedvalue/capteured value = 0.xxx floating point number. I want to stick to using intergers for the uart because then i can use the itoa function and converting float is lots more work. So i multiply this number with 10000 so i get 9812.5 (if the value was 0.98125). Then i place this value into an interger i get 9812.

Code: [Select]
while(button_pressed == false) // wait unit user pressed the button
{
if (HAL_GPIO_BUTTON_read())
cnt = 0;
else if (cnt < 5001)
cnt++;

if (5000 == cnt)
{
button_pressed = true;
}
}
button_pressed = false;
uart_puts("\n");

capturedvalue = adc_read() - Offset_correction;

itoa(capturedvalue, str, 10);
uart_puts(str);

if (capturedvalue > expectedvalue ) // gain lager then > 1
{
gain_correctionf = expectedvalue / capturedvalue ;
gain_correctionf = gain_correctionf *  10000; // to go from float to interger so 0.9999 would be 9999.9
gain_correctionI = gain_correctionf; // so gain_correctionI would be 9999


}
else
{
gain_correctionf = capturedvalue / expectedvalue ;
gain_correctionf = gain_correctionf * 10000; //

gain_correctionI = gain_correctionf;

}
uart_puts("\n Captured Value after Calibration \t");

mesuments_done = true;

4. the i do the calibrated adc  so  i ( (read_adc - offset_correction)
 * gaincorrection /10000:


so for exmple if the adc read 62136 , offset is 180

so the captured value is 61965, then i dived 61565/61956 (because captured value is lager then expected value), this result in a 0.99369 float value * 10000 = 9936.9 is the offsetcorrection float value, in the interger this will be 9936.

so this should result in (62136 -180) * 9936 /1000 = 61559 witch is almost the value that i want

Code: [Select]
Result_value = ((adc_read() - Offset_correction) * gain_correctionI ) / 10000;

itoa(Result_value, str, 16);

uart_puts(str);

But its keeps printing 0? SO what am i doing wrong?
 

Offline ataradov

  • Super Contributor
  • ***
  • Posts: 11260
  • Country: us
    • Personal site
Re: HELP ATSAMD21 ADC bare code
« Reply #15 on: June 21, 2017, 03:47:18 pm »
So what are all the intermediate values? You know what to expect, why not print intermediate results and see where is all goes wrong?

I don't know types for everything, but for example this code:
Code: [Select]
  gain_correctionf = expectedvalue / capturedvalue ;
  gain_correctionf = gain_correctionf *  10000; // to go from float to interger so 0.9999 would be 9999.9
will yield 0 if everything is integer. And even if gain_correctionf is a float, but expectedvalue and capturedvalue are integers, you will still get 0.

If you want to stay in an integer-only arithmetic (and you really do on Cortex-M0), you should rewrite this code like this:
Code: [Select]
  gain_correctionf = (expectedvalue *10000) / capturedvalue ;
And keep in mind ranges for types you are using. I also suggest to use 'int' type for all values. It is not 8-bit world, there is no benefit in using non 32-bit values.
« Last Edit: June 21, 2017, 04:04:25 pm by ataradov »
Alex
 
The following users thanked this post: OliverK

Offline OliverKTopic starter

  • Contributor
  • Posts: 19
  • Country: nl
  • student electrical engineering
Re: HELP ATSAMD21 ADC bare code
« Reply #16 on: June 21, 2017, 08:28:24 pm »
Thank u it works now almost perfect,  the expected value was 61565 and i got now 61533 so that i good enough for me for now.

I got an sensor (analog) connected to an instrumental amplifier, I want to connect the output of the instrumental amplifier to the adc input, one input is connected to the sensor en the other input is connected to the dac of the samd21. I got your dac code and got it working fine.

Now i want that i can input a value in the uart (8bit), in the program im going to multiply it by 10 so i can get a higer value (for example if i enter 10 in the uart, the dac shoud output a voltage of 100 mV)

So this should work for reading out value of the uart?

Code: [Select]
static void uart_readc(void)
{
while(!(SERCOM3->USART.INTFLAG.reg & SERCOM_USART_INTFLAG_RXC));
edbg_rx_data = SERCOM3->USART.DATA.reg;
}

IN A Other code i found this but what is the differance:

they had these items addes to their usart_init (i adaped it a little bit)

Code: [Select]
/* SERCOM3 handler enabled */
NVIC_EnableIRQSERCOM3_IRQn);  // was this system_interrupt_enable(SERCOM3_IRQn);

/* receive complete interrupt set */
SERCOM3->USART.INTENSET.reg = SERCOM_USART_INTFLAG_RXC;

void SERCOM3_Handler()
{
if (SERCOM3->USART.INTFLAG.bit.RXC){
edbg_rx_data = SERCOM3->USART.DATA.reg;
}
}

 

Offline ataradov

  • Super Contributor
  • ***
  • Posts: 11260
  • Country: us
    • Personal site
Re: HELP ATSAMD21 ADC bare code
« Reply #17 on: June 21, 2017, 08:49:36 pm »
The difference is that one is blocking, and nothing else will run while it waits for a character, and the other one is interrupt-based and will let other code to execute.

For the second one you will also need to wait for edbg_rx_data to be filled by the interrupt.
Alex
 

Offline OliverKTopic starter

  • Contributor
  • Posts: 19
  • Country: nl
  • student electrical engineering
Re: HELP ATSAMD21 ADC bare code
« Reply #18 on: June 22, 2017, 08:24:42 pm »
it works fine now thank u, i have one last question.

If i want to add more adc pin to my project, i want to read 2 adc

is this possible?

Code: [Select]
Adc_init();
adc_read();  // this is PA10
ADC->INPUTCTRL.reg = ADC_INPUTCTRL_MUXPOS_PIN1 | ADC_INPUTCTRL_MUXNEG_GND
ADC_INPUTCTRL_GAIN_1X;  //init PA03 (ain1)as adc input

adc_read(); // read the value of PA03 ain1

or is it better to make 2 seperate adc_init funcitions, and call then after eatchother?
 

Offline ataradov

  • Super Contributor
  • ***
  • Posts: 11260
  • Country: us
    • Personal site
Re: HELP ATSAMD21 ADC bare code
« Reply #19 on: June 22, 2017, 08:28:46 pm »
Just change your read function to take a channel number and set mux before reading the value.
Alex
 

Offline OliverKTopic starter

  • Contributor
  • Posts: 19
  • Country: nl
  • student electrical engineering
Re: HELP ATSAMD21 ADC bare code
« Reply #20 on: June 29, 2017, 07:37:42 pm »
Sorry for my late responce, but i had it verry busy with examens, so i didnt have any time to finish this project, but i had some time today.

My read adc funciton doest work now, not able to switch from differant adc ports. I dont know why, it keep giving me errors that there is a invalid number into HAL_GPIO funciton.

Quote
inn my main function i got this

   adc_init();
   adc_read(18, 10); // ADC pin 18 is microconroller pin PA10

Code: [Select]
int adc_read(uint8_t selectadcchannel, uint8_t microcontrollerpin)
{
ADC->INPUTCTRL.reg |= (selectadcchannel << ADC_INPUTCTRL_MUXPOS_Pos);

HAL_GPIO_PIN(ADC,     A, microcontrollerpin)

HAL_GPIO_ADC_in();
HAL_GPIO_ADC_pmuxen(HAL_GPIO_PMUX_B);

HAL_GPIO_X_out();
HAL_GPIO_X_set();

ADC->SWTRIG.reg = ADC_SWTRIG_START;
while (0 == (ADC->INTFLAG.reg & ADC_INTFLAG_RESRDY));

HAL_GPIO_X_clr();

return ADC->RESULT.reg;
}

What am i doing wrong?
 

Offline ataradov

  • Super Contributor
  • ***
  • Posts: 11260
  • Country: us
    • Personal site
Re: HELP ATSAMD21 ADC bare code
« Reply #21 on: June 29, 2017, 07:44:54 pm »
Quote
HAL_GPIO_PIN(ADC,     A, microcontrollerpin)
This should even compile. Look at wehat HAL_GPIO_PIN() macro does. You can only define it in the outside scope. And you don't need to enable PMUX every time. Just do it once in the initialization code for all the pins you plan to use.
Alex
 

Offline OliverKTopic starter

  • Contributor
  • Posts: 19
  • Country: nl
  • student electrical engineering
Re: HELP ATSAMD21 ADC bare code
« Reply #22 on: July 10, 2017, 07:38:24 pm »
Yeah i managed to get it to work im able now to read out 2 adc port . Many thanks for your help. I changed your HAL_GPIO function in the main to set pin config direct, i used it twice for eitch pin i made one, and one to for adc_init. Could make also 1 adc_init code but that is just tweeking.

Code: [Select]
void adc_pin_init2(void) // PA02 AIN00
{
//#define HAL_GPIO_PIN(name, port, pin)
//#define HAL_GPIO_PORTA       0 #define HAL_GPIO_PORTB       1 #define HAL_GPIO_PORTC       2

//#define HAL_GPIO_PMUX_A      0
//#define HAL_GPIO_PMUX_B      1 #define HAL_GPIO_PMUX_C      2 #define HAL_GPIO_PMUX_D      3 #define HAL_GPIO_PMUX_E      4
//#define HAL_GPIO_PMUX_F      5 #define HAL_GPIO_PMUX_G      6 #define HAL_GPIO_PMUX_H      7 #define HAL_GPIO_PMUX_I      8

//HAL_GPIO_PIN(ADC,      A, 03)
//HAL_GPIO_ADC_in();
PORT->Group[0].DIRCLR.reg = (1 << 2);
PORT->Group[0].PINCFG[2].reg |= PORT_PINCFG_INEN;
PORT->Group[0].PINCFG[2].reg &= ~PORT_PINCFG_PULLEN;

//HAL_GPIO_ADC_pmuxen(HAL_GPIO_PMUX_B);
PORT->Group[0].PINCFG[2].reg |= PORT_PINCFG_PMUXEN;
if (2 & 1)
PORT->Group[0].PMUX[2>>1].bit.PMUXO = 1;
else
PORT->Group[0].PMUX[2>>1].bit.PMUXE = 1;

}

In de attatchment ive put my total code i hope it will be use to someon els. ive commented out the DAC, but you can un comment it if u want to use it
 

Offline ataradov

  • Super Contributor
  • ***
  • Posts: 11260
  • Country: us
    • Personal site
Re: HELP ATSAMD21 ADC bare code
« Reply #23 on: July 10, 2017, 08:04:22 pm »
I don't understand why you needed to do any of this.

All you have to do is initialize both pins at startup using HAL_GPIO_xxx(); macros. And then in do something like this:

//-----------------------------------------------------------------------------
int adc_read(int channel)
{
   HAL_GPIO_X_out();
   HAL_GPIO_X_set();

   if (1 == channel)
   {
      ADC->INPUTCTRL.reg = ADC_INPUTCTRL_MUXPOS_PIN0 | ADC_INPUTCTRL_MUXNEG_GND |
         ADC_INPUTCTRL_GAIN_1X;
   }
   else
   {
      ADC->INPUTCTRL.reg = ADC_INPUTCTRL_MUXPOS_PIN18 | ADC_INPUTCTRL_MUXNEG_GND |
         ADC_INPUTCTRL_GAIN_1X;
   }

   ADC->SWTRIG.reg = ADC_SWTRIG_START;
   while (0 == (ADC->INTFLAG.reg & ADC_INTFLAG_RESRDY));

   HAL_GPIO_X_clr();

   return ADC->RESULT.reg;
}


And keep one initialization code.
Alex
 

Offline OliverKTopic starter

  • Contributor
  • Posts: 19
  • Country: nl
  • student electrical engineering
Re: HELP ATSAMD21 ADC bare code
« Reply #24 on: July 10, 2017, 10:07:30 pm »
I tried something like that, but the problem was with the muliplexing

If i wanted to read 2 pins, i needed to pin marcos:
Quote
HAL_GPIO_PIN(ADC,      A, 03)
HAL_GPIO_PIN(ADC,      A, 10)

I even made i function that enters the pin number, see previous post.

But then i would get errors.

I coulld give it another shot....
 


Share me

Digg  Facebook  SlashDot  Delicious  Technorati  Twitter  Google  Yahoo
Smf