Jump to content

    
Sign in to follow this  
Aeore

Странная ошибка с __interrupt

Recommended Posts

Контроллер : 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
}

 

и тут же получаю ошибку:

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 с конфигурацией:

-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

Edited by IgorKossak
[codebox] для длинного кода, [code] - для короткого!!!

Share this post


Link to post
Share on other sites

Вам надо вызывать прерывания из ассемблерного кода.

 

В 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  
...

Edited by desh

Share this post


Link to post
Share on other sites
Вам надо вызывать прерывания из ассемблерного кода.

 

В 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  
...

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

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

Share this post


Link to post
Share on other sites
Зачем так делать? Или порт сделан так что по другому не сделать?

 

А чем этот то способ плох? Такой стиль используется в оригинальном примере из FreeRTOS.

FreeRTOS поддерживает 2 схемы многозадачности: кооперативную и вытесняющую.

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

При вытесняющей многозадачности работа прерывания от системного таймера отличается от работы остальных прерываний.

Поэтому системное прерывание вызывается из ассемблерного кода. Линкеру не нравится, что в одном сегменте необходимо расположить и ассемблерный и сишный код.

 

 

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

 

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

 

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

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

 

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

А вот тут я с Вами совсем не согласен. Что лучше - надо решать исходя из назначения устройства.

Не всех порадует самопроизвольный сброс конечного продукта.

Edited by desh

Share this post


Link to post
Share on other sites
А чем этот то способ плох? Такой стиль используется в оригинальном примере из FreeRTOS.

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

 

При вытесняющей многозадачности работа прерывания от системного таймера отличается от работы остальных прерываний.

Поэтому системное прерывание вызывается из ассемблерного кода.

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

 

Линкеру не нравится, что в одном сегменте необходимо расположить и ассемблерный и сишный код.

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

Ерунда какая-то...

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

Не видел такой ситуации когда "Линкеру не нравится". Но создать её на свою голову наверное можно...

 

 

А вот тут я с Вами совсем не согласен. Что лучше - надо решать исходя из назначения устройства.

Не всех порадует самопроизвольный сброс конечного продукта.

Случаи бывают разные, это - да...

 

Share this post


Link to post
Share on other sites
Эм... Хотелось бы увидеть и обсудить Ваше решение указанной в первом сообщении проблеммы.

Для того чтобы увидеть решение проблемы неплохо было бы увидеть проблему.

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

 

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

 

Ваше решение

Скачал с 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:

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

 

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

Это решение?

 

Share this post


Link to post
Share on other sites

Это решение! :) Прошивки совпадают полностью. Вы победили :cheers:

 

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

Такое обычно делают сами. Кстати, в соседней ветке автор жалуется, что его система глючит после добавления нового кода.

Возможно его проект преодолел рубеж в 64 кб и у него вылезло отличие между таргетами.

Edited by desh

Share this post


Link to post
Share on other sites

_Артём_, часть фреймворка я выложил в этой ветке:

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 по идее никак не должен влиять.

Share this post


Link to post
Share on other sites
Прошивки совпадают полностью.

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

 

Вы победили :cheers:

:beer:

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

 

Такое обычно делают сами.

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

 

у меня размер бинарника всего лишь что-то около 30КБ.

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

 

А по поводу 64KB - RAMPZ влияет если оперативной памяти больше, а у меня как раз ровно 64КБ.

RAPMZ в mega128 используется для доступа к flash за пределами 64 КБ командами ELPM/SPM. То есть не ваш случай, если прошивка меньше 30 КБ.

Share this post


Link to post
Share on other sites
Убрал в файле portmacro.s90 директиву ASEG (какой-такой ASEG? что они этим сказать хотели?):

 

..

 

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

Это решение?

 

Эм.. удалил у себя - все осталось по прежнему O_o

Share this post


Link to post
Share on other sites
Эм.. удалил у себя - все осталось по прежнему O_o

Это я неточно выразился.

Надо было не

Убрал в файле portmacro.s90...
,

а так:

заменил в файле portmacro.s90 директиву ASEG на common INTVEC(1).

Share this post


Link to post
Share on other sites

И так причину такого поведения я раскрыл, но как ее поправить пока не ясно. Причина:

Похоже что линкер видит, что директива 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)

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

 

Это я неточно выразился.

Надо было не

,

а так:

заменил в файле portmacro.s90 директиву ASEG на common INTVEC(1).

 

Компилируется, спасибо!

Edited by Aeore

Share this post


Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Sign in to follow this