continuous sampling stopped example: saadc_advanced_non_blocking_internal_timer

Hello folks,

aim of my task is to transfer ADC data through USB from my nrf5340DK to my windows PC, so I can use this data to controll some python game.

SDK: nrf2.6.2

toolchain: v2.6.2

I evaluated the example "saadc_advanced_non_blocking_internal_timer" and changed the saadc_handler() function, especially the "case NRFX_SAADC_EVT_BUF_REQ:" , so its continuously sampling the ADC channel. Problem was, that 

[00:13:02.882,751] <inf> NRFX_EXAMPLE: 300

--- 76 messages dropped ---

[00:13:02.891,448] <inf> NRFX_EXAMPLE: 302

--- 76 messages dropped ---

[00:13:02.900,146] <inf> NRFX_EXAMPLE: 302

Messages were dropped, so I want to implement the

USB CDC ACM Sample Application example
its for the sdk v2.5.1, but without adjusting its running fine in my build v2.6.1.
The problem I encounter, when I adjust the prj.conf for the USB implementation like
#project configuration
CONFIG_GPIO=n
CONFIG_NRFX_GPIOTE0=y
CONFIG_NRFX_SAADC=y

#usb cobfiguration
CONFIG_USB_DEVICE_STACK=y            # Enables the USB device stack
# Sets the product name
CONFIG_USB_DEVICE_PRODUCT="Zephyr CDC ACM sample"
#ProductID the following line is not allowed to make comments after ID "Remove the Inline Comment"
CONFIG_USB_DEVICE_PID=0x0001    
CONFIG_SERIAL=y                      # Enables UART support
CONFIG_UART_INTERRUPT_DRIVEN=y       # Enables interrupt-driven UART (needed for USB CDC ACM)
CONFIG_UART_LINE_CTRL=y              # Enables line control for UART (needed for DTR detection)

#logging through zephyr
CONFIG_DEBUG=y               # Enable debug symbols
CONFIG_LOG_MODE_IMMEDIATE=y  # Ensure logs are flushed immediately for debugging.
CONFIG_LOG_BACKEND_UART=y    # Logs will output to UART or RTT (depends on your setup).
my familiar irq sequence for the SAADC sampling differes. I ad this image, so it easier to see
irq sequence from the saadc
The last interrupt with event mask = 3, should be = 2 and I dont know why. Afterwards its executing the Saadc_event_handle() and the 
m_cb.buffer_secondary.p_buffer = 0x0 <_vector_table>
so it points to null.
I tried to increase the priority from the saadc to 2
nrfx_saadc_init(2);
My USB implementation works and I can see the device in the Settings - Bluetooth & other Devices properly. When I comment out the init from the USB in my main.c , still persists the error and not continuously sampling. 
When I comment out the added prj.conf configuration for the USB, its sampling continuously again.
Doese someone have any clue why this is happening?
Many thanks in advance,
Christoph 

 

  • Here is something I encountered while investigating. The code commit is where I just code reviewed the example from saadc "saadc_advanced_non_blocking_internal_timer" . Despite that, there is already some USB configuration in the prj.conf . Could be that I already started implementation and commited afterwards the codereview status. Anyway the prj.conf is like:

    #project configuration
    CONFIG_GPIO=n
    CONFIG_NRFX_GPIOTE0=y
    CONFIG_NRFX_SAADC=y
    CONFIG_LOG_BUFFER_SIZE=8192

    CONFIG_NRFX_SAADC_LOG=y #log enable for saadc library

    #config usb data transfer
    CONFIG_USB_CDC_ACM=y
    CONFIG_USB_DEVICE_STACK=y
    CONFIG_USB_DEVICE_MANUFACTURER="Your Company Name"
    CONFIG_USB_DEVICE_PRODUCT="Your Product Name"
    CONFIG_USB_DEVICE_VID=0x1915
    CONFIG_USB_DEVICE_PID=0x520F
    CONFIG_UART_INTERRUPT_DRIVEN=y
    CONFIG_UART_LINE_CTRL=y

    and the code is untouched from the example, just some LOG_INF() and SAMPLING_ITERATIONS

    The code samples as expected all the iterations and buffers. 

    [00:00:00.436,370] <inf> NRFX_EXAMPLE: Starting nrfx_saadc advanced non-blocking sampling with internal timer example.
    [00:00:00.447,448] <inf> NRFX_SAADC: Function: nrfx_saadc_init, error code: NRFX_SUCCESS.
    [00:00:00.447,540] <inf> NRFX_EXAMPLE: GPIOTE status: initialized
    [00:00:00.447,570] <inf> NRFX_EXAMPLE: SAADC calibration will be started.
    [00:00:00.447,570] <inf> NRFX_SAADC: nrfx_saadc_offset_calibrate called
    [00:00:00.447,570] <inf> NRFX_EXAMPLE: Calibration started successfully
    [00:00:00.447,631] <inf> NRFX_EXAMPLE: SAADC event: CALIBRATEDONE
    [00:00:00.447,662] <inf> NRFX_EXAMPLE: saadc_mode_trigger() will be called to start the sampling.
    [00:00:00.447,662] <inf> NRFX_EXAMPLE: SAADC event: READY
    [00:00:00.447,692] <inf> NRFX_EXAMPLE: SAADC event: BUF_REQ
    [00:00:00.447,937] <inf> NRFX_SAADC: m_cb address: 0x20003a3c, buffer_secondary: 0x20002686
    [00:00:00.447,967] <inf> NRFX_EXAMPLE: 274
    [00:00:00.447,967] <inf> NRFX_EXAMPLE: 276
    [00:00:00.447,967] <inf> NRFX_EXAMPLE: 273
    [00:00:00.447,998] <inf> NRFX_EXAMPLE: SAADC event: BUF_REQ
    [00:00:00.448,333] <inf> NRFX_SAADC: m_cb address: 0x20003a3c, buffer_secondary: 0x20002680
    [00:00:00.448,333] <inf> NRFX_EXAMPLE: 273
    [00:00:00.448,333] <inf> NRFX_EXAMPLE: 276
    [00:00:00.448,364] <inf> NRFX_EXAMPLE: 275
    [00:00:00.448,364] <inf> NRFX_EXAMPLE: SAADC event: BUF_REQ
    [00:00:00.448,699] <inf> NRFX_SAADC: m_cb address: 0x20003a3c, buffer_secondary: 0x20002686
    [00:00:00.448,699] <inf> NRFX_EXAMPLE: 275
    [00:00:00.448,699] <inf> NRFX_EXAMPLE: 275
    [00:00:00.448,730] <inf> NRFX_EXAMPLE: 275
    [00:00:00.448,730] <inf> NRFX_EXAMPLE: SAADC event: BUF_REQ
    [00:00:00.449,066] <inf> NRFX_SAADC: m_cb address: 0x20003a3c, buffer_secondary: 0
    [00:00:00.449,066] <inf> NRFX_EXAMPLE: 274
    [00:00:00.449,096] <inf> NRFX_EXAMPLE: 275
    [00:00:00.449,096] <inf> NRFX_EXAMPLE: 275
    [00:00:00.449,096] <inf> NRFX_EXAMPLE: SAADC event: FINISHED

    When I breakpoint in the 

    nrfx_saadc_irq_handler()
    and in the 
    saadc_handler()
    I get the same issue and the sampling goes right only one iteration. The output is like
    [00:00:00.440,429] <inf> NRFX_EXAMPLE: Starting nrfx_saadc advanced non-blocking sampling with internal timer example.
    [00:00:00.451,507] <inf> NRFX_SAADC: Function: nrfx_saadc_init, error code: NRFX_SUCCESS.
    [00:00:00.451,568] <inf> NRFX_EXAMPLE: GPIOTE status: initialized
    [00:00:00.451,599] <inf> NRFX_EXAMPLE: SAADC calibration will be started.
    [00:00:00.451,599] <inf> NRFX_SAADC: nrfx_saadc_offset_calibrate called
    [00:00:00.451,629] <inf> NRFX_EXAMPLE: Calibration started successfully
    [00:00:14.430,664] <inf> NRFX_EXAMPLE: SAADC event: CALIBRATEDONE
    [00:00:14.430,694] <inf> NRFX_EXAMPLE: saadc_mode_trigger() will be called to start the sampling.
    [00:00:21.575,134] <inf> NRFX_EXAMPLE: SAADC event: READY
    [00:00:26.013,061] <inf> NRFX_EXAMPLE: SAADC event: BUF_REQ
    [00:00:30.260,742] <inf> NRFX_SAADC: m_cb address: 0x20003a3c, buffer_secondary: 0x20002686
    [00:00:36.201,141] <inf> NRFX_EXAMPLE: 273
    [00:00:36.201,141] <inf> NRFX_EXAMPLE: 273
    [00:00:36.201,141] <inf> NRFX_EXAMPLE: 273
    [00:00:43.427,459] <inf> NRFX_SAADC: m_cb address: 0x20003a3c, buffer_secondary: 0
    [00:00:52.981,353] <inf> NRFX_EXAMPLE: 274
    [00:00:52.981,353] <inf> NRFX_EXAMPLE: 275
    [00:00:52.981,384] <inf> NRFX_EXAMPLE: 275
    [00:00:56.099,060] <inf> NRFX_EXAMPLE: SAADC event: FINISHED
    The NRFX_SAADC_EVT_BUF_REQ isnt called anymore.
    The flowchart calls from
    nrfx_saadc_irq_handler()
    and 
    saadc_handler()
    when the issue occures is like
    Can someone give me information why this behaviour is present and where to look or how to do some solution?
    Nice regards,
    Christoph
  • Hi Christoph, 

    Could you try not sending the usb data directly from IRQ. This is something you should rather use a workqueue for. See here for how to do it.

    Regards,

    Elfving

  • Thank you for your suggestion Elfving!

    For everyone else who encounter the same behaviour, here is my git commit info, after I succesfully sampled infinite number of buffers and added the USB config / init in main.c and prf.conf

    the issue prev with stopping although remaining buffer iterations was cause by the breakpoints.
    these breakpoints in nrfx_saadc_irq_handler() & saadc_handler() , forces the program to halt at the important events which
    whom the saadc is driven. Also, when you stop at a breakpoint, you might be interfering with the buffer switching mechanism.

    Nice regards,

    Christoph

  • Ah so you figured it out? Glad to hear it.

    And thanks for sharing the solution with the forum.

    Regards,

    Elfving

  • Yes the sampling is now working properly without interrupting the buffer share seqwuence.

    Perhaps you can give me another hint for the suggested workqueue approach. I did the Example 3 from the academy and also the whole multithreading lesson . There the sequence is without main() function, so thread0 and thread1 are sharing the execution time one after another when properly configured.

    My current sequence differs from the Example 3. I init the USB instances, afterwards init the workqueue like:

    //work queue for usb transmission
    #define WORK_QUEUE_STACK_SIZE 1024
    #define WORK_QUEUE_PRIORITY   0
    
    // Define stack area used by workqueue thread
    static K_THREAD_STACK_DEFINE(usb_work_stack, WORK_QUEUE_STACK_SIZE);
    // Define queue structure
    static struct k_work_q usb_work_q = {0};
    
    // Define a structure to hold ADC data and the work item
    struct usb_work_item {
        struct k_work work;    // Work item structure
        uint16_t *data;        // Pointer to ADC buffer
        uint16_t size;         // Number of samples in the buffer
    }adc_usb_work;
    
    // Initialize the work queue
    void init_usb_workqueue(void)
    {
        // Initialize work queue
        k_work_queue_init(&usb_work_q);
        k_work_queue_start(&usb_work_q, usb_work_stack,
                           K_THREAD_STACK_SIZEOF(usb_work_stack),
                           WORK_QUEUE_PRIORITY, NULL);
    }
    Afterwards the SAADC sequence starts with calibration and sampling starts. I thought to submit work in the workqueue in the saadc_handler() specifically in the 
    NRFX_SAADC_EVT_DONE case, which looks like follows:
            case NRFX_SAADC_EVT_DONE:
                NRFX_LOG_INFO("SAADC event: DONE");
    
                // Get the number of samples
                samples_number = p_event->data.done.size;
    
                // Prepare the work item with the buffer and size
                adc_usb_work.data = p_event->data.done.p_buffer;
                adc_usb_work.size = samples_number;
                k_work_init(&adc_usb_work.work, usb_work_handler);
                // Submit the work to the work queue
                int busy_state = k_work_busy_get(&adc_usb_work.work);
                LOG_INF("Work item busy state: %d", busy_state);
                int ret = k_work_submit_to_queue(&usb_work_q, &adc_usb_work);
                if (ret == 0) {
                    LOG_INF("Work submitted successfully");
                }else{
                    LOG_ERR("Failed to submit work: %d", ret);
                }
                
                break;

    I simplified the 
    void usb_work_handler(struct k_work *work)
    {
        LOG_INF("usb_work_handler invoked");
    }

    normaly here should be the USB transmission be placed 
    uart_fifo_fill()
    but its not working at all : (

    The COM port output is 

    [00:00:00.435,577] <inf> NRFX_EXAMPLE: Starting nrfx_saadc advanced non-blocking sampling with internal timer example.
    [00:00:00.446,594] <inf> NRFX_EXAMPLE: Device address: 0x13bec
    [00:00:00.446,624] <inf> NRFX_EXAMPLE: Successfully retrieved device binding
    [00:00:00.446,777] <inf> NRFX_EXAMPLE: Succesfull enable USB
    [00:00:00.446,777] <inf> NRFX_EXAMPLE: Wait for DTR
    [00:00:00.450,897] <inf> usb_cdc_acm: Device suspended
    [00:00:00.549,041] <inf> usb_cdc_acm: Device resumed
    [00:00:00.835,388] <inf> usb_cdc_acm: Device configured
    [00:00:01.247,650] <inf> NRFX_EXAMPLE: DTR set
    [00:00:01.356,536] <inf> NRFX_EXAMPLE: Baudrate detected: 115200
    [00:00:01.356,597] <inf> NRFX_EXAMPLE: USB work queue started
    [00:00:01.356,658] <inf> NRFX_SAADC: Function: nrfx_saadc_init, error code: NRFX_SUCCESS.
    [00:00:01.356,719] <inf> NRFX_EXAMPLE: GPIOTE status: initialized
    [00:00:01.356,750] <inf> NRFX_SAADC: nrfx_saadc_offset_calibrate called
    [00:00:01.356,842] <inf> NRFX_EXAMPLE: SAADC event: READY
    [00:00:01.356,842] <inf> NRFX_EXAMPLE: SAADC event: BUF_REQ
    [00:00:01.357,238] <inf> NRFX_EXAMPLE: SAADC event: DONE
    [00:00:01.357,238] <inf> NRFX_EXAMPLE: Work item busy state: 0
    [00:00:01.357,269] <err> NRFX_EXAMPLE: Failed to submit work: 1
    [00:00:01.357,269] <inf> NRFX_EXAMPLE: SAADC event: BUF_REQ
    [00:00:01.357,727] <inf> NRFX_EXAMPLE: SAADC event: DONE
    [00:00:01.357,757] <inf> NRFX_EXAMPLE: Work item busy state: 0
    [00:00:01.357,757] <err> NRFX_EXAMPLE: Failed to submit work: 1
    [00:00:01.357,757] <inf> NRFX_EXAMPLE: SAADC event: FINISHED

    Is this the correct way to offload transmission work or would you have some better sequence?

    Thanks in advance and nice regards,
    Christoph
Related