Jump to content

JRys

MCC Staff
  • Posts

    1,460
  • Joined

  • Last visited

Posts posted by JRys

  1. The PersonalDaq 54, 55, and 56 do not support Windows 10 or 11. However, some of our customers have found ways to make them work. One tip I have found is to ensure the computer's hardware has the latest updates from the manufacturer. This is especially true for new computers, which often ship with outdated firmware. I have also found that some manufacturers do not make drivers available for Windows 10 or 11 that run on older hardware. I have a Dell Precision 5820 desktop with Windows 11 that works with the PersonalDaqs, so it can work. 

  2. I apologize for the late response. GND and AGND are connected on the PCB board.  However, the AGND path is meant for analog grounds only. Digital grounds tend to have switching noise, and running separate paths reduces overall measurement noise. 

    On the other hand, a ground loop can appear as a noisy signal. If you suspect a ground loop, use a differential connection instead of a single-ended one. 

  3. Hello,

    I've tested the emacspif_speed.c file patch with Vitis 2022.1 and 2023.1 using a Zybo Z7-10 Ref F chip. At first, it didn't work for me, but it was because I applied the patch after I created and built the project. I thought I could just rebuild the project for the patch to work, but it failed. The solution I found was to make a new project. Attached is the patch file I used. Change the extension to .c and copy it to:

    C:\Xilinx\Vitis\2021.1\data\embeddedsw\ThirdParty\sw_services\lwip211_v1_7\src\contrib\ports\xilinx\netif\. 

    Best regards,
    John

    xemacpsif_physpeed.txt

  4. Hello,

    To determine the key being pressed, you must set each column line low one at a time while simultaneously reading the rows. Review the following article to get an idea of what is needed to read the key and update the display: https://fpgacoding.com/pmod-keypad-peripheral-first-look/. Their method uses a counter to create a one-millisecond delay between setting each column low, one at a time, while reading the rows. 

    Best regards,
    John

  5. The driver issue could be caused by the hardware no longer functioning correctly. Unplug the USB connection, then restart Windows. Plug it back in and try again. If it is in working order, Windows will reinstall it. If not, let me know the device's serial number, and I will see if it can be repaired.

  6. None of our current products offer gated control. However, they do have external ADC clock support, and if you could control the external ADC clock, you would be able to control the ADC. A device like the USB-1608GX and USB-1808X have a timer output that can be used as a clock, which is half the battle. The other half is developing a gate circuit to function as a control. 

  7. Please watch the following video about installing DASYLab and the Measurement Computing support. It will show how to install the Measurement Computing driver and access the input and output modules. When the driver installation gets to the destination folder panel, edit the path (press Change) so that it is \Program Files (x86)\DASYLab 2022.1_en\. Otherwise, you will get a path not found error. 

     

  8. The message pops up because 1.) you do not have a sound card installed, and 2.) you have the sound card support enabled in the Configurator. It is enabled by default, and you can either check the box on the message not to display it again or disable the sound card support in the Configurator. I recommended checking the message box so it doesn't bug you anymore.

  9. You can add more USB-TEMPs and use DAQami. But if you want one file with 64 channels, use DASYLab BASIC. You have too many channels for DASYLab LITE. DASYLab modules are limited to 16 channels, which limits the number you can write to file. To get around the limitation, the Multiplexer module can take up to 16 inputs and output them as a single stream. Connect this output to a Data Write module, and, in the setting, configure the number of channels coming in on that input. When properly configured, the Data Write unpacks channels to be written to a file.

  10. The following program generates a ~10 Hz sine wave on analog output 0 with an update rate of 1000 S/s. It also captures data on the analog input channel 0 at 500 S/s. I have also tested it at 1100, which is the max. You should be able to use two channels at 550 S/s. The config(board_num, num_chans) function performs the setting normally done by InstaCal. Attached below is the file.

    from __future__ import absolute_import, division, print_function

    import time

    from builtins import *  # @UnusedWildImport
    from ctypes import addressof, sizeof, cast, POINTER, c_double, c_ushort

    from math import pi, sin
    from time import sleep

    from mcculw import ul
    from mcculw.enums import (AiChanType, BoardInfo, Status, InterfaceType,
                              FunctionType, InfoType, ScanOptions,
                              ULRange, AnalogInputMode)

    use_device_detection = True
    packet_size = 32


    def config(board_num: int, n_channels: int):
        for ch in range(n_channels):
            ul.set_config(
                InfoType.BOARDINFO, board_num, ch,
                BoardInfo.ADCHANTYPE, AiChanType.VOLTAGE
            )
            # ul.set_config(
            #    InfoType.BOARDINFO, board_num, ch,
            #    BoardInfo.CHANTCTYPE, TcType.K
            # )

            ul.set_config(
                InfoType.BOARDINFO, board_num, ch,
                BoardInfo.ADDATARATE, 3750
            )


    def run_example():

        

        dev_id_list = []
        board_num = 0
        desired_rate = 512
        actual_rate = 0
        desired_out_rate = 1000
        actual_out_rate = 0
        file_name = 'scan_data.csv'
        memhandle = None

        # The size of the UL buffer to create, in seconds
        buffer_size_seconds = 2
        # The number of buffers to write. After this number of UL buffers are
        # written to file, the example will be stopped.
        num_buffers_to_write = 5

        board_num = 0
        board_index = 0
        find_device = "USB-2416-4AO"
        if use_device_detection:
            board_num = -1
            ul.ignore_instacal()
            dev_list = ul.get_daq_device_inventory(InterfaceType.USB)
            if len(dev_list) > 0:
                for device in dev_list:
                    if str(device) == find_device:
                        print(f"Found {find_device} board number = {board_index}")
                        print(f"Serial number: {device.unique_id}")
                        print(f"Product type: {hex(device.product_id)}")
                        board_num = board_index
                        ul.create_daq_device(board_num, device)
                    board_index = board_index + 1
                if board_num == -1:
                    print(f"Device {find_device} not found")
                    return
            else:
                print("No devices detected")
                return
        # **********End of Discovery************

        try:

            chan = 0
            num_chans = 1
            config(board_num, num_chans)
            ul.a_chan_input_mode(board_num, chan, AnalogInputMode.SINGLE_ENDED)

            # Create a circular buffer that can hold buffer_size_seconds worth of
            # data, or at least 10 points (this may need to be adjusted to prevent
            # a buffer overrun)
            points_per_channel = max(desired_rate * buffer_size_seconds, 10)
            ul_buffer_count = points_per_channel * num_chans

            # Write the UL buffer to the file num_buffers_to_write times.
            points_to_write = ul_buffer_count * num_buffers_to_write

            # When handling the buffer, we will read 1/10 of the buffer at a time
            write_chunk_size = int(ul_buffer_count / 10)

            scan_options = (ScanOptions.BACKGROUND | ScanOptions.CONTINUOUS |
                            ScanOptions.SCALEDATA)

            memhandle = ul.scaled_win_buf_alloc(ul_buffer_count)

            # Allocate an array of doubles temporary storage of the data
            write_chunk_array = (c_double * write_chunk_size)()

            # Check if the buffer was successfully allocated
            if not memhandle:
                raise Exception('Failed to allocate memory')

            # set output to zero
            zero_volts = 0.0
            ul.v_out(board_num, 0, ULRange.BIP10VOLTS, zero_volts, 0)

            # Allocate a buffer for the scan
            count = 1024
            memhandle2 = ul.win_buf_alloc(count)

            # Convert the memhandle to a ctypes array
            # Note: the ctypes array will no longer be valid after win_buf_free
            # is called.
            # A copy of the buffer can be created using win_buf_to_array
            # before the memory is freed. The copy can be used at any time.
            ctypes_array = cast(memhandle2, POINTER(c_ushort))

            # Check if the buffer was successfully allocated
            if not memhandle2:
                raise Exception('Error: Failed to allocate memory')

            frequencies = add_example_data(board_num, ctypes_array, ULRange.BIP10VOLTS,
                                           num_chans, desired_out_rate, count)

            print("Channel", chan, 'Output Signal Frequency:', frequencies[chan])

            # Start single channel output scan
            actual_out_rate = ul.a_out_scan(board_num,
                                            chan, chan,
                                            count,
                                            desired_out_rate,
                                            ULRange.BIP10VOLTS,
                                            memhandle2,
                                            ScanOptions.BACKGROUND | ScanOptions.CONTINUOUS)

            print('desired output rate =: ' + str(desired_out_rate))
            print('actual output rate  =: ' + str(actual_out_rate))

            # Start the scan
            actual_rate = ul.a_in_scan(
                board_num, chan, chan, ul_buffer_count,
                desired_rate, ULRange.BIP10VOLTS, memhandle, scan_options)

            print('desired input rate =: ' + str(desired_rate))
            print('actual input rate  =: ' + str(actual_rate))

            status = Status.IDLE
            # Wait for the scan to start fully
            while status == Status.IDLE:
                status, _, _ = ul.get_status(board_num, FunctionType.AIFUNCTION)

            # Create a file for storing the data
            with open(file_name, 'w') as f:
                print('Writing data to ' + file_name, end='')

                # Write a header to the file
                for chan_num in range(chan, chan + 1):
                    f.write('Channel ' + str(chan_num) + ',')
                f.write(u'\n')

                prev_count = 0
                prev_index = 0
                write_ch_num = chan
                while status != Status.IDLE:
                    # Get the latest counts
                    status, curr_count, _ = ul.get_status(board_num, FunctionType.AIFUNCTION)

                    new_data_count = curr_count - prev_count

                    # Check for a buffer overrun before copying the data, so
                    # that no attempts are made to copy more than a full buffer
                    # of data
                    if new_data_count > ul_buffer_count:
                        # Print an error and stop writing
                        ul.stop_background(board_num, FunctionType.AIFUNCTION)
                        print('A buffer overrun occurred')
                        break

                    # Check if a chunk is available
                    if new_data_count > write_chunk_size:
                        wrote_chunk = True
                        # Copy the current data to a new array

                        # Check if the data wraps around the end of the UL
                        # buffer. Multiple copy operations will be required.
                        if prev_index + write_chunk_size > ul_buffer_count - 1:
                            first_chunk_size = ul_buffer_count - prev_index
                            second_chunk_size = (
                                    write_chunk_size - first_chunk_size)

                            # Copy the first chunk of data to the
                            # write_chunk_array
                            ul.scaled_win_buf_to_array(
                                memhandle, write_chunk_array, prev_index,
                                first_chunk_size)

                            # Create a pointer to the location in
                            # write_chunk_array where we want to copy the
                            # remaining data
                            second_chunk_pointer = cast(addressof(write_chunk_array)
                                                        + first_chunk_size
                                                        * sizeof(c_double),
                                                        POINTER(c_double))

                            # Copy the second chunk of data to the
                            # write_chunk_array
                            ul.scaled_win_buf_to_array(
                                memhandle, second_chunk_pointer,
                                0, second_chunk_size)
                        else:
                            # Copy the data to the write_chunk_array
                            ul.scaled_win_buf_to_array(
                                memhandle, write_chunk_array, prev_index,
                                write_chunk_size)

                        # Check for a buffer overrun just after copying the data
                        # from the UL buffer. This will ensure that the data was
                        # not overwritten in the UL buffer before the copy was
                        # completed. This should be done before writing to the
                        # file, so that corrupt data does not end up in it.
                        status, curr_count, _ = ul.get_status(
                            board_num, FunctionType.AIFUNCTION)
                        if curr_count - prev_count > ul_buffer_count:
                            # Print an error and stop writing
                            ul.stop_background(board_num, FunctionType.AIFUNCTION)
                            print('A buffer overrun occurred')
                            break

                        for i in range(write_chunk_size):
                            f.write(str(write_chunk_array[i]) + ',')
                            write_ch_num += 1
                            if write_ch_num == chan + 1:
                                write_ch_num = chan
                                f.write(u'\n')
                    else:
                        wrote_chunk = False

                    if wrote_chunk:
                        # Increment prev_count by the chunk size
                        prev_count += write_chunk_size
                        # Increment prev_index by the chunk size
                        prev_index += write_chunk_size
                        # Wrap prev_index to the size of the UL buffer
                        prev_index %= ul_buffer_count

                        if prev_count >= points_to_write:
                            break
                        print('.', end='')
                    else:
                        # Wait a short amount of time for more data to be
                        # acquired.
                        sleep(0.1)
            ul.stop_background(board_num, FunctionType.AOFUNCTION)
            ul.v_out(board_num, 0, ULRange.BIP10VOLTS, zero_volts, 0)
            ul.stop_background(board_num, FunctionType.AIFUNCTION)
        except Exception as e:
            print('\n', e)
        finally:
            print('Done')
            if memhandle:
                # Free the buffer in a final block to prevent  a memory leak.
                ul.win_buf_free(memhandle)
            if use_device_detection:
                ul.release_daq_device(board_num)


    def add_example_data(board_num, data_array, ao_range, num_chans, rate,
                         points_per_channel):
        # Calculate frequencies that will work well with the size of the array
        frequencies = []
        for channel_num in range(num_chans):
            frequencies.append(
                (channel_num + 1) / (points_per_channel / rate) * 10)

        # Calculate an amplitude and y-offset for the signal
        # to fill the analog output range
        amplitude = (ao_range.range_max - ao_range.range_min) / 2
        y_offset = (amplitude + ao_range.range_min) / 2

        # Fill the array with sine wave data at the calculated frequencies.
        # Note that since we are using the SCALEDATA option, the values
        # added to data_array are the actual voltage values that the device
        # will output
        data_index = 0
        for point_num in range(points_per_channel):
            for channel_num in range(num_chans):
                freq = frequencies[channel_num]
                value = amplitude * sin(2 * pi * freq * point_num / rate) + y_offset
                raw_value = ul.from_eng_units(board_num, ao_range, value)
                data_array[data_index] = raw_value

                data_index += 1

        return frequencies


    if __name__ == '__main__':
        run_example()
     

    a_in_scan_file_2416_py.txt

  11. Could you jump into InstaCal and check how channel 0 is configured and how the Data Rate filter property is set? It must be set to 3750 to sample at 550 samples per second. Page 16 in the user manual discusses throughput rates.

    Another thing to keep in mind is that the USB-2416-4AO is a device that remembers how it is set even after power is removed. Not all MCC devices do this. So, if a colleague sets it for temperature and you try to use it for voltage, it will generate an error until it is reconfigured with InstaCal.

  12. You can synchronize two or more devices using the Sync IO output clock. It is turned off by default, but you can enable it with InstaCal or the programming interface. Connect the Sync terminal to both devices, but allow Sync output only on one. Program the device that outputs the Sync last. Sharing the Sync signal will allow both devices to record data simultaneously. 

  13. Below is my get-board number function. It takes a device name string, such as '1208FS', to search for the device. Once it finds a device name that contains '1208FS', it determines if 'Plus' is in the name and, if so, sets the global variable PACKETSIZE to 32. Otherwise, it's 31. It is crucial to size the buffer as a multiple of PACKETSIZE times channel count. I have also attached my test program below that uses this function. 

     

           public static int GetBoardNum(string dev)
            {

                MccDaq.DaqDeviceManager.IgnoreInstaCal();
                MccDaq.DaqDeviceDescriptor[] inventory = MccDaq.DaqDeviceManager.GetDaqDeviceInventory(MccDaq.DaqDeviceInterface.Any);
                int DevicesFound = inventory.Length;
                if (DevicesFound > 0)
                {
                    for (int boardNum = 0; boardNum < DevicesFound; boardNum++)
                    {

                        try
                        {

                            if (inventory[boardNum].ProductName.Contains(dev))
                            {
                                MccDaq.MccBoard daqBoard = MccDaq.DaqDeviceManager.CreateDaqDevice(boardNum, inventory[boardNum]);
                                if (daqBoard.BoardName.Contains("Plus"))
                                    PACKETSIZE = 32;
                                else
                                    PACKETSIZE = 31;

                                return boardNum;
                            }
                        }
                        catch (ULException ule)
                        {
                            Console.WriteLine("Error occurred: " + ule.Message);
                        }
                    }
                }
                return -1;
            }

    USB_1208FS_CONT_EXAMPLE.cs

  14. The MCC 172 is not designed to use an external clock because the clock runs 512x the sample rate, and a sync pulse is used to synchronize the ADCs. GPIO 19 is used to clock other MCC 172 boards on the RPI stack, and a sync pulse on GPIO 6 synchronizes all the ADCs. None of the other MCC daqhat boards can use its clock. After the sync pulse is set low, it takes 128 conversions before data is ready.  You can make the clock appear on GPIO 19 using the SOURCE_MASTER clock mode with the mcc172_a_in_clock_config_write function. 


     

×
×
  • Create New...