|
Not me. I don't buy new cars. The most I've ever paid for one is $5000.
Real programmers use butterflies
|
|
|
|
|
Have you verified that the reference application will work with your hardware? I would do that first or all else will be hopeless.
When I have been in a similar position I did that first and then I cloned the sample and gradually tweaked it while verifying it still works very often.
"They have a consciousness, they have a life, they have a soul! Damn you! Let the rabbits wear glasses! Save our brothers! Can I get an amen?"
|
|
|
|
|
Yes, I have.
I want to clone but, it's written significantly different than mine.
It relies very heavily on the preprocessor, and uses static variables such that you can't actually use that code to control multiple screens on a single device.
Despite it being a class (TFT_eSPI), it just delegates to "global" (static) members defined in CPP source files.
I don't want my code to operate like that for a number reasons, not the least of which is that my codebase is already in use and I don't want to dramatically change the behavior of existing driver code, even as I add new drivers and improve the performance of the old ones.
Edited to add: I've been trying to think of a way to do it incrementally without completely breaking encapsulation but so far ... wait I may have just come up with an idea.
Real programmers use butterflies
|
|
|
|
|
Teaching my granny to suck eggs here, I'm sure, but...
When I've met this before, it's generally timing: making sure all lines are firing at the right moments so the "data" lines are stable before the rise in the "Write" pulse gets to the critical level.
To check that, you don't need all data lines - just a couple and the control lines.
See exactly what the reference code is doing, and compare that to your code. You may find a signal is lagging or leading the data and that can up the whole thing. Or that the whole of your code is too efficient (I've had that and it's a PITA) and you are just too quick for the display.
Good luck!
"I have no idea what I did, but I'm taking full credit for it." - ThisOldTony
"Common sense is so rare these days, it should be classified as a super power" - Random T-shirt
AntiTwitter: @DalekDave is now a follower!
|
|
|
|
|
I was going to suggest this too. Watch the control signals and at least one data, preferably one you know changes the most.
Also,
honey the codewitch wrote: I have a layer to do the 8-bit bus I/O (software bit banging the pins on and off)
might be the source of the problem depending on how it is implemented. Since it is a parallel bus all bits have to change at the same time (using ANDs or ORs or XORs) otherwise the different rise times of the bits can trigger a bad command or cause the command to be ignored.
|
|
|
|
|
No 4 channel oscilloscope handy? - if not, maybe time to steal one somewhere. Even for my hobby tinkering it is extremely useful.
Of course there is a crazy price range here but the cheaper ones (for example Rigol 1054Z) are in a range where I prefer not driving any car that can be bought for the same price.
Synchronization would be tricky though - maybe you will have to sacrifice a data line to see CS on both for synchronization. Or you need to find a 4 channel scope with external sync, but not sure about the price range of those - from what I read, external trigger input is more of a thing with dual channel scopes (so maybe get two of those)
|
|
|
|
|
Make soup.
Really, stop what you're doing and go make soup with all the scraps you have in the fridge.
I helps.
I did that yesterday and by miracle (and RTFM) , InstallShield decided to work this morning.
CI/CD = Continuous Impediment/Continuous Despair
|
|
|
|
|
Maximilien wrote: Make soup.
Chicken soup, by preference. Get some real use out of the dead chickens that you've been waving over your code...
(Sorry, there appears to be no Chicken Soup for the Engineer's Soul )
Freedom is the freedom to say that two plus two make four. If that is granted, all else follows.
-- 6079 Smith W.
|
|
|
|
|
Have you tried another display?
"the debugger doesn't tell me anything because this code compiles just fine" - random QA comment
"Facebook is where you tell lies to your friends. Twitter is where you tell the truth to strangers." - chriselst
"I don't drink any more... then again, I don't drink any less." - Mike Mullikins uncle
|
|
|
|
|
The whole point is I'm writing a driver for this display for my library. Plus I want 8-bit parallel support in general for other TFTs and this is my testbed - i'd use another like you say, but TFTs with 8-bit parallel breakouts are much harder to find than SPI - less selection, and when you do find them they tend to be ILI9341 like I have. The larger displays typically use 16 bit parallel. I have one of those on order but most MCUs don't have enough IO pins to drive it. For that you usually need a specialized board, and a controller with a lot more IO like a little ARM monster.
Real programmers use butterflies
|
|
|
|
|
Sorry, I meant another display of the same type, maybe you have a lemon.
"the debugger doesn't tell me anything because this code compiles just fine" - random QA comment
"Facebook is where you tell lies to your friends. Twitter is where you tell the truth to strangers." - chriselst
"I don't drink any more... then again, I don't drink any less." - Mike Mullikins uncle
|
|
|
|
|
No, it works with the reference implementation I'm using. There is an existing offering called TFT_eSPI that can drive it, but there are issues with it including the inability to drive multiple displays with it. (it's implemented as a class backed by static members so it's essentially singleton)
In fact, I *just* posted a question about this, since I'm now trying to port it.
Is there any way to create a .CPP for a template[^]
The question doesn't really describe the question but it's the best I could do in the limited space.
Real programmers use butterflies
|
|
|
|
|
Quote from the OP: even have a reference implementation someone else wrote that works that I've been following. Sorry, apparently I've lost the ability to comprehend what I've read.
It's going to be a long day...
"the debugger doesn't tell me anything because this code compiles just fine" - random QA comment
"Facebook is where you tell lies to your friends. Twitter is where you tell the truth to strangers." - chriselst
"I don't drink any more... then again, I don't drink any less." - Mike Mullikins uncle
|
|
|
|
|
MOAR COFFEE! That always fixes it, right?
Real programmers use butterflies
|
|
|
|
|
The sad thing is I've already finished the pot. Yes, I'll brew another, but still...
"the debugger doesn't tell me anything because this code compiles just fine" - random QA comment
"Facebook is where you tell lies to your friends. Twitter is where you tell the truth to strangers." - chriselst
"I don't drink any more... then again, I don't drink any less." - Mike Mullikins uncle
|
|
|
|
|
Thanks to the newsletter article I finally write my very first own source code generator, yea!
I found none of the resource on the topic I found were both simple and super helpful, but the cumulative tips in all of them finally unlocked the skill for me!
Turns out it's very simple (the main hurdle is that your generator library need to target .Net Standard 2.0).. someone need to write a "source code generator for dummy" article distilled to the essential!
(hey, maybe that's an idea hey?)
Anyway... I still am left with one.. conundrum?
I made a .resx to C# code generator. I know those exists out of the box, but the resulting class doesn't support static binding event if the current culture change, which is annoying with the live culture update support in my application.
I have a large chunk of code to enable live culture update, but I thought, wouldn't it be nice if I could have a different C# resource class hey? And now I have!
my conundrum is, the default resx class's property looks like that
internal static string About {
get {
return ResourceManager.GetString("About", resourceCulture);
}
}
whereas mine looks like that
public static string? fsf { get; private set; }
public static string? hello { get; private set; }
public static string? name { get; private set; }
static partial void UpdateValues()
{
var resources = GetDictionaries(Culture);
fsf = GetResource("fsf", resources);
hello = GetResource("hello", resources);
name = GetResource("name", resources);
}
so the the default class pay a (negligible) cost on every property access, and my code pay another (negligible but bigger) cost on resource change (but none on property access).
and I keep wondering, which one is the best?
for context, this class is primarily used through databinding to inform a WPF UI.
modified 7-Dec-21 19:19pm.
|
|
|
|
|
I like MS's for the modifiability but assuming yours is generated I guess it doesn't matter so much.
Why the nullable string type though? It's already a reference type. If they're all strings I'd ditch making it nullable to keep it simple. Then you can just use a basic null check on it. Unless there's some reason for it I don't get.
I wouldn't care about the performance unless you're databinding to a real time graph or something (which I've done)
Dictionaries are pretty quick though but the main issue I see with your UpdateValues() routine (given I don't fully understand what it accomplishes) is that if you have a lot of resources it will end up being slow.
Have you considered using Lazy<T> and loading on demand on a property by property basis? Lazy<T> Class (System) | Microsoft Docs[^]
You can dump one behind each get accessor so it loads the resource the first time on demand. That way you're only loading what you use, and you're not potentially causing a burp in your application's responsiveness when UpdateValues() is called for a lot of resources.
But then I'm spitballing, not having seen all of the code.
Real programmers use butterflies
|
|
|
|
|
I decided my option is better.. because it's better to waste (negligible) time on user action (when they change the current culture) instead of while simply viewing data.
honey the codewitch wrote: Why the nullable string type though?
It's just the new syntactic sugar with nullable reference type (which is just a compiler hint, not a runtime truth). Arguably it's true they wont be null because the default culture dictionary will not be empty (with the way it's constructed). null string never bothered me, so I didn't give it a thought.. but yea.. it might a nice touch.
honey the codewitch wrote: Have you considered using Lazy<T>
Well this is clearly counter productive, because the whole point of this generator is that the culture might (will?) change. Lazy have fixed value!
(I particularly wants live change notification since I opened a software in a unintelligible foreign language and I tried to make it English, turns out I had to find the language menu, select "english" and restart... Thanks google or I would have given up)
What you might suggest (and was contemplating) is to have my properties like so instead. Which remove the need for UpdateValues() , this is also more like the MS one is doing it.
public static string? hello => GetResource("hello", GetDictionaries(Culture));
modified 7-Dec-21 22:01pm.
|
|
|
|
|
I didn't realize your culture changed over the life of the application.
You could still do this, but you'd just have to reset your lazy init. If Lazy won't let you do it you can make your own poor man's lazy using lock(object) {} but you don't even need to do that unless your object will be accessed from multiple threads.
If it's not, you can just do
if(myres==null) {
}
return myres;
and then in your update routine you just set myres to null.
Real programmers use butterflies
|
|
|
|
|
mmm... I guess this is a (negligible) over my (negligible) update, which might save a significant amount of negligible time!
mmm.. worth it!
|
|
|
|
|
new generated code thanks to you!
putting it all, just for fun.... (the other partial file is always the same and jut copied from a generator resource)
public partial class TestResource
{
public static string fsf => _fsf ?? (_fsf = GetResource("fsf", GetDictionaries(Culture)));
public static string hello => _hello ?? (_hello = GetResource("hello", GetDictionaries(Culture)));
public static string name => _name ?? (_name = GetResource("name", GetDictionaries(Culture)));
private static string? _fsf;
private static string? _hello;
private static string? _name;
static partial void UpdateValues()
{
_fsf = null;
_hello = null;
_name = null;
}
static TestResource()
{
AddCultureDictionary("", new Dictionary<string, string>
{
{ "fsf", "ffs" },
{ "hello", "hello" },
{ "name", "name" },
});
AddCultureDictionary("fr-FR", new Dictionary<string, string>
{
{ "fsf", "nom de dieu" },
{ "hello", "salut" },
{ "name", "nom" },
});
}
}
modified 7-Dec-21 22:24pm.
|
|
|
|
|
Sweet. Glad to help.
Edit: I was thinking of the case where you do like microsoft and put every error message as a resource. In resource files like that you have hundreds or thousands of resources, and the above code will handle it much better than trying to load them all at once.
I figured it was worth it because this is a code generator, so the uses of it are somewhat open ended. IOW some day someone (maybe you) will use it to generate a particularly large resource and you'll be glad it works this way. =)
Real programmers use butterflies
|
|
|
|
|
In fact... your comment scratched a itch.. and I made a new generator that use an underlying ResourceManager (like Microsoft) instead of static dictionaries! yeah!
Super witch to the rescue!
|
|
|
|
|
How about generating methods for resource strings with placeholders?
For example, if your resource string Greeting contains "Hello, {0}. The date is {1:D}." , your code could generate something like:
private static string _greeting;
public static string Greeting(object p0, object p1)
{
string value = _greeting ??= GetResource("Greeting", GetDictionaries(Culture));
return string.Format(value, p0, p1);
}
"These people looked deep within my soul and assigned me a number based on the order in which I joined."
- Homer
|
|
|
|
|
bah, the class is mostly here for live databinding of resource string in WPF UI. My class fire the static change event supported by bindings! (unlike Microsoft one, obviously)
|
|
|
|