Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Странная ошибка с __interrupt
Форум разработчиков электроники ELECTRONIX.ru > Микроконтроллеры (MCs) > Cредства разработки для МК > IAR
Aeore
Контроллер : ATMega128 + 64KB внешней памяти
Используется внешний xcl файл (настройки линкера)

Есть смешанный C/C++ проект, в котором крутится FreeRTOS. Во FreeRTOS используется одно прерывание, которое там описано в ассемблерном исходнике с помощью директивы ORG. Проект компилится и кое-как работает, с прерываниями проблем нет. Теперь я хочу описать еще одно прерывание, пишу:
Код
// --------------------------------------------------------------------------
// USART1_TXC_vect = 0x80
#pragma vector = USART1_TXC_vect
extern "C" __interrupt void interrupt_UART1_TXComplete( void )
// --------------------------------------------------------------------------
{
   // nop
}


и тут же получаю ошибку:
CODE
Building configuration: p45g - Debug
Updating build tree...
CPTracePrinterStrategy.cpp
Linking
Error[e16]: Segment INTVEC (size: 0x84 align: 0x1) is too long for segment definition. At least 0x2c more bytes needed.
The problem occurred while processing the segment placement command
"-Z(CODE)INTVEC=0-(_..X_INTVEC_SIZE-1)", where at the moment of placement the available memory ranges were
"CODE:0-2f,CODE:34-8b"
Reserved ranges relevant to this placement:
CODE:0-2f ?FILL1
CODE:30-33 Absolute code from portmacro
CODE:34-8b ?FILL2
Warning[w18]: Segment INTVEC (seg part no 7, symbol "interrupt_UART1_TXComplete::??INTVEC 128" in module
"CPTracePrinterStrategy", address [0-83]) overlaps segment ?FILL1 (from module "?FILLER_BYTES", address [0-2f])
Warning[w18]: Segment on the address 30-33 in the module portmacro (F:\PROJECTS\Ð-45\P45G\Firmware\1.00\out\obj\
Debug\portmacro.r90) overlaps segment INTVEC (seg part no 7, symbol "interrupt_UART1_TXComplete::??INTVEC
128" in module "CPTracePrinterStrategy", address [0-83])
Warning[w18]: Segment INTVEC (seg part no 7, symbol "interrupt_UART1_TXComplete::??INTVEC 128" in module
"CPTracePrinterStrategy", address [0-83]) overlaps segment ?FILL2 (from module "?FILLER_BYTES", address [34-8b])
Warning[w70]: The segment "?FILL1" on address 0 overlaps previous content in the raw-binary output file. The previously
content will be overwritten.
Error while running Linker

Total number of errors: 1
Total number of warnings: 4


Теперь немного арифметики: размер сегмента INTVEC_SIZE равен 8C (140 байт), а значит сюда поместятся 35 (140 / 4) векторов. В параметре vector указан адрес 0x80, что равно 128 байтам, т.е. адрес находится в пределе сегмента кода прерываний. Так что его тогда не устраивает?

Вот XCL с конфигурацией:
CODE
-ca90

-D_..X_INTVEC_SIZE=8C /* 4 bytes * 35 vectors */
-D_..X_FLASH_TEND=FF /* End of tiny flash memory */
-D_..X_FLASH_NEND=FFFF /* End of near flash memory */
-D_..X_FLASH_END=1FFFF /* End of flash memory */

-D_..X_SRAM_BASE=100 /* Start of ram memory */
-D_..X_SRAM_TEND=100 /* End of tiny ram memory */
-D_..X_SRAM_END=10FF /* End of ram memory */

-D_..X_EEPROM_END=FFF /* End of eeprom memory */

-D_..X_CSTACK_SIZE=400 /* 1024 bytes for auto variables and saved registers. */
-D_..X_RSTACK_SIZE=400 /* 1024 bytes for return addresses */
-D_SVC_STACK_SIZE=0 /* not used */
-D_IRQ_STACK_SIZE=0 /* scmRTOS uses CSTACK for irq */
-D_..X_NEAR_HEAP_SIZE=CAFA /* 0 bytes of heap. */

-D_..X_EXT_SRAM_BASE=1100
-D_..X_EXT_SRAM_END=FFFF

-D_..X_EXT_EPROM_BASE=_..X_SRAM_BASE
-D_..X_EXT_EPROM_END=_..X_SRAM_END

-D_..X_EXT_EEPROM_BASE=_..X_SRAM_BASE
-D_..X_EXT_EEPROM_END=_..X_SRAM_END





-Z(CODE)INTVEC=0-(_..X_INTVEC_SIZE-1)
-H1895 -h(CODE)0-_..X_INTVEC_SIZE /* RETI */
-Z(CODE)TINY_F=_..X_INTVEC_SIZE-_..X_FLASH_TEND
-Z(CODE)NEAR_F,SWITCH,DIFUNCT=_..X_INTVEC_SIZE-_..X_FLASH_NEND
-Z(CODE)CODE=_..X_INTVEC_SIZE-_..X_FLASH_END
-Z(FARCODE)FAR_F=_..X_INTVEC_SIZE-_..X_FLASH_END
-Z(CODE)HUGE_F,INITTAB=_..X_INTVEC_SIZE-_..X_FLASH_END
-Z(CODE)TINY_ID,NEAR_ID=_..X_INTVEC_SIZE-_..X_FLASH_END
-Z(CODE)CHECKSUM#_..X_FLASH_END

-Z(DATA)TINY_I,TINY_Z,TINY_N=_..X_SRAM_BASE-_..X_SRAM_TEND
-Z(DATA)NEAR_I,NEAR_Z=_..X_EXT_SRAM_BASE-_..X_EXT_SRAM_END
-Z(DATA)RSTACK+_..X_RSTACK_SIZE=_..X_EXT_SRAM_BASE-_..X_EXT_SRAM_END
-Z(DATA)CSTACK+_..X_CSTACK_SIZE=_..X_EXT_SRAM_BASE-_..X_EXT_SRAM_END
-Z(DATA)IOSTREAM_N#_..X_EXT_SRAM_BASE-_..X_EXT_SRAM_END
-Z(DATA)NEAR_HEAP+_..X_NEAR_HEAP_SIZE=_..X_EXT_SRAM_BASE-_..X_EXT_SRAM_END
-Z(XDATA)EEPROM_I,EEPROM_N=0-_..X_EEPROM_END
-Z(CONST)NEAR_C=_..X_EXT_EPROM_BASE-_..X_EXT_EPROM_END
-Z(DATA)NEAR_N=_..X_EXT_EEPROM_BASE-_..X_EXT_EEPROM_END

-e_PrintfLarge=_Printf
-e_medium_write=_formatted_write
-e_small_write_P=_formatted_write_P
-e_ScanfLarge=_Scanf
-e_medium_read=_formatted_read
-e_medium_read_P=_formatted_read_P

-w29


А вот и два MAP файла (сегменты)

ДО добавления прерывания
Код
INTVEC     CODE     00000000 - 00000003     4     Common     1
?FILL1     CODE     00000004 - 0000002F     2C     Relative     0
?FILL2     CODE     00000034 - 0000008B     58     Relative     0
NEAR_F     CODE     0000008C - 00000275     1EA     Relative     0
SWITCH     CODE     00000276 - 000002A9     34     Relative     1
CODE     CODE     000002AA - 000070D5     6E2C     Relative     1
HUGE_F     CODE     000070D6         Predefined     0
INITTAB     CODE     000070D6 - 000070E3     E     Relative     0
TINY_ID     CODE     000070E4         Predefined     0
NEAR_ID     CODE     000070E4 - 000072ED     20A     Relative     0


и ПОСЛЕ:
Код
?FILL1     CODE     00000000 - 0000002F     30     Relative     0
INTVEC     CODE     00000000 - 00000083     84     Common     1
?FILL2     CODE     00000034 - 0000008B     58     Relative     0
NEAR_F     CODE     0000008C - 00000275     1EA     Relative     0
SWITCH     CODE     00000276 - 000002A9     34     Relative     1
CODE     CODE     000002AA - 000070D7     6E2E     Relative     1
HUGE_F     CODE     000070D8         Predefined     0
INITTAB     CODE     000070D8 - 000070E5     E     Relative     0
TINY_ID     CODE     000070E6         Predefined     0
NEAR_ID     CODE     000070E6 - 000072EF     20A     Relative     0
desh
Вам надо вызывать прерывания из ассемблерного кода.

В portmacro.s90 добавить

Код
...
EXTERN interrupt_UART1_TXComplete
...
ORG USART1_TX_vect
  jmp interrupt_UART1_TXComplete


в Вашем коде определить функцию прерывания как

Код
#pragma diag_suppress=Ta006    
extern "C" __interrupt void interrupt_UART1_TXComplete( void )
#pragma diag_default=Ta006
{
}


Еще рекомендую заглушить все неиспользуемые вектора прерываний кодом

Код
...
ORG INT0_vect
  reti  
  
ORG INT1_vect
  reti  
  
ORG INT2_vect          
  reti  
...
_Артём_
Цитата(desh @ Jun 1 2013, 09:05) *
Вам надо вызывать прерывания из ассемблерного кода.

В portmacro.s90 добавить

Код
...
EXTERN interrupt_UART1_TXComplete
...
ORG USART1_TX_vect
  jmp interrupt_UART1_TXComplete


в Вашем коде определить функцию прерывания как

Зачем так делать? Или порт сделан так что по другому не сделать?


Цитата(desh @ Jun 1 2013, 09:05) *
в Вашем коде определить функцию прерывания как

Код
#pragma diag_suppress=Ta006    
extern "C" __interrupt void interrupt_UART1_TXComplete( void )
#pragma diag_default=Ta006
{
}

Обычно этого достаточно. Без редактирования ассемблерных файлов.

Цитата(desh @ Jun 1 2013, 09:05) *
Еще рекомендую заглушить все неиспользуемые вектора прерываний кодом

Код
...
ORG INT0_vect
  reti  
  
ORG INT1_vect
  reti  
  
ORG INT2_vect          
  reti  
...

Опять же ИАР сам с этим справлялся.
P.S. И лучше заполнить вектора не reti, а сбросом.
desh
Цитата
Зачем так делать? Или порт сделан так что по другому не сделать?


А чем этот то способ плох? Такой стиль используется в оригинальном примере из FreeRTOS.
FreeRTOS поддерживает 2 схемы многозадачности: кооперативную и вытесняющую.
При кооперативной многозадачности можно использовать стандартный способ работы с прерываниями, если изменить соответствующим образом порт.
При вытесняющей многозадачности работа прерывания от системного таймера отличается от работы остальных прерываний.
Поэтому системное прерывание вызывается из ассемблерного кода. Линкеру не нравится, что в одном сегменте необходимо расположить и ассемблерный и сишный код.


Цитата
Обычно этого достаточно. Без редактирования ассемблерных файлов.


Обратите внимание, здесь используется директива подавления предупреждения, а не установки адреса прерывания.

Цитата
Опять же ИАР сам с этим справлялся.

В этом случае не справляется, так как сегмент разбит на несколько частей ассемблерными вызовами.

Цитата
P.S. И лучше заполнить вектора не reti, а сбросом.

А вот тут я с Вами совсем не согласен. Что лучше - надо решать исходя из назначения устройства.
Не всех порадует самопроизвольный сброс конечного продукта.
_Артём_
Цитата(desh @ Jun 1 2013, 18:01) *
А чем этот то способ плох? Такой стиль используется в оригинальном примере из FreeRTOS.

Тем что надо прописывать вектора вручную. То есть приходится брать на себя работу ИАРа.

Цитата(desh @ Jun 1 2013, 18:01) *
При вытесняющей многозадачности работа прерывания от системного таймера отличается от работы остальных прерываний.
Поэтому системное прерывание вызывается из ассемблерного кода.

Не вижу, если честно необходимости вызова из ассемблерного файла при вытесняющей многозадачности (может такая необходимость есть, но она неочевидна).

Цитата(desh @ Jun 1 2013, 18:01) *
Линкеру не нравится, что в одном сегменте необходимо расположить и ассемблерный и сишный код.
В этом случае не справляется, так как сегмент разбит на несколько частей ассемблерными вызовами.

Ерунда какая-то...
Что же по-вашему нельзя объявлять обработчики в *.с и *.asm файлах без каких-то трюков?
Не видел такой ситуации когда "Линкеру не нравится". Но создать её на свою голову наверное можно...


Цитата(desh @ Jun 1 2013, 18:01) *
А вот тут я с Вами совсем не согласен. Что лучше - надо решать исходя из назначения устройства.
Не всех порадует самопроизвольный сброс конечного продукта.

Случаи бывают разные, это - да...
desh
Эм... Хотелось бы увидеть и обсудить Ваше решение указанной в первом сообщении проблеммы.
_Артём_
Цитата(desh @ Jun 1 2013, 18:38) *
Эм... Хотелось бы увидеть и обсудить Ваше решение указанной в первом сообщении проблеммы.

Для того чтобы увидеть решение проблемы неплохо было бы увидеть проблему.
ТС тут выложил нам много букв скрипты линкера, который непонятно что линкует, кучу ошибок вызванных непонятно чем, фреймворки которых никто не видел и тп. Вместо того чтобы выложить проект, в котором проблема возникает. ТС наверное думает что тут форум телепатов...

К тому же непонятно как ТС запустил Freertos на M128 - демо-проект с сайта freertos сделан под M323 и для запуска его на M128 требуется некоторая модификация под таргет. Или я не там брал freertos и есть где-то готовый проект под M128 и другие меги? Где такое берут?

Цитата(desh @ Jun 1 2013, 18:38) *
Ваше решение

Скачал с freertos.org демо-проект. Заменил в нём таргет на mega128.

Добавил в файл main.c:
Код
#pragma vector=USART1_UDRE_vect
__interrupt void Uart1_UDRE_Handler()
{
}


Получил в ответ такую ругань:
Цитата
Error[e16]: Segment INTVEC (size: 0x80 align: 0x1) is too long for segment definition. At least 0x44 more bytes needed. The problem occurred while processing the segment placement command
"-Z(CODE)INTVEC=0-(_..X_INTVEC_SIZE-1)", where at the moment of placement the available memory ranges were "CODE:0-2f,CODE:34-47,CODE:50-8b"
Reserved ranges relevant to this placement:
CODE:0-2f ?FILL1
CODE:30-33 Absolute code from portmacro
CODE:34-47 ?FILL2
CODE:48-4f Absolute code from portmacro
CODE:50-8b ?FILL3
Error while running Linker

Total number of errors: 1
Total number of warnings: 1


Убрал в файле portmacro.s90 директиву ASEG (какой-такой ASEG? что они этим сказать хотели?):
Код
    common INTVEC(1)

    ORG TIMER1_COMPA_vect            ; Vector address
        jmp SIG_OUTPUT_COMPARE1A    ; ISR

    ORG USART0_RXC_vect                ; Vector address
        jmp SIG_UART_RECV            ; ISR

    ORG USART0_UDRE_vect                ; Vector address
        jmp SIG_UART_DATA            ; ISR

    
    RSEG CODE



Добавил в main.c:
CODE

volatile char TxData[8];
volatile unsigned char TxIndex, TxSize;

#pragma vector=USART1_UDRE_vect
__interrupt void Uart1_UDRE_Handler()
{
unsigned char tx_index=TxIndex;
UDR1=TxData[tx_index++];
if (tx_index==TxSize)
UCSR1B&=~(1<<UDRIE1);

TxIndex=tx_index;

}

static void vErrorChecks( void *pvParameters )
{
static volatile unsigned long ulDummyVariable = 3UL;
UCSR1A =
0
| (0<<RXC1)
| (1<<TXC1)
| (0<<UDRE1)
| (0<<FE1)
| (0<<DOR1)
| (0<<UPE1)
| (0<<U2X1)
| (0<<MPCM1)
;
UCSR1B=
0
| (0<<RXCIE1)
| (1<<TXCIE1)
| (0<<UDRIE1)
| (0<<RXEN1)
| (1<<TXEN1)
| (0<<UCSZ12)
| (0<<RXB81)
| (0<<TXB81)
;
UCSR1C=
0
| (0<<UMSEL0)
| (0<<UPM01)
| (0<<UPM00)
| (0<<USBS0)
| (1<<UCSZ01)
| (1<<UCSZ00)
| (0<<UCPOL0)
;
UBRR1H=0;
UBRR1L=5;

/* The parameters are not used. */
( void ) pvParameters;

/* Cycle for ever, delaying then checking all the other tasks are still
operating without error. */
unsigned long counter=0;
for( ;; )
{

TxSize=sprintf(TxData, "t=%x", counter++);
TxIndex=0;
UCSR1B|=(1<<UDRIE1);

prvCheckOtherTasksAreStillRunning();
vTaskDelay( 3);//mainCHECK_PERIOD );
}
}


Цитата
IAR Universal Linker V5.2.3.14
Copyright 1987-2011 IAR Systems AB.

12 992 bytes of CODE memory (+ 12 range fill )
1 928 bytes of DATA memory (+ 21 absolute )

Errors: none
Warnings: none


Прерывание работает, но не отвалилось что-нибудь в другом месте не знаю...
Это решение?
desh
Это решение! sm.gif Прошивки совпадают полностью. Вы победили cheers.gif

Цитата
К тому же непонятно как ТС запустил Freertos на M128 - демо-проект с сайта freertos сделан под M323 и для запуска его на M128 требуется некоторая модификация под таргет. Или я не там брал freertos и есть где-то готовый проект под M128 и другие меги? Где такое берут?

Такое обычно делают сами. Кстати, в соседней ветке автор жалуется, что его система глючит после добавления нового кода.
Возможно его проект преодолел рубеж в 64 кб и у него вылезло отличие между таргетами.
Aeore
_Артём_, часть фреймворка я выложил в этой ветке:
http://electronix.ru/forum/index.php?showt...p;#entry1166837
Портировал под М128 я сам.
На счет RETI или RESET - линкеру указан ключ "-H1895 -h(CODE)0-_..X_INTVEC_SIZE" (см первый пост), где это делается автоматически (0x1895 это опкод reti)

desh, у меня размер бинарника всего лишь что-то около 30КБ. А по поводу 64KB - RAMPZ влияет если оперативной памяти больше, а у меня как раз ровно 64КБ. Команды записи во флеш из юзеркода не вызываются, так что RAMPZ по идее никак не должен влиять.
_Артём_
Цитата(desh @ Jun 1 2013, 23:47) *
Прошивки совпадают полностью.

Прошивки могут и не совпадать - линкер как-нибудь по-другому может всё расположить.

Цитата(desh @ Jun 1 2013, 23:47) *
Вы победили cheers.gif

beer.gif
"За нашу победу" и выпил, кстати...

Цитата(desh @ Jun 1 2013, 23:47) *
Такое обычно делают сами.

К сожалению. Зря у freertos так сделано - привязали демо проект к какой-то экзотической mega323. Лучше бы проект под mega256 выложили - его проще на других мегах запустить было бы.

Цитата(Aeore @ Jun 2 2013, 11:12) *
у меня размер бинарника всего лишь что-то около 30КБ.

Тогда RAMPZ нипричом.

Цитата(Aeore @ Jun 2 2013, 11:12) *
А по поводу 64KB - RAMPZ влияет если оперативной памяти больше, а у меня как раз ровно 64КБ.

RAPMZ в mega128 используется для доступа к flash за пределами 64 КБ командами ELPM/SPM. То есть не ваш случай, если прошивка меньше 30 КБ.
Aeore
Цитата(_Артём_ @ Jun 1 2013, 22:56) *
Убрал в файле portmacro.s90 директиву ASEG (какой-такой ASEG? что они этим сказать хотели?):

..

Прерывание работает, но не отвалилось что-нибудь в другом месте не знаю...
Это решение?


Эм.. удалил у себя - все осталось по прежнему O_o
_Артём_
Цитата(Aeore @ Jun 3 2013, 20:57) *
Эм.. удалил у себя - все осталось по прежнему O_o

Это я неточно выразился.
Надо было не
Цитата
Убрал в файле portmacro.s90...
,
а так:
заменил в файле portmacro.s90 директиву ASEG на common INTVEC(1).
Aeore
И так причину такого поведения я раскрыл, но как ее поправить пока не ясно. Причина:
Похоже что линкер видит, что директива org попадает в сегмент прерываний, но он не просто добавляет код инструкции в сегмент начиная с заданного адреса, а усекает весь сегмент на размер org + размер всех инструкций после него (пока не встретится директива смены сегмента). Таким образом
Код
ORG TIMER1_COMPA_vect    ; Vector address
jmp SIG_OUTPUT_COMPARE1A; ISR

(TIMER1_COMPA_vect = 0x30)
и ошибка
Код
Error[e16]: Segment INTVEC (size: 0x84 align: 0x1) is too long for segment definition. At least 0x2c more bytes needed.

для USART1_TXC_vect (= 0x80) связанны таким соотношением:

0x8C - (0x30 + 4) = 0x58

Таким образом он считает, что максимальный размер сегмента равен 0x58 байт. Проверяем так - берем два вектора
Код
#define    ADC_vect             (0x54)
#define    EE_RDY_vect          (0x58)

и пытаемся их использовать. Первый работает, второй нет.

Цитата(_Артём_ @ Jun 3 2013, 21:47) *
Это я неточно выразился.
Надо было не
,
а так:
заменил в файле portmacro.s90 директиву ASEG на common INTVEC(1).


Компилируется, спасибо!
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.