Arduino Zero Pro malloc() in ARM libc.a

Go To Last Post
10 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I was trying to get <SD.h> library to work on my Zero Pro with Arduino v1.7.2

Instead of new the File.cpp uses malloc() and free().

 

This works fine in the AVR libc.a

But the ARM v4.8.3 toolchain does not have a working malloc().

 

Instead of returning memory or NULL on failure,  it always returns 8.    Which is a perfectly valid address.

If the libc.a distribution just contains a stub,  surely this should always return NULL

 

Likewise,  there is no working rand()

 

Does malloc() work on the Due ?

 

Is this a simple startup.s problem?

 

David.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

David, 

 

Surely the ARM newlib source is online? So you should be able to fix and build a local copy. 

 

I'm astonished there's no rand(), it's mandated by the C standard isn't it? I guess you could lift the AVR-LibC source and use that? 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I am pretty certain that it comes down to the linker script.

 

Yes,  I am sure that I could simply add my own malloc().  But I would prefer to see what has gone wrong with the v1.7.x releases

Then all the standard Arduino code should start working.

sbrk() returns NULL so it might be that I need to implement sbrk()

 

The Newlib code is fairly daunting.    It would help if I could find out how the Italians had actually built it.  e.g. what configuration.

 

Yes,  adding a working rand() is very straightforward.    I can just add it to the variants/arduino_zero/ folder.

 

David.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Oh sbrk()? Thread search for that here. You DO need to provide one for malloc() (and by implication, printf). 

 

In fact just generally Google "newlib sbrk", there's tons about this. 

 

EDIT: the mentions of sbrk on this page look useful:

 

http://ieee.uwaterloo.ca/coldfir...

Last Edited: Sun. Apr 26, 2015 - 04:59 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thanks,   Cliff.

 

I edited the linker script:

	.heap (COPY):
	{
		__end__ = .;
		PROVIDE(end = .);
		PROVIDE(_heap_start = .);
		*(.heap*)
		. = . + 0x2000;
		__HeapLimit = .;
		PROVIDE(_heap_end = .);
	} > RAM

to provide some external labels.   (and a fixed 8192 byte heap)

and added a _sbrk() function to samd/core/startup.c

/*
 * _sbrk -- changes heap size size. Get nbytes more
 *         RAM. We just increment a pointer in what's
 *         left of memory on the board.
 */
extern caddr_t _heap_start, _heap_end;
#include <errno.h>

caddr_t _sbrk(int nbytes)
{
  static caddr_t heap_ptr = NULL;
  caddr_t        base;

  if (heap_ptr == NULL) {
    heap_ptr = (caddr_t)&_heap_start;
  }

  if (((caddr_t)&_heap_end - heap_ptr) >= 0) {
    base = heap_ptr;
    heap_ptr += nbytes;
    return (base);
  } else {
    errno = ENOMEM;
    return ((caddr_t)-1);
  }
}

I am not happy that this is the proper way to do things.   But it makes <SD.h> work.    And provides a working library malloc(), sbrk(), ...

Your link showed the heap being tested against RAMSIZE.   Which sounds like a scalar to me.

 

I am happier with limits.    I don't like the idea of the Heap running into the Stack without warning.

 

Hopefully,  an arm-gcc expert will drop by and advise.

 

David.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Submit an issue here: https://github.com/arduino-org/A... ?

(I'm curious as to how they'll handle a bug of any complexity.)

 

_sbrk() is in syscalls_sam3() for the due; I don't see anything similar in samd (nor new(), either!)

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thanks,  Bill.     You have a trailing space in your weblink.

 

I don't see any technical issues posted there.    It is mostly sparring between the two Arduino factions.

 

It looks as if the 'other' side is going to release a 'Zero' soon.    In which case,   we might get cooperation to get any bugs ironed out.

Hopefully,   both Zeros will have the same pin-mapping.     So it should not matter too much to the punter which one is used.

 

It is my bedtime.    I will look at the Due branch in the morning.

 

Meanwhile,   I will have to think about where to put these patches.     i.e. in variants/zero_pro or in syscalls.

Likewise,    I have several changes in variants/zero_pro/libraries and variants/zero_pro/variant.cpp

 

I note your comments about SPI mapping.    I still feel that a board that has UNO geography needs to match the most common UNO shields by default.    (with an option to use the 3x2 ISP header as an alternative)

Obviously a DUE is more similar to a MEGA2560 geography.

 

I will wait until I get a bit more familiar with the system before adding anything to 'issues'

And then I will probably want to get the Zero_Pro running with Rowley.

 

David.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Ah-ha.    There is a far neater solution.    The v1.7.2 contains a samd/cores/arduino/syscalls.c that already implements a compatible _sbrk()

And the existing linker script already supplies compatible external symbols.

Yes,    it gives you a Heap that can crash into Stack in the same way that the AVR memory model that we know and love.

 

However,  if you don't reference _sbrk() anywhere in your project,  the linker will not use this object file.    Presumably,  libc.a has got a default stub version of _sbrk().

 

So I have edited samd/cores/arduino/startup.c :

void Reset_Handler( void )
{
  uint32_t *pSrc, *pDest;

  /* Initialize the initialized data section */
  pSrc = &__etext;
  pDest = &__data_start__;

  if ( (&__data_start__ != &__data_end__) && (pSrc != pDest) )
  {
    for (; pDest < &__data_end__ ; pDest++, pSrc++ )
    {
      *pDest = *pSrc ;
    }
  }

  /* Clear the zero section */
  if ( (&__data_start__ != &__data_end__) && (pSrc != pDest) )
  {
    for ( pDest = &__bss_start__ ; pDest < &__bss_end__ ; pDest++ )
    {
      *pDest = 0 ;
    }
  }

  /* Initialize the C library */
  __libc_init_array();

  pDest = _sbrk(0);		//.kbv dummy ref to ensure that syscalls.o is linked

  SystemInit() ;

  /* Branch to main function */
  main() ;

  /* Infinite loop */
  while ( 1 )
  {
  }
}

If you don't want to patch the distribution,  simply add a dummy reference to _sbrk(0) in your Arduino sketch.

 

David.

 

Edit.   I looked at the Due equivalent: sam/cores/arduino/syscalls_sam3.c

Its version of _sbrk() makes no attempt to return -1 even if you exceed RAM.

 

Edit.   v1.7.2 seems to have a working Arduino random() even if it does not seem to have a working libc.a rand()

Last Edited: Mon. Apr 27, 2015 - 10:05 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I don't see any technical issues posted there.    It is mostly sparring between the two Arduino factions.

 

Well: yes.  But that doesn't mean it isn't the current correct spot to post technical issues.

To a significant extent (and lacking a major legal decision), arduino.org succeeds or fails based on whether they can do "adequate" software support (which I believe is "difficult"), and arduino.cc succeeds or fails based on their ability to find/use other hardware manufacturers (which I believe is "easier", but not without complexity!)  But to give each side a fair chance, you have to treat them seriously.  "I'm going to buy all future hardware from Baite" and "I'm not going to submit SW issues to arduino-org's github repository" are both unhelpful in probing the sores...

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

In an ideal world they will kiss and make up.

 

I would certainly agree that you need software support as well as physical manufacturing.

 

As it turned out,   the malloc() problem was fixed by ensuring an external reference.

Regarding Serial().    I would expect standard sketches to compile out of the box without having to rename all calls to Serial5.

 

David.