NerdKits - electronics education for a digital generation

You are not logged in. [log in]

NEW: Learning electronics? Ask your questions on the new Electronics Questions & Answers site hosted by CircuitLab.

Microcontroller Programming » Malloc Issues

July 08, 2010
by Starwarslegokid
Starwarslegokid's Avatar

Hello everyone,

Im working on a new project and im trying to use the malloc function to allocate space for nodes in a linked list. I just recently took a data structures class and saw it would be very usefull structure and decided to do it, but im having allot of issues in just allocating the space. I haven't gotten to the list making yet.

I wrote some simple code just to see if malloc is working but it keeps failing and returning the null pointer. Can anyone help me on this one? Im using the Atmega168 and the nerdkits bootloader with the default fuse and clock settings

I have tried a whole bunch of combinations with the malloc function but they all compiled and returned the null pointer. I have two of them in the code, ones commented out.

// crystal speed
#ifndef F_CPU
  #define F_CPU 14745600 
#endif

// C library files
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h> 
#include <stdbool.h>

// Avr specific files
#include <avr\io.h>
#include <avr\interrupt.h>
#include <avr\pgmspace.h>
#include <inttypes.h>

// uart functions
#include "C:\Documents and Settings\Scott\My Documents\My Projects\Microcontroler\Libraries\libnerdkits\uart.c"

void main() 
{

  // initialize uart output
  FILE uart_stream = FDEV_SETUP_STREAM(uart_putchar, uart_getchar, _FDEV_SETUP_RW);
  stdin = stdout = &uart_stream;
  uart_init();

  printf_P(PSTR(" List Test ...... \r\n"));

  //~~~~~~~~~~~~~~~//

  int *p;

  //p = (int *)malloc(sizeof(int));

  p = malloc(1);

  // check for error
  if (p == NULL)
  {
    //error
    printf_P(PSTR(" ERROR! \r\n"));

  }
  else
  {
    //is ok
    printf_P(PSTR(" memory allocated \r\n"));
  }

}
July 08, 2010
by bretm
bretm's Avatar

I seem to recall something about malloc not being available by default with Nerdkits makefiles because they only upload the .text section and not the .data section. By uploading the .data section it includes the initialization code that allows malloc to do its stuff.

Look for "-j .text" in the makefile and add "-j .data" to the same command. Or something like that...I don't have files in front of me to look at right now.

July 08, 2010
by Starwarslegokid
Starwarslegokid's Avatar

lol what ya know, that was it! Thanks bretm!

My next question, is there any specific reason or added benefit for leaving the -j .data out of the makefile?

Thanks! Scott

July 09, 2010
by bretm
bretm's Avatar

Two main reasons: 1) the initialization code takes space and time, and many apps don't need it, and 2) it's often better to use program space instead of SRAM for large, static data structures.

Because the Atmega has a lot more program space than SRAM, it's more efficient to use program space for large data structures whenever possible. For example if you have a large list of strings or a font or other data, you'll want to put it in program space. That's both because the SRAM space is more scarce, but also because if the data doesn't change during program execution you don't want to burn the limited SRAM read/write cycles.

Programs for small microcontrollers are much less likely to need malloc or other dynamic heap access when compared to apps built for a larger systems. If you only have a few kilobytes, you shouldn't just use malloc out of habit. It's often easier to design the application in a different way. Explicitly requiring .data can prevent bad habits from forming for people new to microcontrollers. Clearly some applications do require it, but the .data initialization code should only be there when the app actually needs it, as it takes up some space.

October 30, 2010
by kle8309
kle8309's Avatar

This was a lot of help since I need to allocate mem for my struct pointer thanks

October 30, 2010
by kle8309
kle8309's Avatar

// calipers.c // for Caliper DRO with ATmega328p // Kelvin Le // 10-29-2010

define F_CPU 14745600

include <stdio.h>

include <stdlib.h>

include <avr/io.h>

include <avr/interrupt.h>

include <avr/pgmspace.h>

include <inttypes.h>

include "../libnerdkits/delay.h"

include "../libnerdkits/lcd.h"

include "../libnerdkits/uart.h"

// PC5 is clock led // PC3 is data led // PC0 is power led // PB1 DATA in // PB2 CLK in // PB3 power switch

// these are the data types for data storage // bit 9-16 is 16 bits and 17-24 is 32 bits

struct multi_Arr {
uint8_t b8_array[24]; uint16_t b16_array[8]; uint32_t b32_array[8]; double length;

};

// this is the hard part uint8_t read(void){

// sample counts of high and low
uint32_t dh=0;
uint32_t dl=0;

// if clock H most likely to be the longest time
// wait it out
while((PINB&(1<<PB2))!=0)
{

    PORTC|=(1<<PC5);

}
// first low get ready
while((PINB&(1<<PB2))==0)
{

    PORTC&=~(1<<PC5);
    PORTC|=(1<<PC3);

}
// first clock high read data now!!!

while((PINB&(1<<PB2))!=0)
{
    //c++;
    PORTC|=(1<<PC5);
    PORTC&=~(1<<PC3);
    if((PINB&(1<<PB1))!=0) {
    dh++;   
    }
    else{
    dl++;
    }
    // if long read break
    if(dh>200||dl>200){
    break;
    }

}

if(dh>dl){
return 1;

}
else{
return 0;
}

}

void digital_read_out(struct multi_Arr *DRO){

// init counter
uint8_t i=0;
uint32_t accumulator=0;

// read 24 bits: 1-24 /////////////////////
for(i=0;i<24;i++){
    DRO->b8_array[i] = read(); // index 0-23
    }
// cast 8 bits to uint16: 8-15 // cast 8 bits to uint32: 16-23      
for(i=0;i<8;i++){   
    DRO->b16_array[i] = DRO->b8_array[i+8];
    DRO->b32_array[i] = DRO->b8_array[i+16];
    }

// for the purpose of debugging we will display on slave lcd 
//so we need to shift to the bits
for(i=0;i<8;i++){
    accumulator |= ((DRO->b8_array[i])  << (i+0) );
    accumulator |= ((DRO->b16_array[i]) << (i+8) );
}

for(i=0;i<4;i++){
    accumulator |= ((DRO->b32_array[i])<<(i+16) );
}

DRO->length=accumulator/100.0;
// handle negative
if(DRO->b8_array[20]==1){
    DRO->length = -(DRO->length);
}

// handle unit: if inches
if(DRO->b8_array[23]==1){
    DRO->length = (DRO->length)*0.0393700787*1.27;
}

return;

}

void caliper_power_on() { // SET PINS AS INPUT DDRB |= 0x00; // SET PINS AS OUTPUT DDRC |= 0xff; DDRB |=(1<<PB3); // PULL UP PINS 1 2 3 PORTB|=(1<<PB1)|(1<<PB2)|(1<<PB3);

// turning off and on again will eliminate start up error PORTB&=~(1<<PB3); delay_ms(500); PORTB|=(1<<PB3);

// Light Indicator PORTC|=(1<<PC0); }

//////////////////////////////MAIN//////////////////////////////////////

int main() {

// start lcd lcd_init(); FILE lcd_stream = FDEV_SETUP_STREAM(lcd_putchar, 0, _FDEV_SETUP_WRITE); lcd_clear_and_home();

// update time uint16_t n=300;

//turn on caliper caliper_power_on();

// init DRO structure pointer struct multi_Arr *DRO;

// allocate memory memory using calloc DRO=(struct multi_Arr *)calloc(1,sizeof(struct multi_Arr));

// skip first dro while(--n>1){ lcd_line_four(); fprintf_P(&lcd_stream, PSTR("Begin in:%5u"),n); delay_us(500); } lcd_clear_and_home();

while(1){

    if(DRO==NULL){
        lcd_line_one();
        fprintf_P(&lcd_stream, PSTR("Not enough Mem"));
        delay_ms(200);
    }
    else{       
    // pass dro pointer to function
    digital_read_out(DRO);

    //now dro is stored in dro_mem
    // we print 
    if(DRO->b8_array[23]!=1){
    lcd_line_two();
    fprintf_P(&lcd_stream, PSTR("Length: %7.2f mm"),DRO->length);
    }
    else{
    lcd_line_two();
    fprintf_P(&lcd_stream, PSTR("Length: %7.3f in"),DRO->length);
    }

    }

}

return 0;

}

Post a Reply

Please log in to post a reply.

Did you know that talking to the microcontroller over the USB/Serial link is easy under Windows, Linux, and OS X? Learn more...