此问题在此处已有答案:
Makefile failing to flash code to ATmega328p(1个答案)
20天前关闭。
我试图在Arduino上学习嵌入式C的裸金属,没有IDE的方式.我尝试写一些avr/io.h
宏自己以不同的方式.我尝试 Flink LED通过使用直接内存地址(它的作品)和指针的结构位字段(* 这不工作 *).
定义了F_CPU宏。设备:Arduino UNO R3板,其具有ATMEGA328P芯片。
直接内存扩展(按预期工作):
#include <util/delay.h>
int main (void) {
*(volatile unsigned char*) 0x24 |= 1 << 5;
while(1) {
*(volatile unsigned char*) 0x25 |= 1 << 5;
_delay_ms(500);
*(volatile unsigned char*) 0x25 &= ~(1 << 5);
_delay_ms(500);
}
return 0;
}
字符串
通过编译器组装:
.file "main.c"
__SP_H__ = 0x3e
__SP_L__ = 0x3d
__SREG__ = 0x3f
__tmp_reg__ = 0
__zero_reg__ = 1
.text
.section .text.startup,"ax",@progbits
.global main
.type main, @function
main:
/* prologue: function */
/* frame size = 0 */
/* stack size = 0 */
.L__stack_usage = 0
sbi 0x4,5
.L2:
sbi 0x5,5
ldi r18,lo8(1599999)
ldi r24,hi8(1599999)
ldi r25,hlo8(1599999)
1: subi r18,1
sbci r24,0
sbci r25,0
brne 1b
rjmp .
nop
cbi 0x5,5
ldi r18,lo8(1599999)
ldi r24,hi8(1599999)
ldi r25,hlo8(1599999)
1: subi r18,1
sbci r24,0
sbci r25,0
brne 1b
rjmp .
nop
rjmp .L2
.size main, .-main
.ident "GCC: (Fedora 13.2.0-1.fc38) 13.2.0"
型
结构与位字段的方式(不工作,LED刚刚打开):
#include <util/delay.h>
typedef unsigned char byte;
volatile struct {
volatile byte PINB0: 1;
volatile byte PINB1: 1;
volatile byte PINB2: 1;
volatile byte PINB3: 1;
volatile byte PINB4: 1;
volatile byte PINB5: 1;
volatile byte PINB6: 1;
volatile byte PINB7: 1;
} *__ATMEGA_328P_PINB = (void*) 0x23;
volatile struct {
volatile byte DDB0: 1;
volatile byte DDB1: 1;
volatile byte DDB2: 1;
volatile byte DDB3: 1;
volatile byte DDB4: 1;
volatile byte DDB5: 1;
volatile byte DDB6: 1;
volatile byte DDB7: 1;
} *__ATMEGA_328P_DDRB = (void*) 0x24;
volatile struct {
volatile byte PORTB0: 1;
volatile byte PORTB1: 1;
volatile byte PORTB2: 1;
volatile byte PORTB3: 1;
volatile byte PORTB4: 1;
volatile byte PORTB5: 1;
volatile byte PORTB6: 1;
volatile byte PORTB7: 1;
} *__ATMEGA_328P_PORTB = (void*) 0x25;
int main (void) {
__ATMEGA_328P_DDRB->DDB5 = 1;
while(1) {
__ATMEGA_328P_PORTB->PORTB5 = 1;
_delay_ms(500);
__ATMEGA_328P_PORTB->PORTB5 = 0;
_delay_ms(500);
}
return 0;
}
型
通过编译器组装:
.file "main.c"
__SP_H__ = 0x3e
__SP_L__ = 0x3d
__SREG__ = 0x3f
__tmp_reg__ = 0
__zero_reg__ = 1
.text
.section .text.startup,"ax",@progbits
.global main
.type main, @function
main:
/* prologue: function */
/* frame size = 0 */
/* stack size = 0 */
.L__stack_usage = 0
lds r30,__ATMEGA_328P_DDRB
lds r31,__ATMEGA_328P_DDRB+1
ld r24,Z
ori r24,lo8(1<<5)
st Z,r24
.L2:
lds r30,__ATMEGA_328P_PORTB
lds r31,__ATMEGA_328P_PORTB+1
ld r24,Z
ori r24,lo8(1<<5)
st Z,r24
ldi r18,lo8(1599999)
ldi r24,hi8(1599999)
ldi r25,hlo8(1599999)
1: subi r18,1
sbci r24,0
sbci r25,0
brne 1b
rjmp .
nop
lds r30,__ATMEGA_328P_PORTB
lds r31,__ATMEGA_328P_PORTB+1
ld r24,Z
andi r24,lo8(~(1<<5))
st Z,r24
ldi r18,lo8(1599999)
ldi r24,hi8(1599999)
ldi r25,hlo8(1599999)
1: subi r18,1
sbci r24,0
sbci r25,0
brne 1b
rjmp .
nop
rjmp .L2
.size main, .-main
.global __ATMEGA_328P_PORTB
.data
.type __ATMEGA_328P_PORTB, @object
.size __ATMEGA_328P_PORTB, 2
__ATMEGA_328P_PORTB:
.word 37
.global __ATMEGA_328P_DDRB
.type __ATMEGA_328P_DDRB, @object
.size __ATMEGA_328P_DDRB, 2
__ATMEGA_328P_DDRB:
.word 36
.global __ATMEGA_328P_PINB
.type __ATMEGA_328P_PINB, @object
.size __ATMEGA_328P_PINB, 2
__ATMEGA_328P_PINB:
.word 35
.ident "GCC: (Fedora 13.2.0-1.fc38) 13.2.0"
.global __do_copy_data
型
我的Makefile:
PROGRAM := main
PORT := 8080
MEMORY := 512M
ARDUINO_DEV := /dev/ttyACM0
# Toolchains
TOOLCHAIN := avr
CC := $(TOOLCHAIN)-gcc
LD := $(TOOLCHAIN)-ld
OBJCPY := $(TOOLCHAIN)-objcopy
FLASH := avrdude
# File Names
C_DIR := src
C_FILES := $(wildcard ./$(C_DIR)/*.c)
OUTPUT_DIR := build
OUTPUT_FILES := $(patsubst ./$(C_DIR)/%.c, ./$(OUTPUT_DIR)/%.c.o, $(C_FILES))
# Flags
# https://gcc.gnu.org/onlinedocs/gcc/AVR-Options.html
C_FLAGS := -mmcu=atmega328p \
-Wall \
-O2 \
-save-temps \
-c \
-DF_CPU=16000000UL
FLASH_FLAGS := -p m328p \
-c arduino \
-e \
-P $(ARDUINO_DEV)
all: $(OUTPUT_DIR)/$(PROGRAM).hex
clean:
@rm -f build/**
@printf "[CLEANED UP]\n"
./$(OUTPUT_DIR)/%.c.o: ./$(C_DIR)/%.c
@$(CC) $(C_FLAGS) -o $@ $<
@printf "[COMPILED]\t$@!\n"
./$(OUTPUT_DIR)/%.s.o: ./$(ASM_DIR)/%.s
@$(CC) $(C_FLAGS) -o $@ $<
@printf "[COMPILED]\t$@!\n"
$(OUTPUT_DIR)/$(PROGRAM).elf: $(OUTPUT_FILES)
@$(LD) -o $(OUTPUT_DIR)/$(PROGRAM).elf $(OUTPUT_FILES) -Map=$(OUTPUT_DIR)/linker.map
@printf "[LINKED]\t$@!\n"
$(OUTPUT_DIR)/$(PROGRAM).hex: $(OUTPUT_DIR)/$(PROGRAM).elf
@$(OBJCPY) -O ihex $(OUTPUT_DIR)//$(PROGRAM).elf $(OUTPUT_DIR)/$(PROGRAM).hex
@printf "[CREATE BIN]\t$@!\n"
flash: $(OUTPUT_DIR)/$(PROGRAM).hex
@sudo $(FLASH) $(FLASH_FLAGS) -U flash:w:$(OUTPUT_DIR)/$(PROGRAM).hex
@printf "[FLASHED]\t$<!\n"
.PHONY: all clean flash
型
我的目录结构:
.
├── build
│ ├── linker.map
│ ├── main.c.i
│ ├── main.c.o
│ ├── main.c.s
│ ├── main.elf
│ └── main.hex
├── compile_commands.json
├── Makefile
└── src
└── main.c
3 directories, 9 files
型
编辑:添加了完整的程序集(它是编译器由于-save-temps
而生成的程序集,而不是objdump
的反汇编)和我的Makefile
2条答案
按热度按时间cig3rfwq1#
它看起来像你把指针转换为void*,它把它当作16位指针而不是8位指针。
字符串
看一看在__ATMEGA_328P_PORTB的数据表中写了什么,我假设它看起来是这样的
型
因此,它实际上会将0x2425加载到Z寄存器中,而不是预期的0x24
6qfn3psc2#
问题似乎是,无论你使用的是什么编译器,它都不理解你试图将地址加载到寄存器对中,它试图这样做:
字符串
这里实际发生的事情相当于:
型
或者在更多的C风格语法中:
型
这意味着指针寄存器
Z
(也称为r30:r31
)指向地址0x2524
,而不是DDRB
寄存器的地址0x0024
。如果你想通过指针访问寄存器,你会希望生成的程序集是:
型
为了实现这一点,你可以使用与第一个例子等效的东西:
型
我理解你希望使用位集来获得更好的语法,但是如果没有一些讨厌的预处理器宏和编写纯汇编,这是做不到的。