Updates:
[2018-04-27] - Small updates
Last time I have changed a standard Ford 6000CD radio to a new 1din Kenwood one because of poor sound quality and lack of USB port in the first one (driving with a bunch of cd's and switching during it is not very comfortable).
After that I had a non working steering wheel remote because of incompatibility with Kenwood radio remote control.
So I decided to make an adapter that will be connected between Ford remote steering wheel and my radio. Of course you can find a lot of adapters in the market, but they are not so cheap (about 36 € and up) and as you see you can do it yourself for a much more acceptable price (3-4 €).
So lets get started.
My howto is made for a Ford steering wheel remote and Kenwood (mine is a KMM-122Y model from 2017) radios with a remote wire like on a pictures below. It could be helpful for other resistance based steering wheel controls. In that case you have to change a ADC voltage reading part.
![]() |
![]() |
| Figure 1. Ford steering wheel control | Figure 2. Kenwood remote cable |
What stuff we will need to make it:
Ford steering wheel controls are based on a resistance switch (buttons switch on different resistances) as you can see on Figure 3.
![]() |
| Figure 3. Steering wheel control schematic |
What we need to do is to make a voltage divider with a Ford steering remote as one of the resistances, put some voltage on it and read values on a microcontroller ADC.
![]() |
| Figure 4. Voltage divider schematic |
In a voltage divider (Figure 4) I used a 1.47 kΩ resistor because it should give pretty nice results with the remote resistances and a 5V signal.
In the place of resistor R5 should be connected Ford steering wheel control.
In a Table 1 I put measurements of resistances in my steering wheel control and related voltages on a voltage divider.
| Function | Resistance [Ω] | Voltage on a divider [V] |
|---|---|---|
| NC | 5040 | 3.87 |
| SEL | 1050 | 2.08 |
| SEEK- | 562 | 1.38 |
| SEEK+ | 301 | 0.85 |
| VOL+ | 147.8 | 0.46 |
| VOL- | 54.4 | 0.18 |
Whole adapter schematic is shown on Figure 5. As you can see it's quite simple.
![]() |
| Figure 5. Adapter schematic |
In the pace of J3 there may be a reset button.
Steering wheel control pins in the FAKRA connector are shown on Figure 6 (pins 6 and 8 on B part).
![]() |
| Figure 6. Ford FAKRA connector |
On the socket side (black one on the bottom right side) you have to connect wires as shown on Figure 7. This connections were only for testing purpose, on a final product you should make more solid connection that would not fall out of socket when driving.
![]() |
| Figure 7. Steering wheel remote resistance connector |
It turns out that Kenwood radio remote protocol is a NEC protocol, same as in IR remotes. Only inverted and with no carrier. Thanks to that it is not a resistance based one, we don't need any digital potentiometer to generate resistances as it is in some radios.
NEC protocol transmission data info:
How the transmission works:
![]() |
| Figure 8. NEC protocol message format |
Now we need to generate in microcontroller a digital NEC signal related to a pressed key. This signal through a microcontroller digital output (PB1) will control a Q1 NPN transistor. Transistor will switch signal on a Kenwood remote line.
Kenwood address code: 0xb9
Command codes:
| Remote | Command | Remote | Command | Remote | Command |
|---|---|---|---|---|---|
| 0 | 0x00 | 8 | 0x08 | volume + | 0x14 |
| 1 | 0x01 | 9 | 0x09 | volume - | 0x15 |
| 2 | 0x02 | track - | 0x0a | mute | 0x16 |
| 3 | 0x03 | track + | 0x0b | tuner | 0x1c |
| 4 | 0x04 | rev | 0x0c | tape | 0x1d |
| 5 | 0x05 | ff | 0x0d | cd | 0x1e |
| 6 | 0x06 | play/pause | 0x0e | cd-md-ch | 0x1f |
| 7 | 0x07 | source | 0x13 | dnpp | 0x5e |
Data fomat example for signal volume+ :
| Original data | |||
|---|---|---|---|
| Addr | ~Addr | Comm | ~Comm |
| 0xB9 | 0x46 | 0x14 | 0xEB |
| 10111001 | 01000110 | 00010100 | 11101011 |
| LSB | |||
| 0x9D | 0x62 | 0x28 | 0xD7 |
| 10011101 | 01100010 | 00101000 | 11010111 |
Final frame:
This code you need to send (using a NEC protocol with start and end signals) to a Q1 transistor.
And that's all. As you see, you can make such adapter about 10 times cheaper then a market one (without sockets, case and cables).
Maybe I will update this howto, there can be added repeat commands in the microcontroller code.
Below you can get a C code for microcontroller (Atmega8).
pilot1.c
/* pilot1.c * Ford SWC to Kenwood radio (NEC protocol) adapter * Author: Michal Babik <michalb1981@o2.pl> */ // Steering wheel remote resistances with a half values to use // in adc as a compare values // // REMOTE KEY RESISTANCE ADC VAL KEY VAL // NC 5040.0 198 0 // 152 // SEL 1050.0 106 1 // 88 // SEEK - 562.0 70 2 // 56.5 // SEEK + 301.0 43 3 // 33 // VOL + 147.8 23 4 // 16 // VOL - 54.4 8 5 // 4 #define F_CPU 1000000UL #include <avr/io.h> #include <util/delay.h> #include <inttypes.h> #define sbi(x,y) x |= _BV(y) //set bit - using bitwise OR operator #define cbi(x,y) x &= ~(_BV(y)) //clear bit - using bitwise AND operator #define tbi(x,y) x ^= _BV(y) //toggle bit - using bitwise XOR operator #define is_high(x,y) (x & _BV(y) == _BV(y)) //check if the y'th bit of //register 'x' is high ... test if its AND with 1 is 1 /* _BV(a) is a macro which returns the value corresponding to 2 to the * power 'a'. Thus _BV(PX3) would be 0x08 or 0b00001000 */ #define NEC_TIME 562.5f // base time in us #define NEC_LINE_HI 1 // pin value to set line high #define NEC_LINE_LO 0 // pin value to set line low #define NEC_PORT PORTB // kenwood radio remote pin port #define NEC_PIN PB1 // kenwood radio remote pin #define NEC_DDR DDRB // kenwood radio remote direction #define ADC_SAMPLES 50 // number of samples to read pressed key // ---------------------------------------------------------------------------- uint8_t adc_read (void); uint8_t check_pressed_adc_value (uint8_t adc_v); void couple_more_samples (uint8_t *k_pressed); void nec_set_pin (uint8_t hilo); void nec_base (uint8_t hm, uint8_t lm); void nec_start (void); void nec_finish (void); void nec_one (void); void nec_zero (void); void nec_8bit (uint8_t *bits); void nec_data (uint8_t addr, uint8_t dta); // ---------------------------------------------------------------------------- int main (void) { /* uint8_t k_codes[] = {0x00, // 0 0x01, // 1 0x02, // 2 0x03, // 3 0x04, // 4 0x05, // 5 0x06, // 6 0x07, // 7 0x08, // 8 0x09, // 9 0x0a, // track - 0x0b, // track + 0x0c, // rev 0x0d, // ff 0x0e, // play / pause 0x13, // source 0x14, // volume + 0x15, // volume - 0x16, // mute 0x1c, // tuner 0x1d, // tape 0x1e, // cd 0x1f, // cd-md-ch 0x5e // dnpp }; */ uint8_t ken_code = 0xb9; uint8_t key_codes[] = {0x00, 0x13, 0x0a, 0x0b, 0x14, 0x15}; uint8_t key_pressed = 0; uint8_t prev_pressed = 0; NEC_DDR = _BV (NEC_PIN); // Communication pin as output cbi (NEC_PORT, NEC_PIN); // set nec pin low ADMUX= (1 << REFS0) | (1 << ADLAR); //AVCC, left align // only 8 highest adc bits will be used, there is no need for a 10 bit precision ADCSRA= (1 << ADEN) | (1 << ADPS2); //ad enable, prescaler 16 (62.5kHz) while (1) { key_pressed = check_pressed_adc_value (adc_read ()); if (key_pressed != prev_pressed) { if ((key_pressed > 0) && (prev_pressed == 0)) { couple_more_samples (&key_pressed); nec_start (); nec_data (ken_code, key_codes[key_pressed]); nec_finish (); } prev_pressed = key_pressed; } } return 0; } // ---------------------------------------------------------------------------- uint8_t adc_read (void) { //Start Single conversion ADCSRA |= (1 << ADSC); //Wait for conversion to complete while (!(ADCSRA & (1 << ADIF))); //Clear ADIF by writing one to it ADCSRA |= (1 << ADIF); return ADCH; // only 8 highest bits } // ---------------------------------------------------------------------------- uint8_t check_pressed_adc_value (uint8_t adc_v) { uint8_t key_val = 0; // nothing (0) if (adc_v < 152) { key_val++; // SEL (1) if (adc_v < 88) { key_val++; // SEEK - (2) if (adc_v < 57) { key_val++; // SEEK + (3) if (adc_v < 33) { key_val++; // VOL + (4) if (adc_v < 16 && adc_v > 4) { key_val++; // VOL - (5) } } } } } return key_val; } // ---------------------------------------------------------------------------- void couple_more_samples (uint8_t *k_pressed) { // take couple more samples and create a small histogram of // of values, find which key has most counts uint8_t key_rep[] = {0, 0, 0, 0, 0, 0}; key_rep[*k_pressed]++; for (uint8_t i=0; i<ADC_SAMPLES; ++i) { key_rep[check_pressed_adc_value (adc_read ())]++; } uint8_t max_v = 0; for (uint8_t j=1; j<6; ++j) { if (key_rep[j] > max_v) { max_v = key_rep[j]; *k_pressed = j; } } } // ---------------------------------------------------------------------------- void nec_set_pin (uint8_t hilo) { if (hilo) sbi (NEC_PORT, NEC_PIN); // set high else cbi (NEC_PORT, NEC_PIN); // set low } // ---------------------------------------------------------------------------- void nec_base (uint8_t hm, uint8_t lm) { nec_set_pin (NEC_LINE_HI); for (uint8_t i=0; i<hm; ++i) _delay_us (NEC_TIME); nec_set_pin (NEC_LINE_LO); for (uint8_t i=0; i<lm; ++i) _delay_us (NEC_TIME); } // ---------------------------------------------------------------------------- void nec_start (void) { nec_base (16, 8); // 9ms - 1, 4.5ms - 0 } // ---------------------------------------------------------------------------- void nec_finish (void) { nec_base (1, 0); // 562.5us - 1, 0 - 0 } // ---------------------------------------------------------------------------- void nec_one (void) { nec_base (1, 3); // 562.5us - 1, 1.6875us - 0 } // ---------------------------------------------------------------------------- void nec_zero (void) { nec_base (1, 1); // 562.5us - 1, 562.5us - 0 } // ---------------------------------------------------------------------------- void nec_8bit (uint8_t *bits) { for (uint8_t i=0; i<8; ++i) { if (*bits & 0x01) nec_one (); else nec_zero (); *bits = *bits >> 1; } } // ---------------------------------------------------------------------------- void nec_data (uint8_t addr, uint8_t dta) { uint8_t naddr = ~addr; uint8_t ndta = ~dta; nec_8bit (&addr); nec_8bit (&naddr); nec_8bit (&dta); nec_8bit (&ndta); } // ----------------------------------------------------------------------------
References: