Test and Measurement Forum

Cannot disable auto-trigger when doing pure digital trigger

Post your C and C++ discussions here

Cannot disable auto-trigger when doing pure digital trigger

Postby rs20 » Wed May 17, 2017 10:38 am

I'm having huge trouble configuring my 3406D MSO to use a purely digital trigger. The following code ought to wait for 128 falling edges on D11, but the scope nearly instantly progresses between steps 5 and 10 even when D11 is tied to 3.3V (i.e., there should be no falling edges). Steps 5 and 6 show my trigger setup code.

The API documentation is incredibly unclear about how to achieve this: I must call ps3000aSetTriggerChannelProperties (passing a 0 to autoTriggerMilliseconds) to prevent auto triggering; but as I'm not triggering on any analog channels, I must pass 0 to nChannelProperties, which according to the documentation causes triggering to be "switched off". Hence, when read literally according to the documentation, it is impossible to trigger purely off the digital port. But I suspect this isn't true, as the Picoscope 6 software can do this just fine.

The triggering documentation is hopeless in general, how all these different triggering calls interact is totally left as guesswork to the reader.

It's also completely unclear whether I should call ps3000aSetDigitalPort. If I want to record analog waveforms, but just trigger from digital, do I need to enable the port or not? Enabling it implies that I'd end up retrieving the digital waveform, which is not at all desired. But disabling might prevent it from being available for triggering. Again, the documentation falls flat by documenting that the "enabled" parameter controls "whether or not to enable the channel". Not useful.

Any advice on how to do normal (non-"auto") pure digital triggering would be most greatly appreciated.

Code: Select all
void runSweep(LPCTSTR szPort, double start, double stop, int points) {
   _TCHAR buf[400];
   //_stprintf_s(buf, _T("%s Start: %lf, Stop: %lf, Steps: %d"), szPort, start, stop, points);

   //char ch;
   PICO_STATUS status;
   UNIT unit;

   printf("PS3000A driver example program\n");
   printf("\nOpening the device...\n");

   //status = PICO_USER_CALLBACK;


   // 1. Open the oscilloscope using ps3000aOpenUnit().
   status = openDevice(&unit);

   // 2. Select channel ranges and AC / DC coupling using ps3000aSetChannel().
   const PS3000A_RANGE range = PS3000A_1V;
   const float conv = 1.0f / 32512 * 10.0f;
   status = ps3000aSetChannel(unit.handle, PS3000A_CHANNEL_A, TRUE, PS3000A_DC, range, 0.0f);

   // 3.[MSOs only] Set the digital port using ps3000aSetDigitalPort().

   // 3.5. ps3000aMemorySegments
   const uint32_t noCaptures = 128;
   const int32_t noSamples = 100000;
   int32_t maxSamples = 0;
   status = ps3000aMemorySegments(unit.handle, noCaptures, &maxSamples);
   if (maxSamples < noSamples) {
      status = maxSamples;

   // 4. Using ps3000aGetTimebase(), select timebases until the required nanoseconds per sample is located.

   float targetTimeIntervalNs = 1.0f;
   float timeIntervalNs = 0.0f;
   uint32_t timebase = 0;;
      uint64_t timebaseUpper = 1LL << 32;
      int32_t maxSamples2 = 0;
      while (((uint64_t)timebaseUpper - (uint64_t)1) > (uint64_t)timebase) {
         uint32_t timebaseMid = timebase + (timebaseUpper - timebase) / 2;
         status = ps3000aGetTimebase2(unit.handle, timebaseMid, noSamples, &timeIntervalNs, 0, &maxSamples2, 0); // error 14
         if (status == PICO_INVALID_TIMEBASE) {
            timeIntervalNs = -1;
            status = PICO_OK;
         if (timeIntervalNs > targetTimeIntervalNs) {
            timebaseUpper = timebaseMid;
         else {
            timebase = timebaseMid;
      while ((status = ps3000aGetTimebase2(unit.handle, timebase, noSamples, &timeIntervalNs, 0, &maxSamples2, 0)) == PICO_INVALID_TIMEBASE) {
      if (maxSamples2 < noSamples) {
         status = maxSamples2;

   _stprintf_s(buf, _T("Timebase: %d, TimeIntervalNs: %f"), (int)timebase, timeIntervalNs);

   // 5. Use the trigger setup functions ps3000aSetTriggerChannelConditionsV2(), ps3000aSetTriggerChannelDirections() and ps3000aSetTriggerChannelProperties() to set up the trigger if required.
   status = ps3000aSetTriggerChannelProperties(unit.handle, NULL, 0, 0, 0);

   whatevs.channelA = PS3000A_CONDITION_DONT_CARE;
   whatevs.channelB = PS3000A_CONDITION_DONT_CARE;
   whatevs.channelC = PS3000A_CONDITION_DONT_CARE;
   whatevs.channelD = PS3000A_CONDITION_DONT_CARE;
   whatevs.external = PS3000A_CONDITION_DONT_CARE;
   whatevs.aux = PS3000A_CONDITION_DONT_CARE;
   whatevs.pulseWidthQualifier = PS3000A_CONDITION_DONT_CARE;
   whatevs.digital = PS3000A_CONDITION_TRUE;
   status = ps3000aSetTriggerChannelConditionsV2(unit.handle, &whatevs, 1);

   // 6.[MSOs only] Use the trigger setup functions ps3000aSetTriggerDigitalPortProperties() to set up the digital trigger if required.
   trigger.channel = PS3000A_DIGITAL_CHANNEL_11;
   trigger.direction = PS3000A_DIGITAL_DIRECTION_FALLING;

   status = ps3000aSetTriggerDigitalPortProperties(unit.handle, &trigger, 1);

   // {
   // 7. Set the number of memory segments equal to or greater than the number of captures required using ps3000aMemorySegments(). Use ps3000aSetNoOfCaptures() before each run to specify the number of waveforms   to capture.
   status = ps3000aSetNoOfCaptures(unit.handle, noCaptures);

   // 8. Start the oscilloscope running using ps3000aRunBlock().
   status = ps3000aRunBlock(unit.handle, 50000, 50000, timebase, 0, NULL, 0, NULL, NULL);

   // 9. Wait until the oscilloscope is ready using the ps3000aIsReady() or wait on the callback function.
   for (;;) {
      int16_t ready = 0;
      status = ps3000aIsReady(unit.handle, &ready);
      if (ready) break;

   _stprintf_s(buf, _T("Done."));

   // 10. Use ps3000aSetDataBuffer() to tell the driver where your memory buffers are.
   int16_t *buffers[noCaptures];
   for (int segment = 0; segment < noCaptures; segment++) {
      buffers[segment] = (int16_t*)malloc(sizeof(int16_t) * noSamples);
      if (buffers[segment] == 0) {
         status = 1337;
      status = ps3000aSetDataBuffer(unit.handle, PS3000A_CHANNEL_A, buffers[segment], noSamples, segment, PS3000A_RATIO_MODE_NONE);

   // 11. Transfer the blocks of data from the oscilloscope using ps3000aGetValuesBulk().
   uint32_t actualSamples = noSamples;
   int16_t overflow[noCaptures];
   status = ps3000aGetValuesBulk(unit.handle, &actualSamples, 0, noCaptures - 1, 1, PS3000A_RATIO_MODE_NONE, overflow);

   // 14. Repeat steps 7 to 13 if necessary.
   // 15. Stop the oscilloscope using ps3000aStop().
   status = ps3000aStop(unit.handle);

Posts: 0
Joined: Wed May 17, 2017 10:14 am

Re: Cannot disable auto-trigger when doing pure digital trig

Postby rs20 » Wed May 17, 2017 11:12 pm

Just closing the loop here; I tried using ps3000aSetDigitalPort:

Code: Select all
ps3000aSetDigitalPort(unit.handle, PS3000A_DIGITAL_PORT1, 1, 3276 /* 0.5V */);

This caused my program to crash, with a near-identical message to that shown in this other post of mine. However, upgrading to VS2017 has stopped this crash from happening, and my program is now triggering off the digital port as intended.

This is still concerning for a couple of reasons;
-- I still don't have confirmation whether ps3000aSetDigitalPort ought to be necessary. Is the hardware designed such that it is impossible to trigger off a digital pin without also dedicating half the on-device RAM to recording the entire sweep? This might be a perfectly reasonable design compromise to make, but it should be clearly called out in the programmer's guide because I feel that it's non-obvious and anomalous with respect to other oscilloscopes out there.
-- I didn't change my code, PicoScope headers, or PicoScope DLLs during the upgrade from VS2013 to VS2017. This is worrying as it seems far more likely that there is a heisenbug/undefined behaviour in my or Picoscope's code that is merely being masked by the upgrade to VS2017, than there being a fundamental code generation bug in VS2013. Fortunately my usecase is not at all critical, so I can afford to deal with any recurrence of this bug as it comes.
Posts: 0
Joined: Wed May 17, 2017 10:14 am

Re: Cannot disable auto-trigger when doing pure digital trig

Postby Hitesh » Thu May 18, 2017 8:40 am

Hi rs20,

By default, the driver will enable all channels (including the digital ports) when the connection is made to the device via the ps3000aOpenUnit() call. I believe the ranges will be set to the maximum so the User has to call the appropriate function to turn off the appropriate channel/digital port and set the correct settings for the desired channels/ports.

Please note that each digital port consists of 8 digital channel e.g. PORT0 is D0 to D7 inclusive.

You will need to enable the digital port to setup a trigger on a digital channel. The ps3000aSetTriggerChannelConditionsV2() function should be called with at least one of the PS3000A_TRIGGER_CONDITIONS_V2 structures specifying a digital trigger.

When the channel is enabled, the device will allocate memory for it. It should be possible to ignore the data by passing NULL for the data buffer in the call to ps3000aSetDataBuffer() or ps3000aSetDataBuffers().

In the Block mode description of the Programmer's Guide (section 3.7.1), we state:

The maximum number of values depends upon the size of the oscilloscope's memory. The memory buffer is shared between the enabled channels, so if two channels are enabled, each receives half the memory. If three or four channels are enabled, each receives a quarter of the memory. These calculations are handled transparently by the driver. The block size also depends on the number of memory segments in use (see ps3000aMemorySegments).

For the PicoScope 3000 and 3000D Series MSOs, the memory is shared between
the digital ports and analog channels. If one or more analog channels is enabled at
the same time as one or more digital ports, the memory per channel is one quarter
of the buffer size.

With regards to the crash, would it be possible to send your code in to support@picotech.com please? I can then test it here.

I will feed your comment back to the Development Team about the memory allocation and request an update for the Programmer's Guide with respect to enabling a digital port for a digital trigger.

Last edited by Hitesh on Thu May 18, 2017 9:26 am, edited 4 times in total.
Reason: Added information from Programmer's Guide

Technical Support Engineer
Site Admin
Site Admin
Posts: 2387
Joined: Tue May 31, 2011 3:43 pm
Location: St. Neots, Cambridgeshire

Return to C and C++

Who is online

Users browsing this forum: No registered users and 0 guests