Code breaks when small helper function removed

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

Hello,

I wrote a small function that sends a uint8_t sized piece of data via SPI out of a tiny25.

initialization();
while(timer < maxTime) {
/*timer is incremented by a timer overflow interrupt*/
   if (some condition) {
      startTimer();
      while(bitCount < 8) {   

/*the only way to break out of this loop is by a variable bitCount that I have declared volatile. which is incremented by a timer overflow interrupt*/

      }
      //do stuff
      //spiSend(foo); //I put this here for debugging purposes
}
//NEVER REACHES HERE if I comment out spiSend(foo), but if it isn't commented it does get here.

NOTE: do stuff doesn't physically interact with any PORT pins, only computational stuff.

My code breaks when I remove spiSend(foo), this is what spiSend() looks like:

void spiSend(uint8_t spiData, uint8_t strobe) {
   USIDR = spiData;
   PORTB |= (1 << strobe);
   for (int i = 0; i < 16; i++) {
     USICR |= (1 << USITC); //toggle the clock pin 16 times to make 8 clock pulses and pass out data in USIDR
   }
   PORTB &= ~(1 << strobe);
}

could the compiler be optimizing code away which breaks it? I tried to put a asm("") or pin on then off in the //do stuff but nothing works unless I uncomment spiSend();

my makefile sets the optimization to -Os

I don't really know why it isn't working, I'm taking something seemingly benign out of the equation. It did the same thing a while back when I had a delay.

-Robby[/code]

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

It would help to see more of the code. The ISR, timer setup, and initialization of variables.

"I may make you feel but I can't make you think" - Jethro Tull - Thick As A Brick

"void transmigratus(void) {transmigratus();} // recursio infinitus" - larryvc

"It's much more practical to rely on the processing powers of the real debugger, i.e. the one between the keyboard and chair." - JW wek3

"When you arise in the morning think of what a privilege it is to be alive: to breathe, to think, to enjoy, to love." -  Marcus Aurelius

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

robwasab wrote:
My code breaks

Please be more specific. What is the expected behaviour and what are the symptoms?

JW

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

Jan:

//NEVER REACHES HERE if I comment out spiSend(foo), but if it isn't commented it does get here. 

So it seems that something is affecting the operation of:

while(timer < maxTime) { 

I'd like to know more about those variables - types, where they are updated and so on.

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

Maybe the SPI slave needs more time to process a byte, so removing the function execution makes it too fast?

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

Dear Jepael, I was thinking that but I didn't think faster execution couldn't hurt.

I think that I'm actually just going to leave the spi code in. But, to all the big players this code reads flashes from a computer screen sent in RS232 fashion and a uC reads the adc in a polling fashion. However, the intervals in which it times each successive "bit" is sampled via interrupts when the code gets sent into this while loop:

while(timer < maxTime) {

}

Last Edited: Thu. Jun 28, 2012 - 10:35 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

also, the interval of flashes is very slow, and I never send more bytes than BUFFER_SIZE

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

Quote:

I was thinking that but I didn't think faster execution couldn't hurt.

Replace the call to the SPI function with _delay_ms(N) and vary N to see what affect it has.

(by N I mean a constant known at runtime such as 1,10.100 etc not a variable!)

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

Dear clawson, it worked. The same thing happened to me earlier this week when I had a really phat delay in that section of code, but when I removed it, the uC started behaving just as it is now. The code worked with a delay_ms(0); but it generated a lot more code.
without any delays or spi transfer code was 994 bytes, but with either spi or delay 1030. Do you know what's going on? This kind of scares my programming concepts.

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

Quote:

but it generated a lot more code.

Sounds like you are building with -O0 then. If so BIG MISTAKE!

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

robwasab wrote:
but it generated a lot more code.
without any delays or spi transfer code was 994 bytes, but with either spi or delay 1030. Do you know what's going on? This kind of scares my programming concepts.
How can 36 bytes be "a lot more code"? It's at most 18 instructions.

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

Yeah, I read that in your sig. I posted this earlier but I'm pretty sure I'm using -Os, I'm using a makefile from cornfield electronics, perhaps if you have time you can look over it?

So to get things straight, you should, if using any type of optimization, the compiler should be smart enough to realize that delay_ms(0) is nothing? Therefore, some sort of problem could be created there if delay_ms(0) generates more code.

heres something from my terminal:

Linking: pesterSync.elf
avr-gcc -I. -gdwarf-2 -Os -funsigned-char -funsigned-bitfields -fpack-struct -fshort-enums -Wall -Wstrict-prototypes -DF_CPU=1000000 -Wa,-adhlns=pesterSync.o -mmcu=attiny25 -std=gnu99 pesterSync.o --output pesterSync.elf -Wl,-Map=.map,--cref
cp pesterSync.elf pesterSync.elf.debug.elf

Creating load file for Flash: pesterSync.hex
avr-objcopy -O ihex -R .eeprom pesterSync.elf pesterSync.hex
avrdude -p attiny25 -P usb -c usbtiny -U flash:w:pesterSync.hex

And heres my makefile, why not


MCU = attiny25
F_CPU = 1000000   	
AVRDUDE_PROGRAMMER = usbtiny	
AVRDUDE_PORT = usb	# programmer connected to serial port


# Default target.
all: 	begin gccversion \
	combo.hex \
	minipov.hex all_leds.hex alt_leds.hex mypov.hex test_leds.hex \
	largeimage.hex\
	finished end

# Program the device w/various programs

program-blink: blink.hex
program-pesterSync: pesterSync.hex
program-pesterSync2: pesterSync2.hex
program-spi: spi.hex

# this is necessary if you're burning the AVR for the first time...
# sets the proper fuse for 8MHz internal oscillator with no clk div
burn-fuse:
	$(AVRDUDE) $(AVRDUDE_FLAGS) -u -U lfuse:w:0x62:m hfuse:w:0xDF:m efuse:w:0xFF:m

# this programs the dependant hex file using our default avrdude flags
program-%: 
	$(AVRDUDE) $(AVRDUDE_FLAGS) $(AVRDUDE_WRITE_FLASH)$<


FORMAT = ihex 		# create a .hex file

#OPT = s			# assembly-level optimization
OPT = s
# Optional compiler flags.
#  -g:        generate debugging information (for GDB, or for COFF conversion)
#  -O*:       optimization level
#  -f...:     tuning, see gcc manual and avr-libc documentation
#  -Wall...:  warning level
#  -Wa,...:   tell GCC to pass this to the assembler.
#    -ahlms:  create assembler listing
CFLAGS = -gdwarf-2 -O$(OPT) \
-funsigned-char -funsigned-bitfields -fpack-struct -fshort-enums \
-Wall -Wstrict-prototypes \
-DF_CPU=$(F_CPU) \
-Wa,-adhlns=$(<:.c=.lst) \
$(patsubst %,-I%,$(EXTRAINCDIRS)) \
-mmcu=$(MCU)


# Set a "language standard" compiler flag.
CFLAGS += -std=gnu99


# Optional assembler flags.
#  -Wa,...:   tell GCC to pass this to the assembler.
#  -ahlms:    create listing
#  -gstabs:   have the assembler create line number information; note that
#             for use in COFF files, additional information about filenames
#             and function names needs to be present in the assembler source
#             files -- see avr-libc docs [FIXME: not yet described there]
ASFLAGS = -Wa,-adhlns=$(<:.S=.lst),-gstabs 


# Optional linker flags.
#  -Wl,...:   tell GCC to pass this to linker.
#  -Map:      create map file
#  --cref:    add cross reference to  map file
LDFLAGS = -Wl,-Map=$(TARGET).map,--cref


# ---------------------------------------------------------------------------
# Programming support using avrdude.
AVRDUDE = avrdude

# Programming support using avrdude. Settings and variables.

AVRDUDE_WRITE_FLASH = -U flash:w:

AVRDUDE_FLAGS = -p $(MCU) -P $(AVRDUDE_PORT) -c $(AVRDUDE_PROGRAMMER)

# ---------------------------------------------------------------------------

# Define directories, if needed.
DIRAVR = c:/progra~1/winavr
DIRAVRBIN = $(DIRAVR)/bin
DIRAVRUTILS = $(DIRAVR)/utils/bin
DIRINC = .
DIRLIB = $(DIRAVR)/avr/lib


# Define programs and commands.
SHELL = sh

CC = avr-gcc

OBJCOPY = avr-objcopy
OBJDUMP = avr-objdump
SIZE = avr-size

REMOVE = rm -f
COPY = cp

# Define Messages
# English
MSG_ERRORS_NONE = Errors: none
MSG_BEGIN = -------- begin --------
MSG_END = --------  end  --------
MSG_SIZE_BEFORE = Size before: 
MSG_SIZE_AFTER = Size after:
MSG_FLASH = Creating load file for Flash:
MSG_EXTENDED_LISTING = Creating Extended Listing:
MSG_SYMBOL_TABLE = Creating Symbol Table:
MSG_LINKING = Linking:
MSG_COMPILING = Compiling:
MSG_ASSEMBLING = Assembling:
MSG_CLEANING = Cleaning project:


# Define all object files.
OBJ = $(SRC:.c=.o) $(ASRC:.S=.o) 

# Define all listing files.
LST = $(ASRC:.S=.lst) $(SRC:.c=.lst)

# Combine all necessary flags and optional flags.
# Add target processor to flags.
ALL_CFLAGS = -I. $(CFLAGS)
ALL_ASFLAGS = -mmcu=$(MCU) -I. -x assembler-with-cpp $(ASFLAGS)




# Eye candy.
# AVR Studio 3.x does not check make's exit code but relies on
# the following magic strings to be generated by the compile job.
begin:
	@echo
	@echo $(MSG_BEGIN)

finished:
	@echo $(MSG_ERRORS_NONE)

end:
	@echo $(MSG_END)
	@echo



# Display compiler version information.
gccversion : 
	@$(CC) --version


# Create final output files (.hex) from ELF output file.
%.hex: %.elf
	@echo
	@echo $(MSG_FLASH) $@
	$(OBJCOPY) -O $(FORMAT) -R .eeprom $< $@

# Link: create ELF output file from object files.
.SECONDARY : $(TARGET).elf
.PRECIOUS : $(OBJ)
%.elf: %.o
	@echo
	@echo $(MSG_LINKING) $@
	$(CC) $(ALL_CFLAGS) $< --output $@ $(LDFLAGS)
	cp $@ $@.debug.elf

# Compile: create object files from C source files.
%.o : %.c
	@echo
	@echo $(MSG_COMPILING) $<
	$(CC) -c $(ALL_CFLAGS) $< -o $@


# Compile: create assembler files from C source files.
%.s : %.c
	$(CC) -S $(ALL_CFLAGS) $< -o $@


# Assemble: create object files from assembler source files.
%.o : %.S
	@echo
	@echo $(MSG_ASSEMBLING) $<
	$(CC) -c $(ALL_ASFLAGS) $< -o $@





# Target: clean project.
clean: begin clean_list finished end

clean_list :
	@echo
	@echo $(MSG_CLEANING)
	$(REMOVE) *.hex
	$(REMOVE) *.lst
	$(REMOVE) *.obj
#	$(REMOVE) *.elf
	$(REMOVE) *.o

# Listing of phony targets.
.PHONY : all begin finish end \
	clean clean_list program