Flag to prevent use of temporary variables for avrgcc?

Go To Last Post
64 posts / 0 new

Pages

Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

The problem I have is related to the use or the OSA RTOS.
The problem is described by the author of OSA rtos in this http://translate.google.com/tran...

The source of the problem is that unless the code is compiled with O0 setting there are cases (not exactly defined) where the compiler uses temporary variables in the task to access global variables (arrays in my case even if they are volatile) so when the task stops to execute another task and then return back that temporary variables point to different data so the whole thing goes wrong.

I'm using AVRstudio4 + winavr but I have also tried with AVrstudio6 and the included gcc compiler, same error.

Are there any suggestions of a way to prevent that behaviour?

This is an example of the error

/*****************************************************************************
** definitions of hour, min, sec in time array.
*****************************************************************************/
#define H1 line1[0]
#define H2 line1[1]
#define M1 line1[3]
#define M2 line1[4]
#define S1 line1[6]
#define S2 line1[7]

char line1[16] = "00:00:00 I=0.50A";    				// buffer for first line of display


 /************************************************************************************************
  * one of the tasks
  ************************************************************************************************/
void Clock(void) 
{	
    while(1)
    {
        if(OS_Flag_Check_On(flag1, CHANNEL1_ON_FLAG))
        {
            S2++;

            if(S2 == ':')
            {
                S1++;
                S2 = '0';
            }

            if(S1 == '6')
            {
                M2++;
                S1 = '0';
            }

            if(M2 == ':')
            {
                M1++;
                M2 = '0';
            }

            if(M1 == '6')
            {
                H2++;
                M1 = '0';
            }

            if(H2 == ':')
            {
                H1++;
                H2 = '0';
            }
        }

        OS_Delay(1);
    }
}

And the ASM result

@000000FD: Clock
518:      {	
+000000FD:   93DF        PUSH      R29            Push register on stack
+000000FE:   93CF        PUSH      R28            Push register on stack
+000000FF:   B7CD        IN        R28,0x3D       In from I/O location
+00000100:   B7DE        IN        R29,0x3E       In from I/O location
+00000101:   9728        SBIW      R28,0x08       Subtract immediate from word
+00000102:   B60F        IN        R0,0x3F        In from I/O location
+00000103:   94F8        CLI                      Global Interrupt Disable
+00000104:   BFDE        OUT       0x3E,R29       Out to I/O location
+00000105:   BE0F        OUT       0x3F,R0        Out to I/O location
+00000106:   BFCD        OUT       0x3D,R28       Out to I/O location
551:                      H1++;
+00000107:   E687        LDI       R24,0x67       Load immediate
+00000108:   E090        LDI       R25,0x00       Load immediate
+00000109:   9707        SBIW      R24,0x07       Subtract immediate from word
+0000010A:   839A        STD       Y+2,R25        Store indirect with displacement
+0000010B:   8389        STD       Y+1,R24        Store indirect with displacement
545:                      H2++;
+0000010C:   E6E7        LDI       R30,0x67       Load immediate
+0000010D:   E0F0        LDI       R31,0x00       Load immediate
+0000010E:   9736        SBIW      R30,0x06       Subtract immediate from word
+0000010F:   83FC        STD       Y+4,R31        Store indirect with displacement
+00000110:   83EB        STD       Y+3,R30        Store indirect with displacement
539:                      M1++;
+00000111:   E687        LDI       R24,0x67       Load immediate
+00000112:   E090        LDI       R25,0x00       Load immediate
+00000113:   9704        SBIW      R24,0x04       Subtract immediate from word
+00000114:   839E        STD       Y+6,R25        Store indirect with displacement
+00000115:   838D        STD       Y+5,R24        Store indirect with displacement
533:                      M2++;
+00000116:   E6E7        LDI       R30,0x67       Load immediate
+00000117:   E0F0        LDI       R31,0x00       Load immediate
+00000118:   9733        SBIW      R30,0x03       Subtract immediate from word
+00000119:   87F8        STD       Y+8,R31        Store indirect with displacement
+0000011A:   83EF        STD       Y+7,R30        Store indirect with displacement
521:              if(OS_Flag_Check_On(flag1, CHANNEL1_ON_FLAG))
+0000011B:   918000A2    LDS       R24,0x00A2     Load direct from data space
+0000011D:   FF83        SBRS      R24,3          Skip if bit in register set
+0000011E:   C048        RJMP      PC+0x0049      Relative jump
523:                  S2++;
+0000011F:   E6E7        LDI       R30,0x67       Load immediate
+00000120:   E0F0        LDI       R31,0x00       Load immediate
+00000121:   8180        LDD       R24,Z+0        Load indirect with displacement
+00000122:   5F8F        SUBI      R24,0xFF       Subtract immediate
+00000123:   8380        STD       Z+0,R24        Store indirect with displacement
525:                  if(S2 == ':')
+00000124:   338A        CPI       R24,0x3A       Compare with immediate
+00000125:   F449        BRNE      PC+0x0A        Branch if not equal
527:                      S1++;
+00000126:   E6E6        LDI       R30,0x66       Load immediate
+00000127:   E0F0        LDI       R31,0x00       Load immediate
+00000128:   8180        LDD       R24,Z+0        Load indirect with displacement
+00000129:   5F8F        SUBI      R24,0xFF       Subtract immediate
+0000012A:   8380        STD       Z+0,R24        Store indirect with displacement
528:                      S2 = '0';
+0000012B:   E380        LDI       R24,0x30       Load immediate
+0000012C:   E6E7        LDI       R30,0x67       Load immediate
+0000012D:   E0F0        LDI       R31,0x00       Load immediate
+0000012E:   8380        STD       Z+0,R24        Store indirect with displacement
531:                  if(S1 == '6')
+0000012F:   E6E6        LDI       R30,0x66       Load immediate
+00000130:   E0F0        LDI       R31,0x00       Load immediate
+00000131:   8180        LDD       R24,Z+0        Load indirect with displacement
+00000132:   3386        CPI       R24,0x36       Compare with immediate
+00000133:   F449        BRNE      PC+0x0A        Branch if not equal
533:                      M2++;
+00000134:   81EF        LDD       R30,Y+7        Load indirect with displacement
+00000135:   85F8        LDD       R31,Y+8        Load indirect with displacement
+00000136:   8180        LDD       R24,Z+0        Load indirect with displacement
+00000137:   5F8F        SUBI      R24,0xFF       Subtract immediate
+00000138:   8380        STD       Z+0,R24        Store indirect with displacement
534:                      S1 = '0';
+00000139:   E380        LDI       R24,0x30       Load immediate
+0000013A:   E6E6        LDI       R30,0x66       Load immediate
+0000013B:   E0F0        LDI       R31,0x00       Load immediate
+0000013C:   8380        STD       Z+0,R24        Store indirect with displacement
537:                  if(M2 == ':')
+0000013D:   E6E4        LDI       R30,0x64       Load immediate
+0000013E:   E0F0        LDI       R31,0x00       Load immediate
+0000013F:   8180        LDD       R24,Z+0        Load indirect with displacement
+00000140:   338A        CPI       R24,0x3A       Compare with immediate
+00000141:   F449        BRNE      PC+0x0A        Branch if not equal
539:                      M1++;
+00000142:   81ED        LDD       R30,Y+5        Load indirect with displacement
+00000143:   81FE        LDD       R31,Y+6        Load indirect with displacement
+00000144:   8180        LDD       R24,Z+0        Load indirect with displacement
+00000145:   5F8F        SUBI      R24,0xFF       Subtract immediate
+00000146:   8380        STD       Z+0,R24        Store indirect with displacement
540:                      M2 = '0';
+00000147:   E380        LDI       R24,0x30       Load immediate
+00000148:   E6E4        LDI       R30,0x64       Load immediate
+00000149:   E0F0        LDI       R31,0x00       Load immediate
+0000014A:   8380        STD       Z+0,R24        Store indirect with displacement
543:                  if(M1 == '6')
+0000014B:   E6E3        LDI       R30,0x63       Load immediate
+0000014C:   E0F0        LDI       R31,0x00       Load immediate
+0000014D:   8180        LDD       R24,Z+0        Load indirect with displacement
+0000014E:   3386        CPI       R24,0x36       Compare with immediate
+0000014F:   F449        BRNE      PC+0x0A        Branch if not equal
545:                      H2++;
+00000150:   81EB        LDD       R30,Y+3        Load indirect with displacement
+00000151:   81FC        LDD       R31,Y+4        Load indirect with displacement
+00000152:   8180        LDD       R24,Z+0        Load indirect with displacement
+00000153:   5F8F        SUBI      R24,0xFF       Subtract immediate
+00000154:   8380        STD       Z+0,R24        Store indirect with displacement
546:                      M1 = '0';
+00000155:   E380        LDI       R24,0x30       Load immediate
+00000156:   E6E3        LDI       R30,0x63       Load immediate
+00000157:   E0F0        LDI       R31,0x00       Load immediate
+00000158:   8380        STD       Z+0,R24        Store indirect with displacement
549:                  if(H2 == ':')
+00000159:   E6E1        LDI       R30,0x61       Load immediate
+0000015A:   E0F0        LDI       R31,0x00       Load immediate
+0000015B:   8180        LDD       R24,Z+0        Load indirect with displacement
+0000015C:   338A        CPI       R24,0x3A       Compare with immediate
+0000015D:   F449        BRNE      PC+0x0A        Branch if not equal
551:                      H1++;
+0000015E:   81E9        LDD       R30,Y+1        Load indirect with displacement
+0000015F:   81FA        LDD       R31,Y+2        Load indirect with displacement
+00000160:   8180        LDD       R24,Z+0        Load indirect with displacement
+00000161:   5F8F        SUBI      R24,0xFF       Subtract immediate
+00000162:   8380        STD       Z+0,R24        Store indirect with displacement
552:                      H2 = '0';
+00000163:   E380        LDI       R24,0x30       Load immediate
+00000164:   E6E1        LDI       R30,0x61       Load immediate
+00000165:   E0F0        LDI       R31,0x00       Load immediate
+00000166:   8380        STD       Z+0,R24        Store indirect with displacement
556:              OS_Delay(1);
+00000167:   E081        LDI       R24,0x01       Load immediate
+00000168:   E090        LDI       R25,0x00       Load immediate
+00000169:   D2F1        RCALL     PC+0x02F2      Relative call subroutine
+0000016A:   D280        RCALL     PC+0x0281      Relative call subroutine
+0000016B:   CFAF        RJMP      PC-0x0050      Relative jump

This code writes S2,S1, correctly but doesn't work for M2

Alex

"For every effect there is a root cause. Find and address the root cause rather than try to fix the effect, as there is no end to the latter."
Author Unknown

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

Would you show the s output with -save-temps -dp -fverbose-asm and point to the wrong code?

avrfreaks does not support Opera. Profile inactive.

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

Sure but I'm not sure where to add these flags and where to get the s file.

I currently have in the default folder
gcc_m8_osa_charger.eep
gcc_m8_osa_charger.elf
gcc_m8_osa_charger.hex
gcc_m8_osa_charger.lss
gcc_m8_osa_charger.map
gcc_m8_osa_charger.o
lcd595.o
Makefile
osa.o

This is the make file of the AVRstudio project, how should I modify it?

###############################################################################
# Makefile for the project gcc_m8_osa_charger
###############################################################################

## General Flags
PROJECT = gcc_m8_osa_charger
MCU = atmega8
TARGET = gcc_m8_osa_charger.elf
CC = avr-gcc

CPP = avr-g++

## Options common to compile, link and assembly rules
COMMON = -mmcu=$(MCU)

## Compile options common for all C compilation units.
CFLAGS = $(COMMON)
CFLAGS += -Wall -gdwarf-2 -std=gnu99                      -DF_CPU=8000000UL -Os -funsigned-char -funsigned-bitfields -fpack-struct -fshort-enums
CFLAGS += -MD -MP -MT $(*F).o -MF dep/$(@F).d 

## Assembly specific flags
ASMFLAGS = $(COMMON)
ASMFLAGS += $(CFLAGS)
ASMFLAGS += -x assembler-with-cpp -Wa,-gdwarf2

## Linker flags
LDFLAGS = $(COMMON)
LDFLAGS +=  -Wl,-Map=gcc_m8_osa_charger.map


## Intel Hex file production flags
HEX_FLASH_FLAGS = -R .eeprom -R .fuse -R .lock -R .signature

HEX_EEPROM_FLAGS = -j .eeprom
HEX_EEPROM_FLAGS += --set-section-flags=.eeprom="alloc,load"
HEX_EEPROM_FLAGS += --change-section-lma .eeprom=0 --no-change-warnings


## Include Directories
INCLUDES = -I"C:\projects\Copy of gcc_m8_osa_charger\." -I"C:\projects\Copy of gcc_m8_osa_charger\..\..\osa" 

## Objects that must be built in order to link
OBJECTS = gcc_m8_osa_charger.o osa.o lcd595.o 

## Objects explicitly added by the user
LINKONLYOBJECTS = 

## Build
all: $(TARGET) gcc_m8_osa_charger.hex gcc_m8_osa_charger.eep gcc_m8_osa_charger.lss size

## Compile
gcc_m8_osa_charger.o: ../gcc_m8_osa_charger.c
	$(CC) $(INCLUDES) $(CFLAGS) -c  $<

osa.o: ../../../osa/osa.c
	$(CC) $(INCLUDES) $(CFLAGS) -c  $<

lcd595.o: ../lcd595.c
	$(CC) $(INCLUDES) $(CFLAGS) -c  $<

##Link
$(TARGET): $(OBJECTS)
	 $(CC) $(LDFLAGS) $(OBJECTS) $(LINKONLYOBJECTS) $(LIBDIRS) $(LIBS) -o $(TARGET)

%.hex: $(TARGET)
	avr-objcopy -O ihex $(HEX_FLASH_FLAGS)  $< $@

%.eep: $(TARGET)
	-avr-objcopy $(HEX_EEPROM_FLAGS) -O ihex $< $@ || exit 0

%.lss: $(TARGET)
	avr-objdump -h -S $< > $@

size: ${TARGET}
	@echo
	@avr-size -C --mcu=${MCU} ${TARGET}

## Clean target
.PHONY: clean
clean:
	-rm -rf $(OBJECTS) gcc_m8_osa_charger.elf dep/* gcc_m8_osa_charger.hex gcc_m8_osa_charger.eep gcc_m8_osa_charger.lss gcc_m8_osa_charger.map


## Other dependencies
-include $(shell mkdir dep 2>NUL) $(wildcard dep/*)


Alex

"For every effect there is a root cause. Find and address the root cause rather than try to fix the effect, as there is no end to the latter."
Author Unknown

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

Surely this is just the classic FAQ#1 volatile issue? If you don't want something cached into a temporary register so that updates of the RAM based item in another thread/interrupt context are missed then you make it "volatile". Or are you saying it's something more than this?

BTW twice on the linked page it says:

Quote:
Note: OSA version 100531 mechanism found a workaround

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

volatile doesn't solve it, only shutting down the optimization solves it.

What I post here is using

volatile char line1[16] = "00:00:00 I=0.50A";

I think the s file you have asked is the attached one.
The task "Clock" I refer to starts at line 423

Clock:
.LFB13:
.LM69:
	push r29	 ; 	 ;  155	*pushhi/1	[length = 2]
	push r28	 ; 
	in r28,__SP_L__	 ; 	 ;  159	*movhi_sp/2	[length = 2]
	in r29,__SP_H__	 ; 
	sbiw r28,8	 ; ,	 ;  160	*addhi3/3	[length = 1]
	in __tmp_reg__,__SREG__	 ;  161	*movhi_sp/1	[length = 5]
	cli
	out __SP_H__,r29	 ; 
	out __SREG__,__tmp_reg__
	out __SP_L__,r28	 ; 
/* prologue: function */
/* frame size = 8 */
.LM70:
	ldi r24,lo8(line1+7)	 ; ,	 ;  127	*movhi/4	[length = 2]
	ldi r25,hi8(line1+7)	 ; ,
	sbiw r24,7	 ; ,	 ;  82	*addhi3/3	[length = 1]
	std Y+2,r25	 ; ,	 ;  128	*movhi/3	[length = 2]
	std Y+1,r24	 ; ,
.LM71:
	ldi r30,lo8(line1+7)	 ; ,	 ;  129	*movhi/4	[length = 2]
	ldi r31,hi8(line1+7)	 ; ,
	sbiw r30,6	 ; ,	 ;  67	*addhi3/3	[length = 1]
	std Y+4,r31	 ; ,	 ;  130	*movhi/3	[length = 2]
	std Y+3,r30	 ; ,
.LM72:
	ldi r24,lo8(line1+7)	 ; ,	 ;  131	*movhi/4	[length = 2]
	ldi r25,hi8(line1+7)	 ; ,
	sbiw r24,4	 ; ,	 ;  52	*addhi3/3	[length = 1]
	std Y+6,r25	 ; ,	 ;  132	*movhi/3	[length = 2]
	std Y+5,r24	 ; ,
.LM73:
	ldi r30,lo8(line1+7)	 ; ,	 ;  133	*movhi/4	[length = 2]
	ldi r31,hi8(line1+7)	 ; ,
	sbiw r30,3	 ; ,	 ;  37	*addhi3/3	[length = 1]
	std Y+8,r31	 ; ,	 ;  134	*movhi/3	[length = 2]
	std Y+7,r30	 ; ,
.L32:
.LM74:
	lds r24,flag1	 ;  flag1, flag1	 ;  6	*movqi/4	[length = 2]
	sbrs r24,3	 ;  flag1,	 ;  10	*sbrx_branch	[length = 2]
	rjmp .L27	 ; 
.LM75:
	ldi r30,lo8(line1+7)	 ; ,	 ;  135	*movhi/4	[length = 2]
	ldi r31,hi8(line1+7)	 ; ,
	ld r24,Z	 ;  D.1598, line1	 ;  13	*movqi/4	[length = 1]
	subi r24,lo8(-(1))	 ;  D.1598,	 ;  14	addqi3/2	[length = 1]
	st Z,r24	 ;  line1, D.1598	 ;  16	*movqi/3	[length = 1]
.LM76:
	ld r24,Z	 ;  D.1600, line1	 ;  18	*movqi/4	[length = 1]
	cpi r24,lo8(58)	 ;  D.1600,	 ;  19	cmpqi/2	[length = 1]
	brne .L28	 ; ,	 ;  20	branch	[length = 1]
.LM77:
	ldi r30,lo8(line1+6)	 ; ,	 ;  136	*movhi/4	[length = 2]
	ldi r31,hi8(line1+6)	 ; ,
	ld r24,Z	 ;  D.1601, line1	 ;  23	*movqi/4	[length = 1]
	subi r24,lo8(-(1))	 ;  D.1601,	 ;  24	addqi3/2	[length = 1]
	st Z,r24	 ;  line1, D.1601	 ;  26	*movqi/3	[length = 1]
.LM78:
	ldi r24,lo8(48)	 ; ,	 ;  138	*movqi/2	[length = 1]
	ldi r30,lo8(line1+7)	 ; ,	 ;  137	*movhi/4	[length = 2]
	ldi r31,hi8(line1+7)	 ; ,
	st Z,r24	 ;  line1,	 ;  29	*movqi/3	[length = 1]
.L28:
.LM79:
	ldi r30,lo8(line1+6)	 ; ,	 ;  139	*movhi/4	[length = 2]
	ldi r31,hi8(line1+6)	 ; ,
	ld r24,Z	 ;  D.1603, line1	 ;  33	*movqi/4	[length = 1]
	cpi r24,lo8(54)	 ;  D.1603,	 ;  34	cmpqi/2	[length = 1]
	brne .L29	 ; ,	 ;  35	branch	[length = 1]
.LM80:
	ldd r30,Y+7	 ; ,	 ;  140	*movhi/2	[length = 2]
	ldd r31,Y+8	 ; ,
	ld r24,Z	 ;  D.1604, line1	 ;  38	*movqi/4	[length = 1]
	subi r24,lo8(-(1))	 ;  D.1604,	 ;  39	addqi3/2	[length = 1]
	st Z,r24	 ;  line1, D.1604	 ;  41	*movqi/3	[length = 1]
.LM81:
	ldi r24,lo8(48)	 ; ,	 ;  142	*movqi/2	[length = 1]
	ldi r30,lo8(line1+6)	 ; ,	 ;  141	*movhi/4	[length = 2]
	ldi r31,hi8(line1+6)	 ; ,
	st Z,r24	 ;  line1,	 ;  44	*movqi/3	[length = 1]
.L29:
.LM82:
	ldi r30,lo8(line1+4)	 ; ,	 ;  143	*movhi/4	[length = 2]
	ldi r31,hi8(line1+4)	 ; ,
	ld r24,Z	 ;  D.1606, line1	 ;  48	*movqi/4	[length = 1]
	cpi r24,lo8(58)	 ;  D.1606,	 ;  49	cmpqi/2	[length = 1]
	brne .L30	 ; ,	 ;  50	branch	[length = 1]
.LM83:
	ldd r30,Y+5	 ; ,	 ;  144	*movhi/2	[length = 2]
	ldd r31,Y+6	 ; ,
	ld r24,Z	 ;  D.1607, line1	 ;  53	*movqi/4	[length = 1]
	subi r24,lo8(-(1))	 ;  D.1607,	 ;  54	addqi3/2	[length = 1]
	st Z,r24	 ;  line1, D.1607	 ;  56	*movqi/3	[length = 1]
.LM84:
	ldi r24,lo8(48)	 ; ,	 ;  146	*movqi/2	[length = 1]
	ldi r30,lo8(line1+4)	 ; ,	 ;  145	*movhi/4	[length = 2]
	ldi r31,hi8(line1+4)	 ; ,
	st Z,r24	 ;  line1,	 ;  59	*movqi/3	[length = 1]
.L30:
.LM85:
	ldi r30,lo8(line1+3)	 ; ,	 ;  147	*movhi/4	[length = 2]
	ldi r31,hi8(line1+3)	 ; ,
	ld r24,Z	 ;  D.1609, line1	 ;  63	*movqi/4	[length = 1]
	cpi r24,lo8(54)	 ;  D.1609,	 ;  64	cmpqi/2	[length = 1]
	brne .L31	 ; ,	 ;  65	branch	[length = 1]
.LM86:
	ldd r30,Y+3	 ; ,	 ;  148	*movhi/2	[length = 2]
	ldd r31,Y+4	 ; ,
	ld r24,Z	 ;  D.1610, line1	 ;  68	*movqi/4	[length = 1]
	subi r24,lo8(-(1))	 ;  D.1610,	 ;  69	addqi3/2	[length = 1]
	st Z,r24	 ;  line1, D.1610	 ;  71	*movqi/3	[length = 1]
.LM87:
	ldi r24,lo8(48)	 ; ,	 ;  150	*movqi/2	[length = 1]
	ldi r30,lo8(line1+3)	 ; ,	 ;  149	*movhi/4	[length = 2]
	ldi r31,hi8(line1+3)	 ; ,
	st Z,r24	 ;  line1,	 ;  74	*movqi/3	[length = 1]
.L31:
.LM88:
	ldi r30,lo8(line1+1)	 ; ,	 ;  151	*movhi/4	[length = 2]
	ldi r31,hi8(line1+1)	 ; ,
	ld r24,Z	 ;  D.1612, line1	 ;  78	*movqi/4	[length = 1]
	cpi r24,lo8(58)	 ;  D.1612,	 ;  79	cmpqi/2	[length = 1]
	brne .L27	 ; ,	 ;  80	branch	[length = 1]
.LM89:
	ldd r30,Y+1	 ; ,	 ;  152	*movhi/2	[length = 2]
	ldd r31,Y+2	 ; ,
	ld r24,Z	 ;  D.1613, line1	 ;  83	*movqi/4	[length = 1]
	subi r24,lo8(-(1))	 ;  D.1613,	 ;  84	addqi3/2	[length = 1]
	st Z,r24	 ;  line1, D.1613	 ;  86	*movqi/3	[length = 1]
.LM90:
	ldi r24,lo8(48)	 ; ,	 ;  154	*movqi/2	[length = 1]
	ldi r30,lo8(line1+1)	 ; ,	 ;  153	*movhi/4	[length = 2]
	ldi r31,hi8(line1+1)	 ; ,
	st Z,r24	 ;  line1,	 ;  89	*movqi/3	[length = 1]
.L27:
.LM91:
	ldi r24,lo8(1)	 ; ,	 ;  93	*movhi/4	[length = 2]
	ldi r25,hi8(1)	 ; ,
	rcall _OS_InitDelay	 ; 	 ;  94	call_insn/3	[length = 1]
	rcall _OS_ReturnSave	 ; 	 ;  96	call_insn/3	[length = 1]
	rjmp .L32	 ; 	 ;  163	jump	[length = 1]
.LFE13:
	.size	Clock, .-Clock
.global	PWM
	.type	PWM, @function

There is no local variable and there should be no stack frame for temporary variables.

Alex

Attachment(s): 

"For every effect there is a root cause. Find and address the root cause rather than try to fix the effect, as there is no end to the latter."
Author Unknown

Last Edited: Fri. Nov 23, 2012 - 09:52 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

clawson wrote:

BTW twice on the linked page it says:
Quote:
Note: OSA version 100531 mechanism found a workaround

Yes I know, I'm using the latest version.
There is another article (trying to find the link) where the author states that the problem hasn't been solved so he reverted all the changes back.

I'll post it as soon as I find it

Alex

"For every effect there is a root cause. Find and address the root cause rather than try to fix the effect, as there is no end to the latter."
Author Unknown

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

Found it in this page http://translate.google.com/tran...

In the messages below the article, dated June 13, 2012

Quote:

Good day!

I am the author of OSA, the optimization problem acknowledged.

Just a week ago, got a similar question on the mail with the attached example. I am on this issue has come across before, but then it decided, as it turned out, not completely. Unfortunately, this problem is related to incorrect work optimizer WinAVR in version 20081205, and avoid it by means of OSA is extremely difficult. Here I described it with an example without OSA: www.pic24.ru/doku.php/osa/articl...

At one time, the solution was found (the part of the stack, which could spoil, preserved together with the context of the problem), but for a week sent to me poking around with the code and see that the problem is much deeper. To work around this now finished writing a bunch of assembly code to control the stack, but the decision, in my opinion, is too complicated: first, bulky, and secondly, significantly reduces the rate of work, and thirdly, it's like a crutch. Therefore most likely have to revert to an older version of OSA, no maintenance optimization.

Sincerely, Victor.

Alex

"For every effect there is a root cause. Find and address the root cause rather than try to fix the effect, as there is no end to the latter."
Author Unknown

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

But as I read it its not exactly a problem for anyone programming C. He is writing an OS and is complaining about the inner workings of the code generation model and how it doesn't fit with what he's trying to achieve. True it is sad, but the compiler is completely at liberty to implement code as it sees fit (and possibly change behaviour in each new iteration of the compiler) as long as the behaviour of the generated code matches the intent of the C programmer.

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

Yes but we are coming to my original question, if there is a flag to prevent the compiler to do that instead of having to turn off the optimization completely then the problem would be solved.
The question is if there is such a flag.

Alex

"For every effect there is a root cause. Find and address the root cause rather than try to fix the effect, as there is no end to the latter."
Author Unknown

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

alexan_e wrote:
Yes but we are coming to my original question, if there is a flag to prevent the compiler to do that instead of having to turn off the optimization
I still do not understand what is that the compiler does that you do no like? Allocates a frame? Your Clock calls lots of OS stuff, some of which probably gets inlined or defined as macros. Shows us the full code. Or try to come up with a example that does not make any OS calls.

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

And that "flag" is the word "volatile". It means "do not optimize access to this thing".

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

alexan_e wrote:
I think the s file you have asked is the attached one.

The task "Clock" I refer to starts at line 423


There are no line (number)s ;-)

What insn is it? In "; 20 branch" for example is insn 20.

Quote:
There is no local variable and there should be no stack frame for temporary variables.

There is no quarantee for that from the C side.

And it is not possible to reproduce the issue because there is no piece of C code that can be compiled.

Presumably, loop invariants are factored out of the loop raising register pressure so high that a stack frame in needed to hold the temorary values.

Does -fno-tree-loop optimize and / or -fno-move-loop-invariants help?

avrfreaks does not support Opera. Profile inactive.

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

ezharkov wrote:
alexan_e wrote:
Yes but we are coming to my original question, if there is a flag to prevent the compiler to do that instead of having to turn off the optimization
I still do not understand what is that the compiler does that you do no like? Allocates a frame? Your Clock calls lots of OS stuff, some of which probably gets inlined or defined as macros. Shows us the full code. Or try to come up with a example that does not make any OS calls.

In the link I have included in the first post the author of the OS has an example that doesn't use his OS files and demonstrated the problem.

Here is the link again:
http://translate.google.com/tran...

This is his code:

# Include 
# Include 
# Include 

// ************************************************ ******************************
// Variables
// ************************************************ ******************************

char Hello [6] // Buffer to store the word "HELLO"
char World [6] // Buffer to store the word "WORLD"


jmp_buf j_task1, j_task2; // task context


// ************************************************ ******************************
// Function Prototypes
// ************************************************ ******************************

void task1 (void);
void task2 (void);
void strcpy_hello (char * data) __ attribute__ ((noinline));
void strcpy_world (char * data) __ attribute__ ((noinline));

// ************************************************ ******************************
// Functions
// ************************************************ ******************************


void main (void)
{
    task1 (); // Initialize the task
    task2 ();

    longjmp (j_task1, 1) // Start queued execution,
                            // From problem Taks1
}

// ------------------------------------------------ ------------------------------

void strcpy_hello (char * str) // copy a word "HELLO" in str
{
    str [0] = 'H';
    str [1] = 'E';
    str [2] = 'L';
    str [3] = 'L';
    str [4] = 'O';
    str [5] = 0;
}

// ------------------------------------------------ ------------------------------

void strcpy_world (char * str) // copy a word "WORLD" in str
{
    str [0] = 'W';
    str [1] = 'O';
    str [2] = 'R';
    str [3] = 'L';
    str [4] = 'D';
    str [5] = 0;
}

// ------------------------------------------------ ------------------------------

void task1 (void) // TASK 1
{
    if (! setjmp (j_task1)) return; // Initialize the context

    for (; ;)
    {
        Hello [1] ^ = Hello [0] // Address to the two elements of the array
                                                    // Read and write
        if (! setjmp (j_task1)) longjmp (j_task2, 1) // Context Switching
        strcpy_hello (Hello); // Copy the constant "HELLO" to the array
    }
}

// ------------------------------------------------ ------------------------------

void task2 (void) // TASK 2
{
    if (! setjmp (j_task2)) return; // Initialize the context

    for (; ;)
    {
        World [1] ^ = World [0] // Address to the two elements of the array
                                                    // Read and write
        if (! setjmp (j_task2)) longjmp (j_task1, 1) // Context Switching
        strcpy_world (World); // Copy the constant "WORLD" to the array
    }
} 

And the ASM of it

000000c2 :
}

/ / ------------------------------------------------ ------------------------------

void task1 (void) / / TASK 1
{
  c2: df 93 push r29
  c4: cf 93 push r28
  c6: 00 d0 rcall. +0
  c8: cd b7 in r28, SPL
  ca: de b7 in r29, SPH

  cc: 80 e6 ldi r24, 0x60; if (! setjmp (j_task1)) return;
  ce: 90 e0 ldi r25, 0x00
  d0: 28 d0 rcall setjmp
  d2: 89 2b or r24, r25
  d4: 29 f4 brne. +10

  d6: 0f 90 pop r0
  d8: 0f 90 pop r0
  da: cf 91 pop r28
  dc: df 91 pop r29
  de: 08 95 ret

                                                ; For (; ;)
                                                , {
  e0: 8d e7 ldi r24, 0x7D; Note: 0x7D - variable address Hello
  e2: 90 e0 ldi r25, 0x00;
  e4: 89 83 std Y +1, r24;
  e6: 9a 83 std Y +2, r25;
  e8: 03 c0 rjmp. +6;

  ea: 89 81 ldd r24, Y +1; strcpy_hello (Hello);
  ec: 9a 81 ldd r25, Y +2;
  ee: a5 df rcall strcpy_hello;

  f0: ed e7 ldi r30, 0x7D; Hello [1] ^ = Hello [0];
  f2: f0 e0 ldi r31, 0x00;
  f4: 80 81 ld r24, Z
  f6: ee e7 ldi r30, 0x7E;
  f8: f0 e0 ldi r31, 0x00;
  fa: 90 81 ld r25, Z
  fc: 89 27 eor r24, r25
  fe: 80 83 st Z, r24


 100: 80 e6 ldi r24, 0x60; if (! Setjmp (j_task1))
 102: 90 e0 ldi r25, 0x00;
 104: 0e d0 rcall setjmp;
 106: 89 2b or r24, r25
 108: 81 f7 brne 0xEA

 10a: 83 e8 ldi r24, 0x83; longjmp (j_task2, 1);
 10c: 90 e0 ldi r25, 0x00;
 10e: 61 e0 ldi r22, 0x01;
 110: 70 e0 ldi r23, 0x00;
 112: 28 d0 rcall longjmp; 

This is a part of his explanation (translated from Russian using Google )

Quote:
In the address 0xC2 .. 0xCA selection is a 2-byte frames in the stack. Next, in the address 0xCC .. 0xDE is shaping context. We are also interested in the work programs to the 0xE0 .. 0x112, ie work cycle.

Immediately turn our attention to the code 0xE0 .. 0xE6, in which the row address Hello copied to a temporary local variable [Y +1]: [Y +2] (again see the code and make sure that we do not create a local variable). Next (address 0xE8), you switch to the operation Hello [1] ^ = Hello [0] (address 0xF0 .. 0xFE), then get on the preservation of context setjmp () (0x100. .0 x104) and transferring control task task2 () through longjmp () (0x10A. .0 x112).

When transferring control restores the context of the function task2, including the frame pointer r28: r29 (ie, Y). Because functions are identical, and the frame for them to be the same size (2 bytes) and is located at the same address. Function task2 () performs exactly the same steps as task1 (), and most importantly - makes up the address of a variable to a temporary variable World [Y +1]: [Y +2], erasing the value written back function task1 () . When he reached the same way as the task1 (), before calling longjmp (), the function task2 () transfers control task1 () through the saved context j_task1.

Then the problems start. Program counter is restored and points following the call setjmp () command, ie to address 0x89. Then jumps to address 0xEA (after going longjmp () r25! = R24), where he is call to copy a string strcpy_hello (). Please note that as a parameter passed to it is not the actual address of the variable Hello, and the value memorized in a temporary variable [Y +1]: [Y +2], ie that which was frayed function task2 (), and now these addresses stored address not a variable Hello, and a variable World. strcpy_hello Therefore, the function will write the word "HELLO" in a variable World, and not Hello.

Alex

"For every effect there is a root cause. Find and address the root cause rather than try to fix the effect, as there is no end to the latter."
Author Unknown

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

SprinterSB wrote:
alexan_e wrote:
I think the s file you have asked is the attached one.

The task "Clock" I refer to starts at line 423


There are no line (number)s ;-)

I have opened the s file with an editor that showed numbers so I thought to give you a reference.
Actually I had attached the complete .s file but it's not there (no idea what happened) so I'll have to upload again.
The code that exist in that post as code is just the task I refer too that creates the problem while writing the global array.

I'll upload the .s file as soon as I can since I'm not home right now.

SprinterSB wrote:

What insn is it? In "; 20 branch" for example is insn 20.

I'll check and get back to you

SprinterSB wrote:

Does -fno-tree-loop optimize and / or -fno-move-loop-invariants help?

I'll check that too.

Alex

"For every effect there is a root cause. Find and address the root cause rather than try to fix the effect, as there is no end to the latter."
Author Unknown

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

Well, I do not know. Everything looks very suspicious. They call task1, do setjmp inside, return from task1, then longjmp back to it? Is this even legal? I do not see how anything can possibly be guaranteed in this case.

EDIT: If one still wants to push one's luck, why not at least define the tasks as very simple functions, not doing anything but calling another noinline function to do the work? I.e., something like:

void __attribute__ ((noinline)) task1_body(void) {
  strcpy_hello(Hello);
}

void task1(void) {
  if (! setjmp(j_task1)) return;
  for (; ;) {
    task1_body();
    if (! setjmp(j_task1)) longjmp(j_task2, 1);
  }
}
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I have no idea about the author knowledge and I don't know many things about assembly either , all I know is that from what he says there is no such problem with IAR or codevision for AVR.

I just find the OS convenient to use and try to find some kind of solution.
One solution I tried is to use a global pointer to access the array in the task and that seems to work fine, at least in this case but maybe not in other cases.
It would be better is the cause of the problem could be somehow solved instead of similar fixes.

Alex

"For every effect there is a root cause. Find and address the root cause rather than try to fix the effect, as there is no end to the latter."
Author Unknown

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

Basis for a solution would be to file a gcc bug report.

avrfreaks does not support Opera. Profile inactive.

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

So is this considered a bug?
I don't have much knowledge with the low level stuff so I'm not sure I could describe the problem property.

Alex

"For every effect there is a root cause. Find and address the root cause rather than try to fix the effect, as there is no end to the latter."
Author Unknown

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

If "solving the cause of the problem" means that the compiler sources must be changed, then yes.

The GCC page explains what information in needed to reproduce a problem. You find a detailed description on how to retrieve that information:

http://gcc.gnu.org/bugs/#report

avrfreaks does not support Opera. Profile inactive.

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

I have attached the missing s file in the previous post for completeness https://www.avrfreaks.net/index.p...

SprinterSB wrote:

Does -fno-tree-loop and / or -fno-move-loop-invariants help?

When I try -fno-tree-loop-optimize the problem remains.

The second option you have provided -fno-move-loop-invariants actually solves the problem (used alone or in conjunction with -fno-tree-loop-optimize).
I have tried it in the project I refer to in this thread (first post) and in the sample project I have attached in https://www.avrfreaks.net/index.p...

In the first post of this thread I have included the resulting ASM for the task that created the problem.
Using -fno-move-loop-invariants the resulting ASM code for the task (that no longer has a problem) becomes

@00000102: Clock
521:              if(OS_Flag_Check_On(flag1, CHANNEL1_ON_FLAG))
+00000102:   918000A2    LDS       R24,0x00A2     Load direct from data space
+00000104:   FF83        SBRS      R24,3          Skip if bit in register set
+00000105:   C043        RJMP      PC+0x0044      Relative jump
523:                  S2++;
+00000106:   91800067    LDS       R24,0x0067     Load direct from data space
+00000108:   5F8F        SUBI      R24,0xFF       Subtract immediate
+00000109:   93800067    STS       0x0067,R24     Store direct to data space
525:                  if(S2 == ':')
+0000010B:   91800067    LDS       R24,0x0067     Load direct from data space
+0000010D:   338A        CPI       R24,0x3A       Compare with immediate
+0000010E:   F441        BRNE      PC+0x09        Branch if not equal
527:                      S1++;
+0000010F:   E6E7        LDI       R30,0x67       Load immediate
+00000110:   E0F0        LDI       R31,0x00       Load immediate
+00000111:   9182        LD        R24,-Z         Load indirect and predecrement
+00000112:   5F8F        SUBI      R24,0xFF       Subtract immediate
+00000113:   8380        STD       Z+0,R24        Store indirect with displacement
528:                      S2 = '0';
+00000114:   E380        LDI       R24,0x30       Load immediate
+00000115:   93800067    STS       0x0067,R24     Store direct to data space
531:                  if(S1 == '6')
+00000117:   91800066    LDS       R24,0x0066     Load direct from data space
+00000119:   3386        CPI       R24,0x36       Compare with immediate
+0000011A:   F449        BRNE      PC+0x0A        Branch if not equal
533:                      M2++;
+0000011B:   E6E6        LDI       R30,0x66       Load immediate
+0000011C:   E0F0        LDI       R31,0x00       Load immediate
+0000011D:   9732        SBIW      R30,0x02       Subtract immediate from word
+0000011E:   8180        LDD       R24,Z+0        Load indirect with displacement
+0000011F:   5F8F        SUBI      R24,0xFF       Subtract immediate
+00000120:   8380        STD       Z+0,R24        Store indirect with displacement
534:                      S1 = '0';
+00000121:   E380        LDI       R24,0x30       Load immediate
+00000122:   93800066    STS       0x0066,R24     Store direct to data space
537:                  if(M2 == ':')
+00000124:   91800064    LDS       R24,0x0064     Load direct from data space
+00000126:   338A        CPI       R24,0x3A       Compare with immediate
+00000127:   F441        BRNE      PC+0x09        Branch if not equal
539:                      M1++;
+00000128:   E6E4        LDI       R30,0x64       Load immediate
+00000129:   E0F0        LDI       R31,0x00       Load immediate
+0000012A:   9182        LD        R24,-Z         Load indirect and predecrement
+0000012B:   5F8F        SUBI      R24,0xFF       Subtract immediate
+0000012C:   8380        STD       Z+0,R24        Store indirect with displacement
540:                      M2 = '0';
+0000012D:   E380        LDI       R24,0x30       Load immediate
+0000012E:   93800064    STS       0x0064,R24     Store direct to data space
543:                  if(M1 == '6')
+00000130:   91800063    LDS       R24,0x0063     Load direct from data space
+00000132:   3386        CPI       R24,0x36       Compare with immediate
+00000133:   F449        BRNE      PC+0x0A        Branch if not equal
545:                      H2++;
+00000134:   E6E3        LDI       R30,0x63       Load immediate
+00000135:   E0F0        LDI       R31,0x00       Load immediate
+00000136:   9732        SBIW      R30,0x02       Subtract immediate from word
+00000137:   8180        LDD       R24,Z+0        Load indirect with displacement
+00000138:   5F8F        SUBI      R24,0xFF       Subtract immediate
+00000139:   8380        STD       Z+0,R24        Store indirect with displacement
546:                      M1 = '0';
+0000013A:   E380        LDI       R24,0x30       Load immediate
+0000013B:   93800063    STS       0x0063,R24     Store direct to data space
549:                  if(H2 == ':')
+0000013D:   91800061    LDS       R24,0x0061     Load direct from data space
+0000013F:   338A        CPI       R24,0x3A       Compare with immediate
+00000140:   F441        BRNE      PC+0x09        Branch if not equal
551:                      H1++;
+00000141:   E6E1        LDI       R30,0x61       Load immediate
+00000142:   E0F0        LDI       R31,0x00       Load immediate
+00000143:   9182        LD        R24,-Z         Load indirect and predecrement
+00000144:   5F8F        SUBI      R24,0xFF       Subtract immediate
+00000145:   8380        STD       Z+0,R24        Store indirect with displacement
552:                      H2 = '0';
+00000146:   E380        LDI       R24,0x30       Load immediate
+00000147:   93800061    STS       0x0061,R24     Store direct to data space
556:              OS_Delay(1);
+00000149:   E081        LDI       R24,0x01       Load immediate
+0000014A:   E090        LDI       R25,0x00       Load immediate
+0000014B:   D2BF        RCALL     PC+0x02C0      Relative call subroutine
+0000014C:   D24E        RCALL     PC+0x024F      Relative call subroutine
+0000014D:   CFB4        RJMP      PC-0x004B      Relative jump

This seems to solve the problem , at least in this case and maybe permanently, I guess time will tell.

What does this option do?
I didn't find it using google.

A huge thank you for your help.
Alex

"For every effect there is a root cause. Find and address the root cause rather than try to fix the effect, as there is no end to the latter."
Author Unknown

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

I have also tried the same compiler option to the example code provided by the author of the OS to describe the problem (the one above using setjmp/longjmp)

That works fine too!

Alex

"For every effect there is a root cause. Find and address the root cause rather than try to fix the effect, as there is no end to the latter."
Author Unknown

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

maybe your code is betraying and does weird things in the macros you don't show us?

If I compile the following code with the same compiler (WinAVR-20090313, MD5 = abe89850c430a90419070abaa31bf632 as indicated in your .s) then the code is completely reasonable.

#define H1 line1[0]
#define H2 line1[1]
#define M1 line1[3]
#define M2 line1[4]
#define S1 line1[6]
#define S2 line1[7]

char line1[16] = "00:00:00 I=0.50A";

extern char volatile v;
extern void foo (int);

void Clock (void)
{
    while(1)
    {
        if (v & (1 << 3))
        {
            S2++;

            if (S2 == ':')
            {
                S1++;
                S2 = '0';
            }

            if (S1 == '6')
            {
                M2++;
                S1 = '0';
            }

            if (M2 == ':')
            {
                M1++;
                M2 = '0';
            }

            if (M1 == '6')
            {
                H2++;
                M1 = '0';
            }

            if (H2 == ':')
            {
                H1++;
                H2 = '0';
            }
        }

        foo (1);
    }
}
	.file	"foo.c"
__SREG__ = 0x3f
__SP_H__ = 0x3e
__SP_L__ = 0x3d
__CCP__  = 0x34
__tmp_reg__ = 0
__zero_reg__ = 1
 ;  GNU C (WinAVR 20090313) version 4.3.2 (avr)
 ; 	compiled by GNU C version 3.4.5 (mingw-vista special r3), GMP version 4.2.3, MPFR version 2.4.0.
 ;  GGC heuristics: --param ggc-min-expand=47 --param ggc-min-heapsize=32702
 ;  options passed:  -fpreprocessed foo.i -mmcu=atmega8 -Os -Wall
 ;  -std=gnu99 -funsigned-char -funsigned-bitfields -fpack-struct
 ;  -fshort-enums -fverbose-asm
 ;  options enabled:  -falign-loops -fargument-alias -fauto-inc-dec
 ;  -fbranch-count-reg -fcaller-saves -fcommon -fcprop-registers
 ;  -fcrossjumping -fcse-follow-jumps -fdefer-pop -fearly-inlining
 ;  -feliminate-unused-debug-types -fexpensive-optimizations
 ;  -fforward-propagate -ffunction-cse -fgcse -fgcse-lm
 ;  -fguess-branch-probability -fident -fif-conversion -fif-conversion2
 ;  -finline-functions -finline-functions-called-once
 ;  -finline-small-functions -fipa-pure-const -fipa-reference -fivopts
 ;  -fkeep-static-consts -fleading-underscore -fmath-errno
 ;  -fmerge-constants -fmerge-debug-strings -fmove-loop-invariants
 ;  -fomit-frame-pointer -foptimize-register-move -foptimize-sibling-calls
 ;  -fpack-struct -fpeephole -fpeephole2 -freg-struct-return -fregmove
 ;  -freorder-functions -frerun-cse-after-loop -fsched-interblock
 ;  -fsched-spec -fsched-stalled-insns-dep -fsigned-zeros
 ;  -fsplit-ivs-in-unroller -fsplit-wide-types -fstrict-aliasing
 ;  -fstrict-overflow -fthread-jumps -ftoplevel-reorder -ftrapping-math
 ;  -ftree-ccp -ftree-copy-prop -ftree-copyrename -ftree-dce
 ;  -ftree-dominator-opts -ftree-dse -ftree-fre -ftree-loop-im
 ;  -ftree-loop-ivcanon -ftree-loop-optimize -ftree-parallelize-loops=
 ;  -ftree-reassoc -ftree-salias -ftree-scev-cprop -ftree-sink -ftree-sra
 ;  -ftree-store-ccp -ftree-ter -ftree-vect-loop-version -ftree-vrp
 ;  -funit-at-a-time -fverbose-asm -fzero-initialized-in-bss

 ;  Compiler executable checksum: abe89850c430a90419070abaa31bf632

	.text
.global	Clock
	.type	Clock, @function
Clock:
	push r17	 ; 	 ;  114	*pushqi/1	[length = 1]
/* prologue: function */
/* frame size = 0 */
	ldi r17,lo8(48)	 ;  tmp87,	 ;  86	*movqi/2	[length = 1]
.L7:
	lds r24,v	 ;  v.0, v	 ;  6	*movqi/4	[length = 2]
	sbrs r24,3	 ;  v.0,	 ;  10	*sbrx_branch	[length = 2]
	rjmp .L2	 ; 
	lds r24,line1+7	 ;  D.1190, line1	 ;  13	*movqi/4	[length = 2]
	subi r24,lo8(-(1))	 ;  D.1190,	 ;  14	addqi3/2	[length = 1]
	sts line1+7,r24	 ;  line1, D.1190	 ;  16	*movqi/3	[length = 2]
	cpi r24,lo8(58)	 ;  D.1190,	 ;  17	cmpqi/2	[length = 1]
	brne .L3	 ; ,	 ;  18	branch	[length = 1]
	lds r24,line1+6	 ;  line1, line1	 ;  22	*movqi/4	[length = 2]
	subi r24,lo8(-(1))	 ;  line1,	 ;  23	addqi3/2	[length = 1]
	sts line1+6,r24	 ;  line1, line1	 ;  24	*movqi/3	[length = 2]
	sts line1+7,r17	 ;  line1, tmp87	 ;  27	*movqi/3	[length = 2]
.L3:
	lds r24,line1+6	 ;  line1, line1	 ;  31	*movqi/4	[length = 2]
	cpi r24,lo8(54)	 ;  line1,	 ;  32	cmpqi/2	[length = 1]
	brne .L4	 ; ,	 ;  33	branch	[length = 1]
	lds r24,line1+4	 ;  line1, line1	 ;  37	*movqi/4	[length = 2]
	subi r24,lo8(-(1))	 ;  line1,	 ;  38	addqi3/2	[length = 1]
	sts line1+4,r24	 ;  line1, line1	 ;  39	*movqi/3	[length = 2]
	sts line1+6,r17	 ;  line1, tmp87	 ;  42	*movqi/3	[length = 2]
.L4:
	lds r24,line1+4	 ;  line1, line1	 ;  46	*movqi/4	[length = 2]
	cpi r24,lo8(58)	 ;  line1,	 ;  47	cmpqi/2	[length = 1]
	brne .L5	 ; ,	 ;  48	branch	[length = 1]
	lds r24,line1+3	 ;  line1, line1	 ;  52	*movqi/4	[length = 2]
	subi r24,lo8(-(1))	 ;  line1,	 ;  53	addqi3/2	[length = 1]
	sts line1+3,r24	 ;  line1, line1	 ;  54	*movqi/3	[length = 2]
	sts line1+4,r17	 ;  line1, tmp87	 ;  57	*movqi/3	[length = 2]
.L5:
	lds r24,line1+3	 ;  line1, line1	 ;  61	*movqi/4	[length = 2]
	cpi r24,lo8(54)	 ;  line1,	 ;  62	cmpqi/2	[length = 1]
	brne .L6	 ; ,	 ;  63	branch	[length = 1]
	lds r24,line1+1	 ;  line1, line1	 ;  67	*movqi/4	[length = 2]
	subi r24,lo8(-(1))	 ;  line1,	 ;  68	addqi3/2	[length = 1]
	sts line1+1,r24	 ;  line1, line1	 ;  69	*movqi/3	[length = 2]
	sts line1+3,r17	 ;  line1, tmp87	 ;  72	*movqi/3	[length = 2]
.L6:
	lds r24,line1+1	 ;  line1, line1	 ;  76	*movqi/4	[length = 2]
	cpi r24,lo8(58)	 ;  line1,	 ;  77	cmpqi/2	[length = 1]
	brne .L2	 ; ,	 ;  78	branch	[length = 1]
	lds r24,line1	 ;  line1, line1	 ;  82	*movqi/4	[length = 2]
	subi r24,lo8(-(1))	 ;  line1,	 ;  83	addqi3/2	[length = 1]
	sts line1,r24	 ;  line1, line1	 ;  84	*movqi/3	[length = 2]
	sts line1+1,r17	 ;  line1, tmp87	 ;  87	*movqi/3	[length = 2]
.L2:
	ldi r24,lo8(1)	 ; ,	 ;  91	*movhi/4	[length = 2]
	ldi r25,hi8(1)	 ; ,
	rcall foo	 ; 	 ;  92	call_insn/3	[length = 1]
	rjmp .L7	 ; 	 ;  116	jump	[length = 1]
	.size	Clock, .-Clock
.global	line1
	.data
	.type	line1, @object
	.size	line1, 16
line1:
	.ascii	"00:00:00 I=0.50A"
.global __do_copy_data

Compiling w/o debug info makes no difference w.r.t. to the code.

Thus, the weird stuff happend in the part you don't show.

avrfreaks does not support Opera. Profile inactive.

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

Remember we had a discussion about the main loop? https://www.avrfreaks.net/index.p...

Now let me ask you, "Do you consider it a good practice for a programmer to depend" on a feature of a compiler that involves undefined behavior?

And yes, I believe the whole approach in your RTOS does involve undefined behavior. For example, here is what we read in an often cited ISO C pdf document (n1256.pdf): "if the function containing the invocation of the setjmp macro has terminated execution in the interim" ... "the behavior is undefined".

Eugene

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

SprinterSB wrote:
maybe your code is betraying and does weird things in the macros you don't show us?

The shown task is just one of the tasks used in the application but this is the only one that write to the global array and the only one that causes an error so it was the one I posted.

If you want an example you can compile you can try the one I have provided https://www.avrfreaks.net/index.p...

It is just a smaller version of the code, you'll see that it increments the seconds correctly (array[0] and array[1]) but never increases the minutes unless you turn off the optimization or use the -fno-move-loop-invariants

ezharkov wrote:
And yes, I believe the whole approach in your RTOS does involve undefined behavior. For example, here is what we read in an often cited ISO C pdf document (n1256.pdf): "if the function containing the invocation of the setjmp macro has terminated execution in the interim" ... "the behavior is undefined".

I appreciate your point although I have no idea what exactly the actual OS code does or the exact mechanisms involved.

Alex

p.s. I hate CAPTCHA :twisted:

"For every effect there is a root cause. Find and address the root cause rather than try to fix the effect, as there is no end to the latter."
Author Unknown

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

I have checked a the generated code in my project, the parts that change tasks

556:              OS_Delay(1);  // delay one tick
+00000149:   E081        LDI       R24,0x01       Load immediate
+0000014A:   E090        LDI       R25,0x00       Load immediate
+0000014B:   D2BF        RCALL     PC+0x02C0      Relative call subroutine
+0000014C:   D24E        RCALL     PC+0x024F      Relative call subroutine
+0000014D:   CFB4        RJMP      PC-0x004B      Relative jump
 OS_Yield(); // pass control to next task
+0000026B:   D12F        RCALL     PC+0x0130      Relative call subroutine

I think there is no setjmp involved.

Alex

"For every effect there is a root cause. Find and address the root cause rather than try to fix the effect, as there is no end to the latter."
Author Unknown

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

Nobody knows.

We only see teh code /before/ the processor performs arbitrarily changes before the compiler proper sees it.

You have an i file, how looks the code there?

avrfreaks does not support Opera. Profile inactive.

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

What is an "i" file?

"For every effect there is a root cause. Find and address the root cause rather than try to fix the effect, as there is no end to the latter."
Author Unknown

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

It's what comes out of the pre-processor, so it's your .c file with all #include's and #defines expanded. You'll get both .i and .s files with --save-temps.

If you, for example, have this program

#include 

int main(void)
{
    DDRB = 0xFF;
    
    while(1)
    {
        PORTB++;
    }
}

the .i file contains a lot of stuff from the #include followed by this program, which is what the compiler actually sees

int main(void)
{
    (*(volatile uint8_t *)((0x04) + 0x20)) = 0xFF;

    while(1)
    {
        (*(volatile uint8_t *)((0x05) + 0x20))++;
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

snigelen wrote:
It's what comes out of the pre-processor, so it's your .c file with all #include's and #defines expanded. You'll get both .i and .s files with --save-temps.

Oh, OK thanks.
I have previously used -S to generate the .s file that SprinterSB asked but I had no idea about "i" file.
so using --save-temps (and not -fno-move-loop-invariants) I got two i files

These are from the project I referred to before attached
Edit I had the wrong link, here is the correct one https://www.avrfreaks.net/index.p...

It is a sample application with two tasks and a timer interrupt to increment the ticks that demonstrates the global array write problem. It includes the OS files.

Alex

Attachment(s): 

"For every effect there is a root cause. Find and address the root cause rather than try to fix the effect, as there is no end to the latter."
Author Unknown

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

The trigger is the returns_twice function attribute with _OS_ReturnSave.

_OS_ReturnSave will behave like setjmp or vfork. All registers will be dead at the time that function is called and must be saved on the stack for that reason, e.g. any loop invariant.

avrfreaks does not support Opera. Profile inactive.

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

alexan_e wrote:
I think there is no setjmp involved.
I think you are right (I got curious and downloaded the OS source). I assumed that it was because it was used in the "winavr_bug" example that you posted a link to.

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

The OS has been designed with that compromise, any local variable value is lost as soon as you exit the task (OS_Delay(x), OS_Yield(), OS_Wait() etc).
Any value that has to be preserved should either be a global variable or a static.
That is why solving the problem of writing global variables is important.

The OS functions and settings are not too complicated and exiting the task in predefined points where you use the above functions has its advantages (and disadvantages of course) since you know that your code execution will not be paused at a random point.

It's half way between a co-operative scheduler where each task has to run to completion and a pre-emptive OS.

Alex

"For every effect there is a root cause. Find and address the root cause rather than try to fix the effect, as there is no end to the latter."
Author Unknown

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

alexan_e wrote:
The OS has been designed with that compromise, any local variable value is lost as soon as you exit the task (OS_Delay(x), OS_Yield(), OS_Wait() etc).
In general you won't exit an task.

In your code, for example, there is an infinite loop and the tasks never exit.

If a task will be extit (destroyed) the OS will have special means for that.

Quote:
Any value that has to be preserved should either be a global variable or a static. That is why solving the problem of writing global variables is important.
If that limitation is actually true you cannot program in C, only in some not-specified subset of it.

The question is why _OS_ReturnSave is returns_twice in the first place.

If that function just schedules other tasks or treats events or whatever and properly restores the context, then there is no need for returns_twice. If the function clobbers registers that the ABI allows that is no issue.

If the function does not properly restore the context, then you run into problems sooner or later, of course.

Moreover, for how that function is used, it does not look like an exception landing pad, thus there is no need for returns_twice for that purpose.

And it really does not matter if the OS is cooperative or preemptive w.r.t. _OS_ReturnSave.

avrfreaks does not support Opera. Profile inactive.

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

SprinterSB wrote:
In general you won't exit an task.
In your code, for example, there is an infinite loop and the tasks never exit.

I have used a wrong expression.
By exit I meant any statement that pauses the task execution and passes control to another task.

The OS (OSA) requires each task to have an endless loop.

Quote:
Quote:
Any value that has to be preserved should either be a global variable or a static. That is why solving the problem of writing global variables is important.

If that limitation is actually true you cannot program in C, only in some not-specified subset of it.


?
I'm not sure why you say that.

What is wrong with a task like

void Clock(void)
{
    while(1)
    {
        for(uint8_t i = 0; i < 25; i++)
        {
            PORTB = i;
        }

        OS_Delay(10);
    }
}

Another option is the value needs to be preserved is

void Clock(void)
{ 
   static uint8_t i;

    while(1)
    {
        PORTB = i;
        i++;

        OS_Delay(10);
    }
}

The technical details you describe are a little over my neck so I can't really comment on them, I can only quote what the author wrote and hope it makes sense.

Quote:
Cooperative operating system and local variables

For parallel execution of multiple functions (tasks) operating system must have a mechanism that can interrupt the execution of the function in the middle, passing control to other functions to perform, and then return control back to the interrupted function so that it resumes from the same place, which was interrupted. Of course, the same mechanism should take care to preserve the context, ie in addition to the program counter must be saved / restored Other official registers (stack pointer, status register, a set of general purpose registers (GPR)) and local variables. On official registers and RON all clear: they set initially defined, and backup / restore easily do that. But with local variables is more complicated.

In preemptive OS under each task is allocated its own stack area which ensures the safety of all local variables and the entire call history for the current task. But in maloresursnyh controllers preemptive OS will not work due to lack of enough memory to store the context of the problem, for such controllers can use the OS with the cooperative scheduler. Unlike preemptive OS scheduler which can interrupt the task at any time, in a cooperative operating system task switching can occur only where the programmer specifies. For example:

void Task (void)
{
     char x, y;
     lcd_init (); / / initialize the LCD module
 
     OS_Yield (); / / transfer control to other tasks (in fact - Scheduler)
 
     x = lcd_getx (); / / output "Hello world" in the row under the cursor
     y = lcd_gety ();
     lcd_outtext (x, y + 1, "Hello world");
 
     OS_Yield (); / / transfer control
 
     ...
}

In this example, the task may lose control in only two places: in a system service call OS _Yield (). This definition allows us to minimize the amount of stored data when switching tasks. The volume of this data depends not only on the type of microcontroller (program counter, stack pointer, etc.), but also on a particular compiler. WinAVR example assumes that registers r2 .. r17 are saved by the function (if using it), and registers r18 .. r27, r30, r31 - used only for short-term operations (this implies that the return value of the function being called These registers will be lost.) At least it allows a context switch does not save these registers. In addition, WinAVR provides the ability to define some functions with the attribute __ returns_twice__, which frees us from the need to preserve and r2 .. r17. Ie any remaining scope will include: program counter and frame pointer (r28: r29).

There is a problem with local variables. There are two ways:

  • to apply the same approach, which is used in displacing the OS (ie to allocate to each task its own stack);
  • agree that the lifetime of a local variable is not limited to the body of the function, and the interval between the two switching tasks (in the example above - between the two OS _Yield ()).

The first option requires a relatively large amount of memory. Ie this volume, which already allow the use of pre-emptive operating system, which is far preferable to the cooperative, other things being equal. But the second option seems more appropriate. Ie We agreed that the variables x and y will lose their values ​​after each call OS _Yield () (that is, after each transfer of control to the scheduler), and if we need to display the current position after calling OS _Yield (), then we can no longer use the same values ​​of x and y, as they have already lost, and we will need to re-use functions lcd_getx () and lcd_gety (). Why are the x and y are lost? To this question was already answered: because maloresursnyh controllers must use a memory area for the local variables of all tasks, and after switching tasks the local variables of the current function simply zatrutsya values ​​of local variables of concurrent tasks.

What if you still need to keep the values ​​of variables and after a context switch? Very simple: declare a qualifier of static:

void Task (void)
 {
     static char x, y; / / Declare variables outside the stack

     lcd_init (); / / initialize the LCD module

     OS_Yield (); / / transfer control to other tasks (in fact - Scheduler)

     x = lcd_getx (); / / output "Hello world" in the row under the cursor
     y = lcd_gety ();
     lcd_outtext (x, y + 1, "Hello world");

     OS_Yield (); / / transfer control

     lcd_outtext (x, y + 2, "All animals are equal");
     ...
 } 

In this example, we are not afraid of losing x and y, as they have static IP addresses and the stack of other tasks they would not be able to grind.

Alex

"For every effect there is a root cause. Find and address the root cause rather than try to fix the effect, as there is no end to the latter."
Author Unknown

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

ezharkov wrote:
If one still wants to push one's luck, why not at least define the tasks as very simple functions, not doing anything but calling another noinline function to do the work?
Back to this. I see that the RTOS has OS_Delay and OS_Yield. Are these the only ways to switch to the next task (that you plan to use)? If that is the case, my suggesting above may still work. You could add some "wrapper" functions:
#define TaskWrapper(name)			\
void name##_wrapper(void) {			\
  while (1) {					\
    int retval = name();			\
    if (retval != 0) {				\
      OS_Delay(retval);				\
    }						\
    else {					\
      OS_Yield();				\
    }						\
  }						\
}
TaskWrapper(Task1)
TaskWrapper(Task2)

You would then use the wrappers in the create calls:

    OS_Task_Create(0, Task1_wrapper);
    OS_Task_Create(0, Task2_wrapper);

In your tasks themselves, you would add noinline, remove the loop, and instead of delay/yield return a value. Something like that:

int __attribute__ ((noinline)) Task1(void)
{
        myarray[0]++;   // increment seconds

        if(S1 == ':') // : is the next ASCII char after 9
        {
            S2++;   // increase sec decade
            S1 = '0';
        }

        if(S2 == '6')
        {
            M1++; // increase minutes, this is where the error
                  //  happens when the counter reaches "06:00:00"
            S2 = '0';
        }

        if(M1 == ':')
        {
            M2++; // increase minute decade
            M1 = '0';
        }

        if(M2 == '6')
        {
            H1++; // increase hour
            M2 = '0';
        }

        if(H1== ':')
        {
            H2++; // increase minute decade
            H1 = '0';
        }

	return 1; // delay for 1 tick (1ms for this example)
}

int __attribute__ ((noinline)) Task2(void)
{
  return 0; // Yield
}

Does this make sense?

Eugene

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

What is the benefit of using this wrapper and not the normal tasks?

Note that not all tasks are as the one I have provided, for example an LCD refresh task has several OS_Yield in the loop and a delay at the end.
Sure I can use flag variables instead and do multiple calls to a normal function that outputs different characters each time but this would be like using a scheduler that follows a different logic.

There are also task priorities involved (that may or not be used) that complicate things even further.

Alex

"For every effect there is a root cause. Find and address the root cause rather than try to fix the effect, as there is no end to the latter."
Author Unknown

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

alexan_e wrote:
What is the benefit of using this wrapper and not the normal tasks?
I thought the issue was a frame for "temporary" variables. Making the wrapper functions very simple should ensure that there is no frame allocated for them.
Quote:
Note that not all tasks are as the one I have provided, for example an LCD refresh task has several OS_Yield in the loop and a delay at the end.
That is fine. You will just replace the yields with "return 0" and the delay with "return whatever-the-delay-value-is".

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

Quote:
I thought the issue was a frame for "temporary" variables. Making the wrapper functions very simple should ensure that there is no frame allocated for them.

-fno-move-loop-invariants seems to fix the problem in the problematic examples I had so unless there is another case that creates the same problem I don't need to find workarounds.

Quote:
Note that not all tasks are as the one I have provided, for example an LCD refresh task has several OS_Yield in the loop and a delay at the end.
Quote:
That is fine. You will just replace the yields with "return 0" and the delay with "return whatever-the-delay-value-is".

I meant something like

void RefreshLCD(void)
{
    uint8_t i;

    while(1)
    {
        lcd_gotoxy(0, 0);

        for(i = 0; i < 8; i++)	//lcd_puts(line1, 8); // time
        {
            lcd_putchar(line1[i]);
        }

    OS_Yield();
        ULongToStr(i_target, &line1[11], 1, 4);
        lcd_gotoxy(11, 0);
        lcd_putchar(line1[11]);
        lcd_putchar('.');

        for(i = 12; i < 14; i++)
        {
            lcd_putchar(line1[i]);
        }
    
        lcd_gotoxy(0, 1);	// second line
        // show voltage
        ULongToStr(adc_bat1, line2, 1, 4);
	OS_Yield();
        lcd_putchar(line2[0]);
        lcd_putchar('.');

        for(i = 1; i < 4; i++)
        {
            lcd_putchar(line2[i]);
        }

        lcd_putchar('v');
        // show current
        lcd_gotoxy(7, 1);
        ULongToStr(adc_shunt1, &line2[5], 1, 4);
        lcd_putchar(line2[5]);
        lcd_putchar('.');
    OS_Yield();

        for(i = 6; i < 9; i++)
        {
            lcd_putchar(line2[i]);
        }

        lcd_putchar('A');
        ULongToStr(OCR1A, &line2[13], 1, 3);

        for(i = 13; i < 16; i++)	//lcd_puts(&line2[13], 3);
        {
            lcd_putchar(line2[i]);
        }

    OS_Delay(500);
    };
}

I can't replace these with return , the rest of the code would never execute.
I would have to use something like a switch/case and a flag to execute different parts in each call.

Alex

"For every effect there is a root cause. Find and address the root cause rather than try to fix the effect, as there is no end to the latter."
Author Unknown

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

alexan_e wrote:
I can't replace these with return , the rest of the code would never execute.
OK, I see.

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

Any ideas why -fno-move-loop-invariants fixes the problem?

For example

551:                      H1++;
+0000015E:   81E9        LDD       R30,Y+1        Load indirect with displacement
+0000015F:   81FA        LDD       R31,Y+2        Load indirect with displacement
+00000160:   8180        LDD       R24,Z+0        Load indirect with displacement
+00000161:   5F8F        SUBI      R24,0xFF       Subtract immediate
+00000162:   8380        STD       Z+0,R24        Store indirect with displacement 

becomes

551:                      H1++;
+00000141:   E6E1        LDI       R30,0x61       Load immediate
+00000142:   E0F0        LDI       R31,0x00       Load immediate
+00000143:   9182        LD        R24,-Z         Load indirect and predecrement
+00000144:   5F8F        SUBI      R24,0xFF       Subtract immediate
+00000145:   8380        STD       Z+0,R24        Store indirect with displacement 

How can this flag have this effect?
It is a "random" side effect of shunting down the move-loop-invariants optimization or I should expect this kind of behaviour in the future with different code accessing global variables?

Alex

"For every effect there is a root cause. Find and address the root cause rather than try to fix the effect, as there is no end to the latter."
Author Unknown

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

-f[no-]move-loop-invariants is just an optimization. If your code breaks with / without it, the code is wrong.

It's similar to the situation of a missed volatile and where the code works at -O0 but not at -Os. The problem is not -Os, the problem is the missing volatile.

avrfreaks does not support Opera. Profile inactive.

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

I'm under the impression that an RTOS can use compiler options to work properly.

For example I have checked FemtoOS, it provides a default AVRstudio script with the following options

Standard mode

-Wall -gdwarf-2 -Os -funsigned-char -fpack-struct -fshort-enums  -mint8  -Wl,--defsym=__stack=xOS+xOSstackShift  --param inline-call-cost=2  -ffunction-sections  -Wl,--gc-sections  -Wl,--relax  -Wno-main  -Winline  -Wundef  -DF_CPU=8000000UL -fomit-frame-pointer 
          
 -mint8  -Wl,--defsym=__stack=xOS+xOSstackShift  --param inline-call-cost=2  -ffunction-sections  -Wl,--gc-sections  -Wl,--relax  -Wno-main  -Winline  -Wundef  -fomit-frame-pointer 

Compact mode

-Wall -gdwarf-2 -Os -funsigned-char -fpack-struct -fshort-enums  -mint8  -Wl,--defsym=__stack=xOS+xOSstackShift  --param inline-call-cost=2  -ffunction-sections  -Wl,--gc-sections  -Wl,--relax  -Wno-main  -Winline  -Wundef  -fomit-frame-pointer -DF_CPU=8000000UL -DdefExtGCCstartup=cfgReplace  -DdefExtOptimized=cfgTrue  -DdefExtZeroPageStack=cfgTrue
          
 -mint8  -Wl,--defsym=__stack=xOS+xOSstackShift  --param inline-call-cost=2  -ffunction-sections  -Wl,--gc-sections  -Wl,--relax  -Wno-main  -Winline  -Wundef  -fomit-frame-pointer -nostartfiles

I see a few parameters that are not there in a default AVRstudio project, so if I remove for example -fomit-frame-pointer and it stops working does this mean that the OS is not designed correctly?

I think sometimes there is some tuning that needs to be done in the compiler in order to force/prevent some behavior.

In the case of OSA the weak point seems to be the use of temporary variables and for some reason -fno-move-loop-invariants seems to prevent that (unless I'm reading the code wrong).

Alex

"For every effect there is a root cause. Find and address the root cause rather than try to fix the effect, as there is no end to the latter."
Author Unknown

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

Quote:

I'm under the impression that an RTOS can use compiler options to work properly.

But an RTOS almost certainly relies on understanding how a compiler works "under the hood" and it's pretty unusual for the task switch to not get involved in Asm which at least understands the ABI of the compiler. as such it is not "normal" use of the compiler and could easily break if it's code generation changed.

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

If I understand correctly you say that when an RTOS relies on compiler switched to get a specific behaviour then it is not a good OS, right?

You are an experianced programmer and I assume you have used several OS for microconroller, how many of them used compiler switches and didn't rely on default compiler behaviour?
Is this really uncommon?

Alex

"For every effect there is a root cause. Find and address the root cause rather than try to fix the effect, as there is no end to the latter."
Author Unknown

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

Well any compiler that messes with the compilers use of the stack to save TCBs kind of has to know about the internal operation of the compiler so I don't think any of them will be exempted in that sense.

FreeRTOS is widely regarded and used (Atmel even chose to bundle it in ASF). It, as far as I know, has never suffered from the behaviour of the compiler's code generation but it clearly does "know" how GCC operates internally:

http://www.freertos.org/implemen...

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

alexan_e wrote:
If I understand correctly you say that when an RTOS relies on compiler switched to get a specific behaviour then it is not a good OS, right?
It's not uncommon that an OS needs to extend tha compiler that shall compile that OS or applications for it. This only OS that actually cares for this with avr-gcc is RTEMS.

A requirement like "the compiler must not stack" is not reasonable, IMHO, and you cannot change a compiler in that way because there will always be C functions that will need stack.

The only thing you can do in that case is to sanyty-check the generated assembly (not: disassembly) and test if there is no stack frame, e.g. by grepping for "frame size = *", freak if * is nonzero and fiddle with compiler options and source hacks until the test passes.

Quote:
You are an experianced programmer and I assume you have used several OS for microconroller, how many of them used compiler switches and didn't rely on default compiler behaviour?
I don't use OS on AVR because I don't think an OS would meet the real-time requirements of applications like Asteroids Game on AVR Scope Clock (Video).

Only once I had to evaluate a hard real-time embedded OS. It didn't need assumptions like in your topic, and if it needed such assumptions, I would have strongly discouraged to use that OS.

avrfreaks does not support Opera. Profile inactive.

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

I appreciate your views and I probably wouldn't rely for a professional project on a OS that have these quirks but this is currently used for hobby projects so it is not critical if something goes wrong (although I try to prevent it).

SprinterSB wrote:

A requirement like "the compiler must not stack" is not reasonable, IMHO, and you cannot change a compiler in that way because there will always be C functions that will need stack.

I agree but the stack itself is not a problem at all, what is a problem is for global/static variables to be accessed by temporary variables that reside in that stack space and the effect of -fno-move-loop-invariants seems to fix that.
By (OSA OS) design any variable stored in the stack will not retain its value as soon as a OS_Yield() is used so globals that should retain their values shouldn't have anything to do with the stack and should be accessed directly.
As long as there are only locals in the stack and the programmer knows exactly when the values will be lost (since tasks control is only transferred manually) there shouldn't be a problem.

SprinterSB wrote:

The only thing you can do in that case is to sanyty-check the generated assembly (not: disassembly) and test if there is no stack frame, e.g. by grepping for "frame size = *", freak if * is nonzero and fiddle with compiler options and source hacks until the test passes.

I wasn't aware of that so thank you for the idea.
If I interpret this correctly I have to use --save-temps so that the .s files are not deleted and then search in them.

For example in my case for the clock task with no loacal variables without -fno-move-loop-invariants I was getting this

.global	Clock
	.type	Clock, @function
Clock:
.LFB13:
.LM69:
	push r29
	push r28
	in r28,__SP_L__
	in r29,__SP_H__
	sbiw r28,8
	in __tmp_reg__,__SREG__
	cli
	out __SP_H__,r29
	out __SREG__,__tmp_reg__
	out __SP_L__,r28
/* prologue: function */
/* frame size = 8 */

With -fno-move-loop-invariants the frame become 0.

Clock:
.LFB13:
.LM68:
/* prologue: function */
/* frame size = 0 */

I understand that the frame size by itself doesn't tell me if there is a problem or not, it just point my attention to that part to check what is going on.
A frame in a task where I use local variables is not a problem at all, the problem is when static/global variable use that frame.

For example if I modify the code to add some useless local variable

void Clock(void) 
{	    
    while(1)
    {           uint8_t test[6]="12345";
		for(uint8_t i=0;i<5;i++) PORTB=test[i];
		
		if(OS_Flag_Check_On(flag1, CHANNEL1_ON_FLAG))
        {
            S2++;

            if(S2 == ':')
            {
                S1++;
                S2 = '0';
            }

            if(S1 == '6')
            {
                M2++;
                S1 = '0';
            }

            if(M2 == ':')
            {
                M1++;
                M2 = '0';
            }

            if(M1 == '6')
            {
                H2++;
                M1 = '0';
            }

            if(H2 == ':')
            {
                H1++;
                H2 = '0';
            }
        }

        OS_Delay(1);
    }
}

I do get a stack frame but as long as it is just used for the local variables there is no problem at all and the code works perfectly.

Clock:
.LFB13:
.LM68:
	push r29
	push r28
	rcall .
	rcall .
	rcall .
	in r28,__SP_L__
	in r29,__SP_H__
/* prologue: function */
/* frame size = 6 */

Alex

"For every effect there is a root cause. Find and address the root cause rather than try to fix the effect, as there is no end to the latter."
Author Unknown

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

alexan_e wrote:
I do get a stack frame but as long as it is just used for the local variables there is no problem at all and the code works perfectly.
Until you get a case when a local variable gets set in one invocation of a task, and used in the subsequent invocations?

EDIT: Have you looked at some other solutions? If you have resources, maybe an RTOS with separate stacks for tasks? If no resources, maybe something that is pure portable C (like protothreads?) (I think that protothreads is pure C, right? I never used it. Or any other RTOS for that matter (on AVR)).

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

This case will not happen randomly, unlike a normal pre-emptive OS where the task can be cut at any point from the OS controller (in a Round-robin scheme) this one only pauses the execution of a task where the programmer chooses to so the behavior of loosing a local variable content is completely predictable and there are no surprises.
An interrupt that cuts the execution and then returns to the task is not a problem from the stack variable contents.

Alex

"For every effect there is a root cause. Find and address the root cause rather than try to fix the effect, as there is no end to the latter."
Author Unknown

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

You are saying

    "No local variable lives past an OS call"
but you mean
    "No value held in the frame lives past an OS call"
None of these statements implies the other or is needed by the other.

avrfreaks does not support Opera. Profile inactive.

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

ezharkov wrote:

EDIT: Have you looked at some other solutions? If you have resources, maybe an RTOS with separate stacks for tasks? If no resources, maybe something that is pure portable C (like protothreads?) (I think that protothreads is pure C, right? I never used it. Or any other RTOS for that matter (on AVR)).

The majority of OSes are fairly complicated, for example FemotoOS which is considered a very stable Os form AVr is fairly complicated with pages of defines, it took me hours just to make an example work.

FreeRTOS is also a very stable OS but unsuited to a small mcu like mega8.

protothreads is just a co-operative scheduler (right?) and I already have a good enough schedular based on J.Pond book http://www.tte-systems.com/books... , I wanted an pre-emptive alternative.

OSA on the other hand has an executable wizard to set the defines and is quite simple to use, I has able to write my own code using it in less that an hour.

Alex

"For every effect there is a root cause. Find and address the root cause rather than try to fix the effect, as there is no end to the latter."
Author Unknown

Pages