stm32f gnu c++ 工程模板

7 篇文章 0 订阅

stm32f gnu c++ 工程模板

由于工作上的原因,最近需要使用C++与编写stm32f030的程序,在此记录一下,以便后续查找。
背景:
MCU:STM32F030
环境:ubuntu-20.04
编译器:gcc-arm-none-eabi-6-2017-q2-update/bin/arm-none-eabi-g++
gcc-arm-none-eabi-6-2017-q2-update/bin/arm-none-eabi-gcc
问题:
1 printf 问题
非半主机模式下的调试输出主要靠打印,所以选择使用printf的情况居多。在编写C代码时,可以直接使用gcc编译,不过需要以下支持才可正常打印。
可以将这些代码直接存为syscall.c

#pragma import(__use_no_semihosting) 

/* Includes */
#include <sys/stat.h>
#include <stdlib.h>
#include <errno.h>
#include <stdio.h>
#include <signal.h>
#include <time.h>
#include <sys/time.h>
#include <sys/times.h>


/* Variables */
//#undef errno
extern int errno;
extern int __io_putchar(int ch) __attribute__((weak));
extern int __io_getchar(void) __attribute__((weak));

register char * stack_ptr asm("sp");

char *__env[1] = { 0 };
char **environ = __env;


/* Functions */
void initialise_monitor_handles()
{
}

int _getpid(void)
{
	return 1;
}

int _kill(int pid, int sig)
{
	errno = EINVAL;
	return -1;
}

void _exit (int status)
{
	_kill(status, -1);
	while (1) {}		/* Make sure we hang here */
}

__attribute__((weak)) int _read(int file, char *ptr, int len)
{
	int DataIdx;

	for (DataIdx = 0; DataIdx < len; DataIdx++)
	{
		*ptr++ = __io_getchar();
	}

return len;
}

__attribute__((weak)) int _write(int file, char *ptr, int len)
{
	int DataIdx;

	for (DataIdx = 0; DataIdx < len; DataIdx++)
	{
		__io_putchar(*ptr++);
	}
	return len;
}

caddr_t _sbrk(int incr)
{
	extern char end asm("end");
	static char *heap_end;
	char *prev_heap_end;

	if (heap_end == 0)
		heap_end = &end;

	prev_heap_end = heap_end;
	if (heap_end + incr > stack_ptr)
	{
//		write(1, "Heap and stack collision\n", 25);
//		abort();
		errno = ENOMEM;
		return (caddr_t) -1;
	}

	heap_end += incr;

	return (caddr_t) prev_heap_end;
}

int _close(int file)
{
	return -1;
}


int _fstat(int file, struct stat *st)
{
	st->st_mode = S_IFCHR;
	return 0;
}

int _isatty(int file)
{
	return 1;
}

int _lseek(int file, int ptr, int dir)
{
	return 0;
}

int _open(char *path, int flags, ...)
{
	/* Pretend like we always fail */
	return -1;
}

int _wait(int *status)
{
	errno = ECHILD;
	return -1;
}

int _unlink(char *name)
{
	errno = ENOENT;
	return -1;
}

int _times(struct tms *buf)
{
	return -1;
}

int _stat(char *file, struct stat *st)
{
	st->st_mode = S_IFCHR;
	return 0;
}

int _link(char *old, char *new)
{
	errno = EMLINK;
	return -1;
}

int _fork(void)
{
	errno = EAGAIN;
	return -1;
}

int _execve(char *name, char **argv, char **env)
{
	errno = ENOMEM;
	return -1;
}


连接芯片的串口输出有两种方式,任选其一都可以正常使用。
代码如下,可以放在任意位置:

方法一:
extern "C" int _write(int file, char *data, int len)
{
   if ((file != STDOUT_FILENO) && (file != STDERR_FILENO))
   {
      errno = EBADF;
      return -1;
   }

  int cntWait = 100000;
    char *pdata=data;

    pdata=data;
    for(int i=0;i<len;i++)
    {
      USART_SendData(USART2,*pdata);
      while((USART_GetFlagStatus(USART2, USART_FLAG_TXE) == RESET) && (cntWait-- >0));
      pdata++;
    }

    return len;
}
方法二:
extern "C" int __io_putchar(int ch)
{
    int cntWait = 100000;

    USART_SendData(USART2,ch);
    while((USART_GetFlagStatus(USART2, USART_FLAG_TXE) == RESET) && (cntWait-- >0));

    return 0;
}

2 cout 输出问题
由于MCU的资源有限,直接使用标准库,会导致代码过大,所以为减小代码尺寸,需要自行实现cout代码,不再调用iostream库。相关原理不再细述,如需要的话,可以查看相关操作符重载章节,实现代码具体如下:

myoutstream.h

#ifndef _MYOUTSTREAM_H_
#define _MYOUTSTREAM_H_

class MyOutStream
{
public:
    MyOutStream(){};
    ~MyOutStream(){};
    
    const MyOutStream & operator<< (int value) const;//对整型变量的重载

    const MyOutStream & operator<< (char *str) const;//对字符串型的重载    

    const MyOutStream & operator<< (void (*cf_newline)()) const;//对回车换行符的重载
private:

};

void endl(void);

#endif

函数实现代码如下:

myostream.cpp

#include "myOutStream.h"
#include "stdio.h"

const MyOutStream& MyOutStream::operator << (int value) const
{
    printf("%d",value);
    return *this;
}

const MyOutStream& MyOutStream::operator << (char *str) const
{
    printf("%s",str);
    return *this;
}

const MyOutStream & MyOutStream::operator<< (void (*cf_newline)()) const
{
    cf_newline();
    return *this;
}

void endl(void)
{
    printf("\r\n");
}

3 工具链配置问题
由于使用 arm-none-eabi-g++/arm-none-eabi-gcc 工具链,需要对库目录路径,编译工具路径等等进行配置,否则调用相关工具及头文件较繁琐,具体实现为使用一个小的bash脚本处理,具体如下:

将以下代码存成 export.sh文件

#!/bin/bash
root_dir=$(pwd)
echo "current path = $root_dir"
gcc_path=/home/murphy/gcc-arm-none-eabi-6-2017-q2-update/bin
include_path=$root_dir/arch/stm32f0xx/STM32F0xx_HAL_Driver/Inc:$gcc_path
include_path=$root_dir/arch/stm32f0xx/STM32F0xx_HAL_Driver/Inc/Legacy:$include_path
include_path=$root_dir/arch/stm32f0xx/CMSIS:$include_path
include_path=$root_dir/arch/stm32f0xx/CMSIS/Include:$include_path
include_path=$root_dir/src:$include_path

echo $include_path
export PATH=:$include_path:$PATH
echo "export enviroment path success"

4 makefile 问题
由于使用make工具来进行处理,暂时未专门优化makefile文件,仅做到能用而已。如对输出目录,中间文件目录、工程目录有详细要求,需要对另外编写专用的makefile文件。本次使用的代码如下:


TARGET := main

ROOT_DIR := $(shell pwd)
OBJS_DIR := objects

SRCS := $(shell find ./ -name "*.c")
SRCS += $(shell find ./ -name "*.s")
SRCS += $(shell find ./ -name "*.cpp")

OBJS:=$(SRCS:.c=.o)
OBJS:=$(OBJS:.s=.o)
OBJS:=$(OBJS:.cpp=.o)
SSUA:=$(OBJS:.o=.su)

CC=arm-none-eabi-gcc
OC=arm-none-eabi-objcopy
CPP=arm-none-eabi-g++

OFLAGS := -mcpu=cortex-m0 -mthumb -O0 -ffunction-sections -fdata-sections -fstack-usage
#CFLAGS += -g
WFLAGS := -Wall -Wswitch-enum -Wextra

CFLAGS += $(OFLAGS) $(WFLAGS)
CFLAGS += -std=gnu11 -specs=nano.specs

CFLAGS += -DSTM32F030x8 -DUSE_STDPERIPH_DRIVER -DSTM32F030
CFLAGS += -D__weak="__attribute__((weak))" -D__packed="__attribute__((__packed__))"
#CFLAGS += -ffreestanding
CFLAGS += -fno-builtin-printf
#CFLAGS += -mthumb
CPPFLAGS = $(OFLAGS) $(WFLAGS)
CPPFLAGS += -specs=nano.specs
CPPFLAGS += -DSTM32F030x8 -DUSE_STDPERIPH_DRIVER -DSTM32F030
CPPFLAGS += -D__weak="__attribute__((weak))" -D__packed="__attribute__((__packed__))"

#LDFLAGS := -T STM32F030R8_FLASH.ld -specs=nosys.specs -static
LDFLAGS :=-T STM32F030R8_FLASH.ld -specs=nosys.specs -static -Wl,-Map=$(TARGET).map -Wl,--gc-sections -Wl,--defsym=malloc_getpagesize_P=0x80 -Wl,--start-group -lc -lm -Wl,--end-group -specs=nano.specs

INCLUDE_PATH := -I $(ROOT_DIR)/arch/stm32f0xx/CMSIS/
INCLUDE_PATH += -I $(ROOT_DIR)/arch/stm32f0xx/CMSIS/Include/
INCLUDE_PATH += -I $(ROOT_DIR)/arch/stm32f0xx/STM32F0xx_StdPeriph_Driver/inc/
INCLUDE_PATH += -I $(ROOT_DIR)/src/


all: $(TARGET).hex

%.o:%.s 
	$(CC) -c -x assembler-with-cpp $(OFLAGS) -o $@ $<

%.o:%.c 
	$(CC) -c $(CFLAGS) -o $@ $^ $(INCLUDE_PATH)

%.o:%.cpp 
	$(CPP) -c $(CPPFLAGS) -o $@ $^ $(INCLUDE_PATH)

%.hex:%.bin
	$(OC) -I binary -O ihex --change-addresses 0x8000000 $< $@

%.bin:%.elf
	$(OC) -O binary $< $@

$(TARGET).elf: $(OBJS)
	@echo "Linking $@ ..."
	$(CPP) -o $@ $^ $(OFLAGS) $(LDFLAGS)

clean:
	rm -f $(OBJS) $(SSUA) $(TARGET).bin $(TARGET).hex $(TARGET).elf $(TARGET).map

print:
	@echo "SRCs =" $(SRCS)
	@echo "OBJs =" $(OBJS)

OK,以上为环境搭建时的一些主要问题。记录在此,以供查阅。
不知道如何上传附件,郁闷ing。。。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值