Mega 2560 - memory corruption

I’m encountering some bizarre problems with my new Arduino Mega 2560, and no one seems to know what’s causing them. I’m using the latest WinAVR.

#include <stdlib.h>
#include <string.h>
#include <avr/io.h>

int main(void) {
  const char hello[] = "Hello, World!\r\n";
  char *foo = malloc(128);
  if(foo) {
    strncpy(foo, hello, 5); }
  for(;;);
  return 0; }

When uploaded, this code causes the LED attached to pin 13 to blink rapidly. The bootloader is also unresponsive, and the only way to re-flash the Arduino is to unplug the board from the USB port, hold down the reset button, plug it in, and upload working code immediately when letting go of the reset button. If delays are added, they seem to never be executed. Replacing strncpy() with a loop that simply copies five characters from the malloc’d array also fails. The only ways to avoid this seem to be to either place hello in program space, or allocate foo onto the stack.

Another major problem involving memory corruption is illustrated below. The only debugging information I have available is that LED, so I’m using it to determine whether certain code branches are triggered, or whether certain sanity checks hold true. A stack variable is written before and tested after a call to memcpy_P(), and fails, so it’s clear that memory corruption is happening somehow - I just can’t tell how exactly. Furthermore, if a line of code that absolutely is not executed at all is commented out, the LED lights up and the stack variable isn’t corrupted!

#include <stdlib.h>
#include <string.h>
#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/pgmspace.h>

struct buffer {
  char *data;
  unsigned int len, pos, tx; };

/* struct buffer *uart[4] = {}; */

/*
ISR(USART0_TX_vect) {
  if(uart[0] && uart[0]->data && uart[0]->tx != uart[0]->pos) {
    UDR0 = uart[0]->data[uart[0]->tx];
    uart[0]->tx = (uart[0]->tx + 1) % uart[0]->len; } }
*/

unsigned long buffer_init(struct buffer *buf, unsigned int len) {
  if(buf) {
    memset(buf, 0, sizeof *buf);
    if((buf->data = malloc(len))) {
      buf->len = len;
      return buf->len; } }
  return 0; }

unsigned int buffer_insert(struct buffer *buf, const char *data,
                     unsigned int len) {
  unsigned int bytes, tx;
  tx = buf->tx;
  if(buf && data && buf->data && len > 0 && len < buf->len) {
    if(buf->pos >= buf->tx) {
      if(buf->pos + len < buf->len || buf->pos % buf->len < tx) {
      bytes = len; }
      else {
      /* this branch isn't triggered, or the LED would light */
      PORTB = (1 << PB7);
      bytes = buf->len - buf->pos + tx - 1; } }
    else {
      /* this branch isn't invoked either */
      PORTB = (1 << PB7);
      /* however, if this line (which doesn't run) is commented out,
       the stack won't be corrupted and the LED will light! */
      bytes = buf->pos + len < tx ? len : tx - buf->pos - 1; }
    buf->pos = 0;
    if(buf->pos + len >= buf->len) {
      /* will not run */
      PORTB = (1 << PB7);
      memcpy_P(&buf->data[buf->pos], data, buf->len - buf->pos);
      memcpy_P(buf->data, data + buf->len - buf->pos,
             bytes + buf->pos - buf->len); }
    else {
      memcpy_P(buf->data, data, bytes); }
    /* if memcpy_P did not corrupt the stack, this should be true */
    if(buf->pos == 0) {
      /* and the LED should light, but it doesn't */
      PORTB = (1 << PB7); }
    buf->pos = (buf->pos + bytes) % buf->len;
    return buf->pos; }
  return 0; }

void init(void) {
  DDRB |= (1 << DDB7);
  UBRR0 = 16;
  UCSR0A |= (1 << U2X0);
  UCSR0B |= (1 << TXCIE0) | (1 << RXEN0) | (1 << TXEN0);
  UCSR0C |= (1 << UCSZ01) | (1 << UCSZ00); }

int main(void) {
  static const char hello[] PROGMEM = "Hello, World!\r\n";
  struct buffer output;
  init();
  if(buffer_init(&output, 128) == 128) {
    /* uart[0] = &output; */
    if(buffer_insert(&output, hello, sizeof hello) == sizeof hello) {} }
  for(;;);
  return 0; }

I can’t understand why either of these problems are occurring, and no one seems to know what’s causing them. Any ideas?

Can you post the command you are using to compile your program (I'm guessing you're doing this manually and outside the IDE since you've got a main function). Also can you post the linker's MAP file output?

-- The Gadget Shield: accelerometer, RGB LED, IR transmit/receive, light sensor, potentiometers, pushbuttons

Thanks for your reply. Here's the sequence of commands I use to compile and upload this code:

avr-gcc -c -g -Wall -mmcu=atmega2560 -IC:\Apps\WinAVR\avr\include -o serial4.o serial4.c
avr-gcc -lm -g -Wl,-Map,serial.map -o serial.elf serial4.o
avr-objcopy -j .text -j .data -O ihex serial.elf serial.hex
avrdude -p m2560 -e -U flash:w:serial.hex -c stk500v2 -P COM3

The linker MAP output for the first example can be found here: http://codepad.org/lyGHDpNZ

Easy things first...try the avr-objcopy command without the -j options. They shouldn't be necessary. Compile without -g as you won't need the debugging support at runtime (and it won't put stuff in your HEX file that you don't need).

I'd also recommend compiling with some optimizations else code tends to be huge. Use -Os on the first command.

Let's see if that gets you anywhere first.

-- The Quick Shield: breakout all 28 pins to quick-connect terminals

I was only using -j .text, -j .data because I was unfamiliar with objcopy at the time, copying commands from another makefile. The debug tabs were added in an attempt to simulate the code using something called VMLAB, where everything worked fine. I originally used -Os but removed it since I thought it might have been causing problems.

Making these adjustments, the first example still causes the LED to blink rapidly, and the second example still signals stack corruption with no LED lit. No change.

Here’s my current makefile in case anyone wishes to use it. Although this shouldn’t require much modification for Linux, unfortunately Fedora’s mainline avrdude doesn’t seem to communicate with /dev/ttyACM0 correctly.

AVR = 2560
AVR_LIBC = C:\Apps\WinAVR
PGM = stk500v2
PORT = COM3

CFLAGS = -c -Os -Wall -mmcu=atmega$(AVR) -I$(AVR_LIBC)\avr\include
LDFLAGS = -lm
CC = avr-gcc
OBJCOPY = avr-objcopy
OBJDUMP = avr-objdump
AVRDUDE = avrdude

SERIAL = serial

SERIAL_SRC = serial3.c
SERIAL_OBJ = $(SERIAL_SRC:.c=.o)
SERIAL_ELF = $(SERIAL).elf
SERIAL_HEX = $(SERIAL).hex
SERIAL_LST = $(SERIAL).lst
SERIAL_MAP = $(SERIAL).map
LDFLAGS += -Wl,-Map,$(SERIAL_MAP)

all:      $(SERIAL_ELF) $(SERIAL_HEX)

$(SERIAL_ELF):      $(SERIAL_OBJ)
      $(CC) $(LDFLAGS) -o $(SERIAL_ELF) $(SERIAL_OBJ)

.c.o:
      $(CC) $(CFLAGS) \
      -o $@ $<

%.hex:      %.elf
      $(OBJCOPY) -O ihex $< $@

lst:      $(SERIAL_LST)

%.lst:      %.elf
      $(OBJDUMP) -h -S $< > $@

upload:      $(SERIAL_HEX)
      $(AVRDUDE) -p m$(AVR) -e -U flash:w:$(SERIAL_HEX) -c $(PGM) -P $(PORT)

tidy:
      -rm -f $(SERIAL_OBJ) *.core *~

clean:      tidy
      -rm -f $(SERIAL_ELF) $(SERIAL_HEX) $(SERIAL_LST) $(SERIAL_MAP)

Looking over the MAP file there is something odd:

LOAD c:/apps/winavr/bin/../lib/gcc/avr/4.3.3/../../../../avr/lib/crts8515.o

I don't think this is the right startup file for the 2560. I would have expected the crtm2560.o file to link in. Try adding the -mmcu=atmega2560 flag to the avr-gcc command that does the linking too, not just the compiling.

-- Need a custom shield? Let us design and build one for you.

Thanks RuggedCircuits for your advice, the wrong CRT library was being linked. Using the correct library by adding -mmcu=atmega2560 to the linking step fixed all problems; both examples now work as intended.

I really appreciate your support; now I can get back to working on my project!