Embedded software is very different.
On a desktop app, abstractions and libraries save you a lot of development time. You have the luxury of throwing another couple megabytes or gigabytes of RAM or some 2+GHz 64-bit CPU cores at a problem, and someone else (users) is paying for that hardware. You may not know what systems the app will run on.
In an embedded project, resources are often very limited. In one project I worked on (PIC 17X-series processors) the hardware had 2Kwords of program memory, 8 levels of (in-hardware) stack and 192 bytes (< 0.2kB) of RAM. Different I/O pins had different capabilities and you configured the hardware as needed by writing to hardware registers. Debugging involves an oscilloscope and logic-analyzer.
In embedded, abstractions often get in the way and would manage (and cost) resources you don't have. E.g. most embedded systems have no file system. Microwave ovens are embedded systems. Car engine controllers. Some electric toothbrushes. Some noise-cancelling headphones.
One very important factor for me in developing embedded systems is knowing and controlling what the code translates to in terms of instructions, resources, memory and execution time. Often the exact sequence of instructions controls e.g. timing for hardware interface waveforms.
Abstractions and behind-the-scenes 'magic' (e.g. a garbage-collector) is great for desktop apps. Garbage-collectors save you a LOT of time chasing down memory leaks, when memory is / can be dynamically allocated.
However in the real-time embedded world we need to know and control how long things take, sometimes down to nanoseconds, and can't throw another couple meg of RAM or a faster CPU at a problem. One simple example: when doing software dimming of LEDs by controlling duty cycle (the CPU had only on/off control of the LEDs), it is NOT OK for the processor to go off and do e.g. garbage collection for 100ms because the display would visibly flash bright or go out.
A more-hypothetical example is an engine controller that directly fires spark-plugs. If that CPU does off and does garbage-collection for 50ms, the engine would cut out for a moment or fire at the wrong crankshaft engine, potentially stalling the engine (while passing?) or damaging it mechanically. You could get someone killed.