Jump to content
Sign in to follow this  
RobG

LaunchPad and fun with the flash (strobe & slave trigger)

Recommended Posts

Last weekend I was doing a little photo shoot and I was in need of extra flash source. I have an old Nikon SB-28 laying around so I figured I could use it if I had a slave trigger. Sure I can buy one from Amazon for <$10 (dumb one) or build one using 555 (which would ignore TTL pre-flash,) but why not go one step further and use LaunchPad.

 

Step 1, build strobe light.

This is pretty simple, just add opto-isolator and write short program.

FL1 connects to the center pin of the hot shoe, FL2 to the side.

If you need a hot shoe, you can get one cheap from BHPhotoVideo.com, just search for AS-E900 (or SK-E900, you'll get nice bracket as a bonus!)

post-197-135135493645_thumb.png

#include 

unsigned int sw = 0;

void main(void)
{
 WDTCTL = WDTPW + WDTHOLD;                 // Stop WDT

 P1OUT |= 0x01; 							// Port P1.0 will be used to trigger flash
 P1DIR |= 0x01;

 CCTL0 = CCIE;                             // CCR0 interrupt enabled
 CCR0 = 20000;								// 
 TACTL = TASSEL_2 + MC_1 + ID_3;           // SMCLK, upmode

 _bis_SR_register(LPM0_bits + GIE);        // Enter LPM0 w/ interrupt
}

// Timer A0 interrupt service routine
#pragma vector = TIMERA0_VECTOR
__interrupt void Timer_A (void)
{	
 if(sw = ~sw) {				// Flash every other interrupt
 	P1OUT |= 0x01;
 } else {
 	P1OUT &= ~0x01;
 }						
}


 

Step 2, add S2 to control speed.

 

#include 

unsigned int counter = 0;
unsigned int resetCounterAt = 100;
unsigned int pressedS2 = 0;

// BITn of switchReady and switchStatus corresponds to Port P1.n
unsigned int switchReady = 0x0; // When BITn is 0, means switch is unstable H->L or L->H
unsigned int switchStatus = 0x0; // Pressed or released

void main(void)
{
 WDTCTL = WDTPW + WDTHOLD;                 // Stop WDT

 P1OUT |= BIT0; 							// Port P1.0 will be used to trigger flash
 P1DIR |= BIT0;

 P1DIR &= ~BIT3;							// Port P1.3 as input
 P1OUT |= BIT3;							// Pull up resistor
 P1REN |= BIT3;							// Enable pull up resistor

 CCTL0 = CCIE;                             // CCR0 interrupt enabled
 CCR0 = 1250;								// Approx. 10ms 
 TACTL = TASSEL_2 + MC_1 + ID_3;           // SMCLK/8, upmode

 // we will use USI as a delay
 USICTL0 |= USIMST; 						// SPI Master
 USICTL1 |= USICKPH + USIIE;               // Counter interrupt
 USICKCTL = USIDIV_4 + USISSEL_2;          // SMCLK/16
 USICTL0 &= ~USISWRST;                     // USI released for operation

 _bis_SR_register(LPM0_bits + GIE);        // Enter LPM0 w/ interrupt
}

// Timer A0 interrupt service routine
#pragma vector = TIMERA0_VECTOR
__interrupt void Timer_A (void)
{		
switchReady = ~(P1IN ^ switchStatus);
switchStatus = P1IN;
if(switchReady & BIT3 && !(switchStatus & BIT3)) {

		if(!pressedS2) {	// Update only once
			resetCounterAt -= 20;
			if(resetCounterAt < 20) {
				resetCounterAt = 100;
			}
			pressedS2 = 1;	// Set pressedS2 flag
		}
}

if(switchReady & BIT3 && switchStatus & BIT3) pressedS2 = 0; // S2 released, clear pressedS2 flag

counter++;
if( counter > resetCounterAt ) {
	counter = 0;
 		P1OUT |= BIT0;	// Flash on interrupt
	USICNT |= 8;	// Start delay	
}

}

// USI interrupt service routine
#pragma vector = USI_VECTOR
__interrupt void USI_TXRX (void)
{
 USICTL1 &= ~USIIFG;	
 P1OUT &= ~BIT0;		// Clear P1.0
}

 

 

Step 3, add phototransistor to make it work as a slave trigger

Since 70's are long gone, I don't think I will have any use for the strobe, so we will add phototransistor to make it work as a dumb slave trigger

post-197-135135494289_thumb.png

#include 

void main(void)
{
WDTCTL = WDTPW + WDTHOLD;				// stop WDT

P1OUT &= ~BIT0;							// port P1.0 will be used to trigger flash
P1DIR |= BIT0;

P1DIR &= ~BIT7;							// port P1.7 input
P1IE |= BIT7;							// P1.7 interrupt enabled
P1IES &= ~BIT7;							// P1.7  lo/high edge
P1IFG &= ~BIT7;							// P1.7 IFG cleared

_bis_SR_register(LPM0_bits + GIE);		// LPM0 with interrupts
}

// Port 1 interrupt service routine
#pragma vector=PORT1_VECTOR
__interrupt void Port_1(void)
{ 
P1IE &= ~BIT7;							// disable P1.7 interrupt
P1IFG &= ~BIT7;							// P1.7 IFG cleared
P1OUT |= BIT0;							// flash on interrupt
_no_operation();						// 1 cycle delay, just in case
//__delay_cycles(50);					// if there are problems wih trigger, longer delay may be needed
P1OUT &= ~BIT0;							// clear P1.0
P1IE |= BIT7;							// enable P1.7 interrupt
}

 

 

Step 4, add delay to make it work with TTL pre-flash

Since in TTL mode main flash is not the first one, we have to add delay to ignore pre-flash(s)

 

As it turns out, this is not an easy task. Pre-flashes are far more complicated than I thought and simple delay may not work.

So this is my first stab at it. I am simply ignoring first flash and triggering the slave on second one. If there's no second flash within 200ms, counter is reset. This setup works with my D80 and SB-28 in TTL mode except when flashing too close to detector.

 

When I find some extra time, I will improve this thing or hopefully someone else will contribute.

 

#include 

unsigned char mainFlash = 0;				// 0 indicates pre-flash, 1 main flash

void main(void)
{
WDTCTL = WDTPW + WDTHOLD;				// stop WDT

P1OUT &= ~BIT0;							// port P1.0 will be used to trigger flash
P1DIR |= BIT0;

P1DIR &= ~BIT7;							// port P1.7 input
P1IE |= BIT7;							// P1.7 interrupt enabled
P1IES &= ~BIT7;							// P1.7  lo/high edge
P1IFG &= ~BIT7;							// P1.7 IFG cleared

CCTL0 = CCIE;							// CCR0 interrupt enabled
CCR0 = 0;								// timer idle 
TACTL = TASSEL_2 + MC_1 + ID_3;			// SMCLK/8, up mode

_bis_SR_register(LPM0_bits + GIE);		// LPM0 with interrupts
}

// Port 1 interrupt service routine
#pragma vector=PORT1_VECTOR
__interrupt void Port_1(void)
{ 
P1IE &= ~BIT7;							// disable P1.7 interrupt
P1IFG &= ~BIT7;							// P1.7 IFG cleared
if(mainFlash) {							// this is a main flash, trigger slave
	P1OUT |= BIT0;						// trigger slave
	_no_operation();					// 1 cycle delay, just in case
	P1OUT &= ~BIT0;						// clear P1.0
	mainFlash = 0;						// clear flag
	CCR0 = 0;							// no need for timer
} else {								// pre-flash
	CCR0 = 25000;						// start timer, approx. 200ms
	mainFlash = 1;						// set flag
}
	P1IFG &= ~BIT7;						// P1.7 IFG cleared
	P1IE |= BIT7;						// enable P1.7 interrupt
}

// Timer A0 interrupt service routine
#pragma vector = TIMERA0_VECTOR
__interrupt void Timer_A (void)
{	
if(mainFlash) {							// for some reason, there was no main flash
	mainFlash = 0;						// reset flag
	CCR0 = 0;							// no need for timer
}
}

Share this post


Link to post
Share on other sites

Just wanted to poke my head in and say that I am excited for this project. I love photography and would love to find some time to work on some kind of related project with my Nikon (and other goofy little cameras). Can't wait to see more! And thank you for the link for the hot shoe!

Share this post


Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Sign in to follow this  

×
×
  • Create New...