element14 Community
element14 Community
    Register Log In
  • Site
  • Search
  • Log In Register
  • Community Hub
    Community Hub
    • What's New on element14
    • Feedback and Support
    • Benefits of Membership
    • Personal Blogs
    • Members Area
    • Achievement Levels
  • Learn
    Learn
    • Ask an Expert
    • eBooks
    • element14 presents
    • Learning Center
    • Tech Spotlight
    • STEM Academy
    • Webinars, Training and Events
    • Learning Groups
  • Technologies
    Technologies
    • 3D Printing
    • FPGA
    • Industrial Automation
    • Internet of Things
    • Power & Energy
    • Sensors
    • Technology Groups
  • Challenges & Projects
    Challenges & Projects
    • Design Challenges
    • element14 presents Projects
    • Project14
    • Arduino Projects
    • Raspberry Pi Projects
    • Project Groups
  • Products
    Products
    • Arduino
    • Avnet Boards Community
    • Dev Tools
    • Manufacturers
    • Multicomp Pro
    • Product Groups
    • Raspberry Pi
    • RoadTests & Reviews
  • About Us
  • Store
    Store
    • Visit Your Store
    • Choose another store...
      • Europe
      •  Austria (German)
      •  Belgium (Dutch, French)
      •  Bulgaria (Bulgarian)
      •  Czech Republic (Czech)
      •  Denmark (Danish)
      •  Estonia (Estonian)
      •  Finland (Finnish)
      •  France (French)
      •  Germany (German)
      •  Hungary (Hungarian)
      •  Ireland
      •  Israel
      •  Italy (Italian)
      •  Latvia (Latvian)
      •  
      •  Lithuania (Lithuanian)
      •  Netherlands (Dutch)
      •  Norway (Norwegian)
      •  Poland (Polish)
      •  Portugal (Portuguese)
      •  Romania (Romanian)
      •  Russia (Russian)
      •  Slovakia (Slovak)
      •  Slovenia (Slovenian)
      •  Spain (Spanish)
      •  Sweden (Swedish)
      •  Switzerland(German, French)
      •  Turkey (Turkish)
      •  United Kingdom
      • Asia Pacific
      •  Australia
      •  China
      •  Hong Kong
      •  India
      •  Korea (Korean)
      •  Malaysia
      •  New Zealand
      •  Philippines
      •  Singapore
      •  Taiwan
      •  Thailand (Thai)
      • Americas
      •  Brazil (Portuguese)
      •  Canada
      •  Mexico (Spanish)
      •  United States
      Can't find the country/region you're looking for? Visit our export site or find a local distributor.
  • Translate
  • Profile
  • Settings
Test & Tools
  • Technologies
  • More
Test & Tools
Blog understand TinyUSB USBTMC protocols
  • Blog
  • Forum
  • Documents
  • Files
  • Members
  • Mentions
  • Sub-Groups
  • Tags
  • More
  • Cancel
  • New
Join Test & Tools to participate - click to join for free!
  • Share
  • More
  • Cancel
Group Actions
  • Group RSS
  • More
  • Cancel
Engagement
  • Author Author: Jan Cumps
  • Date Created: 4 Oct 2023 4:14 PM Date Created
  • Views 3830 views
  • Likes 10 likes
  • Comments 25 comments
  • pico_usbtmc_scpi
  • USBTMC
  • Pico SCPI labTool
  • labview
  • scpi
Related
Recommended

understand TinyUSB USBTMC protocols

Jan Cumps
Jan Cumps
4 Oct 2023

In this post, I attempt to understand the flows that the USBTMC class driver follows for:

  • standard SCPI query / response
  • standard SCPI command only
  • *STB? status byte requests
  • service requests
  • triggers

For each scenario, I'll try to figure out how the logic flows, what flags are set or cleared, payloads, etc...

SCPI Query: *IDN? 

main.c tud_task()
usbd.c tud_task_ext()
  case DCD_EVENT_XFER_COMPLETE 
    if ( 0 == epnum ) -> else
usbtmc_device.c usbtmcd_xfer_cb()
  case STATE_IDLE
    case USBTMC_MSGID_DEV_DEP_MSG_OUT:
usbtmc_device.c handle_devMsgOutStart()
usbtmc_device.c handle_devMsgOut()
usbtmc_app.c tud_usbtmc_msg_data_cb()
  if(transfer_complete && (len >=1)
    query_received = true;
    queryState = 1
    scpi_instrument_input();

Reply

main.c usbtmc_app_task_iter()
usbtmc_app.c usbtmc_app_task_iter()
  case querystate 1-> 2 case querystate 2:
    querystate 3:
    set MAV 0x10
    set SRQ 0x40
  case querystate 3:
  // here I reply. I (or you :)) need to check what happens if the SCPI engine didn't generate acommand. 
  // that happens if the SCPI was a command, not a query.
  // will it then do the right thing?

After a reply is complete, the usb_tmc.c state machine calls  tud_usbtmc_msgBulkIn_complete_cb()

start side note 1

One thing I found, is that when I send a command (does not reply) instead of a query (replies), tud_usbtmc_msgBulkIn_complete_cb() is not called and MAV isn't reset....
This call originates from the usbtmc_device.c. A file that I do not have control over.

I am taking the "executive" decision" to clear that flag myself if the SCPI didn't return a value (because it got a command instead of a query). This is how I rewrote case 3 (transmit). Check the else clause at the end:

 case 3: // time to transmit;
    if(/* TODO check if I can just ignore this*/ bulkInStarted &&  (buffer_tx_ix == 0)) {
      if(reply_len) // if this was a SCPI query, there will be a reply.
      {
        tud_usbtmc_transmit_dev_msg_data(reply,  tu_min32(reply_len,msgReqLen),true,false);
        queryState = 0;
        bulkInStarted = 0;
        reply_len = 0;
      }
      else
      {
        buffer_tx_ix = tu_min32(buffer_len,msgReqLen);
        tud_usbtmc_transmit_dev_msg_data(buffer, buffer_tx_ix, buffer_tx_ix == buffer_len, false);
      }
      // MAV is cleared in the transfer complete callback.
    }
    else { // this is not thread safe. When you port this to a multi-threaded device, take care to put guard rails
      // jc 20231004: when there is no reply from the scpi engine (the input was a command, not a query)
      // mark as if a reply was sent
      // MAV is cleared here
      if(! reply_len) { 
        // if this was a SCPI query, reply_len woulkd be > 0
        // and tud_usbtmc_msgBulkIn_complete_cb() would clear all of this.
        uint8_t status = getSTB();
        status &= (uint8_t) ~(IEEE4882_STB_MAV); // clear MAV
        setSTB(status);
        queryState = 0;
        bulkInStarted = 0;
        buffer_tx_ix = 0;
        query_received = false;
      }
    }

This code should only be called when a SCPI string is sent that does not generate a reply (a command instead of a query)

end side note 1

start side note 2

or should I not set the MAV bit? if there's no reply? In the end, it's the Message Available Bit

end side note 2

todo

  • Sign in to reply

Top Comments

  • ggabe
    ggabe over 2 years ago in reply to Jan Cumps +1
    The SRQ bit is only set after a certain delay (125ms), for strictly testing purposes with the included python test client. I rebuilt the test example, and the python test cases passing pedantically.…
  • ggabe
    ggabe over 2 years ago in reply to Jan Cumps +1
    The tinyusb build puzzles me. I wanted to add to following function to usbtmc_device.c (and I did), but the usbtmc_app.c breaks at linking time. I don't know what else to say in the tinyusb codebase, neither…
  • ggabe
    ggabe over 2 years ago in reply to ggabe +1
    Some progress: creates a proper Visa handled SRQ, when invoked from tud_usbtmc_msg_trigger_cb, no errors in IO Trace: index 0cf0743a7..e94e7c062 100644 --- a/src/class/usbtmc/usbtmc_device.c +++ b/src…
Parents
  • Jan Cumps
    Jan Cumps over 2 years ago

     ggabe , the TinyUSB example sets SRQ bit (0x40) in the STB when it receives a SCPI command. https://github.com/hathach/tinyusb/blob/b394ae1786911a89ea3437d7090cda477ca7df6c/examples/device/usbtmc/src/usbtmc_app.c#L219


    I ported this to the firmware

    Are you aware that this is normal? I start to expect that this is a test case, not default behaviour ...

    • Cancel
    • Vote Up 0 Vote Down
    • Sign in to reply
    • More
    • Cancel
  • ggabe
    ggabe over 2 years ago in reply to Jan Cumps

    The tinyusb build puzzles me. I wanted to add to following function to usbtmc_device.c (and I did), but the usbtmc_app.c breaks at linking time. I don't know what else to say in the tinyusb codebase, neither the other app functions, like tud_usbtmc_start_bus_read(void); declares anything special to get included in the library.

    bool tud_usbtmc_send_srq(void); 

     

    usbtmc_app.c:(.text.tud_usbtmc_msg_trigger_cb+0xc): undefined reference to `tud_usbtmc_send_srq'

    • Cancel
    • Vote Up +1 Vote Down
    • Sign in to reply
    • More
    • Cancel
  • ggabe
    ggabe over 2 years ago in reply to ggabe

    The SRQ test. While running, push the button on GP27, several times.

    import pyvisa
    import time
    from pyvisa import ResourceManager, constants
    import sys, re, traceback, logging
    import time
    
    rm = pyvisa.ResourceManager('@ivi') 
    
    logging.basicConfig(level=logging.ERROR)
    
    def handle_event(resource, event, user_handle):
        print(f"Handled event {event.event_type} on {resource}")
        #resource.called = True
        stb = instr.read_stb()
        instr.write("*CLS")
    
    with rm.open_resource("USB0::0xCAFE::0x4000::E660C06213865126::INSTR") as instr:
    
        print('Opened\n')
        
        instr.called = False
    
        event_type = constants.EventType.service_request
        event_mech = constants.EventMechanism.handler
        wrapped = instr.wrap_handler(handle_event)
        user_handle = instr.install_handler(event_type, wrapped, 42)
        instr.enable_event(event_type, event_mech, None)
        
        instr.write("STAT:OPER:DIGI:INP:NTR 4\n")
        instr.write("STAT:OPER:DIGI:INP:ENAB 4\n")
        instr.write("STAT:OPER:ENAB 1\n")
    
        instr.write("*CLS")
        instr.write("*SRE 128") #leaving Bit6 MSS - off
        
        print('Done setting up')
           
        cv = 0
        
        try:
            while not instr.called:
                time.sleep(0.01)
                    
        except: 
            instr.close()
            logging.exception("While looping")
    
    try:
        instr.disable_event(event_type, event_mech)
    except:
        print('err while disabling event')
    try:
        instr.uninstall_handler(event_type, wrapped, user_handle)
    except:
        print('err while disabling event')
    
    instr.close()
    print("Done.")

    • Cancel
    • Vote Up +1 Vote Down
    • Sign in to reply
    • More
    • Cancel
  • ggabe
    ggabe over 2 years ago in reply to ggabe

     Jan Cumps putting a reply here, so Jan can get a notification. The thread is having some issue, not scrolling to the end. Need to click the "new" to see the last comments.

    • Cancel
    • Vote Up 0 Vote Down
    • Sign in to reply
    • More
    • Cancel
  • Jan Cumps
    Jan Cumps over 2 years ago in reply to ggabe

    there's a (not obvious) View More link when scrolling comments

    • Cancel
    • Vote Up 0 Vote Down
    • Sign in to reply
    • More
    • Cancel
  • Jan Cumps
    Jan Cumps over 2 years ago in reply to ggabe

    No success yet (with 0x82):

    I added the tests to the existing test set:

    def handle_event(resource, event, user_handle):
    	print(f"Handled event {event.event_type} on {resource}")
    	stb = inst.read_stb()
    	inst.write("*CLS")
    
    
    rm = visa.ResourceManager()
    reslist = rm.list_resources("USB?::?*::INSTR")
    print(reslist)
    
    if (len(reslist) == 0):
    	sys.exit()
    
    i = 0
    inst = None
    while i < len(reslist):
    	inst = rm.open_resource(reslist[i]);
    	inst.timeout = 3000
    	inst.clear()
    
    	print("+ IDN")
    	if(test_idn()):
    		print("Instrument found")
    		# reset
    		inst.write("*RST")
    		# test 3 pins
    		j = 0
    		while j < 3:
    			test_pin(j)
    			j += 1
    	print("SCPI errors during test: "+ inst.query("SYST:ERR:COUNT?"))
    	print("Basis Test complete")
    
    	print("Experimental test")
    	inst.called = False
    	event_type = constants.EventType.service_request
    	event_mech = constants.EventMechanism.handler
    	wrapped = inst.wrap_handler(handle_event)
    	user_handle = inst.install_handler(event_type, wrapped, 42)
    	inst.enable_event(event_type, event_mech, None)
    	
    	inst.write("STAT:OPER:DIGI:INP:NTR 4\n")
    	inst.write("STAT:OPER:DIGI:INP:ENAB 4\n")
    	inst.write("STAT:OPER:ENAB 1\n")
    
    	inst.write("*CLS")
    	inst.write("*SRE 128") #leaving Bit6 MSS - off
    	
    	print('Done setting up')
    	   
    	cv = 0
    	
    	try:
    		while not inst.called:
    			time.sleep(0.01)				
    	except: 
    		inst.close()
    #	   logging.exception("While looping")
    
    	try:
    		inst.disable_event(event_type, event_mech)
    	except:
    		print('err while disabling event')
    	try:
    		inst.uninstall_handler(event_type, wrapped, user_handle)
    	except:
    		print('err while disabling event')
    	
    	inst.close()
    	i += 1
    
    print("All Test complete")

    Looping here:

     while not inst.called:
        time.sleep(0.01)

    I'll try debugging when I have some quality time ....

    • Cancel
    • Vote Up 0 Vote Down
    • Sign in to reply
    • More
    • Cancel
  • ggabe
    ggabe over 2 years ago in reply to Jan Cumps

    My build with the patch file applied over Pico/TinyUSB:      pico_scpi_usbtmc_labtool.uf2      

    • Cancel
    • Vote Up +1 Vote Down
    • Sign in to reply
    • More
    • Cancel
Comment
  • ggabe
    ggabe over 2 years ago in reply to Jan Cumps

    My build with the patch file applied over Pico/TinyUSB:      pico_scpi_usbtmc_labtool.uf2      

    • Cancel
    • Vote Up +1 Vote Down
    • Sign in to reply
    • More
    • Cancel
Children
  • Jan Cumps
    Jan Cumps over 2 years ago in reply to ggabe

    ... confirming that this firmware works  with the test script ...

    • Cancel
    • Vote Up 0 Vote Down
    • Sign in to reply
    • More
    • Cancel
element14 Community

element14 is the first online community specifically for engineers. Connect with your peers and get expert answers to your questions.

  • Members
  • Learn
  • Technologies
  • Challenges & Projects
  • Products
  • Store
  • About Us
  • Feedback & Support
  • FAQs
  • Terms of Use
  • Privacy Policy
  • Legal and Copyright Notices
  • Sitemap
  • Cookies

An Avnet Company © 2025 Premier Farnell Limited. All Rights Reserved.

Premier Farnell Ltd, registered in England and Wales (no 00876412), registered office: Farnell House, Forge Lane, Leeds LS12 2NE.

ICP 备案号 10220084.

Follow element14

  • X
  • Facebook
  • linkedin
  • YouTube