Skip to main content
max239955
Associate II
July 7, 2016
Question

Urgent - Keil uVision code limit reached

  • July 7, 2016
  • 5 replies
  • 3633 views
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.
    This topic has been closed for replies.

    5 replies

    Tesla DeLorean
    Guru
    July 7, 2016
    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 (See Profile) Up vote any posts that you find helpful, it shows what's working..
    max239955
    max239955Author
    Associate II
    July 8, 2016
    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
    max239955Author
    Associate II
    July 8, 2016
    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
    max239955Author
    Associate II
    July 8, 2016
    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

    Tesla DeLorean
    Guru
    July 8, 2016
    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 (See Profile) Up vote any posts that you find helpful, it shows what's working..