3

I'm writing UWP application in C# for Windows 10 IoT Core on Raspberry Pi 3B, which is supposed to interact with TI ADS1601 16-bit ADC. In order to communicate with this chip, I have to bitbang simple SPI-like serial communication protocol, and first init the conversion through timely sent signals, which is illustrated on below image, taken from ADS1601 manual:

enter image description here

In order to init ADC, I have to sent SYNC pulse according to CLK (clock signal) from crystal generator, and upon reading valid response from chip, it is ready for data retrieval. Detecting edges is where I start to experience difficulties.

My code, inspired directly by official Windows IoT Core GPIO example:

// Open GPIO 27 - CLK (clock generator signal) listener
CLK2 = gpio.OpenPin(27);
CLK2.SetDriveMode(GpioPinDriveMode.Input);
CLK2.ValueChanged += EdgeDetCLKOnValueChanged; // event handler

Event handler looks like this:

private void EdgeDetCLKOnValueChanged(GpioPin sender, GpioPinValueChangedEventArgs args)
{
    if (args.Edge.Equals(GpioPinEdge.FallingEdge))
        CLKedge = F_; //F_ == 0b11110000;
    if (args.Edge.Equals(GpioPinEdge.RisingEdge))
        CLKedge = _R; //_R == 0b00001111;
}

It basically just sets a fancy token, indicating which edge occurred. It is being used and cleared in method responsible for communication init. Basically I use (i would like to use) such handlers for ValueChange event for a couple of other pins.

All of these (token, GpioPin instance, event handler and init methods) are members of same public class SimpleSerialProtocol. Whole code can be inspected here.

THE PROBLEM is, when event handler is getting attached and starts firing (because it works), garbage collector goes nuts and starts popping out way too often, to the degree it freezes whole application.

enter image description here

  • top box displays memory usage and yellow dots represent occurrences of GC.

In this project, I have CLK frequency selector, and when I select lowest frequency (around 112Hz) app sorta works (GC fires every 5-10s), but sometimes data frame I receive from ADC gets messed up. As I start selecting higher frequencies, GC pops out more and more frequently (which makes sense, as ValueChanged event on GpioPin is being excited more often) to the point where app freezes and crashes. I can also illustrate this behavior with this image,

enter image description here

taken from in-VisualStudio Performance Profiler test. It represents about 30 sec of idle app operation, on the left there is present (subscribed) ValueChanged handler, on the right it is commented out. Also, in the left picture every other activity is filtered out, so it could fit somehow and show degree of havoc wreaked by garbage collector, represented by orange bars.

I am very intimidated by this problem, as I imagine all garbage collection stuff is infinitely complicated. Could you help me eliminate this, clearly erroneous behavior? Pardon my verbose description, I hope that it is as compact as it could and, nonetheless, understandable.

EDIT

I made a few Snaphots from Memory Usage tool

enter image description here

and there is displayed state of heap and summed up difference in objects/references quantity between those snapshots (I made first one on idle before subscribing handlers to ValueChanged and four more throughout various operation, which are using these handlers).

In differences listing, most of differences is in RuntimeType objects, and when I choose this item for more details, there is this phrase on top of list:

Object[] (pinned access) (it is displayed in Polish, so my attempt at translating it may be wrong).

I do not now, however, what this might mean, and I can't find any more specific information about this objects (like some references to my code).

JPBlanc
  • 70,406
  • 17
  • 130
  • 175
zaguoba
  • 33
  • 7
  • I don't know about .NET/UWP development on RaspPi, but try some more profiling to find out where/what in your program creates a lot of objects. It is clear (as shown in one of your images) that your program creates a lot of objects (of whatever type). Which of course will trigger the GC to clean up. The course of action should be to find the part(s) of your program creating a lot of temp/intermediary objects and try to change/optimize them in some appropriate way so that they don't create that many objects. –  Sep 14 '18 at 19:02
  • (Not sure if the majority of created objects is the event handler argument for the handler you attached or not, but if the creation of those objects filling the heap is practically out of your control, then you might also consider letting your program manually invoking the GC at opportune times...) –  Sep 14 '18 at 19:06
  • In Visual Studio performance profiler there are 4 options: Application Timeline, CPU usage (both available), Memory Usage and Network (both unavailable). If someone would tell me, how to run Memory usage test and why this option is currently disabled, that would be great. Otherwise, I don't know a way to do 'profiling', not a pro here definitely – zaguoba Sep 14 '18 at 19:07
  • The performance report should provide you with different views (https://learn.microsoft.com/en-us/visualstudio/profiling/dotnet-memory-data-views?view=vs-2017) which you can use to identify the type of objects allocated and where those objects were created (call stack). Can't help with details thoug, as i don't have VS at hand to look at the profiler UI :( –  Sep 14 '18 at 19:22
  • What if instead of subscribing to value changed, you create a task which polls the state instead? – bas Sep 14 '18 at 19:22
  • @bas I suppose there are numerous workarounds to this problem, but it is my university project, so main point here is to learn stuff, and I am eager to learn as well as great fan of things working in a way they are supposed to :) – zaguoba Sep 14 '18 at 20:08
  • A typical reason for this is quitting programming too soon. We can't see what the ValueChanged event handler does, but it is common when getting started to not actually process the data you receive but only display it on the UI. That can get out of hand badly, the device data rate can very easily overwhelm the ability of the UI to keep up with that rate. And pointless, the human eye just can't read that fast, updating more than ~20 times per second just looks like a blur. – Hans Passant Sep 17 '18 at 10:49
  • @Hans Passant it's not clear for me what you mean by "quitting programming too soon". As for my program, it does not display data at high rate. It is merely one frame of data (16 bits) collected and displayed for one click of starting button. When there is no action from user, no data is collected, nothing new is displayed, and app is effectively idle. Nonetheless, described effect is present from subscribing handler to event onward. I also presume, that handler routine should be as short as possible (advice from embedded systems I follow here as well). Isn't it the case? – zaguoba Sep 17 '18 at 12:41
  • bitbanging is going to be the problem. At a high frequency like that its going to block the CPU and start to lag, causing all sorts of problems. You would be better of trying to get it working through a hardware implemented protocol. All your pains will go away. Just as a rule of thumb, never bitbang on an event driven OS. You can bitbang on Arduinos because the timings are guaranteed. So maybe getting an atiny as a proxy would be easier too, rather than solving this problem. This a problem that has been discussed allot already. – Piotr Kula Sep 19 '18 at 13:00
  • @ppumpkin this 'protocol' required by my ADS1601 ADC is not a true hardware SPI, hence my name for it, deriving from chip's manual: SimpleSerialProtocol. It w o r k s, on low CLK frequency, even this is not real time device, even that it is still executed from UI thread (which is dumb). But I cannot go further with development without resolving this GC problem - as it should not behave like this no matter above circumstances, locking up entire application on such frequent rate! Furthermore, this is an educational/graduation project, thus it's not feasible for me to use any workarounds. – zaguoba Sep 19 '18 at 13:11
  • @zaguoba, I think you can refer to this document about [how to Improve garbage collection performance](https://learn.microsoft.com/en-us/windows/uwp/debug-test-perf/improve-garbage-collection-performance). – Michael Xu Sep 21 '18 at 07:20

0 Answers0