Hoe bedoel je... een ECHT OS? Er IS helemaal geen OS!
Ik heb er nog ff over na zitten denken, en ik denk dat een werkbare oplossing iets als volgt zou kunnen zijn:
Je maakt een ringbuffer van je 300 bytes. De UART-ISR mikt daar braaf elk volgend character in wat binnen komt tenzij de 'status' flag 'complete' is. Dan doe je helemaal niks (nou ja, UART uitlezen, omdat-ie dat fijn vindt als-ie een IRQ geeft).
Tevens zet je (als je wat doet) de timerCounter variabele op 0 als je een character in de buffer mietert en zet de status op 'reading'.
Je maakt een timer-ISR die zeg elke 100μS ofzo loopt. Die doet iets als: if timerCounter<255 timerCounter++ ofzo.
Verder doet die: if (status=='reading') && (timerCounter>timeout) status='complete'
In je main loop kijk je alleen naar status. Zodra die 'complete' wordt, hebben we blijkbaar een time-out. De laatste 300 bytes zijn blijkbaar mijn data. Je kijkt waar het begin van de ringbuffer zit, doet wat leuks met je data. Let wel: alles wat op dit moment binnen komt wordt naar /dev/null gerouteerd.
Als je data 'veilig' is (of verwerkt...) dan zet je status op 'waiting'. Vanaf nu kan er weer in de buffer geschreven worden en is de data daarin dus 'instabiel'.
De waarden van 'status' zijn iets van 'reading', 'complete' en 'waiting' ofzo. Ik zou daar defines van maken om de code wat leesbaarder te houden.
Door dit foefje voorkom je ook het 16-bit variabele probleem. Immers, OF de ISR zit aan de buffer OF iets wat vanuit main aangeroepen is. Ofwel: als 'main' aan je buffer zit, dan blijft de ISR er vanaf. Als de ISR er aan zit, dan wordt main geacht niks te doen.
Daarnaast zou je kunnen overwegen om met je 300 bytes iets als CRC ofzo mee te sturen. Dat worden dan gewoon een paar bytes extra.
Voorwaarde is wel dat de zendende kant iets met die timing kan. Als timing daar absoluut niet kritisch is, dan zou ik het verzenden gewoon lekker vanuit de main doen. Daarna een delay van 100mS ofzo. En dan ga je weer wat doen. Lomp, maar simpel en effectief.