We describe a three-course upper-division undergraduate sequence at the University of California, Riverside that teaches both the principles and the practice of embedded system design. While many courses teach embedded systems programming, typically at the assembly language level, few teach the principles of the field - especially with respect to hardware and software codesign. The courses have been under development since 1994 and have been quite stable for several years. The courses are based on a new textbook that emphasizes a unified view of hardware and software. All three courses include both lectures and an extensive lab component. Feedback from students who have graduated and work in the embedded systems field has been excellent.