реклама на сайте
подробности

 
 
2 страниц V   1 2 >  
Reply to this topicStart new topic
> GCC и C++ для Cortex-M3
Pavel V.
сообщение Feb 6 2012, 12:20
Сообщение #1


Местный
***

Группа: Свой
Сообщений: 211
Регистрация: 3-06-06
Пользователь №: 17 742



Пытаюсь собрать следующий код:

CODE
#include "LPC17xx.h"

typedef enum
{
ePort0,
ePort1,
ePort2,
ePort3,
ePort4
} LPCPort;

typedef enum
{
eHigh,
eLow
} LPCActive;

typedef enum
{
eInput,
eOutput
} LPCDirection;

template<LPCPort port, uint8_t pin, LPCActive activestate = eHigh> struct Pin;

template<LPCPort port, uint8_t pin, LPCActive activestate>
struct Pin
{
static const uint32_t mask = 1UL << pin;
LPC_GPIO_TypeDef* GetPointer()
{
return (port == ePort0 ? LPC_GPIO0 :
port == ePort1 ? LPC_GPIO1 :
port == ePort2 ? LPC_GPIO2 :
port == ePort3 ? LPC_GPIO3 :
LPC_GPIO4);
}
void On()
{
activestate == eHigh ?
GetPointer()->FIOSET = mask :
GetPointer()->FIOCLR = mask;
}
void Off()
{
activestate == eHigh ?
GetPointer()->FIOCLR = mask :
GetPointer()->FIOSET = mask;
}
void Mode(LPCDirection dir)
{
dir == eOutput ?
GetPointer()->FIODIR |= mask :
GetPointer()->FIODIR &= ~mask;
}
uint32_t IsActive()
{
uint32_t ret = GetPointer()->FIOPIN & mask;
if (activestate == eHigh)
{
return ret > 0 ? 1 : 0;
}
else
{
return ret > 0 ? 0 : 1;
}
}
};


CODE
class IOutput
{
public:
IOutput()
{
}
virtual ~IOutput()
{
}

virtual void Set(uint32_t state) = 0;
virtual uint32_t Get() = 0;
};

template<LPCPort port, uint8_t pin, LPCActive activestate>
class Output: public Pin<port, pin, activestate> , IOutput
{
public:

Output()
{
_pin.Off();
_pin.Mode(eOutput);
}

virtual ~Output()
{
}

virtual void Set(uint32_t state)
{
state ? _pin.On() : _pin.Off();
}

virtual uint32_t Get()
{
return _pin.IsActive();
}
private:
Pin<port, pin, activestate> _pin;
};


Если собирать вот такой main.cpp:

Код
Pin<ePort4, 29, eHigh> g_testPin;

int main(void)
{
    while (1) {
        g_testPin.On();
        g_testPin.Off();
    }
}


Все ОК, выходной файл 800 байт.

Но если попробовать вот такой main.cpp:

Код
Output<ePort4, 29, eHigh> g_testPin;

int main(void)
{
    while (1) {
        g_testPin.Set(1);
        g_testPin.Set(0);
    }
}


Линкер начинает ругаться:

Код
/opt/arm-kgp-eabi/lib/gcc/arm-kgp-eabi/4.7.0/../../../../arm-kgp-eabi/lib/thumb/cortex-m3/libc.a(lib_a-abort.o): In function `abort':
abort.c:(.text.abort+0xa): undefined reference to `_exit'
/opt/arm-kgp-eabi/lib/gcc/arm-kgp-eabi/4.7.0/../../../../arm-kgp-eabi/lib/thumb/cortex-m3/libc.a(lib_a-sbrkr.o): In function `_sbrk_r':
sbrkr.c:(.text._sbrk_r+0xc): undefined reference to `_sbrk'
/opt/arm-kgp-eabi/lib/gcc/arm-kgp-eabi/4.7.0/../../../../arm-kgp-eabi/lib/thumb/cortex-m3/libc.a(lib_a-signalr.o): In function `_kill_r':
signalr.c:(.text._kill_r+0xe): undefined reference to `_kill'
/opt/arm-kgp-eabi/lib/gcc/arm-kgp-eabi/4.7.0/../../../../arm-kgp-eabi/lib/thumb/cortex-m3/libc.a(lib_a-signalr.o): In function `_getpid_r':
signalr.c:(.text._getpid_r+0x0): undefined reference to `_getpid'
/opt/arm-kgp-eabi/lib/gcc/arm-kgp-eabi/4.7.0/../../../../arm-kgp-eabi/lib/thumb/cortex-m3/libc.a(lib_a-writer.o): In function `_write_r':
writer.c:(.text._write_r+0x10): undefined reference to `_write'
/opt/arm-kgp-eabi/lib/gcc/arm-kgp-eabi/4.7.0/../../../../arm-kgp-eabi/lib/thumb/cortex-m3/libc.a(lib_a-closer.o): In function `_close_r':
closer.c:(.text._close_r+0xc): undefined reference to `_close'
/opt/arm-kgp-eabi/lib/gcc/arm-kgp-eabi/4.7.0/../../../../arm-kgp-eabi/lib/thumb/cortex-m3/libc.a(lib_a-fstatr.o): In function `_fstat_r':
fstatr.c:(.text._fstat_r+0xe): undefined reference to `_fstat'
/opt/arm-kgp-eabi/lib/gcc/arm-kgp-eabi/4.7.0/../../../../arm-kgp-eabi/lib/thumb/cortex-m3/libc.a(lib_a-isattyr.o): In function `_isatty_r':
isattyr.c:(.text._isatty_r+0xc): undefined reference to `_isatty'
/opt/arm-kgp-eabi/lib/gcc/arm-kgp-eabi/4.7.0/../../../../arm-kgp-eabi/lib/thumb/cortex-m3/libc.a(lib_a-lseekr.o): In function `_lseek_r':
lseekr.c:(.text._lseek_r+0x10): undefined reference to `_lseek'
/opt/arm-kgp-eabi/lib/gcc/arm-kgp-eabi/4.7.0/../../../../arm-kgp-eabi/lib/thumb/cortex-m3/libc.a(lib_a-readr.o): In function `_read_r':
readr.c:(.text._read_r+0x10): undefined reference to `_read'
collect2: error: ld returned 1 exit status
make: *** [Test2.elf] Error 1


Пытался подсунуть заглушки системных функций, тогда собирается, но размер выходного файла больше 40 Кб sm.gif

Если для класса Output убрать наследование от абстрактного класса IOutput, линкер требует только функцию _sbrk, хотя тоже непонятно почему, ведь в программе нигде не используется динамическое выделение памяти..

Тулчейны пробовал разные - эффект сохраняется.

Ключи компиляции и сборки:

Код
Оптимизация -O2

# GCC
GCFLAGS = -O$(OPTIMIZATION) -gdwarf-2 -mcpu=cortex-m3 -mthumb -mthumb-interwork -mlong-calls -ffunction-sections -fdata-sections -Wall -Wextra --std=gnu99 -DTNKERNEL_PORT_CORTEXM3
GCFLAGS += $(patsubst %,-I%,$(INCDIRS)) -I.

# G++
GPFLAGS = -O$(OPTIMIZATION) -gdwarf-2 -mcpu=cortex-m3 -mthumb -mthumb-interwork -mlong-calls -ffunction-sections -fdata-sections -Wall -Wextra -fno-rtti -fno-exceptions -DTNKERNEL_PORT_CORTEXM3
GPFLAGS += $(patsubst %,-I%,$(INCDIRS)) -I.

# Assembler
ASFLAGS = $(LISTING) -mcpu=cortex-m3 -mthumb -x assembler-with-cpp
ASFLAGS += $(patsubst %,-I%,$(INCDIRS)) -I.

# Linker
LDFLAGS = -T$(LSCRIPT) -mcpu=cortex-m3 -mthumb -O$(OPTIMIZATION) -Wl,-Map=$(PROJECT).map,--cref -nostartfiles -fno-exceptions -fno-rtti -Wl,--gc-sections


Что я неправильно делаю? smile3046.gif

Сообщение отредактировал IgorKossak - Feb 6 2012, 19:48
Причина редактирования: [codebox]


--------------------
Good News Everyone!
Go to the top of the page
 
+Quote Post
neiver
сообщение Feb 6 2012, 14:33
Сообщение #2


Местный
***

Группа: Участник
Сообщений: 214
Регистрация: 22-03-10
Из: Саратов
Пользователь №: 56 123



Деструкторы надо выкинуть, они всё равно никогда не будут вызваны. Это инфраструктура поддержки деструкторов для глобальных объектов с виртуальными функциями такая. Эти деструкторы регестрируются с помощью функции atexit, которая тянет за собой кучу всего остального.
Go to the top of the page
 
+Quote Post
Pavel V.
сообщение Feb 6 2012, 15:43
Сообщение #3


Местный
***

Группа: Свой
Сообщений: 211
Регистрация: 3-06-06
Пользователь №: 17 742



Цитата(neiver @ Feb 6 2012, 18:33) *
Деструкторы надо выкинуть, они всё равно никогда не будут вызваны. Это инфраструктура поддержки деструкторов для глобальных объектов с виртуальными функциями такая. Эти деструкторы регестрируются с помощью функции atexit, которая тянет за собой кучу всего остального.

Спасибо! Действительно, удаление деструкторов помогло sm.gif Как все оказалось просто.


--------------------
Good News Everyone!
Go to the top of the page
 
+Quote Post
AHTOXA
сообщение Feb 6 2012, 18:01
Сообщение #4


фанат дивана
******

Группа: Свой
Сообщений: 3 387
Регистрация: 9-08-07
Из: Уфа
Пользователь №: 29 684



Это только до тех пор, пока вы не используете Get() wink.gif
Правильное решение таково: при использовании в проекте чисто виртуальных функций надо добавить к проекту следующий файл: тынц!


--------------------
Если бы я знал, что такое электричество...
Go to the top of the page
 
+Quote Post
alx2
сообщение Feb 7 2012, 05:25
Сообщение #5


Местный
***

Группа: Участник
Сообщений: 340
Регистрация: 25-10-05
Из: Пермь, Россия
Пользователь №: 10 091



Цитата(Pavel V. @ Feb 6 2012, 17:20) *
Если для класса Output убрать наследование от абстрактного класса IOutput, линкер требует только функцию _sbrk, хотя тоже непонятно почему, ведь в программе нигде не используется динамическое выделение памяти..
Что я неправильно делаю? smile3046.gif

Это Вы думаете, что не используется. sm.gif А линкер думает иначе.
Почему линкер требует тот или иной вимвол, можно узнать из map-файла. Там линер подробно указывает, какой символ из какого модуля берется и кто его затребовал.


--------------------
Всего наилучшего,
Alex Mogilnikov
Go to the top of the page
 
+Quote Post
Pavel V.
сообщение Feb 7 2012, 05:51
Сообщение #6


Местный
***

Группа: Свой
Сообщений: 211
Регистрация: 3-06-06
Пользователь №: 17 742



Цитата(AHTOXA @ Feb 6 2012, 22:01) *
Это только до тех пор, пока вы не используете Get() wink.gif
Правильное решение таково: при использовании в проекте чисто виртуальных функций надо добавить к проекту следующий файл: тынц!

Убрал только деструкторы и проблема исчезла. В том числе при использовании чисто виртуальных функций. Может поправили уже?

Пробовал даже такой пример:
Код
int main(void)
{
    while (1) {
        IOutput *pa = (IOutput *)&g_testPin;
        uint32_t a = pa->Get();
        if(a)
            pa->Set(0);
        else
            pa->Set(1);
    }
}


Компилится без проблем:

Код
arm-kgp-eabi-size Test2.elf
   text       data        bss        dec        hex    filename
    956          4        264       1224        4c8    Test2.elf


Цитата(alx2 @ Feb 7 2012, 09:25) *
Это Вы думаете, что не используется. sm.gif А линкер думает иначе.
Почему линкер требует тот или иной вимвол, можно узнать из map-файла. Там линер подробно указывает, какой символ из какого модуля берется и кто его затребовал.

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


--------------------
Good News Everyone!
Go to the top of the page
 
+Quote Post
AHTOXA
сообщение Feb 7 2012, 08:10
Сообщение #7


фанат дивана
******

Группа: Свой
Сообщений: 3 387
Регистрация: 9-08-07
Из: Уфа
Пользователь №: 29 684



Цитата(Pavel V. @ Feb 7 2012, 11:51) *
Убрал только деструкторы и проблема исчезла. В том числе при использовании чисто виртуальных функций. Может поправили уже?

Ух ты, точно! Попробовал arm-kgp-eabi-gcc 4.7.0 20110328 (experimental) - работает без sys.c. Это радуетsm.gif


--------------------
Если бы я знал, что такое электричество...
Go to the top of the page
 
+Quote Post
Pavel V.
сообщение Feb 7 2012, 09:38
Сообщение #8


Местный
***

Группа: Свой
Сообщений: 211
Регистрация: 3-06-06
Пользователь №: 17 742



Цитата(AHTOXA @ Feb 7 2012, 12:10) *
Ух ты, точно! Попробовал arm-kgp-eabi-gcc 4.7.0 20110328 (experimental) - работает без sys.c. Это радуетsm.gif

Тулчейн от CodeSourcery (последняя версия) тоже корректно компилирует.


--------------------
Good News Everyone!
Go to the top of the page
 
+Quote Post
neiver
сообщение Feb 7 2012, 09:45
Сообщение #9


Местный
***

Группа: Участник
Сообщений: 214
Регистрация: 22-03-10
Из: Саратов
Пользователь №: 56 123



Да, кстати, а зачем делать абстрактные интерфейсы типа IOutput на таком низком уровне как линии ввода вывода?
Моя скромная практика показывает, что много эффективнее по размеру и скорости кода сделать класс Pin полнностью "статическим" и передавать в использующий его код в виде шаблонных параметров. А абстрактные интерфейсы с виртуальными функциями городить уже на уровне повыше.
Ну, а я по случаю порекламирую свою библиотеку по работе с портами. Помимо работы с отдельными линиями там эффективно реализованна работа с произвольными группами линий.
Вот так определелен класс линии ввода-вывода:
https://github.com/KonstantinChizhov/Mcucpp.../mcucpp/iopin.h
Порт ввода-вывода для STM32:
https://github.com/KonstantinChizhov/Mcucpp...M/Stm32/ports.h
Приме использования для STM32:
https://github.com/KonstantinChizhov/Mcucpp..._STM32/main.cpp
Сйечас у меня есть более-менее протестированные порты для AVR, MSP430 и STM32. Еще мне люди присылали свои реализации портов для LPC17xx и STM8, но я их не тестировал и в репозиторий не выкладывал.
Go to the top of the page
 
+Quote Post
ReAl
сообщение Feb 7 2012, 11:21
Сообщение #10


Нечётный пользователь.
******

Группа: Свой
Сообщений: 2 033
Регистрация: 26-05-05
Из: Бровари, Україна
Пользователь №: 5 417



Цитата(neiver @ Feb 7 2012, 11:45) *
Еще мне люди присылали свои реализации портов для LPC17xx и STM8, но я их не тестировал и в репозиторий не выкладывал.
А можно их оба мне на real at real.kiev.ua? Я потестирую :-)


--------------------
Ну, я пошёл… Если что – звоните…
Go to the top of the page
 
+Quote Post
Pavel V.
сообщение Feb 7 2012, 12:39
Сообщение #11


Местный
***

Группа: Свой
Сообщений: 211
Регистрация: 3-06-06
Пользователь №: 17 742



neiver
Спасибо за ссылки, буду изучать sm.gif По коду не сразу получается воткнуть, надо будет для себя диаграммки нарисовать для наглядности.

У меня GPIO в проектах в основном для "медленных" операций используются, типа управления питанием внешних модулей, поэтому накладными расходами на вызов функций работы с портами особо не заморачивался. Зато очень удобно передавать куда угодно по ссылке.

Будьте добры мне тоже на почту реализацию для LPC17хх, как раз сейчас с этим процессором работаю (павел AT posten.ru).

Сообщение отредактировал IgorKossak - Feb 7 2012, 13:05
Причина редактирования: Бездумное цитирование


--------------------
Good News Everyone!
Go to the top of the page
 
+Quote Post
Pavel V.
сообщение Feb 9 2012, 07:00
Сообщение #12


Местный
***

Группа: Свой
Сообщений: 211
Регистрация: 3-06-06
Пользователь №: 17 742



Кстати, заметил еще одну особенность - при уровне оптимизации -O0 проблема сохраняется, тянутся системные вызовы. Начиная с -O1 перестают.


--------------------
Good News Everyone!
Go to the top of the page
 
+Quote Post
Brain13
сообщение Jan 16 2013, 06:50
Сообщение #13


Участник
*

Группа: Участник
Сообщений: 65
Регистрация: 28-08-09
Пользователь №: 52 078



Чтобы не плодить новые темы пишу здесь.

Здравствуйте.

Решил попробовать использовать полиморфизм в МК.
написал такой код:
CODE

// IOutDevice.h
class IOutDevice
{
public:
virtual void On(void) = 0;
virtual void Off(void) = 0;
};

// PC0LED.h
class PC0_LED : public IOutDevice
{
public:
PC0_LED();

virtual void On(void);
virtual void Off(void);
};

// PC0LED.cpp
PC0_LED::PC0_LED()
{
}

void PC0_LED::On()
{
GPIO_PinOutSet(gpioPortC, 0);
}

void PC0_LED::Off()
{
GPIO_PinOutClear(gpioPortC, 0);
}

// PC1LED.h
class PC1_LED : public IOutDevice
{
public:
PC1_LED();

virtual void On(void);
virtual void Off(void);
};

// PC1LED.cpp
PC1_LED::PC1_LED()
{
}

void PC1_LED::On()
{
GPIO_PinOutSet(gpioPortC, 1);
}

void PC1_LED::Off()
{
GPIO_PinOutClear(gpioPortC, 1);
}


// main.cpp
int main(void)
{
init();

PC0_LED pc0;
PC1_LED pc1;

IOutDevice*dev[2];
dev[0] = &pc0;
dev[1] = &pc1;


while (1)
{
dev[0]->On();
dev[1]->On();
delay(2000000);

dev[0]->Off();
dev[1]->Off();
delay(2000000);
}

}

// Интерфейс IOutDevice, и 2 класса его реализующих для PC0 и PC1.

Все время думал, что для абстрактных методов необходим rtti. И компилировал без опции -fno-rtti (размер программы 10456). В этом топике увидел, что работает и с опцией -fno-rtti, попробовал - раотает (размер программы 2228).

Вопрос: почему код успешно компилируется с опцией -fno-rtti без ошибок? Разве для использования абстрактных методов не нужен rtti?
Go to the top of the page
 
+Quote Post
Сергей Борщ
сообщение Jan 16 2013, 08:22
Сообщение #14


Гуру
******

Группа: Модераторы
Сообщений: 8 455
Регистрация: 15-05-06
Из: Рига, Латвия
Пользователь №: 17 095



QUOTE (Brain13 @ Jan 16 2013, 08:50) *
Разве для использования абстрактных методов не нужен rtti?
Нет, не нужен. Полиморфизм реализуется таблицами указателей на виртуальные функции (vtbl) для каждого класса и указателем на таблицу своего класса в каждом объекте. Имея указатель на объект вы можете найти его таблицу указателей и в ней найти указатель на нужную реализацию метода. И все, никакого мошенничества.


--------------------
На любой вопрос даю любой ответ
"Write code that is guaranteed to work, not code that doesn’t seem to break" (C++ FAQ)
Go to the top of the page
 
+Quote Post
dxp
сообщение Jan 16 2013, 08:37
Сообщение #15


Adept
******

Группа: Свой
Сообщений: 3 469
Регистрация: 6-12-04
Из: Novosibirsk
Пользователь №: 1 343



QUOTE (Brain13 @ Jan 16 2013, 13:50) *
Все время думал, что для абстрактных методов необходим rtti. И компилировал без опции -fno-rtti (размер программы 10456). В этом топике увидел, что работает и с опцией -fno-rtti, попробовал - раотает (размер программы 2228).

Вопрос: почему код успешно компилируется с опцией -fno-rtti без ошибок? Разве для использования абстрактных методов не нужен rtti?

1. Что такое абстрактные методы?

2. RTTI - Run-Time Type Identification - определение типа на этапе выполнения. Причём тут полиморфизм, который требует просто наследования и виртуальных функций, механизм реализации которых - это таблицы указателей на функции? Для полиморфизма не требуется никакая информация о типах на этапе выполнения.

RTTI потребуется, если будете использовать dynamic_cast<>.


--------------------
«Отыщи всему начало, и ты многое поймёшь» К. Прутков
Go to the top of the page
 
+Quote Post

2 страниц V   1 2 >
Reply to this topicStart new topic
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0

 


RSS Текстовая версия Сейчас: 1st July 2025 - 08:26
Рейтинг@Mail.ru


Страница сгенерированна за 0.01526 секунд с 7
ELECTRONIX ©2004-2016