QNX I/O Programming

https://code.google.com/p/rt-embedded-project6/source/browse/trunk/Project3.c?r=6

http://rt-embedded-project6.googlecode.com/svn-history/r6/trunk/Project3.c

/**********************************************************************
 * Project3.c
 *
 * Configures the parallel port to generate a 1kHz square wave.
 *
 * Authors:
 * 		Sajin George
 * 		Russ Martin
 * 		Oliver Wing
 *
 * Credit to http://psy.swan.ac.uk/staff/carter/qnx/tut_nto_parout.htm 
 * for the otherwise very tricky setup of the parallel port for output.
 */

#include <stdlib.h>
#include <stdio.h>
#include <unistd.h> 		// for sleep()
#include <stdint.h>
#include <time.h>
#include <hw/inout.h> 		// for in*() and out*() functions
#include <sys/neutrino.h>	// for ThreadCtl()
#include <sys/mman.h>		// for mmap_device_io()
#include <sys/siginfo.h>	// for sigevent and signal handling
#include "types.h"

/* The Neutrino IO port used here corresponds to a single register, which is
 * one byte long */
#define PORT_LENGTH 1
/* The first parallel port usually starts at 0x378. Each parallel port is
 * three bytes wide. The first byte is the Data register, the second byte is
 * the Status register, the third byte is the Control register. */
#define DATA_ADDRESS 0x378
#define CTRL_ADDRESS 0x37a
/* bit 2 = printer initialisation (high to initialise)
 * bit 4 = hardware IRQ (high to enable) */
#define INIT_BIT 0x04

// One-bit constants.
#define LOW 0x00
#define HIGH 0xFF
// Arbitrary test value for post. Can be any byte
#define TEST_VAL 0x55


/* Clock resolution in nanoseconds. Must be less than or equal to 500 us for
 * the 1kHz clock to properly be generated.*/
#define CLOCK_RESOLUTION 500000

// Variables that control the square wave.
bool outputHigh = false;
bool portInitialized = false;
uintptr_t data_handle;

/* Flip the output bits.
 * Param: signo: ID of signal that generates the call to this method
 * 					This is unused, but required by signal/event handler
 */
void FlipOutput(int signo)
{
	if (portInitialized) {
		if (outputHigh) {
			out8( data_handle, LOW );
			outputHigh = false;
		}
		else {
			out8( data_handle, HIGH );
			outputHigh = true;
		}
	}
}

// Power-on self test functions.
bool POST() {
	UINT8 testIn;
	//write a bit out to register
	out8(data_handle, TEST_VAL);
	//now read in; the parallel port is write-only,
	//but reading it will return the last byte sent
	testIn=in8(data_handle);
	//fail if not equal to byte sent
	return(testIn==TEST_VAL);
}

int main(int argc, char *argv[]) {

	// Control register for parallel port
	uintptr_t ctrl_handle;

	// Structs and values needed for timer and event handler
	struct sigevent event;
	timer_t timer2KHz;
	struct itimerspec timerInfo;
	struct _clockperiod clockResolution;

	// Give the thread root permissions to access the hardware
	if ( ThreadCtl( _NTO_TCTL_IO, NULL ) == -1 )
	{
		fprintf( stderr, "Can't get root permissions!\n" );
		return -1;
	}

	// Set the clock resolution to something below 500 usec.
	clockResolution.nsec = CLOCK_RESOLUTION;
	clockResolution.fract = 0;
	if ( ClockPeriod( CLOCK_REALTIME, &clockResolution, NULL, 0 /* unimportant parameter */ ) == -1 )
	{
		fprintf( stderr, "Clock not allowing the necessary resolution change!\n" );
		return -1;
	}

	// Get a handle to the parallel port's Control register
	ctrl_handle = mmap_device_io( PORT_LENGTH, CTRL_ADDRESS );

	// Initialise the parallel port
	out8( ctrl_handle, INIT_BIT );

	// Get a handle to the parallel port's Data register
	data_handle = mmap_device_io( PORT_LENGTH, DATA_ADDRESS );

	// Set up a basic signal notification to trigger SIGUSR1.
	SIGEV_SIGNAL_INIT ( &event, SIGUSR1 );

	// Connect a timer to the signal notification.
	timer_create( CLOCK_REALTIME, &event, &timer2KHz );

	// Everything's ready to go.
	portInitialized = true;

	// Run POST tests.
	if ( POST() )
	{
		// Everything passed!
		printf( "POST successful!\n" );
	}
	else
	{
		// Something is wrong.
		printf( "POST failed!\n" );
		return -1;
	}

	// Install the timer signal handler.
	signal( SIGUSR1, FlipOutput );


	/* Set up the timer to trigger a signal once every 500 us (twice per cycle).
	 * Wait 500 us until the first signal, and then 500 us for each future signal. */
	timerInfo.it_value.tv_sec = 0;					// Timer period div 1E9 nsec
	timerInfo.it_value.tv_nsec = CLOCK_RESOLUTION;	// Timer period mod 1E9 nsec
	timerInfo.it_interval = timerInfo.it_value;		// Timer is pure periodic
	timer_settime( timer2KHz, 0 /* relative time */, &timerInfo, NULL );

	// Wait for and process signals as they arise.
	for ( ;; )
	{
	}

	return 0;
}
posted @ 2014-05-22 12:11  集成块儿  阅读(652)  评论(0编辑  收藏  举报