#redefine stamp (stamp+1)

Last post
22 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I would like the preprocessor to run through my files (not to be confused with program flow) and to substitute all occurences of some #define with the next in sequence, starting from initial value.
So the question has nothing to do with CPU resources - just purely dumb precompiler's txt job.

Example 1 (avr asm, works):

.set my_stamp =6 ; initial value

.macro increment_stamp
 .if(my_stamp>0x5A)
  .error "Too many stamps"
 .else
  .set my_stamp (my_stamp+1)
 .endif
.endmacro ;increment_stamp

Whenever I need a stamp, I just insert it into the code and increment it later if necessary:

ldi temp,my_stamp ; ldi temp,6
increment_stamp ; .set my_stamp = 7 
...
subi pointer,my_stamp ;subi pointer,7
.org my_stamp*7 ; .org 49
increment_stamp ; .set my_stamp =8
...

Example 2 pseudocode in C:

#define OCDR_STAMP 1 //Initial value

#define DEBUG_PRINT(report_string) \
 #ifdef DEBUG
  #if(OCDR_STAMP > 0xFF) \
   #error "Too many OCDR stamps" \
  #else \
  { \
   //__attribute(section((.debug_str_section)) char my_string[]=report_string; \
   OCDR=OCDR_STAMP; \
   #redefine OCDR_STAMP (OCDR_STAMP+1) \
  } \
  #endif \
 #endif 

So that such code worked as I expect it to:

...
void Init_hardware(void){
 Enable_LDO();
 DEBUG_PRINT("LDO running"); //pushes 1 to OCDR
 Enable_PLL();
 DEBUG_PRINT("PLL running"); //pushes 2 to OCDR
 USB_Init();
}

int
main(void){
 DEBUG_PRINT("Entering main()"); //pushes 3 to OCDR
 Init_hardware();
 DEBUG_PRINT("USB Initializatin completed"); //pushes 4 to OCDR
 PORTB=LED_ON;
...

Occurences of DEBUG_PRINT should also place some strings into some elf section to be read out by debugger later but never mind that now - just how to make a define increment/redefine inside of a macro in C?

No RSTDISBL, no fun!

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

Does this help:

#define FOO __COUNTER__

int main (void)
{
   PORTB = FOO;
   PORTB = FOO;
   PORTB = FOO;
   PORTB = FOO;
   PORTB = FOO;
  ce:	15 b8       	out	0x05, r1	; 5
   PORTB = FOO;
  d0:	81 e0       	ldi	r24, 0x01	; 1
  d2:	85 b9       	out	0x05, r24	; 5
   PORTB = FOO;
  d4:	82 e0       	ldi	r24, 0x02	; 2
  d6:	85 b9       	out	0x05, r24	; 5
   PORTB = FOO;
  d8:	83 e0       	ldi	r24, 0x03	; 3
  da:	85 b9       	out	0x05, r24	; 5

But this is just an incrementing variable each time it is used and is not available for all C compilers (but as you see it is in GCC).

Cliff

PS I thought:

#define __COUNTER__ 6

#define FOO __COUNTER__

might allow you to initialise the counter but this just resulted in all 4 uses being 6.

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0
#define OCDR_STAMP_INIT 1 //Initial value

#define OCDR_STAMP_CAT(a,b) (a##+##b)
#define OCDR_STAMP  OCDR_STAMP_CAT(OCDR_STAMP_INIT,__COUNTER__)

(untested, possibly an intermediate step is needed for the concatenation)

Stefan Ernst

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

BTW as well as __COUNTER__ some Google results show __LINE__ being used on the basis that each line where it's used is going to have a unique number.

 

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

The __COUNTER__ seems to be working!
It always starts from 0, so the offset must be added but I will try sternst's trick later if I go that far..
I thought of some general idea of #define "variables", but for now __COUNTER__ helps in what I need actually.

As you can see each time I must check if __COUNTER__ didn't hit 0x100 which would mean an overflow on OCDR.

I cannot test the value of __COUNTER__ in the code, nor use its value more than once as this increments __COUNTER__.. But even when I use(wasting last write):

if((OCDR=__COUNTER__)>0xFE) 

how to insert:

#error "Too many OCDR stamps"

in a macro function (same as in a pseudocode example)? That # generates a compile time error..

Quote:
__LINE__ (...) is going to have a unique number.

OCDR accepts values from 0x00 to 0xFF so __func__, __FILE__, __LINE__ is good with assert() but not with OCDR/DWDR.

No RSTDISBL, no fun!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0
static const int foo=__COUNTER__;
static const int bar=__COUNTER__;

foo and bar will have consecutive values known at compiler-time.
In C++, they can even be used in constant expressions.
They cannot be used in preprocessor expressions.

Is it racist to discriminate against someone who changes species?

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

Some related ideas:
http://www.avrfreaks.net/index.php?name=PNphpBB2&file=viewtopic&t=110946

I have problems with several things in here:

    A. I do not know how to pass a warning string from asm("") macro into .warning in case the count of debug strings is exceeded
    B. How to send only low(debug_message_index)? LOW() macro does not work..
    C. I do not want additional "ldi r16,0" in the code if a compiler already has some register==0 with appropriate value.. How to tell it to the compiler?
    D. How to create new section in elf and put string there? Obviously I do not want to place those strings in .progmem
    and other

//substitute percent sign..

//initialization of ".set" variable
asm("debug_message_index=0 \n");	

#define DEBUG_IO_REGISTER OCDR //JTAG
//#define DEBUG_IO_REGISTER DIDR //dW

#ifndef NDEBUG
	#define debug_print(string) {								\
	/*__attribute__ ((section (".progmem"))) char report_str[]=string;*/\
		uint8_t value;											\
		asm volatile(	".if(debug_message_index==0x100)\n\t"	\
						"	.warning /*add warning*/ \n\t"		\
						".endif \n\t"							\
						"	ldi percent0,debug_message_index \n\t"	\
						"	out  percent1,percent0 \n\t"					\
						"	/*add string to elf secton*/ \n\t"	\
						"	debug_message_index = debug_message_index+1 \n\t"	\
						: "=d" (value) \
						: "I" (_SFR_IO_ADDR(DEBUG_IO_REGISTER))\
						);\
						}
		
#else
	#define debug_print(string) //prevent compile warnings
#endif

No RSTDISBL, no fun!

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

Try lo8() for low()

See: http://sourceware.org/binutils/docs-2.21/as/AVR_002dModifiers.html#AVR_002dModifiers

The compiler keeps 0 in R1.

Quote:
How to create new section in elf and put string there? Obviously I do not want to place those strings in .progmem
and other

Do it in C then see the .s file:

__attribute__((section(".foo"))) char text[] = "Hello";

yields:

.global	text
	.section	.foo,"aw",@progbits
	.type	text, @object
	.size	text, 6
text:
	.string	"Hello"

 

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

Ad. B: lo8 does the job, problem solved.

Ad. C: But I do not know which values it has in which registers - I would like to tell it:
"If you have 0x74 in r7 currently, be so kind and write it to OCDR".

What I did right now is asm volatile so even when it has 0 in r0, it is still pushing ldi temp,0 as I told it..

Ad. D:
But foo:

Quote:
../compiler_pitfalls.c:136: error: section attribute cannot be specified for local variables

cannot be local. Unfortunately the debug macro must be local..

No RSTDISBL, no fun!

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

Quote:

Ad. C: But I do not know which values it has in which registers - I would like to tell it:
"If you have 0x74 in r7 currently, be so kind and write it to OCDR".

I'll defer to others but I don't know how (short of compile time simulation of the running code) the assembler could possibly know what values may be in any registers at any given time.

Clearly a local (unless 'static') cannot be located at a given address (or within a given section placed by the linker) because it's dynamically created and destroyed on the stack. So I'm afraid that's never going to be possible.

 

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

Quote:
I don't know how

I am sure it is aware of r0. If so, it can also be aware of other values. Anyway, that "C" problem is a minor problem.

Now coming back to "D" - foo section. It must be local as all of those strings have the same name(which I do not need at all). But when I define those as static, "string" macro argument does not seem to be appended correctly:

	#define debug_print(string) {								\
	 static __attribute__((section(".foo"))) char report_str[] = string; \
	}

and there is no .foo section in .s file (not mentioning it warns about unused report_str)

The strings are global and are not to be placed on the stack. Actually these are in the section which is neither allocable nor loadable.
The linker script is a problem close to "K" in here :)

No RSTDISBL, no fun!

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

I am answering to the question from this topic:
http://www.avrfreaks.net/index.php?name=PNphpBB2&file=viewtopic&t=110946

clawson wrote:
That would require the PC side debugger to be modified to know to look up string 0x74 in the .elf? How do you plan to modify AVR Studio's internal debugger code?

I know that would be challenging to print in AS message window, but if I had a JTAG dongle driver, then I do not think that trick would be hard with GDB..

No RSTDISBL, no fun!

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

Does avarice report OCDR events on to GDB? I presumed it just talks GDB's "serial protocol" - does that have a mechanism for something like this?

 

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

I am not sure about avarice functionality on this matter. But I do not see a problem to add it, if needed. It is open-source.

Never mind about Mk1 and all other Atmel's crippled tools. I was thinking about FT232H.

No RSTDISBL, no fun!

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

I have just found out that a similar functionality is already implemented on Code Red's LPCXpresso using ARM's system debug ITM:
http://knowledgebase.nxp.com/showthread.php?t=461
It is called hoststrings and:

Code Red wrote:
(..)However with hoststrings, the message is actually read by the debugger from within your project structure - and all that the MCU has to do is send a reference to the debugger as to which message it wants printing, (..)

No RSTDISBL, no fun!

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

Quote:

is already implemented on Code Red's LPCXpresso using ARM's

Yes it's a great facility. In fact it's actually more complex to work out how to get printf() redirected to go via a real UART ;-)

 

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

Quote:
Yes it's a great facility.

Did you try it? AFAIK only Red Probe dongle (150$) supports it and Red Suite is required. Perhaps other vendors have similar features like hoststrings but as far as I know the naming convention is not standardized.
Anyone knows these names so I could read more about it?

No RSTDISBL, no fun!

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

Sorry I thought you simply meant the printing of printf() output to the debugger. You get that with a $20 LPCXpresso. I take it you meant he further extension of this to simply pass a single byte token to identify which host side held string to print? I have no experience of that and don't know if Code Red for LPCXpresso has that or not. But apart from debug link bandwidth what's wrong with the app passing the strings or do you mean you don't want the app size bloated by the local storage of the strings? (not usually a problem in LPCXpresso as they are relatively huge compared to AVRs).

 

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

Quote:
Sorry I thought you simply meant the printing of printf() output to the debugger.

This printf is called semihosting on ARMs and uses unique asm("bkpt 0xAB")=0xBEAB opcode to halt the target. When the dongle sniffs that target is stopped and it happened 0xBEAB was the cause, it polls memory space pointed in r0 to r3 register set (which contains your printf content) and prints on your console. When dongle is done, it forces the target to continue(run). These steps are automated, but process is controlled by the host/dongle and purely in Halting mode so it is intrusive (target is stopped in the meantime -> overflows, overruns etc, because peripherals are not being stopped then).
OTOH hoststrings use ITM from system debug (Instruction Trace Macrocell, this is a low cost tracing interface implemented inside the core) which does not halt the target at all - it is a dedicated (typically 32 channel) hardware with FIFOs, priorities, timestamps and what not. It can emit PC snapshots, accessed data read, written or both, etc.

LPCXpresso does not support ITM interface.

Quote:
I take it you meant he further extension of this to simply pass a single byte token to identify which host side held string to print?

You would not gain much with that - shorter timings, but still intrusive Halting mode on ARMs.

Quote:
But apart from debug link bandwidth what's wrong with the app passing the strings

AVR halts peripherals when halted (all but some). ARMs do not do that*.

Seems that on AVRs writing to OCDR register does not halt the target at all. But OCDR has some (unknown) limited depth and no overwrite detection so a care should be taken with that. I do not plan to continue the development as today I know my dongle (JTAGICE Mk1) does not support this feature.

I am just curious how other vendors (Keil, IAR, Segger etc) implemented and named hoststrings :)

*EDIT: Behaviour is implementation dependent actually. Some chips ( for example STM32F40X) have the option to halt peripherals when the core is halted. But some do not (LPC17XX can only halt RIT, but not regular timers).

No RSTDISBL, no fun!

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

http://www.atmel.no/webdoc/jtagicemkii/jtagicemkii.special_considerations_mega.html

Mentions the OCDR register, it's polled every 100ms. No queuing it seems.

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

Quote:

...the OCDR register, it's polled every 100ms...

That must be the Obsessive/Compulsive Disorder Register as it just does it over and over and ... ?

You can put lipstick on a pig, but it is still a pig.

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

jayjay1974 wrote:

Mentions the OCDR register, it's polled every 100ms. No queuing it seems.

Thanks for info. If that 100ms is a limit, the throughput of 10 Bps is $%^&&* and not worth the effort.

No RSTDISBL, no fun!