|
GCC и C++ для Cortex-M3 |
|
|
|
Feb 6 2012, 12:20
|

Местный
  
Группа: Свой
Сообщений: 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 Кб  Если для класса 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 Что я неправильно делаю?
Сообщение отредактировал IgorKossak - Feb 6 2012, 19:48
Причина редактирования: [codebox]
--------------------
Good News Everyone!
|
|
|
|
|
Feb 6 2012, 15:43
|

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

|
Цитата(neiver @ Feb 6 2012, 18:33)  Деструкторы надо выкинуть, они всё равно никогда не будут вызваны. Это инфраструктура поддержки деструкторов для глобальных объектов с виртуальными функциями такая. Эти деструкторы регестрируются с помощью функции atexit, которая тянет за собой кучу всего остального. Спасибо! Действительно, удаление деструкторов помогло  Как все оказалось просто.
--------------------
Good News Everyone!
|
|
|
|
|
Feb 7 2012, 05:25
|

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

|
Цитата(Pavel V. @ Feb 6 2012, 17:20)  Если для класса Output убрать наследование от абстрактного класса IOutput, линкер требует только функцию _sbrk, хотя тоже непонятно почему, ведь в программе нигде не используется динамическое выделение памяти.. Что я неправильно делаю?  Это Вы думаете, что не используется.  А линкер думает иначе. Почему линкер требует тот или иной вимвол, можно узнать из map-файла. Там линер подробно указывает, какой символ из какого модуля берется и кто его затребовал.
--------------------
Всего наилучшего, Alex Mogilnikov
|
|
|
|
|
Feb 7 2012, 05:51
|

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

|
Цитата(AHTOXA @ Feb 6 2012, 22:01)  Это только до тех пор, пока вы не используете Get()  Правильное решение таково: при использовании в проекте чисто виртуальных функций надо добавить к проекту следующий файл: тынц!Убрал только деструкторы и проблема исчезла. В том числе при использовании чисто виртуальных функций. Может поправили уже? Пробовал даже такой пример: Код 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)  Это Вы думаете, что не используется.  А линкер думает иначе. Почему линкер требует тот или иной вимвол, можно узнать из map-файла. Там линер подробно указывает, какой символ из какого модуля берется и кто его затребовал. Я, к сожалению, пока не очень в нем ориентируюсь, но невооруженным взглядом видно, что использование деструкторов в абстрактных классах тянет за собой exceptions и другую требуху, несмотря на запрещающие флаги компилятора.
--------------------
Good News Everyone!
|
|
|
|
|
Feb 7 2012, 09:45
|
Местный
  
Группа: Участник
Сообщений: 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, но я их не тестировал и в репозиторий не выкладывал.
|
|
|
|
|
Feb 7 2012, 12:39
|

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

|
neiverСпасибо за ссылки, буду изучать  По коду не сразу получается воткнуть, надо будет для себя диаграммки нарисовать для наглядности. У меня GPIO в проектах в основном для "медленных" операций используются, типа управления питанием внешних модулей, поэтому накладными расходами на вызов функций работы с портами особо не заморачивался. Зато очень удобно передавать куда угодно по ссылке. Будьте добры мне тоже на почту реализацию для LPC17хх, как раз сейчас с этим процессором работаю (павел AT posten.ru).
Сообщение отредактировал IgorKossak - Feb 7 2012, 13:05
Причина редактирования: Бездумное цитирование
--------------------
Good News Everyone!
|
|
|
|
|
Jan 16 2013, 06:50
|
Участник

Группа: Участник
Сообщений: 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?
|
|
|
|
|
Jan 16 2013, 08:37
|

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<>.
--------------------
«Отыщи всему начало, и ты многое поймёшь» К. Прутков
|
|
|
|
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|