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 

 

Parents Reply
  • 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

Children
  • 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
  • Sorry about the wait Christoph,

    with your first issue being solved I assume this wasn't that urgent. Though I forgot to note that you had another one here.

    ChrtistophAT said:
    NRFX_SAADC_EVT_DONE case, which looks like follows:

    You initialize the work in the event handler here. There are some details here about how k_work_init() should be invoked.

    And k_work_submit_to_queue() returning 0 doesn't mean success.

    Checking the value of k_work_busy_get() and busy_state might also be an idea.

    Regards,

    Elfving

  • Thanks Elfving! I simple changed the previously used 

    k_work_submit_to_queue()

    to

    k_work_submit()

    and its working as expected.

  • Great!

    Glad to hear it got solved, and that you shared the solution here, so that others can use it if they run into the same problem.

    Let us know if there is anything else!

    Regards,

    Elfving

Related