I have experience with C, but don't really know where to start with the lower level stuff.
I'm thinking I should start with a simple book like Electrical Engineering 101 (http://www.amazon.com/Electrical-Engineering-101-Third-Schoo...). Once I have a grasp on some EE basics I might be able to step into the Microprocessor programming a bit better, knowing a bit of what's happening behind the scenes.
Any thoughts/suggestions?
So one one hand you need to understand your host processor (and it's constellation of helper chips) inside and out. Some modern SoC systems like the ones in smartphones have everything built into the same chip, so you wind up combing through 5,700 page Technical Reference Manuals like this one for the Freescale i.MX6:
http://cache.freescale.com/files/32bit/doc/ref_manual/IMX6DQ...
Or, in the case of more generic micro-based systems like an Arduino or something, you're reading datasheets for other little chips and figuring out how to interface them to your host's kernel.
But yeah, knowing how to wire up a transistor or LED to a processor without cooking it (or your power supply) is a good thing. You can learn a lot from taking apart other people's projects and seeing how they do it. Common patterns start showing up.
If you are specially interested in embedded programming, try to start using avr-gcc directly- you'll be forced to learn lot of low level stuff which is hidden by Arduino IDE.
I have an ISP and Arduino. I yanked the AVR chip off the Arduino and stuck it on a breadboard. I just found it difficult to do anything due to my lack of EE knowledge. I could understand the programming basics due to past experience, but had no clue what was going on under the hood.
I think I'll read that EE book and then continue on the path I'm on.
If not, well, you may need to learn assembly, C, or something else entirely (but probably not EE), and the experiment will help you discover what exactly you need.
One project that might help out is to re-write the 8150 USB network adapter project. The devices that have this chipset are easy and cheap to find and the data sheet is easily available. There's a PCI version of this chip, the 8139, too. The USB project would be easier since you're passing URBs back and forth. The LDD3 book and the data sheet is more or less all you need.
I'm wondering if I might be able to help out, but I'm not sure I understand the question. I'm an EE with a lot of digital design background and some software.
TLDR : Pick up any of the hundreds of books on it and start learning! If you're having trouble motivating yourself, try solving Competition Programming problems in it - it's usually a good way to learn a new language.
One thing that's surprised me with Linux development is how nice the APIs are to work with. Things like the file_operations struct, and the linked list stuff are very well thought out and easy to use (as easy as they could be for C programming).
My only complaint is that a lot of the written documentation is out of date about a number of topics. As the kernel has evolved it's gained and lost a number of APIs and depending on when resources were published they may say a number of conflicting things about how to carry out a task (registering a character device and getting it in /dev is the big one that comes to mind).
Debugging, by the other side...
Another a great tool while developing for the kernel is the LXR [2] which is a browser-based indexer of the kernel source, for each of the kernel versions. Again great for checking out how to interface with a subsystem or how different calls are used.
So, if you can, try to connect with actual kernel engineers, do an interesting project in school for a professor doing hardware work, etc.
One project that might help out is to re-write the 8150 USB network adapter project. The devices that have this chipset are easy and cheap to find and the data sheet is easily available. There's a PCI version of this chip, the 8139, too.
Having a driver-writing background, I silently laugh at the recent unit testing hype - I simply know from experience there are areas where you need much more care, gut and skill than def test_something(). And besides, you just can't unit-test a DMA transfer.
Or are drivers loaded while holding a global lock? Even though driver (un)loading probably is fairly rare, that seems a bit heavy to me.
Worse, the 'goto fail' path, if it is ever hit, seems to leak a register_chrdev call.
I liked the clarity and ease it offered to a first timer. I was somehow miffed about moving to kernel team from Java(app dev) but after this tut and some more articles I was disappointed when finally I didn't. This was one of the articles that changed my leaning towards learning C in a positive way. C is now my interview language :-).