我们正在为 STM32F103 MCU 开发。我们使用带有 ARM GCC 工具链的裸机 C++ 代码。在与一个可疑的表达式斗争了几个小时之后,我们发现 constant 关键字会触发该表达式的不同结果。使用x86 GCC工具链测试同一段代码时,问题不存在。
我们正在使用STM的GPIO进行调试。
这是完全重现问题的代码:
#include "stm32f10x.h"
#include "system_stm32f10x.h"
#include "stdlib.h"
#include "stdio.h"
const unsigned short RTC_FREQ = 62500;
unsigned short prescaler_1ms = RTC_FREQ/1000;
int main()
{
//********** Clock Init **********
RCC->CFGR |= RCC_CFGR_ADCPRE_0 | RCC_CFGR_ADCPRE_1; // ADC prescaler
RCC->APB2ENR |= RCC_APB2ENR_AFIOEN; // Alternate Function I/O clock enable
RCC->APB2ENR |= RCC_APB2ENR_IOPCEN; // I/O port C clock enable
RCC->APB2ENR |= RCC_APB2ENR_IOPAEN; // I/O port A clock enable
RCC->APB2ENR |= RCC_APB2ENR_ADC1EN; // ADC 1 interface clock enable
RCC->APB1ENR |= RCC_APB1ENR_TIM2EN; // Timer 2 clock enable
RCC->AHBENR = RCC_AHBENR_DMA1EN; // DMA1 clock enable
RCC->CSR = RCC_CSR_LSION; // Internal Low Speed oscillator enable
//********************************
/* GPIO Configuration */
GPIOC->CRH = GPIO_CRH_MODE12_0; //GPIO Port C Pin 12
GPIOC->CRH |= GPIO_CRH_MODE13_1 | GPIO_CRH_MODE13_0;
GPIOC->CRH |= GPIO_CRH_MODE10_0;
GPIOC->CRH |= GPIO_CRH_MODE9_0;
GPIOC->CRH |= GPIO_CRH_MODE8_0;
GPIOC->CRL = GPIO_CRL_MODE7_0;
GPIOC->CRL |= GPIO_CRL_MODE6_0;
GPIOC->CRL |= GPIO_CRL_MODE4_0;
GPIOC->CRL |= GPIO_CRL_MODE3_0;
while(1){
if(prescaler_1ms & (1<<0))GPIOC->BSRR |= GPIO_BSRR_BR13;
else GPIOC->BSRR |= GPIO_BSRR_BS13;
if(prescaler_1ms & (1<<1))GPIOC->BSRR |= GPIO_BSRR_BR12;
else GPIOC->BSRR |= GPIO_BSRR_BS12;
if(prescaler_1ms & (1<<2))GPIOC->BSRR |= GPIO_BSRR_BR10;
else GPIOC->BSRR |= GPIO_BSRR_BS10;
if(prescaler_1ms & (1<<3))GPIOC->BSRR |= GPIO_BSRR_BR9;
else GPIOC->BSRR |= GPIO_BSRR_BS9;
if(prescaler_1ms & (1<<4))GPIOC->BSRR |= GPIO_BSRR_BR8;
else GPIOC->BSRR |= GPIO_BSRR_BS8;
if(prescaler_1ms & (1<<5))GPIOC->BSRR |= GPIO_BSRR_BR7;
else GPIOC->BSRR |= GPIO_BSRR_BS7;
if(prescaler_1ms & (1<<6))GPIOC->BSRR |= GPIO_BSRR_BR6;
else GPIOC->BSRR |= GPIO_BSRR_BS6;
if(prescaler_1ms & (1<<7))GPIOC->BSRR |= GPIO_BSRR_BR4;
else GPIOC->BSRR |= GPIO_BSRR_BS4;
if(prescaler_1ms & (1<<8))GPIOC->BSRR |= GPIO_BSRR_BR3;
else GPIOC->BSRR |= GPIO_BSRR_BS3;
}
return 0;
}
当该代码编译时,我们期望 GPIOS 的结果为 0b111110。当我们改变时
const unsigned short RTC_FREQ = 62500;
到
unsigned short RTC_FREQ = 62500;
我们得到0b111111111。
这是我们使用的 Makefile:
EABI_PATH=$(ROOT_DIR)"arm_toolchain/gcc-arm-none-eabi-6-2017-q2-update/arm-none-eabi/"
CMSIS_INC_PATH=$(ROOT_DIR)"STMLib/STM32F10x_StdPeriph_Lib_V3.5.0/Libraries/CMSIS/CM3/"
PROJECT_INC=$(ROOT_DIR)
CXXINCS = -I$(EABI_PATH)"include" -I$(CMSIS_INC_PATH)"CoreSupport" -I$(CMSIS_INC_PATH)"DeviceSupport/ST/STM32F10x" -I$(PROJECT_INC)"Source" -I$(PROJECT_INC)"Includes"
CXXLIBS = -L$(EABI_PATH)"lib" -L$(EABI_PATH)"6.3.1"
CXXFLAGS = --specs=nosys.specs -DSTM32F10X_MD -DVECT_TAB_FLASH -fdata-sections -ffunction-sections -fno-exceptions -mthumb -mcpu=cortex-m3 -march=armv7-m -O2
LDFLAGS = -lstdc++ -Wl,--gc-sections
CC = $(EABI_PATH)"../bin/arm-none-eabi-gcc"
CXX = $(EABI_PATH)"../bin/arm-none-eabi-g++"
LD = $(EABI_PATH)"../bin/arm-none-eabi-ld"
STRIP = $(EABI_PATH)"../bin/arm-none-eabi-strip"
all:
$(CC) $(CXXINCS) -c $(PROJECT_INC)"Source/syscalls.c" $(PROJECT_INC)"Source/startup.c" $(CXXFLAGS)
$(CXX) $(CXXINCS) -c $(PROJECT_INC)"Source/main.cpp" $(CMSIS_INC_PATH)"DeviceSupport/ST/STM32F10x/system_stm32f10x.c" $(CXXFLAGS)
$(CXX) $(CXXLIBS) -o main syscalls.o main.o startup.o -T linker.ld system_stm32f10x.o $(LDFLAGS)
$(STRIP) --strip-all main
$(EABI_PATH)"bin/objcopy" -O binary main app
$(EABI_PATH)"bin/objdump" -b binary -m arm_any -D app > app_disasm
rm -f *.o main adc timer task solenoid dma startup syscalls system_stm32f10x
有人知道什么会导致这样的问题吗?那是编译器错误吗?我们错过了什么吗?
最佳答案
将我的理论提升为答案,因为它已被启动代码和 LD 脚本证实。
本应将 62 复制到 prescaler_1ms 中的 C++ 初始化代码未被调用。当您将 RTC_FREQ 定义为 const 时,此计算的结果在编译时已知,62 存在于闪存中并且不需要初始化。
C++ 初始化由许多生成的函数执行,名称如 _Z41__static_initialization_and_destruction_0ii。指向这些函数的指针由编译器收集在 .init_array 和 .pre_init_array 部分中。在调用 main() 之前,启动代码应该遍历这些指针并调用它们中的每一个。这些指针数组的边界对于启动代码来说是已知的,因为这些特殊符号是由链接描述文件定义的:
__preinit_array_start, __preinit_array_end
__init_array_start, __init_array_end
我还不清楚 _preinit_array 和 __init_array 之间的区别。前一节在调用 _init 函数之前调用,后一节在之后调用。在我的项目中,gcc 提供的_init 函数似乎不是一个有效的函数,所以我没有调用它。
当使用 __fini_array_start 和 __fini_array_end 调用全局对象的 C++ 析构函数时,程序终止时有一个对称过程。但是,对于嵌入式系统,它可能不相关。
使项目调用 C++ 初始化内容的最少步骤是:
.init_array 部分。从您提供的文档来看,.init_array 部分似乎已定义为:
. = ALIGN(4);
__preinit_array_start = .;
KEEP(*(.preinit_array))
__preinit_array_end = .;
. = ALIGN(4);
__init_array_start = .;
KEEP(*(SORT(.init_array.*)))
KEEP(*(.init_array))
__init_array_end = .;
您可以将以下代码(或类似代码)添加到 startup.c 中的 __Init_Data() 函数中:
// usually these are defined with __attribute__((weak)) but I prefer to get errors when required things are missing
extern void (*__preinit_array_start[])(void);
extern void (*__preinit_array_end[])(void);
extern void (*__init_array_start[])(void);
extern void (*__init_array_end[])(void);
void __Init_Data(void) {
// copying initialized data from flash to RAM
...
// zeroing bss segment
...
// calling C++ initializers
void (**f)(void);
for (f = __preinit_array_start; f != __preinit_array_end; f++)
(*f)();
// init(); // _init and _fini do not work for me
for (f = __init_array_start; f != __init_array_end; f++)
(*f)();
}
同样,我不确定_init 函数,所以在这里注释掉了。稍后我可能会问自己的问题。
关于C++常量关键字异常行为,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47242388/
在我的gem中,我需要yaml并且在我的本地计算机上运行良好。但是在将我的gem推送到rubygems.org之后,当我尝试使用我的gem时,我收到一条错误消息=>"uninitializedconstantPsych::Syck(NameError)"谁能帮我解决这个问题?附言RubyVersion=>ruby1.9.2,GemVersion=>1.6.2,Bundlerversion=>1.0.15 最佳答案 经过几个小时的研究,我发现=>“YAML使用未维护的Syck库,而Psych使用现代的LibYAML”因此,为了解决
我的瘦服务器配置了nginx,我的ROR应用程序正在它们上运行。在我发布代码更新时运行thinrestart会给我的应用程序带来一些停机时间。我试图弄清楚如何优雅地重启正在运行的Thin实例,但找不到好的解决方案。有没有人能做到这一点? 最佳答案 #Restartjustthethinserverdescribedbythatconfigsudothin-C/etc/thin/mysite.ymlrestartNginx将继续运行并代理请求。如果您将Nginx设置为使用多个上游服务器,例如server{listen80;server
我正在使用active_admin,我在Rails3应用程序的应用程序中有一个目录管理,其中包含模型和页面的声明。时不时地我也有一个类,当那个类有一个常量时,就像这样:classFooBAR="bar"end然后,我在每个必须在我的Rails应用程序中重新加载一些代码的请求中收到此警告:/Users/pupeno/helloworld/app/admin/billing.rb:12:warning:alreadyinitializedconstantBAR知道发生了什么以及如何避免这些警告吗? 最佳答案 在纯Ruby中:classA
我收到这个错误:RuntimeError(自动加载常量Apps时检测到循环依赖当我使用多线程时。下面是我的代码。为什么会这样?我尝试多线程的原因是因为我正在编写一个HTML抓取应用程序。对Nokogiri::HTML(open())的调用是一个同步阻塞调用,需要1秒才能返回,我有100,000多个页面要访问,所以我试图运行多个线程来解决这个问题。有更好的方法吗?classToolsController0)app.website=array.join(',')putsapp.websiteelseapp.website="NONE"endapp.saveapps=Apps.order("
我有一个用户工厂。我希望默认情况下确认用户。但是鉴于unconfirmed特征,我不希望它们被确认。虽然我有一个基于实现细节而不是抽象的工作实现,但我想知道如何正确地做到这一点。factory:userdoafter(:create)do|user,evaluator|#unwantedimplementationdetailshereunlessFactoryGirl.factories[:user].defined_traits.map(&:name).include?(:unconfirmed)user.confirm!endendtrait:unconfirmeddoenden
我正在学习Rails,并阅读了关于乐观锁的内容。我已将类型为integer的lock_version列添加到我的articles表中。但现在每当我第一次尝试更新记录时,我都会收到StaleObjectError异常。这是我的迁移:classAddLockVersionToArticle当我尝试通过Rails控制台更新文章时:article=Article.first=>#我这样做:article.title="newtitle"article.save我明白了:(0.3ms)begintransaction(0.3ms)UPDATE"articles"SET"title"='dwdwd
在Cooper的书BeginningRuby中,第166页有一个我无法重现的示例。classSongincludeComparableattr_accessor:lengthdef(other)@lengthother.lengthenddefinitialize(song_name,length)@song_name=song_name@length=lengthendenda=Song.new('Rockaroundtheclock',143)b=Song.new('BohemianRhapsody',544)c=Song.new('MinuteWaltz',60)a.betwee
我有用于控制用户任务的Rails5API项目,我有以下错误,但并非总是针对相同的Controller和路由。ActionController::RoutingError:uninitializedconstantApi::V1::ApiController我向您描述了一些我的项目,以更详细地解释错误。应用结构路线scopemodule:'api'donamespace:v1do#=>Loginroutesscopemodule:'login'domatch'login',to:'sessions#login',as:'login',via::postend#=>Teamroutessc
我想获取模块中定义的所有常量的值:moduleLettersA='apple'.freezeB='boy'.freezeendconstants给了我常量的名字:Letters.constants(false)#=>[:A,:B]如何获取它们的值的数组,即["apple","boy"]? 最佳答案 为了做到这一点,请使用mapLetters.constants(false).map&Letters.method(:const_get)这将返回["a","b"]第二种方式:Letters.constants(false).map{|c
我早就知道Ruby中的“常量”(即大写的变量名)不是真正常量。与其他编程语言一样,对对象的引用是唯一存储在变量/常量中的东西。(侧边栏:Ruby确实具有“卡住”引用对象不被修改的功能,据我所知,许多其他语言都没有提供这种功能。)所以这是我的问题:当您将一个值重新分配给常量时,您会收到如下警告:>>FOO='bar'=>"bar">>FOO='baz'(irb):2:warning:alreadyinitializedconstantFOO=>"baz"有没有办法强制Ruby抛出异常而不是打印警告?很难弄清楚为什么有时会发生重新分配。 最佳答案