Projector ballast bypass

I'm trying to get my projector to stay on without the lamp so I can change the bulb for an LED.
It's an NEC NP300, I've read the data from pin 1 on the ballast connector on Saleae Logic.
Unfortunately it appears to be a 24Mhz signal, this may be too high for playback on the Ardunio?
I know the projector will stay on if this 3.3V signal is present.
I have an Arduino Uno and an Arduino pro mini
So my question is
does anyone have a sketch I could try?

Your not going to get a 24MHz signal out of the Arduino(s) you have as they only clock in at 16MHz.
Maybe something like the Teensy3.1 would do this but best check to be sure first. Does the signal need to be 24MHz?

Does the signal need to be 24MHz?

I wondered that too, thinking that if I ran a capture program on the Arduino at 16Mhz and sent it back to the projector, and see if it would work.

However there are the occasional 41.67 nano second pulses, as if NEC deliberately went out of their way to stop anyone bypassing the ballast, (back in 2009 anyway, when it was released)

And more

Okay my bad, turns out I'm looking at a 2600baud serial stream (UART?) the 24Mhz sampling was overkill, plus I was getting glitches,

Here's my progress so far;

photo hosting sites

All I want to do is send this serial stream back to the projector from the Arduino (I'm using an optocoupler off a spare NP300 to keep the beamer happy with the 3.3 Volt logic level)

It's a series of 10bit bytes, 1 stop bit, no parity.
There's a few bytes at first then a regular series of 3 bytes with a varying delay of about 1 second between them.

Here's my idea for the sketch;

void setup(){

void loop(){

Serial.write(0x22D); // send this 10 bit byte
Serial.write(0x139); // send this 10 bit byte
Serial.write(0x2C1); // send this 10 bit byte

delay (1041);

Serial.write(0x20C); // send this 10 bit byte
Serial.write(0x2C1); // send this 10 bit byte

delayMicroseconds (9513);

Serial.write(0x02C); // send this 10 bit byte
Serial.write(0x20C); // send this 10 bit byte

delay (4671);

//Loop: While 1
while (1)

Serial.write(0x2C1); // first of three byte sequence
Serial.write(0x02C); // second byte of repeating sequence
Serial.write(0x20C); // third byte of repeating sequence

delay (1000);

// not bothered about the shutdown sequence, once it's on I plan on keeping it running.

Can someone convert my idea into valid Arduino code?
I'm confused on how to send a 10bit byte of 8 bit serial as I believe it has to be sent as two bytes
MSB LSB etc.
Also would I just be better off just reading the 2600 baud signal on the Arduino to a file and then writing a sketch to send it back?

It's a series of 10bit bytes, 1 stop bit, no parity.

So to be sure of this you think it's 1 start bit, 10 data bits, 1 stop bit.
Or could it be 1 start bit, 9 data bits, 2 stop bits (or 1 stop bit & 1 parity bit).

If it's not standard serial protocol then just write a little bit banging function that you pass the 10 bit number to and it toggles an output pin with the correct timing to emulate your signal.

That's the thing, I'm not sure, it's open to interpretation, a program to send the bits out would be just what I'm after.
How would I go about it though, I've tried it with digital.write and I'm not getting accurate/consistent timings, would need to be done with serial.write AFAIK?

However serial.write seems to be fixed at 8bit(data), confusing for me, and since this is a one off project I'm not wanting to get out of my depth just a little bit banging function as you mentioned sounds like the plan.

The signal looks like it could be 1 start bit , 9 data bits, 2 stop bits but as you need to send so few values repeatedly then maybe just put them into a timings table and send then that way.

As an example here is some code I wrote to send a captured wireless doorbell code so I could trigger the doorbell receiver without pressing the doorbell button.
You could turn the loop code into a function that you pass the timing array as a parameter and then call it with the three one off startup codes from setup() and then write a loop procedure to call it with the repeat the same coded every second, forever.

// High/Low microsecond timings, first value is low timing, the rest alternate high/low
const uint16_t hlUsTimings[] = {
const uint8_t hlUsSize = sizeof(hlUsTimings) / sizeof(hlUsTimings[0]);

const uint8_t outPin = 3;                         // Transmitter output pin
const uint8_t ledPin = 13;                        // LED output pin

void setup() {

void loop() {
  for (uint8_t y = 0; y < hlUsSize; y++){
    digitalWrite(outPin,!digitalRead(pinState));  // Flip the pin
    uint32_t z = hlUsTimings[y];

Can you zip up the Salea logic capture and attach it here or somewhere else people can get to it. That way I can hopefully load it in and check the results.

Thanks for the code you posted, I have attached the zip. (4.16 KB)

I'm running into problems, I have the timings of all the bytes used;

0x22Dstart[] = {2222,384,444,1212,444,384,444,384,858}; // 0x22D with start delay/low

0x22D[] = {384,444,1212,444,384,444,384,858}; // 0x22D normal

0x139[] = {798,444,798,858,798,858}; //0x22D

0x2C1[] = {384,444,382,860,1624,860}; //0x2C1

0x20C[] = {384,444,2040,444,798,444}; //0x20C

0x02C[] = {2040,444,384,444,795,445}; //0x02C

I would need to write an array for each one and then call these arrays in the code, add any delays, and loop the three byte repeating sequence.

Thanks for the code you posted, I have attached the zip.

Just tried to have a quick look at the zip data but for some reason it won't load into my LLC software. Maybe your using a newer version than me. I will try and look again tomorrow at home.

I was on version 1.2.08, now on 1.2.10 and my logic save loads ok on that.
Can re upload new zip if necessary

I was on version 1.2.08, now on 1.2.10 and my logic save loads ok on that.

I have version 1.1.15 installed so that's probably the cause.

You don't seem to have enough high/low transitions in the timing arrays you created but as I cannot read the Salea file I cannot be sure.
Attached is a possible means to do the job but you would need to check its output and compare to what you want.
This would easily run on a smaller AVR like the Tiny85 if you needed to reduce size.

sketch_jul15a_Projector.ino (1.28 KB)

Okay, I downloaded the latest Saleae software onto my other PC (I don't want to risk mixing versions between work and home) and the file loads okay now.
Checking it and I have to disagree with your 2600,10,N,1 serial protocol assumption as it looks more like 2400,9,N,1 to me.
This opens another option to you as you could find a serial library that supports 9 bit data and just use that to send the byte data or just continue down the bit banging route.

Checking it and I have to disagree with your 2600,10,N,1 serial protocol assumption as it looks more like 2400,9,N,1 to me.

You are absolutely right, after adjusting the analyser settings in Saleae to 2400,9,N,1
all looks 100%.

I'll have a go with your code first of all, and like you point now there's the option for using a 9bit library.
As this is a one off project I'm more than happy to stick with bit banging code you posted.

Thanks for your help,

I noticed my delays were off, I have sorted these, now when I run the code I am getting the first bit of each byte (or start byte of each byte sequence) as a state change, but after this first high I am not getting the remaining changes.
It's as if the first number in the array is being read, but not the following numbers.
So it's almost there if I could find out why the array is not being read?

Try the below code.
You will need to adjust the timing arrays to match you findings but it now does all the values in an array and not just the first one over.

sketch_jul15a_Projector.ino (1.66 KB)

Have updated your code with my new timings.
Had to experiment a little with the numbers to get as close a match to the original signal as possible as this seems quite critical to the projector.
Your code works 100%, no issues at all with that:-)
The projector now starts up as it would when the bulb and ballast are good, albeit with the ballast disconnected and the bulb removed.
Where I'm running into problems is with the repeating sequence, there seems to be more to this than just a regular pulse, the timings possibly.

I have added more lines of code to try and emulate the timings of the original;


xSend 3 bytes


xSend 3 bytes

etc,etc (May have to run original again for longer to check for repetition, can't see any so far)

before I did this it was getting to this point and cutting off, now it does run for longer, however it is still cutting off so I am looking at running the SA again on the complete projector for a closer look.
I have a number of options here, suffice to say I'm fairly confident the projector is very close to staying on.
I may even do what I did before and run it next to the good projector with the ballast wire and gnd wires linked over to check what happens on a longer run time etc.

As the signal your trying to emulate is a serial signal it might have both the RX & TX connected, and maybe the module/thing that is sending it only does so when requested by the ballast?
might be worth looking for a return serial signal (or maybe something as simple as a line pulsed high/low) from the ballast that is a request signal.

As the signal your trying to emulate is a serial signal it might have both the RX & TX connected

That's what it's doing, I'm going to have to reorganise my setup and take another look, not had a chance to do much at the moment.

There's a 2400 baud signal being sent out by the projector to the ballast, will write back as soon as I've got an idea on the bytes being sent.

Sorry for the delay on this, after moving to a more practical area to continue with this project I am getting plagued with noise on the signal analyser, however after applying a glitch filter to the data I can confirm it is indeed just a single pulse that is being sent from the projector to the ballast.
I'm thinking that some sort of amendment to the code like this might be worth a try,

if DigitalRead = HIGH then

xSend(x22D, s22D);
xSend(x139, s139);
xSend(x2C1, s2C1);

if DigitalRead = HIGH then

xSend(x20C, s20C);
xSend(x2C1, s2C1);

if DigitalRead = HIGH then

xSend(x02C, s02C);
xSend(x20C, s20C);