Вот так, например, в GCC делал. Это - вызов ассемблерной функции в
main: case 's': { // Кто есть на шине?
for (temp1 = 0xFF; (temp1 != 0); temp1--) {
if (!i2c_rep_start(temp1)) {
send_int(temp1);
error_msg(descriptor4,' ');
}
i2c_stop();
_delay_ms(5);
}
break;
}
Это - файл asm.s. Учтены соглашения GCC о передаче параметров в функции (см. раздел "What registers are used by the C compiler?" в avr-lib-user-manual.pdf):
;***** Функции, реализующие обмен по интерфейсу I2C.
#include <avr/io.h>
.global i2c_rep_start, i2c_write, i2c_read, i2c_stop
.equ i2cdata,24 ; R24
.equ i2cdelay,25 ; R25
.equ FORCE_PORT,DDRC
.equ SENSE_PORT,PINC
; Регистр данных порта, используемого для I2C
; Номера выводов, используемых как:
.equ SCLP,0 ; SCL
.equ SDAP,1 ; SDA
;***************************************************************************
;* Ожидание освобождения линии SCL ведомым устройством
;***************************************************************************
wait_SCL_high: ; high = 3.5uS @ 4MHz - 14 cycles
ldi i2cdelay,0xE
form_SCL_high:
dec i2cdelay
brne form_SCL_high
do_wait_SCL_high:
sbis _SFR_IO_ADDR(SENSE_PORT),SCLP
rjmp do_wait_SCL_high
ret
small_delay:
ldi i2cdelay,0xE
do_small_delay:
dec i2cdelay
brne do_small_delay
ret ; low ~ 3uS @ 4MHz - 12 cycles
; Итого ~ 150 kHz
;***************************************************************************
;* Передача повторного условия СТАРТ и адреса ведомого.
;***************************************************************************
i2c_rep_start:
sbi _SFR_IO_ADDR(FORCE_PORT),SCLP ; SCL = 0
cbi _SFR_IO_ADDR(FORCE_PORT),SDAP ; SDA = Z
cbi _SFR_IO_ADDR(FORCE_PORT),SCLP ; SCL = Z
rcall wait_SCL_high ; Ожидание освобождения SCL
;***************************************************************************
;* Передача условия СТАРТ и адреса ведомого.
;***************************************************************************
i2c_start: ; адрес - в регистре i2cdata
sbi _SFR_IO_ADDR(FORCE_PORT),SDAP ; SDA = 0 ( старт )
rcall small_delay
;***************************************************************************
;* Передача байта ( адрес или данные ).
;***************************************************************************
i2c_write:
sec ; Установить "С"
rol i2cdata ; Сохранить "С" и выдвинуть первый бит
rjmp i2c_write_first
i2c_write_bit:
lsl i2cdata
i2c_write_first:
breq i2c_get_ack ; если регистр передачи не пуст
sbi _SFR_IO_ADDR(FORCE_PORT),SCLP ; SCL = 0
brcc i2c_write_low
cbi _SFR_IO_ADDR(FORCE_PORT),SDAP ; SDA = Z
rjmp i2c_write_high
i2c_write_low:
sbi _SFR_IO_ADDR(FORCE_PORT),SDAP ; или SDA = 0
i2c_write_high:
rcall small_delay
cbi _SFR_IO_ADDR(FORCE_PORT),SCLP ; SCL = Z
rcall wait_SCL_high ; Ожидание освобождения SCL
rjmp i2c_write_bit
;***************************************************************************
;* Получение подтверждения ведомого устройства.
;* "R24" = 0 - есть подтверждение
;***************************************************************************
i2c_get_ack:
sbi _SFR_IO_ADDR(FORCE_PORT),SCLP ; SCL = 0
cbi _SFR_IO_ADDR(FORCE_PORT),SDAP ; SDA = Z
rcall small_delay
cbi _SFR_IO_ADDR(FORCE_PORT),SCLP ; SCL = Z
rcall wait_SCL_high ; Ожидание освобождения SCL
sbic _SFR_IO_ADDR(SENSE_PORT),SDAP ; если SDA = 1
ldi i2cdata,0x1 ; установить "NACK"
ret
.....
.....
Сам файл asm.s - подключен через makefile:
.....
.....
# Название ассемблерного файла проекта (без расширения)
MY_ASM = asm
.....
.....
# List Assembler source files here.
# Make them always end in a capital .S. Files ending in a lowercase .s
# will not be considered source files but generated files (assembler
# output from the compiler), and will be deleted upon "make clean"!
# Even though the DOS/Win* filesystem matches both .s and .S the same,
# it will preserve the spelling of the filenames, and gcc itself does
# care about how the name is spelled on its command-line.
ASRC = $(MY_ASM).S
.....
.....