High speed serial and port control for logic analysis

March 23, 2013 Coded in C for the Atmel AVR32
#ifndef TESTPOINTS_H
#define TESTPOINTS_H

#include "gpio.h"

class TpHw
{

public:

//===================================================================================
// TOG, CLR, SET macros provide a means to quickly clear, set or toggle a pin.
// Each macro compiles into a single machine instruction when optimized. 
// usage is: 
//			TOG(AVR32_PIN10);
//===================================================================================

	#define TOG(pin) {											\
	volatile avr32_gpio_port_t *gpio_pin = &AVR32_GPIO.port[pin >> 5];	\
		gpio_pin->ovrt = 1 << (pin & 0x1F); } 

	#define CLR(pin) {											\
	volatile avr32_gpio_port_t *gpio_pin = &AVR32_GPIO.port[pin >> 5];	\
		gpio_pin->ovrc = 1 << (pin & 0x1F); } 

	#define SET(pin) {											\
	volatile avr32_gpio_port_t *gpio_pin = &AVR32_GPIO.port[pin >> 5];	\
		gpio_pin->ovrs = 1 << (pin & 0x1F); } 
		
//===================================================================================
// TAG provides a means to insert static real time serial data to be displayed on a 
// logic analyzer. The TAG macro should be optimized for a baud rate that matches 
// the instruction cycle time of the compiler. Each letter compiles into 10 
// machine instructions when optimized. Use 8 data bits, no parity and one stop bit. 
// usage is:
//			TAG(AVR32_PIN10, 'H', 'E', 'L', 'L', 'O');
//===================================================================================

	// this macro builds the bit
	#define BT(pin, letter, bit) {											\
		volatile avr32_gpio_port_t *gpio_pin = &AVR32_GPIO.port[pin >> 5];	\
		if (letter & bit)													\
			gpio_pin->ovrs = 1 << (pin & 0x1F);								\
		else																\
			gpio_pin->ovrc = 1 << (pin & 0x1F); } 
 
	// this macro builds the letter
	#define LETTER(pin, letter) {		\
		BT(pin, letter, 0x00);			\
		BT(pin, letter, 0x01);			\
		BT(pin, letter, 0x02);			\
		BT(pin, letter, 0x04);			\
		BT(pin, letter, 0x08);			\
		BT(pin, letter, 0x10);			\
		BT(pin, letter, 0x20);			\
		BT(pin, letter, 0x40);			\
		BT(pin, letter, 0x80);			\
		BT(pin, 0xff, 0xff);			}
	 
	// these build the tag
	#define LETTER1(pin, letter)      LETTER(pin, letter)
	#define LETTER2(pin, letter, ...) LETTER1(pin, letter) LETTER1(pin, __VA_ARGS__)
	#define LETTER3(pin, letter, ...) LETTER1(pin, letter) LETTER2(pin, __VA_ARGS__)
	#define LETTER4(pin, letter, ...) LETTER1(pin, letter) LETTER3(pin, __VA_ARGS__)
	#define LETTER5(pin, letter, ...) LETTER1(pin, letter) LETTER4(pin, __VA_ARGS__)
	#define LETTER6(pin, letter, ...) LETTER1(pin, letter) LETTER5(pin, __VA_ARGS__)
	#define LETTER7(pin, letter, ...) LETTER1(pin, letter) LETTER6(pin, __VA_ARGS__)
	#define LETTER8(pin, letter, ...) LETTER1(pin, letter) LETTER7(pin, __VA_ARGS__)
	 
	// these calculate the number of arguments passed
	#define ARGS_N(x1, x2, x3, x4, x5, x6, x7, x8, N, ...) N
	#define RSEQ_N()         8, 7, 6, 5, 4, 3, 2, 1, 0
	#define NARG_N(...)      ARGS_N(__VA_ARGS__)
	#define NARG(...)        NARG_N(__VA_ARGS__, RSEQ_N())
	 
	// these build the macro to start with (T1 - T8) base on number of arguments
	#define PASTE(a, b)      a ## b
	#define XPASTE(a, b)     PASTE(a, b)
	#define T_(pin, M_, ...) M_(pin, __VA_ARGS__)
	#define TAG(pin, ...)    T_(pin, XPASTE(LETTER, NARG(__VA_ARGS__)), __VA_ARGS__) 

//=====================================================================================
// textOut provides a means to insert dynamic real time serial data to be displayed 
// on a logic analyzer. The code below should be optimized for a baud rate that matches 
// the instruction cycle time of the compiler by stuffing no ops where appropriate 
// to balance the bit output. Use 8 data bits, no parity and one stop bit. This 
// gives a character that should take 55 cycles and doesn't take any time to set up. 
// usage is:
//			TpHw::textOut(AVR32_PIN_PA22, "HELLO");
//=====================================================================================

	static void serialOut(uint32_t pin, uint8_t value)
	{
		volatile avr32_gpio_port_t *gpio_pin = &AVR32_GPIO.port[pin >> 5];
		volatile uint32_t out = 1 << (pin & 0x1F);

		// start bit
		gpio_pin->ovrc = out;
		asm("nop"); 
	               
		// bit 0
		if (value & (1 << 0))
		{
			gpio_pin->ovrs = out;	  
		} 
		else
		{
			gpio_pin->ovrc = out;	  
			asm("nop"); 
		}
	          
		// bit 1
		if (value & (1 << 1))
		{
			gpio_pin->ovrs = out;	  
		}
		else
		{
			gpio_pin->ovrc = out;	  
			asm("nop"); 
		}
	    
		// bit 2
		if (value & (1 << 2))
		{
			gpio_pin->ovrs = out;	  
		}
		else
		{
			gpio_pin->ovrc = out;	  
			asm("nop"); 
		}

		// bit 3
		if (value & (1 << 3))
		{
			gpio_pin->ovrs = out;	  
		}
		else
		{
			gpio_pin->ovrc = out;	  
			asm("nop"); 
		}

		// bit 4
		if (value & (1 << 4))
		{
			gpio_pin->ovrs = out;	  
		}
		else
		{
			gpio_pin->ovrc = out;	  
			asm("nop"); 
		}

		// bit 5
		if (value & (1 << 5))
		{
			gpio_pin->ovrs = out;	  
		}
		else
		{
			gpio_pin->ovrc = out;	  
			asm("nop"); 
		}

		// bit 6
		if (value & (1 << 6))
		{
			gpio_pin->ovrs = out;	  
		}
		else
		{
			gpio_pin->ovrc = out;	  
			asm("nop"); 
		}

		// bit 7
		if (value & (1 << 7))
		{
			gpio_pin->ovrs = out;	  
		}
		else
		{
			gpio_pin->ovrc = out;	  
			asm("nop"); 
		}
	      
		// stop bit
		asm("nop");
		asm("nop");
		asm("nop");
		
		gpio_pin->ovrs = out;	  
	      
	}

	static void textOut(uint32_t pin, char *text)
	{
	   while (*text != 0)
	   {
		  serialOut(pin, *text++);
	   }
	}

};

#endif