I've been getting back into C, and I've been working on an 'academic' exercise to sharpen some old skills again. My project revolves around the rather simple process of generating sines. I started out just coding for x86 on the command line (Fedora Core 20) and everything worked fine. I then migrated the code to AVR, and I started learning a lot. For example, how to set up the UART as stdout. However, as sines are floating-point, I ran into problems using printf and sprintf.
The program generates 30 sines, and then prints the values to terminal. The text "Sine: " prints properly, but then I get question marks for the float. Replacing the variable with a constant had no effect.
The first thing I was suggested was if I had remembered the linker option for full floating point support - indeed I had forgotten. Again, adding this into my makefile had no effect.
I'm not sure of the policy here of copying and pasting code: should I paste it and my makefile here for inspection?
EDIT: Sorry for the long delay. I've done some more reading, including what the first answer links to. I had already read that reference before (the GNU one) and I have included the link in my Makefile, which is why I'm so confused. Here's my Makefile in all its glory:
P = sines
OBJ = sines.o
PROGRAMMER = buspirate
PORT = /dev/ttyUSB0
MCU_TARGET = atmega328p
AVRDUDE_TARGET = atmega328p
HZ = 16000000
DEFS =
LIBS = -lprintf_flt -lm
CC = avr-gcc
override CFLAGS = -g -DF_CPU=$(HZ) -Wall -O1 -mmcu=$(MCU_TARGET) $(DEFS)
override LDFLAGS= -Wl,-Map,$(P).map -u,vfprintf
OBJCOPY = avr-objcopy
OBJDUMP = avr-objdump
all: $(P).elf lst text
$(P).elf: $(OBJ)
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $^ $(LIBS)
clean:
rm -rf *.hex *.bin *.map *~ sine*.csv *.o $(P).elf *.lst
lst: $(P).lst
%.lst: %.elf
$(OBJDUMP) -h -S $< > $@
text: hex bin
hex: $(P).hex
bin: $(P).bin
%.hex: %.elf
$(OBJCOPY) -j .text -j .data -O ihex $< $@
%.bin: %.elf
$(OBJCOPY) -j .text -j .data -O binary $< $@
install: $(P).hex
avrdude -p $(AVRDUDE_TARGET) -c $(PROGRAMMER) -P $(PORT) -v -U flash:w:$(P).hex
What I'm concerned about is that perhaps the linker arguments aren't in the correct order? From what I can tell, they are but...
I'm fairly sure my code itself is fine. If wanted, I can post it here as well. Also, thanks for transferring my question over here. Didn't quite understand the difference between the two!
Here's the source code. It's being run on an ATmega328P. This current version is printing a constant as a debug, instead of the result from sinescalc(), even though I know that function is working (at least, it should be, I'm pretty sure I checked using avr-gdb at one point -- it definitely works on the command line, and also on an MSP430).
#include <avr/io.h>
//#include <util/delay.h>
#include <string.h>
#include <stddef.h>
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
static int uart_putchar(char c, FILE *stream);
static FILE mystdout = FDEV_SETUP_STREAM(uart_putchar, NULL, _FDEV_SETUP_WRITE);
static int uart_putchar(char c, FILE *stream) {
if (c == '\n')
uart_putchar('\r', stream);
while(!(UCSR0A & (1<<UDRE0)));
UDR0 = c;
return 0;
}
void sinescalc(double *sinptr, int cycles, int size) {
double pi = acos(-1);
double step = ((pi * (cycles*2))/ size);
float temp;
double z = step;
int y;
for(y = 0; y<= size; y++) {
temp = sin(z); // calculate the current sine
*sinptr = (double)temp; // pass it into the array from main()
z += step; // add the step value to prepare for next sine
sinptr++; // should move the pointer by correct size of variable
}
}
int main(void) {
unsigned long _fosc = 16000000;
unsigned int _baud = 19200;
unsigned long _myubrr = _fosc/16/_baud-1;
unsigned int array_size = 256;
UBRR0L = (unsigned char)_myubrr;
UCSR0B = (1<<RXEN0)|(1<<TXEN0); //enable receiver and transmitter
stdout = &mystdout;
double sines[array_size];
double *sinepointer = sines; // set sinepointer to first element of sines array
sinescalc(sinepointer, 2, array_size); // calculate two cycles of sine, with 255 data points
int y;
//char msg[6] = ("Sine: ");
char output[40];
for(y = 0; y <= array_size; y++) {
sprintf(output, "Sine:\t %.6f", 1.354462);
printf(output);
printf("\n");
}
return 0;
}