Timing is off. When I'm debugging this process (used in several projects) I send easy, obvious patterns: $00, $ff, $00 or $55, $aa, $55 or $18, $00, $18 then combinations thereof. These make it more obvious which end is losing sync (or never got it). If possible, send a burst one way and look at what's received. Sending out & back makes it a Lot tougher to find the problem.
I've found the I2C protocol a great serial method. It'll take some time getting the routines right (BTDT2), but once done, it's deterministic (not timing dependent) and much faster than any async (no start or stop bits, short to no pause between bytes...). G.H. <<<)))