8000 Add adc driver nrf52 · Pull Request #7515 · RIOT-OS/RIOT · GitHub
[go: up one dir, main page]
More Web Proxy on the site http://driver.im/
Skip to content

Add adc driver nrf52 #7515

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 4 commits into from
Closed

Add adc driver nrf52 #7515

wants to merge 4 commits into from

Conversation

ghost
Copy link
@ghost ghost commented Aug 25, 2017

This PR includes the ADC driver for nrf52.
Based on PR #7501.

@haukepetersen haukepetersen added Platform: ARM Platform: This PR/issue effects ARM-based platforms Type: new feature The issue requests / The PR implemements a new feature for RIOT State: waiting for other PR State: The PR requires another PR to be merged first labels Aug 25, 2017
@haukepetersen haukepetersen added this to the Release 2017.10 milestone Aug 25, 2017
@haukepetersen
Copy link
Contributor

I think there are quite some things in the adc_sample funcitons, that might as well be moved into the adc_init function, so that they don't have to be computed/written on every call to sample.

int adc_sample(adc_t line, adc_res_t res)
{
int val;

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

add assert(line < ADC_NUMOF);

NRF_SAADC->CH[0].PSELP = adc_config[line] + 1;
NRF_SAADC->CH[0].CONFIG = (SAADC_CH_CONFIG_GAIN_Gain1_4 << SAADC_CH_CONFIG_RESN_Pos) |
(SAADC_CH_CONFIG_REFSEL_VDD1_4 << SAADC_CH_CONFIG_REFSEL_Pos);
NRF_SAADC->RESOLUTION = res - 1;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this could lead to a negative res value (in case res := 0)? Why not override adc_res_t for the CPU, so that it takes exactly the values allowed/needed?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@haukepetersen Yes, of course.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also here...

prep();

/* set line, resolution and use VDD (+5V) as reference */
NRF_SAADC->CH[0].PSELP = adc_config[line] + 1;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this should most likely be NRF_SAADC->CH[line]..., right?!

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I thougth it must be line?!

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I thought it must be line?!


/* set the data pointer */
NRF_SAADC->RESULT.PTR = (uint32_t)&val;
NRF_SAADC->RESULT.MAXCNT = 1;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why not use a static global var instead of val? Then you can program RESULT.PTR once during adc_init() and don't have to care about it ever again.

NRF_SAADC->RESULT.MAXCNT = 1;

/* calibrate the SAADC */
NRF_SAADC->TASKS_CALIBRATEOFFSET = 1;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Calibration should be only carried out once during initialization, or not?!

/* start the SAADC and wait for the started event */
NRF_SAADC->TASKS_START = 1;
while (NRF_SAADC->EVENTS_STARTED == 0) {}
NRF_SAADC->EVENTS_STARTED = 0;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the safer variant here (and below) would be:

    NRF_SAADC->EVENTS_STARTED = 0;
    NRF_SAADC->TASKS_START = 1;
    while (NRF_SAADC->EVENTS_STARTED == 0) {}

/* free device */
done();

if (val > (1 << 15)) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what is this about? The maximum resolution is 14-bit, so this is always false.

*/
#define ADC_CONFIG {0, 4, 5, 6} /* BAT, POT, LIGHT, TEMP */
#define ADC_NUMOF (4)
/** @} */
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We could actually remove this block (and the need for board specific configuration for this driver), and simply always map all available (8) channels in order to RIOT adc lines. So using ADC_LINE(x) will always map to the NRFs line x.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Then we just need to define ADC_NUMOF in the CPUs periph_cpu.h and we are done.

/**
* @brief Load the ADC configuration
*/
static const uint8_t adc_config[] = ADC_CONFIG;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This also is not needed anymore if we simply map all ADC channels per default.

@ghost
Copy link
Author
ghost commented Aug 30, 2017

@haukepetersen new commit :)

@@ -116,6 +126,7 @@ typedef enum {
ADC_RES_14BIT = 0xf2, /**< ADC resolution: 14 bit */
ADC_RES_16BIT = 0xf3 /**< ADC resolution: 16 bit */
} adc_res_t;
#endif
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

looking at this now, I think we should move the typedefs into nrf51/periph_cpu.h and nrf52/periph_cpu.h. That way there is no need for an #ifdef anymore...

@smlng
Copy link
Member
smlng commented Oct 5, 2017

please squash

@smlng smlng added the CI: needs squashing Commits in this PR need to be squashed; If set, CI systems will mark this PR as unmergable label Oct 5, 2017
@tcschmidt
Copy link
Member

Can we get this completed for the release?

< 67ED /option>

@ghost
Copy link
Author
ghost commented Oct 6, 2017

I guess so.

@haukepetersen
Copy link
Contributor

Hm, did you significantly change the implementation from the first time I reviewed this? The current implementation is quite inefficient in both run-time and resource usage! Why do you always sample all configured channels if we are only interested in the result of a single one? The way the ADC interface is build, there is just no need for that!

@ghost
Copy link
Author
ghost commented Oct 9, 2017

37.5.1 One-shot mode
One-shot operation is configured by enabling only one of the available channels defined by CH[n].PSELP,
CH[n].PSELN, and CH[n].CONFIG registers.
Upon a SAMPLE task, the ADC starts to sample the input voltage. The CH[n].CONFIG.TACQ controls the
acquisition time.
A DONE event signals that one sample has been taken.
In this mode, the RESULTDONE event has the same meaning as DONE when no oversampling takes place.
Note that both eve A3DB nts may occur before the actual value has been transferred into RAM by EasyDMA. For more information, see EasyDMA on page 361.

37.5.4 Scan mode
A channel is considered enabled if CH[n].PSELP is set. If more than one channel, CH[n], is enabled, the
ADC enters scan mode.

In scan mode, one SAMPLE task will trigger one conversion per enabled channel. The time it takes to
sample all channels is:
Total time < Sum(CH[x].tACQ+tCONV), x=0..enabled channels
A DONE event signals that one sample has been taken.
In this mode, the RESULTDONE event signals has the same meaning as DONE when no oversampling
takes place. Note that both events may occur before the actual values have been transferred into RAM by
EasyDMA.

Therefore?! How else we should handle it?

@haukepetersen
Copy link
Contributor

Therefore?! How else we should handle it?

It is one thing what the hardware has to offer, but another what the interface is abstracting. In our case, the ADC interface is only providing access to the most simple one-shot mode, so there is no need to implement any scan mode behavior in the driver -> the driver should simply implement the functionality needed to comply with the interface in the most efficient way possible!

@ghost
Copy link
Author
ghost commented Oct 9, 2017

Yeah, I'm understand.
But it will not work, if you use more than one ADC channel.

@haukepetersen
Copy link
Contributor

But it will not work, if you use more than one ADC channel.

Yes, it will and does. See https://github.com/dnahm/RIOT/pull/1

@tcschmidt
Copy link
Member
F438 tcschmidt commented Oct 10, 2017

What is the status: are we progressing here?

@ghost
Copy link
Author
ghost commented Oct 12, 2017

@haukepetersen How should we continue?

@haukepetersen
Copy link
Contributor

What is the status: are we progressing here?

depends on the angle.

How should we continue?

How about you look at the changes I proposed and you merge them into your branch if you find them valid? Then its just a matter of verifying the changes and we can merge this PR I would say.

cpu/nrf52: optimized and fixed ADC driver
@haukepetersen
Copy link
Contributor

closing in favor of #7985. This was agreed upon offline with @PeterKietzmann and @dnahm

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
CI: needs squashing Commits in this PR need to be squashed; If set, CI systems will mark this PR as unmergable Platform: ARM Platform: This PR/issue effects ARM-based platforms State: waiting for other PR State: The PR requires another PR to be merged first Type: new feature The issue requests / The PR implemements a new feature for RIOT
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants
0