Sorry, typo. I was giving example code, not a literal copy of my source.

I haven't tried looking at the assembly code (I'm not very familiar with
AVR style assembler), but here is the makefile I am using to compile, as
well as the actual original source file (which compiled previously and
behaved as expected) and benc.c library which is used by
ultraluminous_v6.c.

I compile with make clean; make. With -O3 the code works, with -O
anything else, it fails, and commenting out the code and inserting
breakpoints showed that it's failing as soon as it's doing things with
the long variable in the delay function (which I turned into a for loop
with nop's to isolate the problem).

The chip is still running, because the way I actually inserted the
breakpoint was to set the PWM value for one of my outputs to 0x20 out of
0xFF. The pin is still PWMing, so I know that the interrupts are still
being called -- the main loop just stops progressing (so, not a watchdog
issue, or oscillator problem).

The code had the same behavior on two different boards, so I don't think
it is a hardware failure. I am using the ATmega1281

On Fri, 2008-11-07 at 08:37 +0100, Josef Eisl wrote:
> Hello,
> 
> Brian Neltner wrote:
> > Very oddly, the code runs when I compile it with -O3, but not with any
> > other optimization level.
> >> This works:
> >>
> >> int main(void) {
> >>    uint8_t i;
> >>    for(i=1;i<0xFF;i++) asm volatile("nop/n/t");
> >>    PORTA=0x01;
> >>    while(1);
> >> }
> 
> You are using /n  and /t instead of \n \t (backslash-slash). Anyway I
> don't think this is the problem in your case. Could you please give us
> the avr-gcc command with all parameters and compiler flags you use to
> compile the code.
> 
> Which target device are you using? Have you already took a look into the
> dissembled code (using avr-objdump)? May that will give you some hints.
> 
> BR,
> Josef
> 
-- 
Brian Neltner
CC=avr-gcc
OBJCOPY=avr-objcopy

MCU=ATmega1281

CFLAGS=-O3 -g -mmcu=`echo $(MCU) | tr 'A-Z' 'a-z'` -D$(MCU)

TARGET=ultraluminous_v6

all: $(TARGET).hex

foo:
	echo $(CFLAGS)


%.hex : %.out
	$(OBJCOPY) -j .text -O ihex $*.out $*.hex

%.out : %.o
	$(CC) $(CFLAGS) -o $*.out -Wl,-Map,$*.map $*.o

%.o : %.c
	$(CC) $(CFLAGS) -c $*.c

clean:
	rm -f *.o *.out *.map *.hex
	
program: $(TARGET).hex
	avrdude -c avrispmkII -b 115200 -P usb -B 10 -p $(MCU) -e
	avrdude -c avrispmkII -b 115200 -P usb -B 10 -p $(MCU) -U  flash:w:$(TARGET).hex
/* --------------------------------------------------------------

   Byte Encoding system for ultraluminous v5

   This library includes functions to send 8-bit byte encoded 
   brightnesses out to port A on the ultraluminous illuminator v5
   for 7 colors.

   Author: Brian Neltner
   Copyright: 2008

   Changelog:

   2008-06-30  Brian Neltner
   
   Made RED, ORANGE, GREEN, etc aliases for BENC[n] elements so that
   users can abstract to other colors, or even pick colors using the
   random number generator.
   
   2008-06-22  Brian Neltner
   
   I got everything working, and put it in this library to aid 
   modularity. Everything seems to work as advertized, although a
   few compiler directives could help with BENC redefining values, etc.
   The abstraction barrier at the prescaler will hopefully hold, but
   it's borderline. For now, in the unlikely event that it is needed,
   it will have to be changed in this library file.


   Details:

   This library implements 7-channel, 8-bit resolution byte encoding
   as a method for controlling the intensities of each channel. It 
   uses the Timer 3 - Comparator A to time the length of each bit pulse.

   To avoid timing glitches, only the MSB is timed using an actual
   interrupt -- all of the LSBs are done by polling the timer count in
   a while loop. This is necessary because the length of the pulse
   associated with each bit is actually the desired length plus the
   interrupt overhead. In other words, if the overhead is 1us and the
   LSB is supposed to be 5us long, while the 2LSB is 10us long,
   you will actually see 6us and 11us. So, the 2LSB is not actually
   quite twice the length of the LSB, resulting in a non-monotonically
   increasing brightness with desired value. The only clean way around
   this is to remove the interrupt overhead by using polling.

   The result of this compromise is that only half of the clock cycles,
   at a maximum, are available for other computation. However, this
   compromise also means a clean monotonically increasing brightness,
   as well as insanely high overall byte encoding cycles -- of order
   100kHz easily. This allows all sorts of neat possibilities in the
   persistance of vision realm.

   Updating BENC values is done with double buffering, and waits to
   update until the next BENC cycle begins to avoid glitches as well
   as put requiBENC[6] computation in the largest timer interrupt gap.


   Use:

   All you should need to do to use this is to define:

   #define F_CPU 8000000UL
   #define benc_freq 200

   which says that the clock speed is 8MHz and to make the overall
   byte encoding cycle frequency 200 Hz. This library will do the
   rest of the setup.

   Call init_timer() from the main function to set up PORTA as an
   output and configure the timer interrupts.

   Change brightnesses by updating, respectively:

   RBLUE = BENC[0]
   BLUE = BENC[1]
   CYAN = BENC[2]
   GREEN = BENC[3]
   AMBER = BENC[4]
   ORANGE = BENC[5]
   RED = BENC[6]

   with your desired 8-bit brightness.

   After you make all desired changes to light brightnesses, call
   
   update_benc();

   to load those values into the output registers on the beginning
   of the next cycle.

   For a light with fewer lights, some of the BENC[n] values will
   not be meaningful and will be outputting to non-existant power
   modules.

-----------------------------------------------------------------*/

#define prescale 1UL // CS1 = 0b010 on timer 1 = 1:8 prescale
#define benc_period 0x2000
//F_CPU/(benc_freq*prescale)
#define max_interrupt benc_period>>1
#define max_benc_index 7

#include <avr/io.h>
#include <avr/interrupt.h>

void benc_handler();
void init_timer();
void update_benc(void);

ISR(TIMER3_COMPA_vect) { //timer1 comparator A interrupt
  //  TCNT3 = 0x0000; // Reset timer.
  benc_handler();
}

volatile uint8_t benc_index;
volatile uint8_t update_ready;
volatile uint8_t longest_cycle;

// BENCn is the actual values to be written to PORTA on index n
volatile uint8_t BENC7 = 0b00000000;
volatile uint8_t BENC6 = 0b00000000;
volatile uint8_t BENC5 = 0b00000000;
volatile uint8_t BENC4 = 0b00000000;
volatile uint8_t BENC3 = 0b00000000;
volatile uint8_t BENC2 = 0b00000000;
volatile uint8_t BENC1 = 0b00000000;
volatile uint8_t BENC0 = 0b00000000;

// After update_benc(), the new BENCn values are stored here until
// the start of the next brightness loop
volatile uint8_t BENC7_TEMP = 0b00000000;
volatile uint8_t BENC6_TEMP = 0b00000000;
volatile uint8_t BENC5_TEMP = 0b00000000;
volatile uint8_t BENC4_TEMP = 0b00000000;
volatile uint8_t BENC3_TEMP = 0b00000000;
volatile uint8_t BENC2_TEMP = 0b00000000;
volatile uint8_t BENC1_TEMP = 0b00000000;
volatile uint8_t BENC0_TEMP = 0b00000000;

// These are the desired 8-bit brightnesses for each color.
volatile uint8_t BENC[7];

#define RBLUE BENC[6]
#define BLUE BENC[5]
#define CYAN BENC[4]
#define GREEN BENC[3]
#define AMBER BENC[2]
#define ORANGE BENC[1]
#define RED BENC[0]

void update_benc(void) {
  uint16_t brightness;
  uint8_t i;
  if(update_ready != 2) {
    brightness = BENC[6]+BENC[5]+BENC[4]+BENC[3]+BENC[2]+BENC[1]+BENC[0];
    if(brightness>512) {
      BENC[6] = (BENC[6]*512UL)/brightness;
      BENC[5] = (BENC[5]*512UL)/brightness;
      BENC[4] = (BENC[4]*512UL)/brightness;
      BENC[3] = (BENC[3]*512UL)/brightness;
      BENC[2] = (BENC[2]*512UL)/brightness;
      BENC[1] = (BENC[1]*512UL)/brightness;
      BENC[0] = (BENC[0]*512UL)/brightness;
    }
    //    for(i=0;i<7;i++) {
    //      if(BENC[i]==16) BENC[i]=17; // To make monotonic due to interrupt time.
    //    }
    
    BENC7_TEMP = ((BENC[6] & 0b10000000) >> 7) | (((BENC[0] & 0b10000000) >> 7) << 6) | (((BENC[1] & 0b10000000) >> 7) << 5) | (((BENC[2] & 0b10000000) >> 7) << 4) | (((BENC[3] & 0b10000000) >> 7) << 3) | (((BENC[4] & 0b10000000) >> 7) << 2) | (((BENC[5] & 0b10000000) >> 7) << 1);
    // Because of the timing, BENC7 is special.
    BENC6_TEMP = ((BENC[6] & 0b01000000) >> 6) | (((BENC[0] & 0b01000000) >> 6) << 6) | (((BENC[1] & 0b01000000) >> 6) << 5) | (((BENC[2] & 0b01000000) >> 6) << 4) | (((BENC[3] & 0b01000000) >> 6) << 3) | (((BENC[4] & 0b01000000) >> 6) << 2) | (((BENC[5] & 0b01000000) >> 6) << 1);
    BENC5 = ((BENC[6] & 0b00100000) >> 5) | (((BENC[0] & 0b00100000) >> 5) << 6) | (((BENC[1] & 0b00100000) >> 5) << 5) | (((BENC[2] & 0b00100000) >> 5) << 4) | (((BENC[3] & 0b00100000) >> 5) << 3) | (((BENC[4] & 0b00100000) >> 5) << 2) | (((BENC[5] & 0b00100000) >> 5) << 1);
    BENC4_TEMP = ((BENC[6] & 0b00010000) >> 4) | (((BENC[0] & 0b00010000) >> 4) << 6) | (((BENC[1] & 0b00010000) >> 4) << 5) | (((BENC[2] & 0b00010000) >> 4) << 4) | (((BENC[3] & 0b00010000) >> 4) << 3) | (((BENC[4] & 0b00010000) >> 4) << 2) | (((BENC[5] & 0b00010000) >> 4) << 1);
    BENC3_TEMP = ((BENC[6] & 0b00001000) >> 3) | (((BENC[0] & 0b00001000) >> 3) << 6) | (((BENC[1] & 0b00001000) >> 3) << 5) | (((BENC[2] & 0b00001000) >> 3) << 4) | (((BENC[3] & 0b00001000) >> 3) << 3) | (((BENC[4] & 0b00001000) >> 3) << 2) | (((BENC[5] & 0b00001000) >> 3) << 1);
    BENC2_TEMP = ((BENC[6] & 0b00000100) >> 2) | (((BENC[0] & 0b00000100) >> 2) << 6) | (((BENC[1] & 0b00000100) >> 2) << 5) | (((BENC[2] & 0b00000100) >> 2) << 4) | (((BENC[3] & 0b00000100) >> 2) << 3) | (((BENC[4] & 0b00000100) >> 2) << 2) | (((BENC[5] & 0b00000100) >> 2) << 1);
    BENC1_TEMP = ((BENC[6] & 0b00000010) >> 1) | (((BENC[0] & 0b00000010) >> 1) << 6) | (((BENC[1] & 0b00000010) >> 1) << 5) | (((BENC[2] & 0b00000010) >> 1) << 4) | (((BENC[3] & 0b00000010) >> 1) << 3) | (((BENC[4] & 0b00000010) >> 1) << 2) | (((BENC[5] & 0b00000010) >> 1) << 1);
    BENC0_TEMP = (BENC[6] & 0b00000001) | ((BENC[0] & 0b00000001) << 6) | ((BENC[1] & 0b00000001) << 5) | ((BENC[2] & 0b00000001) << 4) | ((BENC[3] & 0b00000001) << 3) | ((BENC[4] & 0b00000001) << 2) | ((BENC[5] & 0b00000001) << 1);
    
    update_ready = 1;
  }
}

void benc_handler() {
  switch(benc_index) {
  case 7: // Reordering the bits.
    PORTA = BENC7;
    OCR3A = (uint16_t)benc_period*160UL/255;
    benc_index--;
    if(update_ready==2) {
      BENC6=BENC6_TEMP;
      BENC4=BENC4_TEMP;
      BENC3=BENC3_TEMP;
      BENC2=BENC2_TEMP;
      BENC1=BENC1_TEMP;
      BENC0=BENC0_TEMP;
      update_ready=0;
    }
    break;
  case 6: // Take care of all the LSBs with polling.
    PORTA = BENC6;
    while(TCNT3<(uint16_t)benc_period*224UL/255);// Wait for next bit.
    PORTA = BENC0;
    while(TCNT3<(uint16_t)benc_period*225UL/255);// Wait for next bit.
    PORTA = BENC1;
    while(TCNT3<(uint16_t)benc_period*227UL/255);// Wait for next bit.
    PORTA = BENC2;
    while(TCNT3<(uint16_t)benc_period*231UL/255);// Wait for next bit.
    PORTA = BENC3;
    while(TCNT3<(uint16_t)benc_period*239UL/255);// Wait for next bit.
    PORTA = BENC4;
    while(TCNT3<(uint16_t)benc_period*255UL/255);// Wait for next bit.
    TCNT3=0x0000;
    PORTA = BENC5;
    OCR3A = (uint16_t)benc_period*32UL/255;
    if(update_ready==1) {
      BENC7=BENC7_TEMP;
      update_ready=2;
    }
    benc_index=7;
    break;
  default:
    break;
  }
}	

void init_timer() {
  PORTA=0x00; // Start with all off.
  DDRA=0xFF;  // outputs for lights
  
  // Timer setup.
  
  benc_index = max_benc_index;
  longest_cycle = 0;
  
  TCCR3A=0x00; // Timer control register A.
  TCCR3B=0x00 | (0<<CS31) | (1<<CS30) ;
  // Timer control register B -- no prescale CS1 = 0b001
  TCCR3C=0x00; // Timer control register C.
  OCR3A=max_interrupt; // Output compare register 1A.
  TIMSK3=0x00 | (1<<OCIE3A); // Enable OCR3A interrupts.
  
  sei();      //global enable interrupts
}

/* --------------------------------------------------------------------

   Ultraluminous version 5 main control loop.

   Author: Brian Neltner, Dan Taub
   Copyright: 2008
   Dependencies: benc.c avr/io.h avr/interrupt.h

   Details:

   This is the top level function to control the ultraluminous
   illuminator. Some example default code for light fading is 
   included.

   Structure:

   benc.c provides byte encoded outputs. brightnesses are controlled
   through RED, ORANGE, AMBER, GREEN, CYAN, BLUE, and RBLUE, are double
   buffered, written with benc_update(), and load to the brightness
   module at the start of the next loop to avoid glitches.

   benc.c requires a timer interrupt (TIMER3_COMPA_vect) to function.

   This should be the higest priority interrupt in order to avoid
   glitches. Unfortunately, because this is a one interrupt architecture,
   that means serial communication will have to be done via polling in
   the main loop.

   Dan is going to implement RF with the ATAVRRZ502 Evaluation Board.
   It will require timer 1.

   -------------------------------------------------------------------*/

#define F_CPU 8000000UL // in Hz
#define benc_freq 300UL // byte encoding total frequency in Hz
#define delay_time 5000UL
//#define light_location 4

#include <avr/io.h>
#include <avr/interrupt.h>
#include "benc.c"
#include <stdlib.h>
#include "com.h"
#include "com.c"

int main(void);
void init_uart(void);
void delay(long);

uint8_t mode;
uint8_t stop_fade;
uint8_t freeze_fade;

int main(void) {
  uint8_t light;
  uint8_t newlight;
  uint8_t light_location;
  uint8_t received_byte;
  uint8_t first_digit, second_digit, third_digit;
  uint8_t digit_location;
  uint8_t j;
  init_timer();
  init_uart();
  mode = 0;
  digit_location = 0;
  first_digit = 0;
  second_digit = 0;
  third_digit = 0;
  stop_fade = 0;
  freeze_fade = 0;
  light_location = 0;
  
  if(mode==0) {
    light=(uint8_t)(rand() % 7);
    while((BENC[light]<0xFF) && (stop_fade==0)) {
      if(freeze_fade==0) {
	BENC[light]++;
	update_benc();
      }
      delay(delay_time);
    }
  }
  
  while(1) {

    switch(mode) {
    case 0: // This randomly picks a color and switches to it each cycle.
      BENC[light]=0xFF;
      while((newlight=(uint8_t)(rand() % 7))==light);		
      while((BENC[newlight]<0xFF) && (stop_fade==0)) {
	if(freeze_fade==0){
	  BENC[newlight]++;
	  BENC[light]--;
	  update_benc();
	}
      	delay(delay_time);
      }
      BENC[light]=0x00;
      BENC[newlight]=0xFF;
      light=newlight;
      break;
    case 1:
      while( !(UCSR1A & (1<<RXC1)) );
      received_byte=UDR1;
      while(!(UCSR1A & (1<<UDRE1)));
      UDR1 = received_byte; 
      switch(received_byte) {
      case 13:
	while(!(UCSR1A & (1<<UDRE1)));
	UDR1 = '\n';
	digit_location = 0;
       	light_location = 0;
	update_benc();
	break;
      case ',':
	if(light_location<6) light_location++;
	digit_location = 0;	
	break;
      case 'T':
	mode = 0;
	for(j=0;j<7;j++) BENC[j]=0x00;
	light=(uint8_t)(rand() % 7);
	stop_fade=0;
	while((BENC[light]<0xFF) && (stop_fade==0)) {
	  if(freeze_fade==0) {	
	    BENC[light]++;
	    update_benc();
	  }
	  delay(delay_time);
	}
	digit_location = 0;
	break;
      default: 
	switch(digit_location) {
	case 0:
	  BENC[light_location] = received_byte-48;
	  break;
	case 1:
	  BENC[light_location] = BENC[light_location]*10+(received_byte-48);
	  break;
	case 2:
	  BENC[light_location] = BENC[light_location]*10+(received_byte-48);
	  break;
	}
	if(digit_location<2) digit_location++;
	break;
      }
    }
  }
}

void delay(long max) {
  long i;
  int j;
  for(i=0;i<max;i++) {	
    if((UCSR1A & (1<<RXC1))) {
      switch(UDR1) {
      case 'T':	
	while(!(UCSR1A & (1<<UDRE1)));
	UDR1 = 'T';	
	for(j=0;j<7;j++) BENC[j]=0x00;
	update_benc();
	stop_fade = 1;
	mode = 1;
	break;
      case 'Z':
	while(!(UCSR1A & (1<<UDRE1)));
	UDR1 = 'Z';	
	if(freeze_fade) freeze_fade = 0;
	else freeze_fade = 1;
	break;
      }
    }
  }
}

void init_uart(void) {
  UCSR1A |= (1<<U2X1); // Double Baud Rate
  UBRR1 = 8; // 115.2 kbps
  UCSR1B |= (1<<TXEN1) | (1<<RXEN1); // Enable Transmitter and Receiver
  
  /*

  // This sets the baud rate from 9600 to 152000 bps for a
  // fresh Xbee chip, and shouldn't need to be done after
  // that.

  // This enters AT Command Mode on the XBee Tranceiver
  
  delay(1000000UL);

  while(!(UCSR1A & (1<<UDRE1)));
  UDR1 = '+';
  while(!(UCSR1A & (1<<UDRE1)));
  UDR1 = '+';
  while(!(UCSR1A & (1<<UDRE1)));
  UDR1 = '+';
  delay(1000000UL);

  // This sets the interface baud rate on the XBee Transceiver to 115.2kbps
  
  while(!(UCSR1A & (1<<UDRE1)));
  UDR1 = 'A';
  while(!(UCSR1A & (1<<UDRE1)));
  UDR1 = 'T';
  while(!(UCSR1A & (1<<UDRE1)));
  UDR1 = 'B';
  while(!(UCSR1A & (1<<UDRE1)));
  UDR1 = 'D';
  while(!(UCSR1A & (1<<UDRE1)));
  UDR1 = ' ';
  while(!(UCSR1A & (1<<UDRE1)));
  UDR1 = '0';
  while(!(UCSR1A & (1<<UDRE1)));
  UDR1 = '7';
  while(!(UCSR1A & (1<<UDRE1)));
  UDR1 = ',';

  // Write baud rate to firmware.

  while(!(UCSR1A & (1<<UDRE1)));
  UDR1 = 'A';
  while(!(UCSR1A & (1<<UDRE1)));
  UDR1 = 'T';
  while(!(UCSR1A & (1<<UDRE1)));
  UDR1 = 'W';
  while(!(UCSR1A & (1<<UDRE1)));
  UDR1 = 'R';
  while(!(UCSR1A & (1<<UDRE1)));
  UDR1 = ',';

  // Leave AT Command Mode.

  UDR1 = 'A';
  while(!(UCSR1A & (1<<UDRE1)));
  UDR1 = 'T';
  while(!(UCSR1A & (1<<UDRE1)));
  UDR1 = 'C';
  while(!(UCSR1A & (1<<UDRE1)));
  UDR1 = 'N';
  while(!(UCSR1A & (1<<UDRE1)));
  UDR1 = 13;

  UBRR1 = 8;	// Set the UART1 Baud Rate to 115.2kbps to accomodate.

  */
}
_______________________________________________
AVR-GCC-list mailing list
AVR-GCC-list@nongnu.org
http://lists.nongnu.org/mailman/listinfo/avr-gcc-list

Reply via email to