Assembly programming is programming at the lowest level. It is where the programmer (using mnemonics) describes the program in the processors own instruction set. It is the best approach to efficient, lean, fast coding. The problem with assembly programming is that it is a slow, laborious task, and the resultant code tends to be very hard to maintain, except for the smallest of programs.
Assembly programming is most suitable for hard and fast applications. At Absolute Software we occasionally write drivers in assembly language, but we would still write the application code in C. Most decent compilers make it very straight-forward to mix C and assembly within the same program.
A recent project that we have used assembly programming was an RFID project. The project required us to decode RFID data on-the-fly as it came in on a port pin. In this case, every processor cycle counted - in fact, we didn't even have time for context saving in our interrupts. This meant that the whole application needed to be in assembly, as we had to have very low level control on how the working register (in the PIC) was used.
Another example of a project where we needed assembly programming, was for a scientific instrument where we had to scan a photo-diode array every 10ms. The diode array consisted of 512 elements, so we had to scan through them very quickly, with optimisations such as clocking data whilst A to D conversions were being performed. This is a classic example of where assembly programming comes into its own, as it is very difficult to multi-task in this way using C programming.
In conclusion, there is a time and a place for assembly programming. In most cases we would recommend using C for embedded programming.