Go to Post This thread is a reminder to myself that I have 29 more days to sleep. :) - Seth Mallory [more]
Home
Go Back   Chief Delphi > ChiefDelphi.com Website > Extra Discussion
CD-Media   CD-Spy  
portal register members calendar search Today's Posts Mark Forums Read FAQ rules

 
 
 
Thread Tools Rate Thread Display Modes
Prev Previous Post   Next Post Next
  #3   Spotlight this post!  
Unread 16-05-2007, 12:38
dcbrown dcbrown is offline
Registered User
AKA: Bud
no team
Team Role: Mentor
 
Join Date: Jan 2005
Rookie Year: 2005
Location: Hollis,NH
Posts: 236
dcbrown has much to be proud ofdcbrown has much to be proud ofdcbrown has much to be proud ofdcbrown has much to be proud ofdcbrown has much to be proud ofdcbrown has much to be proud ofdcbrown has much to be proud ofdcbrown has much to be proud ofdcbrown has much to be proud ofdcbrown has much to be proud of
Re: paper: Low Latency Interrupt Framework

You'd do a functional driver port. The resulting port into the framework results in its ability to utilize it within projects under MPLAB and EasyC/WPILIB - one set of code from that point forward.

The new framework utilizes a run-time binding of interrupt to isr/data structures vs the compile time binding in Kevin's code. This permits a library to be utilized. You can tweak the "standard" driver if you want or just call it and use it as is. The tweaking could get you all the way back to the point that the driver you are using for your robot is essentially equivalent to compile-time binding... or you could have/utilize or choose an available driver package that is more generic such as the example to follow.

For example. The quad encoder is bound to the interrupt (phase_a) and phase_b pins via the driver writer supplied "package" routine. The user calls this "package" to declare/setup the system. Typically this is done only once so the Bind/unBind will reflash program memory jump tables for the appropriate physical and logical service routines. Typically only Binds will be done to hook or register the driver we want invoked by the respective interrupt as this physical configuration usually doesn't change while the robot is running. The user of the driver doesn't need to know how it works, just that pin 'X' is the phase a encoder pin and pin 'Y' is the B-phase encoder pin. The driver supplier in this case only supports 2 channels, but the driver programmer could easily expand to include 6 channel support.

The user of the driver then calls start/read/set/stop routines. Start enables the interrupt and stop disables the interrupt to control loading on the processor. As part of start, it specifies whether to invert the counting or not. Read returns the current count value for the channel and set changes the value to the number provided. These routines are provided by the driver writer. The driver writer could have decided to only invert the data at Read time, but in this case does it within the logical ISR handler.

The two handlers provided include one that is run at interrupt level (physical driver), while interrupts are disabled and a 2nd half of the driver (logical driver) to be run while interrupts are enabled. The user could have bound a third user driver to the same interrupt to do other processing (like changing the motor speed to accelerate or stop the robot after so many counts).

Anyway, the physical driver grabs the phase 'a' and phase 'b' values from the pins and saves them away. You wouldn't need phase 'a' if this was a programmable edge interrupt but we don't know which interrupt line the user will bind the driver to so its generic.

The logical driver then processes this information while interrupts are enabled. This logical driver inverts the count here, but that code could easily be moved to the Read user API routine to reduce the logical driver cpu run-time footprint.

Code:
/*
 * User provided routines... bind a user driver to encoder 
 *
void QuadEncoder0_MyCode( void )
{
      // Tie my function to encoder0 which is my lft wheel
      UsrISR_Bind( &MyLeftWheel_LogISR, XYZ_interrupt );
}

/*
 * Driver writer supplied routines...
  *   bind or configure driver to desired robot-specific interrupts/pins...
 */
void QuadEncoder_Package( channel, interrupt, phase_b_pin )
{
    if (channel == 0) {
        PhyISR_Bind( &QuadEncoder0_PhyISR, interrupt, RISING_EDGE );
        LogISR_Bind( &QuadEncoder0_LogISR, interrupt                     );
	
        QuadEncoder_Initialize( channel, interrupt, phase_b_pin );
        return;
    }

    if (channel == 1) {
        PhyISR_Bind( &QuadEncoder1_PhyISR, interrupt, RISING_EDGE );
        LogISR_Bind( &QuadEncoder1_LogISR, interrupt                     );
	
        QuadEncoder_Initialize( channel, interrupt, phase_b_pin );
        return;
    }

}
void QuadEncoder_unPackage( channel, interrupt, phase_b_pin )
{
    if (channel == 0) {
        PhyISR_unBind( &QuadEncoder0_PhyISR, interrupt );
        LogISR_unBind( &QuadEncoder0_LogISR, interrupt );
	
        QuadEncoder_UnInitialize( channel, interrupt, phase_b_pin );
        return;
    }

    if (channel == 1)
   {
        PhyISR_unBind( &QuadEncoder1_PhyISR, interrupt );
        LogISR_unBind( &QuadEncoder1_LogISR, interrupt );
	
        QuadEncoder_UnInitialize( channel, interrupt, phase_b_pin );
        return;
    }
}


/*
 * Driver writer supplied API (user callable) routines...
 */
unsigned char QuadEncoder_Start( channel, invert )
{
	if (channel > QUADENCODER_CHANNEL_MAX) return(1);
	switch(channel)
	{
		case 0: quadencoder0.invert = invert;
			InterruptEnable( quadencoder0.interrupt );
			return(0);
		case 1: quadencoder1.invert = invert;
			InterruptEnable( quadencoder1.interrupt );
			return(0);
		default: return(1);
	}
	return(0);
}
unsigned char QuadEncoder_Stop( channel )
{
	if (channel > QUADENCODER_CHANNEL_MAX) return(1);
	switch(channel)
	{
	  case 0: DisableInterrupt( quadencoder0.interrupt ); return(0);
	  case 1: DisableInterrupt( quadencoder1.interrupt ); return(0);
	  default: return(1);
	}
	return(0);
}
	
long QuadEncoder_Read( channel )
{
long tmp;
	if (channel > QUADENCODER_CHANNEL_MAX) return(0);
	switch(channel)
	{
	  case 0: CRITICAL_REGION_QUADENCODER0_BGN;
	 	tmp = quadencoder0.count;
 	             CRITICAL_REGION_QUADENCODER0_END;
		break;
	  case 1: CRITICAL_REGION_QUADENCODER1_BGN;
		tmp = quadencoder1.count;
 	             CRITICAL_REGION_QUADENCODER1_END;
		break;
	  default: tmp = 0;
	}
	return(tmp);
}
unsigned char QuadEncoder_Set( channel, value )
{
	if (channel > QUADENCODER_CHANNEL_MAX) return(0);
	switch(channel)
	{
	  case 0: CRITICAL_REGION_QUADENCODER0_BGN;
		quadencoder0.count = value;
 	             CRITICAL_REGION_QUADENCODER0_END;
		break;
	  case 1: CRITICAL_REGION_QUADENCODER1_BGN;
		quadencoder1.count = value;
 	             CRITICAL_REGION_QUADENCODER1_END;
		break;
	  default: return(1);
	}
	return(0);
}

/* 
 * Driver write supplied handler routines...
 */
void QuadEncoder0_PhyISR( void )
{
  quadencoder0.a_phase = ReadInterruptState( quadencoder0.interrupt   );
  quadencoder0.b_phase = ReadPin               ( quadencoder0.phase_b_pin );
  return;
}
void QuadEncoder0_LogISR( void )
{
long delta;

  if (quadencoder0.lastphase == quadencoder0.a_phase) return;
  quadencoder0.lastphase = quadencoder0.a_phase;

  if (quadencoder0.a_phase == 0) return;	// 1->0 transition, don't care

  delta = 1;
  if (quadencoder0.invert == 0)
  {
      if (quadencoder0.b_phase == 0)
	delta = -1;
  }
  else
  {
      if (quadencoder0.b_phase != 0)
	delta = -1;
  }
  CRITICAL_REGION_QUADENCODER0_BGN;
  quadencoder0.count += delta;
  CRITICAL_REGION_QUADENCODER0_END;

  return;
}
:
.
Just an example of what a driver writer could choose to do within the framework. They could also decide to make channel==phase a pin, i.e. channel 0 was always portb<2> or something similar.

Last edited by dcbrown : 16-05-2007 at 12:41.
Reply With Quote
 


Thread Tools
Display Modes Rate This Thread
Rate This Thread:

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

vB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Forum Jump

Similar Threads
Thread Thread Starter Forum Replies Last Post
Robot Framework lord Purity Pneumatics 3 21-01-2007 15:57
paper: NEMO White Paper: How to Host a Profitable Pasta Dinner Fundraiser KathieK Fundraising 2 27-03-2006 17:14
White Paper Discuss: AIM LOW: DODGEBALL 1 of 3 Waynep Extra Discussion 2 17-02-2006 13:46
White Paper Discuss: Comparison Paper for Teacher Involvement CD47-Bot Extra Discussion 1 13-11-2004 00:09
White Paper Discuss: Locking the Bosch 3360 Drill in low gear CD47-Bot Extra Discussion 4 05-08-2003 02:10


All times are GMT -5. The time now is 17:23.

The Chief Delphi Forums are sponsored by Innovation First International, Inc.


Powered by vBulletin® Version 3.6.4
Copyright ©2000 - 2017, Jelsoft Enterprises Ltd.
Copyright © Chief Delphi