Skip to content
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

Unable to capture adc signal at 8ksps when using nrf52840dk board. #28469

Closed
Navin-Sankar opened this issue Sep 17, 2020 · 6 comments
Closed
Assignees
Labels
area: ADC Analog-to-Digital Converter (ADC)

Comments

@Navin-Sankar
Copy link
Member

Navin-Sankar commented Sep 17, 2020

Describe the bug
When trying to capture adc signal at 8ksps it captures only 1000 samples per second.

To Reproduce
Steps to reproduce the behavior:

  1. west build -b nrf52840dk_nrf52840
  2. west flash

Expected behavior
nrf52840 should capture 8000 samples

Impact
Cannot capture 8000 samples. It capture's only 1000 samples per second

Code

#include <drivers/adc.h>
#include <string.h>
#include <zephyr.h>
#include <stdio.h>

#include <hal/nrf_saadc.h>

#define CLOCK_DEVICE_NAME	DT_LABEL(DT_INST(0, nordic_nrf_clock))
#define ADC_DEVICE_NAME		DT_LABEL(DT_INST(0, nordic_nrf_saadc))
#define ADC_RESOLUTION		14
#define ADC_GAIN		ADC_GAIN_1_6
#define ADC_REFERENCE		ADC_REF_INTERNAL
#define ADC_ACQUISITION_TIME    ADC_ACQ_TIME(ADC_ACQ_TIME_MICROSECONDS, 10)
#define ADC_1ST_CHANNEL_ID      0
#define ADC_1ST_CHANNEL_INPUT   NRF_SAADC_INPUT_AIN1

static const struct adc_channel_cfg m_1st_channel_cfg = {
	.gain 			= ADC_GAIN,
	.reference		= ADC_REFERENCE,
	.acquisition_time 	= ADC_ACQUISITION_TIME,
	.channel_id		= ADC_1ST_CHANNEL_ID,
	.input_positive		= ADC_1ST_CHANNEL_INPUT,
};

#define BUFFER_SIZE 	8000
int16_t m_sample_buffer[BUFFER_SIZE];

const struct adc_sequence_options options = {
	.extra_samplings	= (BUFFER_SIZE - 1),	/* No of Samples to be captured */
	.interval_us		= 125,  		              /* Time interval between Samples */
};

const struct adc_sequence sequence = {
	.channels	= BIT(ADC_1ST_CHANNEL_ID),
	.buffer		= m_sample_buffer,
	.options	= &options,
	.buffer_size	= sizeof(m_sample_buffer),
	.resolution	= ADC_RESOLUTION,
};

int main()
{
	int ret, i;
	int64_t time_stamp, milliseconds_spent;
	const struct device *adc_dev = device_get_binding(ADC_DEVICE_NAME);
	if (adc_dev < 0) {
		printk("failed to get adc device\n");	
	}

	ret = adc_channel_setup(adc_dev, &m_1st_channel_cfg);
	if (ret < 0) {
		printk("Failed to setup channel 1 \n");
	}

	while (1) {
		(void)memset(m_sample_buffer, 0, sizeof(m_sample_buffer));
		
		time_stamp = k_uptime_get();

		ret = adc_read(adc_dev, &sequence);
		if (ret < 0) {
			printk("Failed to read adc\n");
			return -1;
		}

		milliseconds_spent = k_uptime_delta(&time_stamp);

#if 1	
		for (i = 11500; i < BUFFER_SIZE; i++) {
			int16_t sample_value = m_sample_buffer[i];
			printk("%d \n", sample_value);
		}
#endif
		printk("Milliseconds_spent: %lld\n", milliseconds_spent);
		k_sleep(K_MSEC(5000));
		printk("Next Sample\n");
	}
}

In the above code channel 0 is initialized to capture adc signal at 125us as a sampling interval. Theroritically it should capture 8000 samples, but it capture's only 1000 sample. If I change the buffer size to 12000 and time period to 83us, that time also it capture's only 1000 samples.

when setting sampling interval_us as 0, it capture's all samples based on the buffer size at 180ms. Can't achieve the precision when trying to sample particular frequency.

By default nrf52840dk board uses low frequency clock(32KHz) as system clock.

CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC=32768

How to switch the clock from LF to HF to capture more samples precisely.

@Navin-Sankar Navin-Sankar added bug The issue is a bug, or the PR is fixing a bug area: ADC Analog-to-Digital Converter (ADC) question labels Sep 17, 2020
@carlescufi carlescufi removed the bug The issue is a bug, or the PR is fixing a bug label Sep 17, 2020
@Navin-Sankar
Copy link
Member Author

Navin-Sankar commented Oct 1, 2020

Here the timer always generate the interrupt in ms to sample the adc signal.

k_timer_start(&ctx->timer, K_NO_WAIT, K_MSEC(interval_ms));
.

uint32_t interval_ms = ceiling_fraction(interval_us, 1000UL);

ceiling_factor also result the time in ms. That why it captures only 1000 samples per second.

@anangl
Copy link
Member

anangl commented Oct 1, 2020

@Navin-Sankar I apologize it took me so long to get to this issue. As you already correctly figured out, the problem is in the routine that sets up the kernel timer. I created #28841 to solve it.

@Navin-Sankar
Copy link
Member Author

@anangl By default nrf52840dk board uses LFCLK(rtc) as a system clock. How to switch the clock to HFCLK(systick timer)?

@anangl
Copy link
Member

anangl commented Oct 6, 2020

@Navin-Sankar Try to use this in your configuration:

CONFIG_NRF_RTC_TIMER=n
CONFIG_CORTEX_M_SYSTICK=y
CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC=64000000
CONFIG_SYS_CLOCK_TICKS_PER_SEC=<desired_tick_frequency>

@Navin-Sankar
Copy link
Member Author

@anangl working perfectly.

@parthitce
Copy link
Member

@anangl Although this is closed ticket, I would like to ask here as it makes sense.
I tried the above mentioned configurations for nrf9160dk, but the target fails to boot. Do we need different settings for nrf9160? I see the clock control driver is same for both the SoC. Thanks in advance.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area: ADC Analog-to-Digital Converter (ADC)
Projects
None yet
Development

No branches or pull requests

4 participants