It's not that we don't see how you could create an abstraction that works, it's that we're questioning the value of doing so.
In your example, if I want a DMA-based transfer it's fine to just hide it and block the thread waiting for the DMA interrupt. But if the hardware designer expects me to poll, now I have to find a way to put the thread to sleep and schedule it. And there are performance and timing implications for either scheme that your abstraction hides from me. At some point I'm going to stumble on those implications and get screwed badly enough by your abstraction that I need to rip it out or work around it to solve a problem. This has happened to me too many times before.
On systems that are small enough to be considered "embedded" I would much rather the OS gets the hell out of my way and lets me pick a sensible abstraction myself.
I don't see much value in having an abstraction layer in these systems unless it's for a hobby project. In an established project you would never recompile your code for a completely different hardware platform "just to see how it performs." You'd stick with the hardware you know, and you'd already have de-risked the performance questions early enough in the project that you wouldn't have written a bunch of application code yet. It's not a problem that needs to be solved in a professional environment.
There is just no way an abstraction is going to pick the best process for my needs.
And yea, while it might be a nice idea to switch chips... I’d have to go through sourcing to figure out if they make a chip in the package i would need at a price I’m willing to pay at a lead time I’m willing to wait, a week or two reading data sheets and reference manuals, updating the board hardware, changing the BOM, getting with purchasing to update the next PO, changing the assembly programming and stencils... plus documentation, plus fragmenting our hardware variations, etc.
The abstraction to switch chips, might be nice for prototyping, but yea, it’s not really useful for production, so I think I would rather my OS developers focus on other things.
In your example, if I want a DMA-based transfer it's fine to just hide it and block the thread waiting for the DMA interrupt. But if the hardware designer expects me to poll, now I have to find a way to put the thread to sleep and schedule it. And there are performance and timing implications for either scheme that your abstraction hides from me. At some point I'm going to stumble on those implications and get screwed badly enough by your abstraction that I need to rip it out or work around it to solve a problem. This has happened to me too many times before.
On systems that are small enough to be considered "embedded" I would much rather the OS gets the hell out of my way and lets me pick a sensible abstraction myself.
I don't see much value in having an abstraction layer in these systems unless it's for a hobby project. In an established project you would never recompile your code for a completely different hardware platform "just to see how it performs." You'd stick with the hardware you know, and you'd already have de-risked the performance questions early enough in the project that you wouldn't have written a bunch of application code yet. It's not a problem that needs to be solved in a professional environment.