Writing embedded software w/o hardware
Not having hardware during the initial stages of firmware development happens. Common strategies to deal with this are:
- Spend time up front architecting the system carefully before you write any code. Of course you should do this anyway, but in this case it's even more important than usual. It's much easier to debug well thought out software than a pasta-based mess.
- Properly modularize everything, minimizing the interfaces between modules. This will help contain bugs to individual modules, and allow easier testing of individual modules.
- Write code bottom-up, hardware-touching drivers go first, high level application logic last. This allows discovering inconveniences imposed by the architecture early on. Don't be afraid to change the architecture as hardware realities come to light, but make sure all the documentation is updated accordingly.
- Simulate. Most microcontrollers companies provide software simulators of their microcontrollers. These can only go so far, but can still be very useful. Simulating the inputs and measuring the outputs of the hardware may be difficult, but checking higher level logic this way shouldn't be too hard.
This is where the modular design helps again. If you can't reasonably simulate some low level hardware interactions, you use a different version of the module that touches that hardware but that passes its own simulated actions to the upper levels. The upper levels won't know this is happening. You won't be checking the low level module this way, but most everything else.
In short, use good software desing practices, which of course you should be doing anyway.
Without any insight into what it is you're developing, or which family of microcontrollers your hardware will eventually be based on, most families of microcontrollers have low cost development systems available that have a suite of common peripherals on them, which may allow you to simulate at least some of your eventual target hardware.
Depending on how hardware dependent the application is going to be, you could just start implementing the project on a standard pc (Windows, Linux...). Most peripheral access should be abstracted anyways, so it's not a big deal to implemented some dummy functions, that are going to be replaced later. If it's not possible to simulate some behaviour, you could at least do a mockup of the system (API...), so the actual implementation is going to go a lot faster and clearer, as soon as the hardware is ready.
There are of course many things that can't be simulated, like real time behaviour or complex hardware drivers. On the other hand, a interrupt driven ADC can easily be simulated using a thread that reads values from a file or a network port.
Of course all this highly depends on various factors:
- Can you use the same/similar toolchain on controller and pc (e.g. gcc)?
- How hardware dependent is the system?
- How experienced are you with pc programming?
I, for one am designing pretty much every firmware module on a pc first.