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;
}
}
};
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;
};
{
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();
}
}
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);
}
}
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
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
# 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
Что я неправильно делаю?
