Есть несколько вариантов объединения.
1) Самый простой - можно объединить на уровне хекс-файлов. Компилируете ассемблерную подпрограмму (или программу в общем случае) с определенного адреса, а в сишной программе указываете адрес вызова (или перехода) перехода на данный адрес. Прошивки можно объединить на уровне хекс-текста, или прошить независимо, не стирая кусок, прошитый первым.
2) Оформляете ассемблерную подпрограмму в стиле, понятном компилятору cи, скажем, winavr. Ну там есть мощные ограничения, и вообще ублюдочно сделано на уровне компилятора. Вот яркий пример "ублюдочности"
Код
void static inline Signal_OUT(const uint8_t *signal, uint8_t ad2, uint8_t ad1, uint8_t ad0)
{
asm volatile(
"eor r18, r18 ;r18<-0" "\n\t"
"eor r19, r19 ;r19<-0" "\n\t"
"1:" "\n\t"
"add r18, %0;1 cycle" "\n\t"
"adc r19, %1;1 cycle" "\n\t"
"adc %A3, %2;1 cycle" "\n\t"
"lpm ;3 cycles" "\n\t"
"out %4, __tmp_reg__;1 cycle" "\n\t"
"sbis %5, 2;1 cycle if no skip" "\n\t"
"rjmp 1b ;2 cycles. Total 10 cycles" "\n\t"
:
:"r" (ad0),"r" (ad1),"r" (ad2),"e" (signal),"I" (_SFR_IO_ADDR(PORTA)), "I" (_SFR_IO_ADDR(SPCR))
:"r18", "r19"
);
}
3) Оформляете ассемблерную подпрограмму в отдельном файле с расширением .S Чуть попозже подготовлю пример оформления.