Open Wurstnase opened 9 years ago
D'oh. Must have gotten lost. Will add you in a second.
Done. Welcome to Teacup Development!
Thanks. I will upload it maybe this evening. But I need some rework. Something went wrong. My first binary size is only ~460byte. Yours was >900.
My first binary size is only ~460byte.
That's fine, certainly not a problem.
I mean, the obvious reason for a too small binary is, there are some missing functions. Or unneeded functions in the bigger one. Neither is a problem, missing functions will ineviteably show up sooner or later.
Can't wait for your push :-)
Took the lunchtime for some research. I think I've taken the wrong startup-file. For the sam it's a c-file. I took the s-template.
%appdata%\Roaming\Arduino15\packages\arduino\hardware\sam\1.6.4\system\CMSIS\Device\ATMEL\sam3xa\source\gcc_arm\startup_sam3xa.c
Also for reference: http://forum.arduino.cc/index.php?topic=135403.msg1033950#msg1033950 under number 7 are some interesting folders.
For this extreme low level stuff (placing reset and interrupt vectors, copying the initial RAM contents from Flash, etc.), assembly is usually the better choice.
If you'd take the minute to do a push, I could see what you're doing. Topic branches are by no means permanent, you can change them later as much as you want.
Just pushed.
I put a copy of the c-file also in that branch.
Well, I don't know what I'm doing but:
replace in startup.s:
/* External interrupts */
.long Default_Handler
with
/* External interrupts */
.long SUPC_Handler, /* 0 Supply Controller */
.long RSTC_Handler, /* 1 Reset Controller */
.long RTC_Handler, /* 2 Real Time Clock */
.long RTT_Handler, /* 3 Real Time Timer */
.long WDT_Handler, /* 4 Watchdog Timer */
.
.
.
and setting up each unique handler in the end with def_irq_default_handler
?
Just pushed.
Thanks. I took a brief look and what you did looks fine. The .s file looks also fine. The only thing I'm missing is a SystemInit() function, but if the compiler doesn't complain, that's fine as well.
Which problem do you try to solve?
I stumble a bit with it. I tried to combile some steps further but the size doesn't increase. So I thought it's something in the first files I missed.
Could the SystemInit() be in the .a-file? I found a libsam_sam3x8e_gcc_rel.a.
If the size doesn't increase, the additional stuff isn't used and removed at the link stage. You have to actually use the code you add.
Slowly, but I think I'm learning it. The main-difference of your first compile was only the Reset_Handler.
The UART-stuff takes me a lot of time. Maybe next week I can try to send some stuff.
Not that complicated I thought first.
On the sam we don't need to calculate so much stuff (DLL, DLM, FDR).
It's simple port->UART_BRGR = (SystemCoreClock / BAUDRATE) >> 4;
On the sam we don't need to calculate so much stuff (DLL, DLM, FDR).
All the better, then you can simply wrap this part with #ifdef LPC1114.
BTW., this simple strategy would work on the LPC1114, too, but the User Manual says using a divider and multiplier makes baud rate more precise. As the code was already there I kept it and made kind of an easter egg from it.
Yes, right. Just read something about this. It could be also possible with sam on the PLLA (maybe I'm wrong?). But this is maybe for later.
Thanks for your feedback.
Also I found a great tutorial about the UART on the Due. http://codetron.net/uart-interface-sam3x8e-arduino-due/
Not sure how similar the serial blocks are, but https://github.com/mbedmicro/mbed/pull/116 may give you some ideas for UART PLL setup :)
Definitely applies to the lpc1117 target!
@triffid Thx for that link. Traumflug already use it :) https://github.com/Traumflug/Teacup_Firmware/blob/experimental/serial-arm.c#L108
Should I see any echo on a serial connection?
Right after releasing the reset button you should see
start
ok
Characters sent aren't echoed normally, but you can put arbitrary code into main.c, before the endless loop for testing. Just echoing incoming characters would be something like this:
for (;;) {
if (serial_rxchars() != 0) {
serial_writechar(serial_popchar());
}
}
If the size doesn't increase, the additional stuff isn't used and removed at the link stage. You have to actually use the code you add.
I think this is my actual problem. But at this moment I have no clue to solve or to see where my new code is not linked in.
The linker builds a set of "used references" starting from the entry point (usually _start which eventually calls main) and other root references such as interrupts.
If your functions are never called from main, or from something that main calls, etc, then the linker will discard them as unreachable code.
Ok, but my code should be called. In mendel.c the serial_init() is called. This goes from serial.c to serial-arm.c.
I think there is something missing to initialize the due or whatelse :/
On any other Makefile for the Due I see that they use the libchip_sam3x8_gcc_rel.a. Do I need this also?
serial_init() isn't much, it just sets a few registers. Perhaps 100 bytes binary, much less than what the LPC1114 had. LPC1114 intitially had extensive baud rate calculations there, which the SAM apparently doesn't need.
I'd try to ignore binary size and concentrate on what works and what not. If getting serial working at all requires additional code or interrupts, go for it. Once you can see what's happening it's much easier to refine it. This looks like a good code sample: http://codetron.net/uart-interface-sam3x8e-arduino-due/
Well, it wont grow up. With or without serial_init() it's 124 bytes.
CC build/mendel.o
CC build/cpu.o
CC build/serial.o
CC build/sermsg.o
CC build/sersendf.o
CC build/cmsis-system_sam3xa.o
LINK build/teacup.elf
OBJCOPY teacup.hex
OBJDUMP build/teacup.lst
SYM build/teacup.sym
SIZES ARM... sam3x8e
FLASH : 124 bytes 1%
RAM : 28 bytes 1%
EEPROM : 0 bytes 0%
arm-startup_due.s isn't compiled. This is where the reset handler is called, which in turn calls SystemInit() and _start(). _start() inititalises a few things, then jumps to main(). My take is, your binary doesn't even call main(), so pretty much everything is optimised out.
To see which functions end up in the binary, you can use something like this:
nm -Cg path/to/teacup.elf
Small progress. Got the compiler stuff I think. I use now a modified LPC.ld. Size increase now with more functions inside.
But I can't read or write anything over UART (programming port).
Today I give up.
The nm
helps alot!
It's still something with the start part.
After some hours I've got this to run. I've made also a simple main.c with the serial stuff. The good news, this works pretty good.
The bad news, it's heavy bloated, has it's own Makefile. It uses the libsam_sam3x8e_gcc_rel.a with all arduino libraries.
Actually I have no idea how the startup.c or .s will work.
I want to implement the 'low level' from atwillys. But I'm not very good in makefiles. Where I should put that part in the makefile? Especially the libsam-part?
My intend of this is to take that part of code and reduce it step by step.
LIBSAM_ARCHIVE=$(ROOT)/lib/libsam_sam3x8e_gcc_rel.a
# -> .elf
$(OBJ_DIR)/$(OUTPUT_NAME).elf: $(OBJ_DIR)/$(OUTPUT_NAME).a
"$(LKELF)" -Os -Wl,--gc-sections -mcpu=cortex-m3 \
"-T$(LNK_SCRIPT)" "-Wl,-Map,$(OBJ_DIR)/$(OUTPUT_NAME).map" \
-o $@ \
"-L$(OBJ_DIR)" \
-lm -lgcc -mthumb -Wl,--cref -Wl,--check-sections -Wl,--gc-sections \
-Wl,--entry=Reset_Handler -Wl,--unresolved-symbols=report-all -Wl,--warn-common \
-Wl,--warn-section-align -Wl,--warn-unresolved-symbols \
-Wl,--start-group \
$^ $(LIBSAM_ARCHIVE) \
-Wl,--end-group
Put it wherever you want, Makefiles don't rely on a specific order.
Ok, do I need to copy the complete part for the libsam? Or do I need to just copy
-Wl,--start-group \
$^ $(LIBSAM_ARCHIVE) \
-Wl,--end-group
anywhere?
A few Makefile basics:
Thanks again :+1:
I'm getting closer. There are some predefined linker scripts. Which one do I need? gcc or gcc-arm?
Which ones work? There are several flavours of gcc for ARM. The one coming with Ubuntu is arm-none-eabi-gcc, so neither "gcc" nor "gcc-arm".
From cmsis-core_cm0.h:
#if defined ( __CC_ARM )
#define __ASM __asm /*!< asm keyword for ARM Compiler */
#define __INLINE __inline /*!< inline keyword for ARM Compiler */
#define __STATIC_INLINE static __inline
#elif defined ( __ICCARM__ )
#define __ASM __asm /*!< asm keyword for IAR Compiler */
#define __INLINE inline /*!< inline keyword for IAR Compiler. Only available in High optimization mode! */
#define __STATIC_INLINE static inline
#elif defined ( __GNUC__ )
#define __ASM __asm /*!< asm keyword for GNU Compiler */
#define __INLINE inline /*!< inline keyword for GNU Compiler */
#define __STATIC_INLINE static inline
#elif defined ( __TASKING__ )
#define __ASM __asm /*!< asm keyword for TASKING Compiler */
#define __INLINE inline /*!< inline keyword for TASKING Compiler */
#define __STATIC_INLINE static inline
#endif
As one can see: the differences are small, but existing. Perhaps these two linker scripts are almost identical anyways. I'd compare and try both. When different and both working, a die (Würfel) enters the game :-)
Ok. What i found out, that some weak handlers are defined in one and in the other someone removed them and put them in the mainfile, because with the arduino (whatever that exactly means) needs this.
I think that this could be my issue at the moment. Actually when I compile my test-code the linking goes up to the main. But not init() is calling.
IIRC, weak references are similar to "if this function happens to exist, put it here". If the function doesn't exist, it isn't linked in. Accordingly, weak references don't really matter, unless you want to use them.
What makes you think that init() should be called?
What makes you think that init() should be called?
Because the serial_init() works on a pure Arduino sketch. https://github.com/arduino/Arduino/commit/65f00a69c74ca0def8d7f1d7597327945a04a33f
Hi,
today I cut anything out I don't need from the libsam archive (atwillys low level version).
Start:
adc12_sam3u.o
adc.o
can.o
dacc.o
efc.o
emac.o
gpbr.o
interrupt_sam_nvic.o
pio.o
pmc.o
pwmc.o
rstc.o
rtc.o
rtt.o
spi.o
ssc.o
tc.o
timetick.o
trng.o
twi.o
udp.o
udphs.o
uotghs.o
uotghs_device.o
uotghs_host.o
usart.o
wdt.o
system_sam3xa.o
startup_sam3xa.o
ends with:
timetick.o
wdt.o
system_sam3xa.o
startup_sam3xa.o
@Traumflug where do you initialize the systick_handler? When I make the systick_handler weak on my version at home, the sam doesn't start.
(I don't know exactly what is going wrong, but the UART-thing won't work)
Actually I need the timetick, and I want to delete this also. https://github.com/arduino/Arduino/blob/master/hardware/arduino/sam/system/libsam/source/timetick.c
where do you initialize the systick_handler?
In timer_init() in timer-arm.c: https://github.com/Traumflug/Teacup_Firmware/blob/master/timer-arm.c#L31
Ah, ok. That will come some steps later. Thanks.
I'm hanging around this step: https://github.com/Traumflug/Teacup_Firmware/tree/32480bdfb62f95677db20f38c55db8cf6b4c30bc
Here it looks like you don't use any systick_handler. Could this be elementary for sam3x?
System clock != SysTickTimer. System clock is the clock which makes the CPU running. Often a quartz oscillator. On top of the system clock there's a PLL which makes a 48 MHz clock from a 12 MHz one, depending on some register settings.
SysTickTimer is a timer, a peripheral, something outside the CPU, still on chip. Very similar to the other timers.
I've found that missing key. :)
and finally:
system_sam3xa.o
startup_sam3xa.o
How can I print an uint8_t with serial_write_char()?
I answer myself: SOURCES += sermsg.c and serwrite_hex32().
Uhm, serial_writechar() is one of the functions you have to implement for a port. Examples are in serial-avr.c and serial-arm.c.
serial_writechar() was not my issue. Sending an uint_8 or something like that won't help me, because it was translated to a char. serwrite_hex does that job perfect for me to read some registers.
hex32 is for uint32s and pointers, not uint8s
Sending an uint_8 or something like that won't help me, because it was translated to a char.
Now I got it, you want a hex string of this character. In this case it's no problem add sersendf.c, too, it's platform independent and should compile flawlessly. sersendf() works similar to printf(), with formatting string and such stuff. uint8_t would be "%su", then. Formatting is described in the source code file.
Hi @Traumflug
first commit works and upload also. Just tried to upload it as a new branch, but I don't have write access.