Перейти к содержанию
    

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

 

#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;
	}
}
};

 

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

 

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

Изменено пользователем IgorKossak
[codebox]

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Деструкторы надо выкинуть, они всё равно никогда не будут вызваны. Это инфраструктура поддержки деструкторов для глобальных объектов с виртуальными функциями такая. Эти деструкторы регестрируются с помощью функции atexit, которая тянет за собой кучу всего остального.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Деструкторы надо выкинуть, они всё равно никогда не будут вызваны. Это инфраструктура поддержки деструкторов для глобальных объектов с виртуальными функциями такая. Эти деструкторы регестрируются с помощью функции atexit, которая тянет за собой кучу всего остального.

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Это только до тех пор, пока вы не используете Get() ;)

Правильное решение таково: при использовании в проекте чисто виртуальных функций надо добавить к проекту следующий файл: тынц!

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

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

Это Вы думаете, что не используется. :) А линкер думает иначе.

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

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Это только до тех пор, пока вы не используете 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

 

Это Вы думаете, что не используется. :) А линкер думает иначе.

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

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

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

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Да, кстати, а зачем делать абстрактные интерфейсы типа 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, но я их не тестировал и в репозиторий не выкладывал.

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

neiver

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

 

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

 

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

Изменено пользователем IgorKossak
Бездумное цитирование

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

 

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

 

Решил попробовать использовать полиморфизм в МК.

написал такой код:

// 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?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

 

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

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

 

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

 

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

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

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

Гость
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...