IAR Embedded Workbench IDE, використання асемблера у C-проекті, avr, programming

Зазвичай необхідність використовувати асемблер буває в обробниках переривань. Розглянемо кроки, як це робиться.

1. Для обробників переривань краще створити окремий файл - виберіть меню File\New\File, вставте в новий файл модуля текст:

#pragma vector=TIMER0_OVF_vect __interrupt void TIMER0_OVF_routineTIMER0_OVF_routine( void ) OCR0 = ampl1; if (idx else if (idx else if (idx else ampl1 = 255 - SINUS[255-idx]; >> 8; fi1 += freq1; > ;

Збережіть файл як int.c.

2. Права кнопка на кореневій папці проекту у браузері "Workspace", Add\Add Files. Виберіть файл int.c.

3. Права кнопка на int.c, Options. поставте галку на Override inherited settings. Далі перейдіть на закладку List, поставте галки на Output assembler file і Include source. Після перекомпіляції проекту з'явиться асемблерний файл Debug\List\int.s90. Розберемо його вміст.

4. На початку файлу знаходиться заголовок, де вказано командний рядок для компілятора C:\Program Files\IAR Embedded Workbench 4.0\avr\bin\iccavr.exe: int.c --cpu=m16 -mt -o c:\MyDoc\FLOPPI\ANOTHER\avr\BLDC\Debug\Obj\ -lB c:\MyDoc\FLOPPI\ANOTHER\avr\BLDC\Debug\List\ --initializers_in_flash -z2 --no_cse --no_inline --no_code_motion --no_cross_call --no_clustering --no_tbaa --debug - e -I "C:\Program Files\IAR AVR Embedded Workbench 4.0\avr\INC\" -I "C:\Program Files\IAR AVR Embedded Workbench 4.0\avr\INC\CLIB\" --eeprom_size 512

5. Розглянемо налаштування компілятора детальніше. Це допоможе розібратися в тому, що відбувається, і далі компілювати c-файли окремо, без IDE.

6. Для того, щоб розібратися в асемблерному файлі, знадобиться dataseet на процесорATmega16, опис сегментів пам'яті (CSTACK, RSTACK, ..), яке можна знайти в апноуті AVR032 [2], а також опис системи команд 8-бітових AVR (8-bit AVR Instruction Set).

Отже, вийшов із вихідника int.c такий вихідний текст асемблера:

NAME int ;дає ім'я програмному модулю для подальших посилань на нього лінкером

EXTERN ?need_segment_init ;імпортує зовнішній символ ?need_segment_init

TIMER0_OVF_routineTIMER0_OVF_routine SYMBOL "TIMER0_OVF_routineTIMER0_OVF_routine" `??TIMER0_OVF_routineTIMER0_OVF_routine??INTVEC ` SYMBOL "??INTVEC 36", TIMER

RSEG TINY_Z:DATA:NOROOT(0) REQUIRE `?` // 6 uchar idx; idx: DS 1

RSEG TINY_Z:DATA:NOROOT(0) REQUIRE `?` // 7 uchar ampl1; ampl1: DS 1

ASEGN ABSOLUTE:DATA:NOROOT,01cH ;далі навіщось йде опис регістрів EEPROM __?EECR: ; (навіщо, незрозуміло - все одно вони не використовуються)

ASEGN ABSOLUTE:DATA:NOROOT,01dH __?EEDR:

ASEGN ABSOLUTE:DATA:NOROOT,01eH __?EEARL:

ASEGN ABSOLUTE:DATA:NOROOT,01fH __?EEARH:

COMMON INTVEC:CODE:ROOT(1) ;загальний (COMMON) сегмент коду, що знаходиться ; гарантовано, вирівнювання за парними байтами (1) ORG 36 ; за векторами переривань, з 36 байти `??TIMER0_OVF_routineTIMER0_OVF_routine??INTVEC`: JMPTIMER0_OVF_routineTIMER0_OVF_routine

RSEG INITTAB:CODE:NOROOT(0) `?`: DWSFE(TINY_Z) - SFB(TINY_Z) DWSFB(TINY_Z) DW0 REQUIRE ?need_segment_init

END7. Тепер залишилося замінити файл int.c на отриманий файл int.s90, що дуже просто. Для цього копіюємо файл Debug\List\int.s90 у кореневу папку проекту (там, де у нас int.c) - мається на увазі не дерево каталогів IDE (Workspace), а саме файлова папка. Потім здерева каталогів IDE (тепер мається на увазі вже не файлова система, а саме IDE) видаляється int.c (права кнопка\Remove) і додається int.s90 (права кнопка на кореневій папці проекту в браузері IDE\Add\Add Files. тип файлів вибираємо Assembler Files (*.s*;*.msa;*.asm), потім вибираємо файл int.s90 і тиснемо Open).

8. Є сенс також згадати так звані inline-оператори, які дозволяють вставляти асемблерні інструкції відразу в код C, наприклад:

або керування ніжкою порту в обробниках переривання:

#pragma vector=TIM1_OVF_vect __interrupt void TIMER1_OVF_routine( void ) asm("CBI 0x18, 2"); //asm("CBI PORTB, SERVO"), скинути SERVO 0 >

#pragma vector=TIM0_COMPA_vect __interrupt void TIMER1_COMPA_routine( void ) asm("SBI 0x18, 2"); //asm("SBI PORTB, SERVO"), встановити SERVO 1 >