⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 pcm.c

📁 This is a futaba PCM decode source. You can study futaba pcm code.
💻 C
字号:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<!-- saved from url=(0077)http://cvs.sf.net/viewcvs.py/*checkout*/autopilot/onboard/rev2/pcm.c?rev=HEAD -->
<HTML><HEAD>
<META http-equiv=Content-Type content="text/html; charset=iso-8859-1">
<META content="MSHTML 6.00.2900.2802" name=GENERATOR></HEAD>
<BODY><PRE>/* -*- indent-tabs-mode:T; c-basic-offset:8; tab-width:8; -*- vi: set ts=8:
 * $Id: pcm.c,v 1.22 2003/02/03 05:30:50 tramm Exp $
 *
 * Decode a PCM signal on the ICP pin.
 *
 * (c) 2002 Trammell Hudson &lt;hudson@swcp.com&gt;
 *
 *************
 *
 *  This file is part of the autopilot onboard code package.
 *  
 *  Autopilot is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *  
 *  Autopilot is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *  
 *  You should have received a copy of the GNU General Public License
 *  along with Autopilot; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 *
 */
/**
 * The CPU clock is 8 MHz.
 * The bit clock is 150 usec or 150 * 8 == 1200 ticks.
 */
#define		CLOCK		(8ul)	/* Mhz */
#define		BIT_CLOCK	(150ul * CLOCK)	


/**
 *  Define VERBOSE to get raw field/frame data instead of
 * processed packets
 */
#undef VERBOSE
#undef RAW_DATA_PACKETS

#include &lt;io.h&gt;

#include "timer.h"
#include "uart.h"
#include "string.h"
#include "memory.h"


/*
 * Input is on the ICP (Port D pin 6).  These inlines wrap access to
 * the control registers to make it clearer what is happening.
 */
#define			PCM_PUD		PORTD
#define			PCM_PORT	PIND
#define			PCM_DDR		DDRC
#define			PCM_PIN		6

static inline void
capture_falling_edge( void )
{
	cbi( TCCR1B, ICES1 );
}


static inline void
capture_rising_edge( void )
{
	sbi( TCCR1B, ICES1 );
}



static inline void
capture_clear_flag( void )
{
	outp( 1 &lt;&lt; ICF1, TIFR );
}


static inline uint8_t
capture_flag( void )
{
	return bit_is_set( TIFR, ICF1 );
}

static inline uint16_t
capture_wait( void )
{
	while( !capture_flag() )
		;

	return __inw( ICR1L );
}


/*
 * We use the 16 bit Timer 1B for our software uart.
 * These inlines just wrap access to the registers.
 */
static inline void
compare_disable( void )
{
	cbi( TIMSK, OCIE1B );
}


static inline void
compare_enable( void )
{
	sbi( TIMSK, OCIE1B );
}


static inline void
compare_set( 
	uint16_t		when
)
{
	__outw( when, OCR1BL );
}


static inline uint16_t
compare_get( void )
{
	return __inw( OCR1BL );
}

static inline void
compare_clear_flag( void )
{
	outp( 1 &lt;&lt; OCF1B, TIFR );
}



static void
pcm_init( void )
{
	/* No noise cancelation */
	cbi( TCCR1B, ICNC1 );

	/* Set ICP to input, internal pull up */
	sbi( PCM_PUD, PCM_PIN );
	cbi( PCM_DDR, PCM_PIN );

	/* Disable timer overflow for now and run at Clk/32 */
	cbi( TIMSK, TOIE2 );
	outp( 0x02, TCCR2 );

	/* Disable the OC1B servo bank */
	compare_disable();

	/* We will trigger on port C */
	outp( 0xFF, DDRC );
	outp( 0x00, PORTC );

	/* We have to enable to ADC to sink the opamp output */
	outp( 0x00, PORTA );
	outp( 0x00, DDRA );
}


static uint16_t		sync_offset;
static uint16_t		pcm_byte;
static volatile uint8_t	pcm_ready;
static uint8_t		bit_counter;

/*
 * Store the fields here until the can be processed
 */

struct pcm_packet
{
	uint16_t	pos;
	uint8_t		aux;
	uint8_t		diff;
	uint8_t		crc;
};

static struct pcm_packet	packets[4];
static uint16_t			raw[4];
static uint16_t			pos[9];


/*
 * Wait for a sync pulse of 3 ms
 */
static void
wait_for_sync(
	uint8_t			hi,
	uint8_t			flag
)
{
	uint16_t		diff;
	uint16_t		stop;

	outp( 0x00, PORTC );

	do {
		uint16_t		start;

		/*
		 * Catch the start of the sync pulse.
		 * Rising for hi sync, falling for low sync
		 */
		if( hi )
			capture_rising_edge();
		else
			capture_falling_edge();

		capture_clear_flag();
		start = capture_wait();

		/*
		 * Catch the end of the sync pulse.
		 * Falling for hi sync, rising for lo sync.
		 */
		if( hi )
			capture_falling_edge();
		else
			capture_rising_edge();

		capture_clear_flag();
		stop = capture_wait();

		diff = stop - start;

	} while( diff &lt; 2500 * CLOCK );

#if 0
	/* Wait for the next edge */
	if( hi )
		capture_rising_edge();
	else
		capture_falling_edge();

	capture_clear_flag();
	stop = capture_wait();
#endif

	outp( flag, PORTC );

	/*
	 * The bit clock is always 300 useconds long.
	 * We don't actually need the length of the sync pulse.
	 */
	compare_set( stop + sync_offset );
	compare_clear_flag();

	/* Reset our counters for the interrupt routine */
	bit_counter	= 10;
	pcm_ready	= 0;

	/* Enable our interrupt */
	compare_enable();
}



/**
 *  Sample the bits when ever our timer interrupt fires
 */
SIGNAL( SIG_OUTPUT_COMPARE1B )
{
	static uint16_t	byte;
	uint16_t	temp;

	sbi( PORTC, 7 );

	/* Push it onto our byte */
	temp = byte &lt;&lt; 1;
	if( bit_is_set( PCM_PORT, PCM_PIN ) )
		temp |= 1;


	/* Interrupt us in 150 usec */
	compare_set( compare_get() + BIT_CLOCK );

	if( --bit_counter == 0 )
	{
		pcm_ready	= 1;
		pcm_byte	= temp;
		bit_counter	= 10;
		byte		= 0;
	} else {
		byte = temp;
	}

	cbi( PORTC, 7 );
}


/*
 * Convert the 10 bit encodings to 6 bit data packets.
 */
static uint8_t
ten2six(
	uint16_t		word
)
{
	uint8_t			high	= (word &amp; 0x300) &gt;&gt; 8;
	uint8_t			low	= (word &amp; 0x0FF) &gt;&gt; 0;

	if( high == 0x03 )
	{
		if( low == 0xF8 ) return 0x00; /* 1111111000 */
		if( low == 0xF3 ) return 0x01; /* 1111110011 */
		if( low == 0xE3 ) return 0x02; /* 1111100011 */
		if( low == 0xE7 ) return 0x03; /* 1111100111 */
		if( low == 0xC7 ) return 0x04; /* 1111000111 */
		if( low == 0xCF ) return 0x05; /* 1111001111 */
		if( low == 0x8F ) return 0x06; /* 1110001111 */
		if( low == 0x9F ) return 0x07; /* 1110011111 */

		if( low == 0x3F ) return 0x0B; /* 1100111111 */
		if( low == 0x1F ) return 0x0C; /* 1100011111 */
		if( low == 0x0F ) return 0x0D; /* 1100001111 */
		if( low == 0x87 ) return 0x0E; /* 1110000111 */
		if( low == 0xC3 ) return 0x0F; /* 1111000011 */

		if( low == 0xCC ) return 0x14; /* 1111001100 */
		if( low == 0x9C ) return 0x15; /* 1110011100 */
		if( low == 0x3C ) return 0x16; /* 1100111100 */
		if( low == 0x33 ) return 0x17; /* 1100110011 */
		if( low == 0xF0 ) return 0x18; /* 1111110000 */
		if( low == 0xE0 ) return 0x19; /* 1111100000 */
		if( low == 0x83 ) return 0x1A; /* 1110000011 */
		if( low == 0x07 ) return 0x1B; /* 1100000111 */
		if( low == 0x1C ) return 0x1C; /* 1100011100 */
		if( low == 0x98 ) return 0x1D; /* 1110011000 */
		if( low == 0x8C ) return 0x1E; /* 1110001100 */
		if( low == 0x38 ) return 0x1F; /* 1100111000 */

		if( low == 0x30 ) return 0x2C; /* 1100110000 */
		if( low == 0x18 ) return 0x2D; /* 1100011000 */
		if( low == 0x0C ) return 0x2E; /* 1100001100 */
		if( low == 0x03 ) return 0x2F; /* 1100000011 */

		if( low == 0xC0 ) return 0x35; /* 1111000000 */
		if( low == 0x80 ) return 0x36; /* 1110000000 */
		if( low == 0x00 ) return 0x37; /* 1100000000 */
 	} else
	if( high == 0x00 )
	{
		if( low == 0xFF ) return 0x08; /* 0011111111 */
		if( low == 0x7F ) return 0x09; /* 0001111111 */
		if( low == 0x3F ) return 0x0A; /* 0000111111 */

		if( low == 0xFC ) return 0x10; /* 0011111100 */
		if( low == 0xF3 ) return 0x11; /* 0011110011 */
		if( low == 0xE7 ) return 0x12; /* 0011100111 */
		if( low == 0xCF ) return 0x13; /* 0011001111 */
		
		if( low == 0xC7 ) return 0x20; /* 0011000111 */
		if( low == 0x73 ) return 0x21; /* 0001110011 */
		if( low == 0x67 ) return 0x22; /* 0001100111 */
		if( low == 0xE3 ) return 0x23; /* 0011100011 */
		if( low == 0xF8 ) return 0x24; /* 0011111000 */
		if( low == 0x7C ) return 0x25; /* 0001111100 */
		if( low == 0x1F ) return 0x26; /* 0000011111 */
		if( low == 0x0F ) return 0x27; /* 0000001111 */
		if( low == 0xCC ) return 0x28; /* 0011001100 */
		if( low == 0xC3 ) return 0x29; /* 0011000011 */
		if( low == 0x63 ) return 0x2A; /* 0001100011 */
		if( low == 0x33 ) return 0x2B; /* 0000110011 */

		if( low == 0x3C ) return 0x30; /* 0000111100 */
		if( low == 0x78 ) return 0x31; /* 0001111000 */
		if( low == 0xF0 ) return 0x32; /* 0011110000 */
		if( low == 0xE0 ) return 0x33; /* 0011100000 */
		if( low == 0xC0 ) return 0x34; /* 0011000000 */

		if( low == 0x60 ) return 0x38; /* 0001100000 */
		if( low == 0x70 ) return 0x39; /* 0001110000 */
		if( low == 0x30 ) return 0x3A; /* 0000110000 */
		if( low == 0x38 ) return 0x3B; /* 0000111000 */
		if( low == 0x18 ) return 0x3C; /* 0000011000 */
		if( low == 0x1C ) return 0x3D; /* 0000011100 */
		if( low == 0x0C ) return 0x3E; /* 0000001100 */
		if( low == 0x07 ) return 0x3F; /* 0000000111 */
	}

	return 0xFF;
}


static void
get_packet(
	uint8_t *		packet,
	uint8_t			invert
)
{
	uint8_t			byte_counter = 0;

	while( byte_counter &lt; 4 )
	{
		uint8_t			byte;

		while( !pcm_ready )
			;

		pcm_ready	= 0;

		byte		= ten2six(
			invert ? ~pcm_byte : pcm_byte
		);

		raw[ byte_counter ] = pcm_byte;
		packet[ byte_counter++ ] = byte;
#ifdef VERBOSE
		put_uint12_t( pcm_byte );
#endif
	}
}


static void
process_packet(
	struct pcm_packet *	p,
	const uint8_t *		data
)
{
	p-&gt;aux	= (data[0] &amp; 0x30) &gt;&gt; 4;

	p-&gt;diff	= (data[0] &amp; 0x0F) &gt;&gt; 0;

	p-&gt;pos	= (data[1] &amp; 0xFF) &lt;&lt; 4
		| (data[2] &amp; 0x3C) &gt;&gt; 2;

	p-&gt;crc	= (data[2] &amp; 0x03) &lt;&lt; 6
		| (data[3] &amp; 0x3F) &gt;&gt; 0;

	if( data[0] == 0xFF
	||  data[1] == 0xFF
	||  data[2] == 0xFF
	||  data[3] == 0xFF
	)
	{
		p-&gt;aux = 0xFF;
	}

#ifdef RAW_DATA_PACKETS
{
	uint8_t			i;

	for( i=0 ; i&lt;4 ; i++ )
	{
		if( data[i] == 0xFF )
		{
			putc( 'X' );
			put_uint12_t( raw[i] );
		} else
			put_uint8_t( data[i] );
		putc( ' ' );
	}
}
#else
/*
	if( p-&gt;aux == 0xFF )
		putc( '!' );

	puts( " a=" );
	putc( hexdigit( p-&gt;aux ) );

	puts( " d=" );
	putc( hexdigit( p-&gt;diff ) );

	puts( " p=" );
	put_uint12_t( p-&gt;pos );

	puts( " c=" );
	put_uint8_t( p-&gt;crc );
*/
#endif
}


static void
update_pos(
	const struct pcm_packet *	packet,
	uint8_t			chan1,
	uint8_t			chan2
)
{
	if( packet-&gt;aux == 0xFF )
	{
		putc( '!' );
		return;
	}

	pos[chan1] = packet-&gt;pos;
	pos[chan2] += (int8_t) packet-&gt;diff - 8;
}


static void
get_frame(
	struct pcm_packet *	packets,
	uint8_t			invert,
	uint8_t			field
)
{
	uint8_t			data[4];
	struct pcm_packet *	packet;

	get_packet( data, invert );
	packet = &amp;packets[0];
	process_packet( packet, data );
	update_pos( packet,
		field == 1 ? 0 : 1,
		field == 1 ? 1 : 0
	);

	put_uint12_t( pos[0] ); putc( ' ' );
	put_uint12_t( pos[1] ); putc( ' ' );


	get_packet( data, invert );
	packet = &amp;packets[1];
	process_packet( packet, data );
	update_pos( packet,
		field == 1 ? 2 : 3,
		field == 1 ? 3 : 2
	);

	put_uint12_t( pos[2] ); putc( ' ' );
	put_uint12_t( pos[3] ); putc( ' ' );

	get_packet( data, invert );
	packet = &amp;packets[2];
	process_packet( packet, data );
	update_pos( packet,
		field == 1 ? 4 : 5,
		field == 1 ? 5 : 4
	);

	put_uint12_t( pos[4] ); putc( ' ' );
	put_uint12_t( pos[5] ); putc( ' ' );


	get_packet( data, invert );
	packet = &amp;packets[3];
	process_packet( packet, data );
	update_pos( packet,
		field == 1 ? 6 : 7,
		field == 1 ? 7 : 6
	);

	put_uint12_t( pos[6] ); putc( ' ' );
	put_uint12_t( pos[7] ); putc( ' ' );

	/* Disable our interrupt */
	compare_disable();
	putnl();
}




static void
get_field1( void )
{
	/* Offset of -35 and skip the first six bits of header */
	sync_offset	= BIT_CLOCK * 7 - 35 * CLOCK;

	wait_for_sync( 0, 1 );
	puts( "1:" );
	get_frame( packets, 1, 1 );

	/* Offset of -35 and skip the first eight bytes of header */
	sync_offset	= BIT_CLOCK * 9 - 35 * CLOCK;

	wait_for_sync( 0, 2 );
	puts( "2:" );
	get_frame( packets, 1, 2 );
}


static void
get_field2( void )
{
	/* Offset of +25 and skip the first six bits of header */
	sync_offset	= BIT_CLOCK * 6 + 25 * CLOCK;

	wait_for_sync( 1, 4 );
	puts( "3:" );
	get_frame( packets, 0, 1 );

	/* Offset of +25 and skip the first eight bits of header */
	sync_offset	= BIT_CLOCK * 8 + 25 * CLOCK;

	wait_for_sync( 1, 8 );
	puts( "4:" );
	get_frame( packets, 0, 2 );
}



int main( void )
{
	timer_init();
	uart_init();
	pcm_init();
	sei();

	puts( "PCM decoder" );
	putnl();

	while( 1 )
	{
		get_field1();
		get_field2();
	}
}
</PRE></BODY></HTML>

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -