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
  • 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 3248 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 1 year 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 1 year 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 1 year 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…
  • Jan Cumps
    Jan Cumps over 1 year ago in reply to Jan Cumps

    Also tested with NI VISA Interactive Control:

    image

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

     ggabe , good news - your tud_usbtmc_send_srq() works. Without the patching need. With the endpoint 0x82

    image

    Yesterday's failure was probably due to pull-up resistor that was sitting bad on the breadboard...

    • Cancel
    • Vote Up 0 Vote Down
    • Sign in to reply
    • More
    • Cancel
  • Jan Cumps
    Jan Cumps over 1 year 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
  • ggabe
    ggabe over 1 year 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
  • Jan Cumps
    Jan Cumps over 1 year 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
>
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