我一直在开发 Nucleo STM32L433RCP,并进行了很好的设置,其中我有一个自定义 _write 函数,该函数获取由
printf
缓冲的字符并通过 UART 传输它们。所有这些都是用 C 语言编写的,并且运行得非常好。从那以后,为了与我正在参与的项目组兼容,我已经过渡到 C++,但它不再起作用了。 printf
仍然会在刷新时调用 write 函数,但据我所知,缓冲区充满了垃圾。我正在裸机工作,没有使用 STM32CubeIDE 或其附带的 HAL 工具。
我在 C 和 C++ 之间切换时所做的唯一更改是使用
extern "C"
将 _write 和我的重置处理程序作为 C 代码运行(没有它,什么也不会发生)。
下面是我的main.cpp,请忽略一些丑陋的格式
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#define GPIOBS 0x48000400
#define RCC_APB2ENR 0x4002104C
// #define ODR 0x14
// #define OTR 0x04
#define SERIAL_PORT "/dev/ttyACM0"
#include "../bsp/stm32l433xx.h"
uint32_t SystemCoreClock = 0;
extern uint32_t _sidata, _sdata, _edata, _sbss, _ebss;
uint32_t arr[2000];
extern "C" {
// Reset handler: set the stack pointer and branch to main().
__attribute__((naked)) void reset_handler(void) {
// Set the stack pointer to the 'end of stack' value.
__asm__("LDR r0, =_estack\n\t"
"MOV sp, r0");
// Branch to main().
__asm__("B main");
}
}
extern "C" {
int __io_putchar(int ch){
while (!(USART2->ISR & USART_ISR_TXE)) {};
USART2->TDR = ch;
return ch;
}
int _write(int handle, const char* data, int size) {
int count = size;
while (count--) {
__io_putchar(*data++);
}
while (!(USART2->ISR & USART_ISR_TXE)) {};
USART2->TDR = 74;
while (!(USART2->ISR & USART_ISR_TXE)) {};
USART2->TDR = 10;
while (!(USART2->ISR & USART_ISR_TXE)) {};
USART2->TDR = 13;
return size;
}
void init(){
// copy the flash varibales into ram
memcpy(&_sdata, &_sidata, 4*(&_edata - &_sdata));
// Clear the .bss section in RAM.
memset(&_sbss, 0x00, 4* (&_ebss -&_sbss));
for (int i = 0; i < 10000; ++i){
arr[i] = i;
}
// Enable floating-point unit.
SCB->CPACR |= (0xF << 20);
RCC->AHB2ENR |= 7;
// Enable floating-point unit.
SCB->CPACR |= (0xF << 20);
// Default clock source is the "multi-speed" internal oscillator.
// Switch to the 16MHz HSI oscillator.
RCC->CR |= (RCC_CR_HSION);
while (!(RCC->CR & RCC_CR_HSIRDY)) {
};
RCC->CFGR &= ~(RCC_CFGR_SW);
RCC->CFGR |= (RCC_CFGR_SW_HSI);
while ((RCC->CFGR & RCC_CFGR_SWS) != RCC_CFGR_SWS_HSI) {
};
SystemCoreClock = 16000000;
RCC->APB1ENR1 |= (RCC_APB1ENR1_USART2EN);
RCC->AHB2ENR |= (RCC_AHB2ENR_GPIOAEN);
// Configure pins A2, A15 for USART2 (AF7, AF3).
GPIOA->MODER &= ~((0x3 << (2 * 2)) | (0x3 << (15 * 2)));
GPIOA->MODER |= ((0x2 << (2 * 2)) | (0x2 << (15 * 2)));
GPIOA->OTYPER &= ~((0x1 << 2) | (0x1 << 15));
GPIOA->OSPEEDR &= ~((0x3 << (2 * 2)) | (0x3 << (15 * 2)));
GPIOA->OSPEEDR |= ((0x2 << (2 * 2)) | (0x2 << (15 * 2)));
GPIOA->AFR[0] &= ~((0xF << (2 * 4)));
GPIOA->AFR[0] |= ((0x7 << (2 * 4)));
GPIOA->AFR[1] &= ~((0xF << ((15 - 8) * 4)));
GPIOA->AFR[1] |= ((0x3 << ((15 - 8) * 4)));
uint16_t uartdiv = SystemCoreClock / 9600;
USART2->BRR = uartdiv;
USART2->CR1 |= (USART_CR1_RE | USART_CR1_TE | USART_CR1_UE);
//printf("starting, Clock speed is: %lu \r\n", SystemCoreClock);
// LED Test
GPIOB->MODER &= (~(1 << 27));
GPIOB->MODER |= (1 << 26);
GPIOB->ODR |= (1 << 13);
printf("Test\n");
}
}
int main() {
init();
int x = 0;
;
while (1) {
GPIOB->ODR |= (1 << 13);
for (int i = 0; i < 500000; i++) {
};
GPIOB->ODR &= (~(1 << 13));
for (int i = 0; i < 500000; i++) {
};
x++;
printf("APPLE\n");// %d\r\n", x);
_write(0, "APE TOGETHER",12);
fflush(stdout);
}
}
目前我的 _write 函数还输出换行符和回车符,因此通过 uart 查看输出时看起来不那么糟糕。我已经用 C 测试了所有内容并且它有效。
我正在使用arm-none-eabi-g++/gcc进行编译,具体取决于它是否是C文件。
谢谢你
您的C/C++运行时启动不充分。 它只是建立一个堆栈并跳转到
main()
。 它必须做其他事情来建立 C 和 C++ 运行时所期望的完整运行时环境,并且通常应该在 main()
之前完成,期望在 main()
运行时环境完成。
您正在在
init()
做的一些事情,尽管是来自而不是之前main()
。 例如,您似乎正在执行 .data
和 .bss
段的静态初始化,但对于 C++ 来说这是不够的。 您还需要迭代静态 constructors,在此之前可能需要调用一些 C 库初始化来 extablish stdin
、stdout
、stderr
和堆等。
一些应该做的事情(通常从
__start
到main
之前):
main()
中完成了该部分)。根据应用程序和运行时环境,可能需要额外的运行时初始化步骤,例如:
您最好采用提供的 C/C++ 运行时启动并使其适应您平台的需求,而不是采用相当简约的方法,这种方法显然无法为完整的 C 或 C++ 运行时建立合适的环境。