cancel
Showing results for 
Search instead for 
Did you mean: 

Urgent - Keil uVision code limit reached

max239955
Associate II
Posted on July 08, 2016 at 01:28

Hi all,

I'm a student, mainly using Keil uVision to program an STM32F4 for my own quadcopter flight controller. I'm also nearing the end of a small contract using the same MCU and uVision software.

Last week I reached the code limit (32kb) for Keil, so had to activate a 7 day trial licence. This has now finished and I desperately need to continue developing my code.

Is there any way that I can easily transfer the project to another development package? Or extend the code limit? Any add-ons to Visual Studio or something? I need to get this work back on track today ideally!

Cheers, guys.
5 REPLIES 5
Posted on July 08, 2016 at 01:57

Avoid large static allocations, if you have large structures, expand the heap and malloc() them.

If it is the linker limit, then perhaps you can reconfigure Keil to use the GNU/GCC tools instead.

http://www.keil.com/arm/gnu.asp

Outside of Keil one can just use GNU/GCC with a makefile, and have no limitations on the build side. You need a different .s file because Keil's syntax is different, but beyond that it isn't that complex. I've posted complete GNU/GCC projects for the STM32F4

Tips, buy me a coffee, or three.. PayPal Venmo Up vote any posts that you find helpful, it shows what's working..
max239955
Associate II
Posted on July 08, 2016 at 11:07

It is the linker limit sadly.

I've installed the GNU tools and switched the project over. Originally I got 1069 errors - I've now managed to reduced these down to 500ish which all seem to be from the startup file (as you mentioned):

''junk at end of line, first unrecognized character is '*''

''bad instruction ...''

How would I go about converting/making/finding a new startup file?

Cheers

max239955
Associate II
Posted on July 08, 2016 at 11:26

So I found a couple of potential startup file replacements:

startup_stm32f429xx.s    (GCC-equivalent of the one I was previously using)

startup_ARMCM4.s (found somewhere in the GNU->samples directory)

They both remove all of the previous ~500 errors, but give another one. Below is the output I get using the first file (this comes after successfully compiling everything else).

linking...

c:/program files (x86)/gnu tools arm embedded/5.4 2016q2/bin/../lib/gcc/arm-none-eabi/5.4.1/../../../../arm-none-eabi/lib/armv7e-m\libc.a(lib_a-exit.o): In function `exit':

exit.c:(.text.exit+0x16): undefined reference to `_exit'

c:/program files (x86)/gnu tools arm embedded/5.4 2016q2/bin/../lib/gcc/arm-none-eabi/5.4.1/../../../../arm-none-eabi/lib/armv7e-m\libc.a(lib_a-sbrkr.o): In function `_sbrk_r':

sbrkr.c:(.text._sbrk_r+0xc): undefined reference to `_sbrk'

c:/program files (x86)/gnu tools arm embedded/5.4 2016q2/bin/../lib/gcc/arm-none-eabi/5.4.1/../../../../arm-none-eabi/lib/armv7e-m\libc.a(lib_a-writer.o): In function `_write_r':

writer.c:(.text._write_r+0x12): undefined reference to `_write'

c:/program files (x86)/gnu tools arm embedded/5.4 2016q2/bin/../lib/gcc/arm-none-eabi/5.4.1/../../../../arm-none-eabi/lib/armv7e-m\libc.a(lib_a-closer.o): In function `_close_r':

closer.c:(.text._close_r+0xc): undefined reference to `_close'

c:/program files (x86)/gnu tools arm embedded/5.4 2016q2/bin/../lib/gcc/arm-none-eabi/5.4.1/../../../../arm-none-eabi/lib/armv7e-m\libc.a(lib_a-lseekr.o): In function `_lseek_r':

lseekr.c:(.text._lseek_r+0x12): undefined reference to `_lseek'

c:/program files (x86)/gnu tools arm embedded/5.4 2016q2/bin/../lib/gcc/arm-none-eabi/5.4.1/../../../../arm-none-eabi/lib/armv7e-m\libc.a(lib_a-readr.o): In function `_read_r':

readr.c:(.text._read_r+0x12): undefined reference to `_read'

collect2.exe: error: ld returned 1 exit status

''.\vinbot\vinbot.elf'' - 1 Error(s), 0 Warning(s).

Target not created.

Build Time Elapsed:  00:00:10

This is all using a linker file that I found in another example project using the same board.

I'm afraid I don't really know anything about startup/linker files, so there may be an easy fix!

max239955
Associate II
Posted on July 08, 2016 at 12:01

Okay it turns out I found the solution myself thanks to this link:

https://answers.launchpad.net/gcc-arm-embedded/+question/249756

Posted on July 08, 2016 at 12:09

You'd need a newlib_stubs.c type file to handle the stdio/heap, with your own routines to implement USART/SWV IO

/*
* newlib_stubs.c
*
* Minimal implementation after nanoage.co.uk
*/
#include <
errno.h
>
#include <
sys
/stat.h>
#include <
sys
/times.h>
#include <
sys
/unistd.h>
#include ''stm32f429i_discovery.h''
extern int __io_putchar(int ch);
extern int __io_getchar(void);
#undef errno
extern int errno;
/*
environ
A pointer to a list of environment variables and their values.
For a minimal environment, this empty list is adequate:
*/
char *__env[1] = { 0 };
char **environ = __env;
int _write(int file, char *ptr, int len);
void _exit(int status) {
_write(1, ''exit'', 4);
while (1) {
;
}
}
int _close(int file) {
return -1;
}
/*
execve
Transfer control to a new process. Minimal implementation (for a system without processes):
*/
int _execve(char *name, char **argv, char **env) {
errno = ENOMEM;
return -1;
}
/*
fork
Create a new process. Minimal implementation (for a system without processes):
*/
int _fork() {
errno = EAGAIN;
return -1;
}
/*
fstat
Status of an open file. For consistency with other minimal implementations in these examples,
all files are regarded as character special devices.
The `sys/stat.h' header file required is distributed in the `include' subdirectory for this C library.
*/
int _fstat(int file, struct stat *st) {
st->st_mode = S_IFCHR;
return 0;
}
/*
getpid
Process-ID; this is sometimes used to generate strings unlikely to conflict with other processes. Minimal implementation, for a system without processes:
*/
int _getpid() {
return 1;
}
/*
isatty
Query whether output stream is a terminal. For consistency with the other minimal implementations,
*/
int _isatty(int file) {
switch (file){
case STDOUT_FILENO:
case STDERR_FILENO:
case STDIN_FILENO:
return 1;
default:
//errno = ENOTTY;
errno = EBADF;
return 0;
}
}
/*
kill
Send a signal. Minimal implementation:
*/
int _kill(int pid, int sig) {
errno = EINVAL;
return (-1);
}
/*
link
Establish a new name for an existing file. Minimal implementation:
*/
int _link(char *old, char *new) {
errno = EMLINK;
return -1;
}
/*
lseek
Set position in a file. Minimal implementation:
*/
int _lseek(int file, int ptr, int dir) {
return 0;
}
/*
sbrk
Increase program data space.
Malloc and related functions depend on this
*/
caddr_t _sbrk(int incr) {
extern char _ebss; // Defined by the linker
static char *heap_end;
char *prev_heap_end;
if (heap_end == 0) {
heap_end = &_ebss;
}
prev_heap_end = heap_end;
char * stack = (char*) __get_MSP();
if (heap_end + incr > stack)
{
_write (STDERR_FILENO, ''Heap and stack collision
'', 25);
errno = ENOMEM;
return (caddr_t) -1;
//abort ();
}
heap_end += incr;
return (caddr_t) prev_heap_end;
}
/*
read
Read a character to a file. `libc' subroutines will use this system routine for input from all files, including stdin
Returns -1 on error or blocks until the number of characters have been read.
*/
int _read(int file, char *ptr, int len) {
int n;
int num = 0;
switch (file) {
case STDIN_FILENO:
for (n = 0; n < 
len
; n++) {
*ptr++ = __io_getchar();
num++;
}
break;
default:
errno
= 
EBADF
;
return -1;
}
return num;
}
/*
stat
Status of a file (by name). Minimal implementation:
int _EXFUN(stat,( const char *__path, struct stat *__sbuf ));
*/
int _stat(const char *filepath, struct stat *st) {
st->st_mode = S_IFCHR;
return 0;
}
/*
times
Timing information for current process. Minimal implementation:
*/
clock_t _times(struct tms *buf) {
return -1;
}
/*
unlink
Remove a file's directory entry. Minimal implementation:
*/
int _unlink(char *name) {
errno = ENOENT;
return -1;
}
/*
wait
Wait for a child process. Minimal implementation:
*/
int _wait(int *status) {
errno = ECHILD;
return -1;
}
/*
write
Write a character to a file. `libc' subroutines will use this system routine for output to all files, including stdout
Returns -1 on error or number of bytes sent
*/
int _write(int file, char *ptr, int len) {
int n;
switch (file) {
case STDOUT_FILENO: /*stdout*/
case STDERR_FILENO: /* stderr */
for (n = 0; n < len; n++) {
__io_putchar(*ptr++);
}
break;
default:
errno = EBADF;
return -1;
}
return len;
}

Tips, buy me a coffee, or three.. PayPal Venmo Up vote any posts that you find helpful, it shows what's working..