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;
}
浙公网安备 33010602011771号