lauantai 25. marraskuuta 2017

Where did my code crash?


If you don't have suitable JTAG debugger handy, program crash in microcontroller can be annoyingly difficult to trace, especially if it happens only occasionally. Here is one trick for tracking those crashes with relatively low overhead;

char dtraceBuff[32];
 
void dtrace(char *data)
{
  memcpy(dtraceBuff, data, 32);
}


void dtraceOut()
{
  dtraceBuff[sizeof(dtraceBuff)-1] = 0; 
  printf("DTrace: %s\n", dtraceBuff);
}


And now you can sprinkle dtraces liberally around the code;

dtrace("intHandler");
dtrace("intHandlerEnd");
dtrace("mainloop 1");
dtrace("mainloop 2");
...


And in the beginning of main() (after your output system is initialized, of course) put call  to dtraceOut(). Replace print here with your favorite method of getting debug data out of your MCU.

So, when the code crashes, you can see immediately that DTrace says "mainloop 1". So what happens between "mainloop 1" and "mainloop 2"? If the issue isn't immediately clear, put more outputs there and try again. Eventually you will find the crash point.

But wait, if you just copy paste above to your program, you will quickly find out that this doesn't actually work. No matter what happens, DTrace will only print out empty string. Why is this?

The C standard requires that all uninitialized data is initialized to zeros. So when program crashes, MCU is reset and the C startup code will wipe all data - including dtraceBuff here.

There are however ways to prevent this, and exact method depends on compiler used. For Microchip's XC16, there is persistent-attribute:

char dtraceBuff[32] __attribute__((persistent));

For GCC (ARM), I couldn't quickly find similar simple attribute to make this easy. So next best option is to play around with linker script and related __attribute__s, allocating part of RAM for persistent (non-cleared) data and putting your data there. This is however a bit more complex task than simple attribute, so I will not go into details in this post. Personally I have modified the startup code I use to not clear any variables - but if you do that, you absolutely must remember to initialize everything yourself. And this can be cause for more subtle bugs by itself.

There is also option of using nonvolatile memory for trace data, but I'd recommend not going that route unless you absolutely, positively have to. Nonvolatile memories typically can only handle so many writes before they are worn out (Flash some 10k erase cycles; EEPROM some 10M; MRAM and FRAM on the other hand have "infinite" life), and they (unless embedded to MCU core) are slower to access. Sometimes, however, that may be only option.




lauantai 18. marraskuuta 2017

Super AAA


It seems I found an supercharged AA battery today.


While for moment this seemed very interesting, after few seconds of consideration I came into a conclusion that my multimeter is more or less at fault here.

This specific meter one is one I have at home. It retails (in brick-and-mortar store) for something like 20€ (or at least it was, some 10 years ago), and today you could get similar one for some 5-10€ or so on ebay. While it claims to be CAT III rated, I wouldn't let let it anywhere close of high voltages. In other words, it's a PoS that is barely sufficient for checking if a battery is full or empty. And apparently it can't do even that that well.

But I don't blame the meter for all that. I knew what I was buying when I got that one.

Now, if you take a closed look at the picture above, you may see a small "battery" symbol on the screen of the meter, meaning that its battery is almost empty. Unlike newer models, this one has toggle-button for power. You always must remember to turn it off after you're done with it.

What isn't immediately obvious is that the same battery symbol also means that the readings aren't to be trusted anymore, as we can see here. I haven't really bothered to check how these things work (in circuit level), but I guess that there is a reference voltage somewhere - generated from battery voltage by some kind of accurate reference, be it of shunt or whatever type - which isn't correct anymore due to low battery voltage and this is causing readings to be higher than they should be.



As proven by quick battery change. With fresh 9v battery the reading is much closer to what I'd expect it to be. Old battery read about 4,9v when I took it out so it clearly was at end of its life.

So, in short, if your multimeter reading seems suspicious, take another meter and cross-check. And never, ever, take these cheap ones anywhere close to mains voltages, for any reason. The protections they contain are simply insufficient and they will kill you for that.





torstai 9. marraskuuta 2017

This is supposed to be a server?


Annoyed ranting ahead. I've been incredibly busy lately and will be for some time still, so I guess there'll be no exciting posts coming anytime soon.

I just bought a new server to our office. This is essentially backup machine, in case main system lets the operating smoke out, with planned use for other, less important purposes like staging/testing and whatnot in the mean time.

Since this is supposed to be server, it will eventually be headless, accessible via SSH key login only. Before that, however, I do need monitor of OS installation and so on.

But here I hit a problem: Some un-friggin-believeable idiot has decided to equip this server with no other display connections than two Displayport 1.2  connectors. Which cannot even be converted to more useful signals - like, oh, HDMI - without nothing less than active converters (so no, DP-HDMI cable won't just work. I tried.)

And really, two displayports? What is this machine supposed to be, some movie prop with separate huge monitors scrolling text logs for anyone to see?

Guess what: I don't have even one display that has displayport here anywhere. And by quick review, displays that have DP aren't exactly the cheapest ones there are. I don't like the idea of having to get a new display just for this, but damn it if I just have to... Or maybe I'll have to get a converter. We'll see...