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
  • 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
  • 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.

Reply Children
Related