This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts

ADC sampling @ 8kHz

Hello,

I want to use the ADC for a burst @ 8khz.

I use this sample "test_adc_sample_with_interval" from https://github.com/zephyrproject-rtos/zephyr/blob/master/tests/drivers/adc/adc_api/src/test_adc.c

I set the interval regarding to 8khz to 125us. 

        const struct adc_sequence_options sequence_opt = {
                .interval_us = 125,
                .callback = adc_finished,
                .extra_samplings = 399,
        };

But when i execute the code i have got a samplerate from 100hz.

Could you help me?

Parents
  • Hi,

    Any progress on this? If not, can you upload the complete code with any modifications you have made to the test/example? (I assume you made more modifications since nRF91 is not supported out of the box as it is not in the list of boards on line 33-38).

  • /*
     * Copyright (c) 2018 Nordic Semiconductor ASA
     *
     * SPDX-License-Identifier: LicenseRef-BSD-5-Clause-Nordic
     */
    
    #include <net/socket.h>
    #include <nrf9160.h>
    #include <stdio.h>
    #include <string.h>
    #include <uart.h>
    #include <adc.h>
    #include <gpio.h>
    #include <zephyr.h>
    
    #define CONFIG_BOARD_NRF9160_PCA10090
    
    static int i = 0;
    
    struct device *adc_dev;
    struct device *gpio_dev;
    
    #if defined(CONFIG_BOARD_NRF52_PCA10040) ||                                    \
    	defined(CONFIG_BOARD_NRF52840_PCA10056) ||                             \
    	defined(CONFIG_BOARD_NRF9160_PCA10090) ||                              \
    	defined(CONFIG_BOARD_NRF52840_BLIP)
    
    #include <hal/nrf_saadc.h>
    #define ADC_DEVICE_NAME DT_ADC_0_NAME
    #define ADC_RESOLUTION 12
    #define ADC_GAIN ADC_GAIN_1_4
    #define ADC_REFERENCE ADC_REF_INTERNAL
    #define ADC_ACQUISITION_TIME ADC_ACQ_TIME(ADC_ACQ_TIME_MICROSECONDS, 40)
    #define ADC_1ST_CHANNEL_ID 0
    #define ADC_1ST_CHANNEL_INPUT NRF_SAADC_INPUT_AIN0
    #define ADC_2ND_CHANNEL_ID 2
    #define ADC_2ND_CHANNEL_INPUT NRF_SAADC_INPUT_AIN2
    #endif
    
    #define PIN SW0_GPIO_PIN 
    static struct gpio_callback button_cb;
    static const u8_t led_pins[] = { LED0_GPIO_PIN, LED1_GPIO_PIN, LED2_GPIO_PIN, LED3_GPIO_PIN };
    
    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,
            .differential = 0,
    #if defined(CONFIG_ADC_CONFIGURABLE_INPUTS)
    	.input_positive = ADC_1ST_CHANNEL_INPUT,
    #endif
    };
    
    
    #define BUFFER_SIZE 600
    static int16_t m_sample_buffer[BUFFER_SIZE];
    
    enum adc_action adc_finished(struct device *dev,const struct adc_sequence *sequence, u16_t sampling_index){
     
            if(sampling_index == BUFFER_SIZE-1){
                    // Print the AIN0 values
                    gpio_pin_write(gpio_dev, led_pins[0], 0);                   // Led off when burst is finished
                    for (int i = 0; i < BUFFER_SIZE/10; i++) {
                            printk("%4d\n%4d\n%4d\n%4d\n%4d\n%4d\n%4d\n%4d\n%4d\n%4d\n", // send the results to the uart...
                            m_sample_buffer[i*10+0],
                            m_sample_buffer[i*10+1],
                            m_sample_buffer[i*10+2],
                            m_sample_buffer[i*10+3],
                            m_sample_buffer[i*10+4],
                            m_sample_buffer[i*10+5],
                            m_sample_buffer[i*10+6],
                            m_sample_buffer[i*10+7],
                            m_sample_buffer[i*10+8],
                            m_sample_buffer[i*10+9]);
                    }  
                    gpio_pin_configure(gpio_dev, PIN, GPIO_DIR_IN | GPIO_INT | GPIO_INT_EDGE | GPIO_INT_ACTIVE_HIGH | GPIO_PUD_PULL_UP);  // activate the interrupt pin
            }
            
           
           k_busy_wait(67);     // workaround for the 8khz samplerate - determined by hand :/
    
           return ADC_ACTION_CONTINUE;    
    }
    
    static int adc_sample(void)
    {
    	int ret;
    
            const struct adc_sequence_options sequence_opt = {
                    .interval_us = 0,
                    .callback = adc_finished,
                    .extra_samplings = BUFFER_SIZE-1,
            };
    
    	const struct adc_sequence sequence = {
                    .options = &sequence_opt,
    		.channels = BIT(ADC_1ST_CHANNEL_ID),
    		.buffer = m_sample_buffer,
    		.buffer_size = sizeof(m_sample_buffer),
    		.resolution = ADC_RESOLUTION,
                    .oversampling = 0,
    	};
    
    	if (!adc_dev) {
    		return -1;
    	}
    
    	ret = adc_read(adc_dev, &sequence);
    	//printk("ADC read err: %d\n", ret);
    
    	return ret;
    }
    
    void button_pressed(struct device *dev, struct gpio_callback *cb, u32_t pin)
    {
              int err = 0;
              err = adc_sample();
                        if (err) {
    		printk("Error in adc sampling: %d\n", err);
              }
              gpio_pin_configure(gpio_dev, PIN, GPIO_DIR_IN | GPIO_INT_ACTIVE_HIGH );   //deactivate the interrupt pin.
              gpio_pin_write(gpio_dev, led_pins[0], 1);                                 //led on for the read process
    }
    
    int dk_leds_init(void)
    {
    	int err = 0;
    
    	gpio_dev = device_get_binding(DT_GPIO_P0_DEV_NAME);
    	if (!gpio_dev) {
    		printk("Cannot bind gpio device");
    		return -ENODEV;
    	}
    
    	for (size_t i = 0; i < ARRAY_SIZE(led_pins); i++) {
    		err = gpio_pin_configure(gpio_dev, led_pins[i], GPIO_DIR_OUT);
    
    		if (err) {
    			printk("Cannot configure LED gpio");
    			return err;
    		}
    	}
    	gpio_pin_configure(gpio_dev, PIN, GPIO_DIR_IN | GPIO_INT | GPIO_INT_EDGE | GPIO_INT_ACTIVE_HIGH | GPIO_PUD_PULL_UP );
    	gpio_init_callback(&button_cb, button_pressed, BIT(PIN));
    	gpio_add_callback(gpio_dev, &button_cb);
    	gpio_pin_enable_callback(gpio_dev, PIN);	
    
    	return err;
    }
    
    int dk_adc_init(void)
    {
            int err = 0;
    
    	adc_dev = device_get_binding("ADC_0");
    	if (!adc_dev) {
    		printk("device_get_binding ADC_0 failed\n");
    	}
    
    
    	err = adc_channel_setup(adc_dev, &m_1st_channel_cfg);
    	if (err) {
    		printk("Error in adc setup: %d\n", err);
    	}
    
            return err;
    }
    
    
    int main(void)
    {
    	int err;
    
    	printk("nrf91 saadc sampling AIN0 (P0.13)\n");
            
            dk_adc_init();
            dk_leds_init();
    
    	/* Trigger offset calibration
    	 * As this generates a _DONE and _RESULT event
    	 * the first result will be incorrect.
    	 */
    	NRF_SAADC_NS->TASKS_CALIBRATEOFFSET = 1;
    
    	while (1){
                          k_cpu_idle();
                     }
    	
    }
    

    Hello,

    above the full Code. If the switch 0 is pressed the cpu wake up and make a burst with 600 samples.

    Then the values will be sent via uart.

    I have implemented a work around to reach the 8khz. I use the k_busy_wait() function to reach the 8Khz.

    But this is not really professional. 

     I hope we can find a solution. :)

Reply
  • /*
     * Copyright (c) 2018 Nordic Semiconductor ASA
     *
     * SPDX-License-Identifier: LicenseRef-BSD-5-Clause-Nordic
     */
    
    #include <net/socket.h>
    #include <nrf9160.h>
    #include <stdio.h>
    #include <string.h>
    #include <uart.h>
    #include <adc.h>
    #include <gpio.h>
    #include <zephyr.h>
    
    #define CONFIG_BOARD_NRF9160_PCA10090
    
    static int i = 0;
    
    struct device *adc_dev;
    struct device *gpio_dev;
    
    #if defined(CONFIG_BOARD_NRF52_PCA10040) ||                                    \
    	defined(CONFIG_BOARD_NRF52840_PCA10056) ||                             \
    	defined(CONFIG_BOARD_NRF9160_PCA10090) ||                              \
    	defined(CONFIG_BOARD_NRF52840_BLIP)
    
    #include <hal/nrf_saadc.h>
    #define ADC_DEVICE_NAME DT_ADC_0_NAME
    #define ADC_RESOLUTION 12
    #define ADC_GAIN ADC_GAIN_1_4
    #define ADC_REFERENCE ADC_REF_INTERNAL
    #define ADC_ACQUISITION_TIME ADC_ACQ_TIME(ADC_ACQ_TIME_MICROSECONDS, 40)
    #define ADC_1ST_CHANNEL_ID 0
    #define ADC_1ST_CHANNEL_INPUT NRF_SAADC_INPUT_AIN0
    #define ADC_2ND_CHANNEL_ID 2
    #define ADC_2ND_CHANNEL_INPUT NRF_SAADC_INPUT_AIN2
    #endif
    
    #define PIN SW0_GPIO_PIN 
    static struct gpio_callback button_cb;
    static const u8_t led_pins[] = { LED0_GPIO_PIN, LED1_GPIO_PIN, LED2_GPIO_PIN, LED3_GPIO_PIN };
    
    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,
            .differential = 0,
    #if defined(CONFIG_ADC_CONFIGURABLE_INPUTS)
    	.input_positive = ADC_1ST_CHANNEL_INPUT,
    #endif
    };
    
    
    #define BUFFER_SIZE 600
    static int16_t m_sample_buffer[BUFFER_SIZE];
    
    enum adc_action adc_finished(struct device *dev,const struct adc_sequence *sequence, u16_t sampling_index){
     
            if(sampling_index == BUFFER_SIZE-1){
                    // Print the AIN0 values
                    gpio_pin_write(gpio_dev, led_pins[0], 0);                   // Led off when burst is finished
                    for (int i = 0; i < BUFFER_SIZE/10; i++) {
                            printk("%4d\n%4d\n%4d\n%4d\n%4d\n%4d\n%4d\n%4d\n%4d\n%4d\n", // send the results to the uart...
                            m_sample_buffer[i*10+0],
                            m_sample_buffer[i*10+1],
                            m_sample_buffer[i*10+2],
                            m_sample_buffer[i*10+3],
                            m_sample_buffer[i*10+4],
                            m_sample_buffer[i*10+5],
                            m_sample_buffer[i*10+6],
                            m_sample_buffer[i*10+7],
                            m_sample_buffer[i*10+8],
                            m_sample_buffer[i*10+9]);
                    }  
                    gpio_pin_configure(gpio_dev, PIN, GPIO_DIR_IN | GPIO_INT | GPIO_INT_EDGE | GPIO_INT_ACTIVE_HIGH | GPIO_PUD_PULL_UP);  // activate the interrupt pin
            }
            
           
           k_busy_wait(67);     // workaround for the 8khz samplerate - determined by hand :/
    
           return ADC_ACTION_CONTINUE;    
    }
    
    static int adc_sample(void)
    {
    	int ret;
    
            const struct adc_sequence_options sequence_opt = {
                    .interval_us = 0,
                    .callback = adc_finished,
                    .extra_samplings = BUFFER_SIZE-1,
            };
    
    	const struct adc_sequence sequence = {
                    .options = &sequence_opt,
    		.channels = BIT(ADC_1ST_CHANNEL_ID),
    		.buffer = m_sample_buffer,
    		.buffer_size = sizeof(m_sample_buffer),
    		.resolution = ADC_RESOLUTION,
                    .oversampling = 0,
    	};
    
    	if (!adc_dev) {
    		return -1;
    	}
    
    	ret = adc_read(adc_dev, &sequence);
    	//printk("ADC read err: %d\n", ret);
    
    	return ret;
    }
    
    void button_pressed(struct device *dev, struct gpio_callback *cb, u32_t pin)
    {
              int err = 0;
              err = adc_sample();
                        if (err) {
    		printk("Error in adc sampling: %d\n", err);
              }
              gpio_pin_configure(gpio_dev, PIN, GPIO_DIR_IN | GPIO_INT_ACTIVE_HIGH );   //deactivate the interrupt pin.
              gpio_pin_write(gpio_dev, led_pins[0], 1);                                 //led on for the read process
    }
    
    int dk_leds_init(void)
    {
    	int err = 0;
    
    	gpio_dev = device_get_binding(DT_GPIO_P0_DEV_NAME);
    	if (!gpio_dev) {
    		printk("Cannot bind gpio device");
    		return -ENODEV;
    	}
    
    	for (size_t i = 0; i < ARRAY_SIZE(led_pins); i++) {
    		err = gpio_pin_configure(gpio_dev, led_pins[i], GPIO_DIR_OUT);
    
    		if (err) {
    			printk("Cannot configure LED gpio");
    			return err;
    		}
    	}
    	gpio_pin_configure(gpio_dev, PIN, GPIO_DIR_IN | GPIO_INT | GPIO_INT_EDGE | GPIO_INT_ACTIVE_HIGH | GPIO_PUD_PULL_UP );
    	gpio_init_callback(&button_cb, button_pressed, BIT(PIN));
    	gpio_add_callback(gpio_dev, &button_cb);
    	gpio_pin_enable_callback(gpio_dev, PIN);	
    
    	return err;
    }
    
    int dk_adc_init(void)
    {
            int err = 0;
    
    	adc_dev = device_get_binding("ADC_0");
    	if (!adc_dev) {
    		printk("device_get_binding ADC_0 failed\n");
    	}
    
    
    	err = adc_channel_setup(adc_dev, &m_1st_channel_cfg);
    	if (err) {
    		printk("Error in adc setup: %d\n", err);
    	}
    
            return err;
    }
    
    
    int main(void)
    {
    	int err;
    
    	printk("nrf91 saadc sampling AIN0 (P0.13)\n");
            
            dk_adc_init();
            dk_leds_init();
    
    	/* Trigger offset calibration
    	 * As this generates a _DONE and _RESULT event
    	 * the first result will be incorrect.
    	 */
    	NRF_SAADC_NS->TASKS_CALIBRATEOFFSET = 1;
    
    	while (1){
                          k_cpu_idle();
                     }
    	
    }
    

    Hello,

    above the full Code. If the switch 0 is pressed the cpu wake up and make a burst with 600 samples.

    Then the values will be sent via uart.

    I have implemented a work around to reach the 8khz. I use the k_busy_wait() function to reach the 8Khz.

    But this is not really professional. 

     I hope we can find a solution. :)

Children
Related