我只是想从头开始处理arm-none-eabi-gcc中的stm32编程,只是通过寄存器工作,而不是驱动程序! 这么简单的代码就是将PortC.8设置为1并打开stm32f1发现板上的LED。 我正在编写这个脚本:
arm-none-eabi-gcc --specs=nosys.specs -T *.ld -o main.elf main.c system_*.c *.s
和main.elf文件已成功完成......但无法正常工作!并且LED熄灭。
目录中的文件是:
core_cm3.c
core_cm3.h
main.c
main.elf
startup_stm32f100xb.s
STM32F100RBTx_FLASH.ld
stm32f10x.h
system_stm32f10x.c
system_stm32f10x.h
从ST官方网站下载的STM32F10x_StdPeriph_Lib_V3.5.0文件夹中的所有文件。
main.c中:
#include "stm32f10x.h"
void EnableClock(void);
void InitPort(void);
int main(void)
{
EnableClock();
InitPort();
}
void EnableClock(void)
{
//Enable HSI
RCC->CR |= (uint32_t)(0x00000001);
//APB2 Prescalar to 1(HCLK not devided)
RCC->CFGR &= (uint32_t)(0xFFFFFF0F);
//APB2 GPIOC Enable
RCC->APB2ENR |= (uint32_t)(0x00000010);
}
void InitPort(void)
{
//PORTC Bit 8 set as output max speed 2MHz GPIOC_CRH->Mode8
//PORTC Bit 8 set as Push Pull
GPIOC->CRH &= (uint32_t)(0x00000002);
GPIOC->ODR |= (uint32_t)(0x00000100);
}
我不知道问题出在哪里......任何人都可以帮助我?
答案 0 :(得分:2)
您的main()
终止。接下来会发生什么取决于startup_stm32f100xb中__main
调用之后的内容;可能会强制复位,或者无限循环(直到启用看门狗复位)。
在嵌入式系统中,main()
返回是不正常的。
“Enable HSI
”可能是不必要的,甚至是不正确的。核心时钟默认为HSI - 必须已经建立了一个时钟才能完全执行代码,并且启用HSI要么没有效果,要么禁用先前建立的时钟,系统时钟将被设置为system_stm32f10x.c,如果您有特定的时钟要求,则需要修改它以适合您的电路板和/或应用程序。使用HSI直接允许8MHz工作,将其馈入PLL支持高达64MHz,当PLL由外部4-16MHz振荡器(HSE)馈电时,芯片将以高达72MHz的频率运行。
如果你没有在system_stm32f10x.c中正确建立时钟(或者让它运行HSI-direct),那么有可能在system_stm32f10x.c中的SystemInit()
中停止执行,等待PLL锁定,或者如果你真的错了就根本不运行。
要在电路板启动级别上处理任何裸机处理器,理想情况下应该有一个硬件调试器(JTAG / SWI),这样您就可以使用工具链的调试器来确定您的代码正在做什么它在哪里摔倒您至少可以确定它是否运行到main()
- 在main()
运行之前,startup_stm32f100xb.s和system_stm32f10x.c实现了重要的初始化。后者通常需要修改以适合您的目标。
答案 1 :(得分:2)
这是一个完整的例子,它来自一个闪烁pc13(在pc8未经测试,但在pc13工作,如果你有问题可以测试它)
flash.s
@.cpu cortex-m0
@.cpu cortex-m3
.thumb
.thumb_func
.global _start
_start:
stacktop: .word 0x20001000
.word reset
.word hang
.word hang
.word hang
.word hang
.word hang
.word hang
.word hang
.word hang
.word hang
.word hang
.word hang
.word hang
.word hang
.word hang
.thumb_func
reset:
bl notmain
b hang
.thumb_func
hang: b .
.thumb_func
.globl PUT32
PUT32:
str r1,[r0]
bx lr
.thumb_func
.globl GET32
GET32:
ldr r0,[r0]
bx lr
.thumb_func
.globl dummy
dummy:
bx lr
blinker01.c
void PUT32 ( unsigned int, unsigned int );
unsigned int GET32 ( unsigned int );
void dummy ( unsigned int );
#define GPIOCBASE 0x40011000
#define RCCBASE 0x40021000
int notmain ( void )
{
unsigned int ra;
ra=GET32(RCCBASE+0x18);
ra|=1<<4; //enable port c
PUT32(RCCBASE+0x18,ra);
//config
ra=GET32(GPIOCBASE+0x04);
ra&=~(0xF<<0); //PC8
ra|= (0x1<<0); //PC8
PUT32(GPIOCBASE+0x04,ra);
while(1)
{
PUT32(GPIOCBASE+0x10,1<<(8+0));
for(ra=0;ra<200000;ra++) dummy(ra);
PUT32(GPIOCBASE+0x10,1<<(8+16));
for(ra=0;ra<200000;ra++) dummy(ra);
}
return(0);
}
flash.ld
MEMORY
{
rom : ORIGIN = 0x08000000, LENGTH = 0x1000
ram : ORIGIN = 0x20000000, LENGTH = 0x1000
}
SECTIONS
{
.text : { *(.text*) } > rom
.rodata : { *(.rodata*) } > rom
.bss : { *(.bss*) } > ram
}
生成文件
ARMGNU = arm-none-eabi
#ARMGNU = arm-linux-gnueabi
AOPS = --warn --fatal-warnings -mcpu=cortex-m0
AOPS3 = --warn --fatal-warnings -mcpu=cortex-m3
COPS = -Wall -Werror -O2 -nostdlib -nostartfiles -ffreestanding -mcpu=cortex-m0 -march=armv6-m
COPS32 = -Wall -Werror -O2 -nostdlib -nostartfiles -ffreestanding -mcpu=cortex-m3 -march=armv7-m
all : blinker01.bin
clean:
rm -f *.bin
rm -f *.o
rm -f *.elf
rm -f *.list
flash.o : flash.s
$(ARMGNU)-as $(AOPS) flash.s -o flash.o
blinker01.o : blinker01.c
$(ARMGNU)-gcc $(COPS) -mthumb -c blinker01.c -o blinker01.o
blinker01.bin : flash.ld flash.o blinker01.o
$(ARMGNU)-ld -o blinker01.elf -T flash.ld flash.o blinker01.o
$(ARMGNU)-objdump -D blinker01.elf > blinker01.list
$(ARMGNU)-objcopy blinker01.elf blinker01.bin -O binary
或
arm-none-eabi-as --warn --fatal-warnings -mcpu=cortex-m0 flash.s -o flash.o
arm-none-eabi-gcc -Wall -Werror -O2 -nostdlib -nostartfiles -ffreestanding -mcpu=cortex-m0 -march=armv6-m -mthumb -c blinker01.c -o blinker01.o
arm-none-eabi-ld -o blinker01.elf -T flash.ld flash.o blinker01.o
arm-none-eabi-objdump -D blinker01.elf > blinker01.list
arm-none-eabi-objcopy blinker01.elf blinker01.bin -O binary
最初使用内部振荡器复位时,你不需要弄乱时钟。因此,除非您有自己的固件将其设置为其他东西,否则您不需要将其设置为HSI。需要时钟初始化来改变它以使用外部时钟和/或使用PLL。
GPIOC->CRH &= (uint32_t)(0x00000002);
这会将寄存器从0x44444444更改为0x44444444(抱歉,请参阅下面的编辑)。这是另一种说法你没有做任何事情的方式。如果你想读取修改写入更清洁,你需要0x44444442为2mhz,但是没有必要,因为我们知道你应该做的上电复位状态就像我上面所做的那样读取数值掩码从零到零然后设置位你想要的,整个模式。或者你可以推送0x44444442或0x44444441或0x44444443。
你做过一次或者等于它会产生0x44444446这是一个开漏输出。因此,如果有一个上拉,那么它可能会点亮LED,但是你会想要使用开漏来沉没而不是采购。 led的哪一端是连接到的gpio引脚,你需要将它来源或接收它以将其打开吗?您将输出设置为1以将输出设置为高,这在开漏上意味着不要下沉。虽然对于输入设置,odr会将输入上拉/下拉拉高,但作为开漏输出,不确定设置odr是否会将其拉高。更容易尝试推拉,如果你只是想要它,那么BSRR可以很容易地设置或重置端口中的单个引脚,而不是用odr触摸整个端口。
开漏模式:输出寄存器中的“0”激活N-MOS 输出寄存器中的“1”将端口留在Hi-Z中。 (P-MOS 永远不会被激活)
因此,首先要更改代码以将端口设置为推挽输出,然后如果您想真正从头开始,则可以替换您借用的其余代码并拥有所有代码。不必使用我使用的put32 / get32组件,我有很多理由和大量的经验,但那是裸机之美,做你自己的事情,你可以使用易失性指针方法,这很可能是什么头文件你链接了,并简化了引导程序。如果你确定你的入口点函数永远不会退出,你不依赖.data也不依赖.bss那么你可以减少你的引导程序
.thumb
.thumb_func
.global _start
_start:
stacktop: .word 0x20001000
.word main
.word hang
.word hang
.word hang
.word hang
.word hang
.word hang
.word hang
.word hang
.word hang
.word hang
.word hang
.word hang
.word hang
.word hang
hang: b hang
或者为其他向量定义C函数或为未使用的向量定义转储地。请注意,我没有将所有向量放在bootstrap中,取决于芯片和内核,但可能是数百个向量(最多128或256)
并匹配您对堆栈指针初始化值的ram数量(上例中为0x20001000)。
编辑,实际上,抱歉0x44444444&amp; = 0x00000002 = 0x00000000,它将所有端口设置为模拟输入。你希望它是0x44444441或0x44444442或0x44444443