Inline macros, #define, and a solution

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

Tried FreeRTOS+trace, and discovered that the most useful version not only takes up lots of memory, but also is 1400 dollars or so.

I have a logic analyzer, and needed to figure out when certain routines were called in relationship to the TWI messages to be sent.

Easy idea, since this was in a debugging hardware environment where the processor had extra pins. Just tag a routine and output it to an 8 bit port when you enter the routine, and also when you exit. Set both parts of the logic analyzer to state machine and interleave them, so you get to see the entry and exit points of a routine, time tagged, and with the corresponding data.

How to do this?

First I tried #define and passing arguments, that didn't work well.
Secondly I tried inline assembler, which also did not work well. Examples compiled, but my modified code did not.

Finally managed to get a solution to the whole thing

(I had wanted a compound #define #ifdef kind of solution which is not possible. Have to try the conditional operations on this one, but I think it will work.)

First, start off with definitions:


	// ************************************************************************************************
	// ******************************** hardware trace DEFINITIONS ************************************
	// ************************************************************************************************

	#define HARDWARE_DEBUG_VALID	0X80			// BIT SET MASK
	#define HARDWARE_ENTRY			0X40			// ENTRY POINT FLAG
	#define HARDWARE_EXIT			0X0				// EXIT POINT FLAG
	
	// ******************************************* TAG LOCATIONS **************************************
	#define TAG_INIT				0x0				// just because for now
	#define TAG_TWI_IRQ				0X1				// TWI MASTER IRQ
	#define TAG_TWI_SMART_TASK		0X2				// SMART TASK LOOP (STATE MACHINE)
	#define TAG_TWI_COMMAND_TASK	0X3				// DUMB TASK SEND ONLY STATE MACHINE
	#define TAG_TWI_SLAVE_IRQ		0x4				// TWI SLAVE IRQ

which defines the hardware conditions and trace points

You get the msb of an 8 bit port going high then low to define a valid state (logic analyzer clocks on this). You get the next MSB of the port to be logic one if entering the routine, logic zero if exiting. The remaining 6 bits allow you to define 64 different routines.

Next, to define macros where one instruction will insert the code or not. (these are not yet conditional).


	#define ENTER(arg)											\
	({															\
		HARDWARE_DEBUG_PORT = (arg + HARDWARE_ENTRY);								\
		HARDWARE_DEBUG_PORT = (HARDWARE_DEBUG_VALID + arg + HARDWARE_ENTRY);		\
		HARDWARE_DEBUG_PORT = 0;								\
	});
	
	

	#define EXIT(arg)											\
	({															\
		HARDWARE_DEBUG_PORT = (arg + HARDWARE_EXIT);								\
		HARDWARE_DEBUG_PORT = (HARDWARE_DEBUG_VALID + arg + HARDWARE_EXIT);		\
		HARDWARE_DEBUG_PORT = 0;								\
	});
	

Note the use of \ to extend the line, and nested {} to force the compiler to keep the whole item as a unit.

Not needed do define arg, since it's replaced by the actual argument.

Insert this in your code as follows:


						break;									// handles state "to ping" which is not needed, also task_set_idle
					}
				}			
			}
			EXIT(TAG_TWI_SMART_TASK);
		}									

which is found at the end of a routine.

This produces (for an entry macro)

    307c:	8c 01       	movw	r16, r24
    307e:	81 e4       	ldi	r24, 0x41	; 65
    3080:	80 93 84 06 	sts	0x0684, r24
    3084:	81 ec       	ldi	r24, 0xC1	; 193
    3086:	80 93 84 06 	sts	0x0684, r24
    308a:	10 92 84 06 	sts	0x0684, r1

This is the desired result, output the condition to the port, set the MSB, then write 0 to the port.

The logic analyzer's symbol table decodes the results.

Hope that this might help someone.

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

Why you do not use functions like this?

void inline ENTER(unsigned char arg)
{
      HARDWARE_DEBUG_PORT = (arg + HARDWARE_ENTRY);
      HARDWARE_DEBUG_PORT = (HARDWARE_DEBUG_VALID + arg + HARDWARE_ENTRY);
      HARDWARE_DEBUG_PORT = 0;
} 

At least, this is trivial to get compile, without "{(" and "\".
Also, with function it is safe for any expression for arg, example ENTER(f()); where f is some function. In you code, f will (may) be called twice.

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

Mostly because I never saw an example quite like that, and I was trying to make sense out of what examples I *could* find. You'd be surprised (or not) of how many google queries lead to dead ends.

Problem seems to be that (as usual for me) all the examples do *almost* what I want them to do, with no real explanation of syntax. Basic syntax seems to be hidden (or I didn't find it), leaving me to hit on a solution by chance....

INLINE directive did not come up in my searches. AVR inline assembler cookbook had insufficient examples.

Oh, and #define
#ifdef
#endif

structures do *not* work, even though they'd be useful

but

#ifdef ......

insert something from #define here

#endif

works wonderfully, so much for a one line insert

Thanks, though, I will try that the next time.