AC-CDI 16F628 v5.4

This version is discontinued.
Consider to build v7 instead!

16F84 or 16F628 based digital ignition.



The part CDI (Capacitive Discharge Ignition) is described in the page “fixed ignition“.
The PIC receives the pulses from the 36° sensor and:

  • delay this pulse at low RPM.
  • retransmits this pulse immediately at high RPM
  • between these 2 extremes, the PIC delays the pulse according to the curve programmed.

Let us see this in details…

Pulses coming from the 12° pickup directly trigger the SCR via D7 R7 C10.
(If the bike has only one pickup, connect it to the 36° input and leave the 12° input unconnected)

At the same time, the pulses coming from the 36° pickup are limited to 5 volts by the Zener D9 then drive the PIC (pin 10).
( The PIC input detect a tension higher than 1.8 Volts. That mean that pickup signal must be > 2 volts)

At each good pulse received from sensor 36°, the green LED D1 blink.

A delayed pulse, according to the programmed advance curve, is available on pin 8 and trigger the SCR T1 via D2,R7,C10.

A +5V output is available at RA2 (in example to drive a LED) when the maximum RPM is reached.

RA3 provide a inverted signal (revcoil)

Ways of the 12 and 36deg signals:

There are 2 sparks by revolution: one before the TDC
(from the 36deg pickup)
and another at TDC (from the 12deg pickup – if connected)

This second spark is supernumerary.


Max Ignition Frequency 730Hz.

Warning! If there is one spark lose, the max rpm is divided by 2

IE: 88000tr/mn with ONE spark by rotation and 44000tr/mn with TWO sparks by rotation (as on the XT)


Compatibility with others pickups.

This ignition need either
2 pickups:
or only one pickup
pickup at 36° BTDC:
and 2nd pickup at 12° BTDC:
Positive than negative:
But not negative than positive!

If your pickup signal is negative than positive (ie: Honda,Suzuki…), you must invert the trigger!

You can build this interface to invert the negative pulse and suppress the postive one.


Main functions

Easy kickstart

At the beginning of the program, the advance is fixed at minimum:

movlw 0xff ; rpmhi = FF initially
movwf rpmhi


Ignition Coil protection

After 0,5 seconde without pulses, the PIC consider
that the engine is stopped, and reinitialise the ignition.

; if rpmcount > 1400h, 5120 x 100us=0.5 Sec, then
it is assumed that the

; motor has stopped. Reinitialize system.
movlw 0x14
subwf rpmhi,W
btfsc STATUS,Z ;
rpmhi - 14 = 0 ?

goto start ; yes

RPM Limitation:

Over 8000 RPM, the delay between the pickup signal and the spark is
fixed to 0ms

maxadv clrf rtdset ; > 8000RPM retard value = 0ms
bsf rpmmax ; turn led on

Under 1000 RPM, the delay between the pickup signal and the spark
is fixed to 5ms

maxret movlw 31h ; < 1000RPM
movwf rtdset ; retard value = 31h (~4.9ms)
bsf rpmmax ; turn led on

(You can set another RPM limitation in your 131 advance values too)

Advance calculation:

Between the maximum and the minimum
RPM, the PIC measure the duration between 2 pick up pulses [the number
of 100us (hundred microsecondes) period between two pulses] to deduce
the speed engine.
According to the speed, the PIC calculate the position in the map.

caladv movlw d'74' ; rpmhi/lo - 74
subwf rpmlo,F ; rpmlo = rpmlo - 74
btfss STATUS,C
decf rpmhi,F

; divide result by 4

rrf rpmhi,F
rrf rpmlo,F ; / 2
rrf rpmhi,F
rrf rpmlo,F ; / 4

The value of the delay (variable retlw)
is extracted from a table of 131 values

map org h'200' ; store map at 200h
addwf PCL,1 ; add W + PCL
; *********** INSERT YOUR OWN VALUES HERE *******************
retlw 31h ;4,9ms 1000rpm
retlw 30h ;4,8ms 1016rpm
retlw 2Fh ;4,7ms 1023rpm

The choice between 2 maps is made by the jumper.
no jumper = map N°1 at h200
jumper on = map N°2 at h300

btfss table ; is table select low?
bsf PCLATH,0 ; yes,then select table N°2 at h'300'

The PIC receives the pulse from the sensor at 36 deg.
It waits until a time = retlw *
100us, then after this delay, a pulse (fixed at 2ms) is
sent to the thyristor.

;****************** YOU CAN MODIFY THE DWELL VALUE BELLOW ********
movlw .20 ; 20 X 100uS = 2mS
movwf dwell ; set dwell time

Duration of the spark:

The duration of the spark cannot be adjust on a CDI, it depend of the capacitor value and the coil value. After all we can adjust the duration of the pulse that trigger the thyristor. This pulse duration (called: dwell time) can be change for some slow thyristor but without impact on the spark duration:

A reverse output is available pin8 to drive a revmeter:

The pic measure the duration between 2 pick up pulses. So it’s able to calculate the engine speed.
If the speed is 1000RPM ,the PIC search into the 131 lines for the FIRST line.

At 1000RPM, the duration between 2 pulses is 60ms with one wasted spark.
(without wasted spark the duration would be 120ms)
Convert in microsecond: 60ms = 60.000us

I said (see higher) that the PIC count in 100us loops.
At 1000RPM, the PIC count 600 loops of 100us between 2 pickup pulses.
Than the pic use the formula :

;        rpmhi|lo count - 74
; 131 -  ___________________
;            4

The formula become:

;       600 - 74
;131 - _________ = 0
;        4

The result of the formula is “0”, so the Pic take the very first line of the map (1+0)
the first line return:   retlw 31h     ;4,9ms   1000rpm
(As you know it: semicolon prefix a comment and h mean Hexadecimal)
31 (hexadecimal) = 49 (decimal)

So the pic will wait 49 loops of 100microseconds.
49 x 100useconds = 4900useconds = 4,9 milliseconds
then the PIC will wait 4,9 ms after the pickup pulse, before providing a spark.
If the speed is 1015RPM ,the PIC search into the 131 lines for the SECOND line.
Why again!
At 1015RPM, the duration between 2 pulses (with one wasted spark) is 59,1ms
Convert in microsecond: 59.1ms = 59100us

We knows that the PIC count in 100us loops.
At 1015RPM, the PIC count 591 loops of 100us between 2 pulses
Than the pic use the formula witch become:

;     591 - 74
;131 - --------
;        4

;      517
;131 - ---
;      4

;131 - 129,25 = 1,75 = 1 (we use the integer)

The result of the formula is “1”, so the Pic take the second line of the map (1+1)
It get:   retlw 30h

30 (hexa) = 48 (decimal)

The pic will wait 48 loops of 100microseconds.
48 x 100useconds = 4,8 milliseconds
so the PIC will wait 4,8 ms after the pick up pulse, before providing a spark.

And so on until 8000RPM and the LAST line where the pic get retlw 0h
Meaning that it must wait 0 x 100us = no delay
so the PIC providing a spark immediately.
Even if you write “retlw 0h” the lower retard is 100us (0.1ms). That mean you cannnot have a spark EXACTLY at the same moment of the pickup pulse)

Another calculation example:
At 8000RPM, the duration between 2 pulses (with one wasted spark) is 7,5ms
Convert in microsecond: 7,5ms is 7500us
At 8000RPM, the PIC count 75 loops of 100us between 2 pulses
Using the formula:

;     75 - 74
;131 - -------
;        4

;      1
;131 – —
;      4

;131 – 0,25 = 130,75 = 130 (integer part)

The pic get the number of line (130+1)=131. The last line

Flow Diagram:

Here is a flow chart that describe the software.


The curve is thus defined by 131 points, authorising a tuning. But the accuracy is rough:
+/- 1 deg at 1660tr/mn
+/- 5 deg at 8330tr/mn
This low precision is due to the 100us step, “the measuring unit” used for measuring the duration between 2 pulses and to set the delay before the spark.
Those durations are counted in 100us units.
100us unit is small enough at low RPM but is not at high RPM!
This value is a compromise for low and high RPM.

ie: a 8300rpm, 30° mean 0.026ms while 35° mean 0.029ms, and both value are rounded to 0.03ms (multiple of 100us)

A 10us unit would be more accurate but in another hand, the table would be ten time larger, and would overflow the 8bits counter capacity at low RPM…

Changing the quartz will not improve the precision either. 4MHz is fast enought, to replace it by a 8Mhz crystal will not improve the accuracy.

This is the biggest change between PCM5.4 and PCM6.4: the software is different so the accuracy reach 0.7 deg


How to change the curve

2 ways: manualy or with the help of a excel sheet.


To modify the delay value, you can alter the hexadecimal values directly into the map


Supposing that you want to wait during 7.9ms between the pickup pulse and the spark at 1000rpm:

  • 7.9ms = 79 loops of 100us
  • use a scientific calculator to convert 79 into hexadecimal value:
    ie: 79 (decimal) = 4F (hexadecimal)
  • replace  retlw 31h
    4,9ms 1000rpm

map org h'200' ; store map at 200h
addwf PCL,1 ; add W + PCL
; *********** INSERT YOUR OWN VALUES HERE *******************
retlw 31h ;4,9ms 1000rpm
retlw 30h ;4,8ms 1016rpm
retlw 2Fh ;4,7ms 1023rpm
retlw 2Fh ;4,7ms 1030rpm

  • by  retlw 4Fh

    ; 7,9ms 1000rpm

The map is now:

map org h'200' ; store map at 200h
addwf PCL,1 ; add W + PCL
; *********** INSERT YOUR OWN VALUES HERE *******************
retlw 4Fh ;7,9ms 1000rpm
retlw 30h ;4,8ms 1016rpm

etc etc….

Or with the help of this excel sheet:

Please look at the Tutorial

Create your own curve with this Excel 2003 sheet :

This sheet use

DECHEX (french)
or DEC2HEX (english,greek,finnish,portuguese)
or DEC.N.HEX (dutch,nl)
function providing by the Analysis toolpak.

[ sweeden ] = “DEC.TILL.HEX”
[ spanish ] = “DEC.A.HEX”

You may install the Analysis
and Solver by clicking on the Tools menu and selecting Add-Ins.
If the Analysis ToolPak is not listed in the Add-Ins dialog box, click Browse and locate the drive, folder name, and file name for the Analysis ToolPak add-in, Analys32.xll – this is usually located in the Microsoft Office\Office\Library\Analysis folder – or run the Setup program if it isn’t installed (you will probably need your Microsoft Office CD-ROM for this).
Select the Analysis ToolPak and Solver check boxes and click OK.

If it doesn’t work,  give the working of the function DEC2HEX a try. In a new cell, write:
=DEC2HEX(24)   does it work?

If yes, “refresh” the cell F17
(copy the formula from F17, delete it, than paste it in F17)
to force Excel to calculate the formula again.

(It seem that when excel got a error, it doesn’t calculate it anymore)

excel file


  1. Enter the position of the pick up into cell

    (ex: 32 BTDC)
  2. Enter the RPM limitation into cell D8
    (ex: 6200)
  3. Enter the 131 advance values that you want into column C
    (ie: 8 for 500RPM     8,7 for 625RPM and so on…)
  4. Edit the curve with the “graphic map” tab: point and select one value then move it up or down
  5. You can move the entire curve up or down by entering a “shift” value into cell D10
  6. Once the curve is draw, select and copy the 131 blue values beginning by retlw ….. (column E)
  7. Edit the source file .ASM with a good editor like ConTEXT (freeware)
  8. Paste this 131 lines beginning by retlw, in the map

  9. map org h'200' ; store map at 200h
    addwf PCL,1 ; add W + PCL
    ; *********** INSERT YOUR OWN VALUES HERE *******************
    retlw 31h ;4,9ms 1000rpm
    retlw 30h ;4,8ms 1016rpm
    retlw 2Fh ;4,7ms 1023rpm
    . . . .etc etc . . . . . .
    retlw 0h ;0ms
    ; *********** END OF YOUR OWN VALUES *******************
    retlw 31h ;in case of overlap
  10. Save the file .ASM


Extra advance:

It’s possible to get more advance without changing the pickup position

What is “Extra advance”


PIC programming.

  1. Compile the .ASM file with MPASMWIN.exe then:
    1. Choose the PIC: 16F84,16F628, 16F628A according to the .ASM used.
    2. Browse and select the .ASM file (ie: C:\cdi\bikeign.ASM)
    3. Assemble the file (= transform to .HEX according to the processor type).
    4. Compiled file is available at C:\cdi\bikeign.HEX
  2. Insert your PIC in a programmer.
    (I bought a “USB DIP PIC Microcontroller Development Programmer ICSP” for 10€ on Ebay)
  3. Transfer .HEX file in the PIC with ICPROG
  4. Insert your PIC on the ignition board.

On animation below, one can see (in white), the signal coming from the pickup (connected to PIC input pin10)
and the signal for the SCR (PIC output, between D2 and R9) at various speeds between 1300rpm to
6000rpm :

scale (5ms/div 2v/div)

We see:
At high rpm, the output signal is provided at the same time as the
pickup signal, therefore before the TDC.
at low rpm, the output signal is provided after the input signal,
therefore at the TDC.



for XT400-550(2600-6500rpm)
for XT600(1920-7320rpm)
for SR500(1920-7320rpm)
for 2 strokes(3170-10900rpm)
for 2 strokes(3446-13020rpm)



PIC16F84 + quartz


Source 16F84
PIC16F84 + quartz


Source 16F84
PIC16F628 no quartz


Source 16F628
PIC16F628A no quartz


Source 16F628A

(From PIC16F84 to PIC16F628)



PCM5.4 Schema PCB Componants Part list Eagle Files
CDI for
Schema.PDF circuit.PDF componants.PDF liste.TXT SCH+BRD


Printed Circuit Board.

Warning: PCB for version 5 is different than the one for v6 !
Zoom Zoom



Zoom Zoom

Zoom Zoom

pin 3 +12Vcc (battery) brown
pin 2 spark coil orange
pin 1 Alternator red
pin 4 Kill switch white/black
pin 8 12° pickup white/green
pin 7 36° pickup white/red
pin 5 pickup common ground green
pin 5 CDI ground black
pin 6 alternator ground brown


Revue Technique



  • Remove the PIC of its support.
  • Take out the spark plug of the engine and connect it to a good metal part of the bike frame.
  • Just connect the CDI to the alternator.
    (Don’t connect the +12v, the sensor and the kill switch)
  • Kick start several times to charge the big condensator C11.
  • Measure the tension between Anode (+) and Kathode (-) of thyristor T1. You must get around 150Vdc. (Voltage is slowly decreasing because condensator C11 is getting decharge in the voltmeter…)
    Test point
  • Measure, then wait 30sec, then measure again: the voltage should not drop while the multimetre is removed.
  • Kick several times to reload the big condensator C11.
  • Touch the 12deg input with a wire connected to the +12vdc battery, to trigger the SCR.
  • You must see a blue spark at the spark plug.
  • Connect all the wires from the pickup.
    (But don’t connect the +12v and don’t connect the kill switch)
  • Kick, the 12deg pickup must provide a pulse each
    turn, this pulse trigger the SCR T1 through D7, R9, C10 and produce a spark.
  • Insert the PIC in its support, in the right way!. Plug the +12v power in.



This ignition fitting a scooter:

Advance regulation view in oscilloscope:


  • Version 1.0:
    • Initial release.
  • Version 1.1:
    • [hard.] U3D and U3B inversion to make the PCB easier.
    • [soft.] Modification of the comments.
  • Version 2.0:
    • [hard.] Adding R15+R16. value of R2,R7,R10,C7. JP7=ground
    • [hard.] Adding R15+R16, JP7=gnd, pin connection of bridge D4,
      thyristor Q1, U4, moving SIOV RV1
    • [soft.] Advance calculation correction.
  • Version 2.1:
    • [hard.] Value of C7, C9
    • [soft.] Excel sheet version= XLSA1.3
  • Version PCM2.2:
    • [soft.] Advance calculation modification.
      (15000RPM max, dwell=2ms)
    • [soft.] Excel sheet version= XLSA1.4
  • Version PCM2.8:
    • [soft.] Modification of register definitions.
    • [soft.] Excel sheet version= XLSA2.2
  • Version PCM3.0:
    • [soft.] Advance calculation correction.
      (26000RPM max at dwell=1ms)
    • [soft.] Possibility of large advance values.
    • [soft.] Excel sheet version= XLSA3.0
  • Version PCM3.2:
    • [soft.] Advance calculation correction.
      (80000RPM max at dwell=1ms)
    • [soft.] Excel sheet version= XLSA3.2
  • Version PCM4.2:
    • [soft.] simplification, 4MHz crystal, suppression extra pluses at low RPM, reliabily. 1000 to 8000rpm
    • [soft.] Excel sheet version= XLSA4.2
  • Version PCM4.3:
    • [soft.] same as PCM4.2 but 1500 to 16000rpm. 2 strokes curve.
    • [soft.] Excel sheet version= XLSA4.3
  • Version 5.0:
    • [hard.] With DB9 connector
  • Version 5.1:
    • [soft.] Corrections in software for XT400.
  • Version 5.2:
    • [hard.] Suppress D4. Change R6,R7 values.
  • Version 5.3:
    • [soft.] 2 map selectables. – ASM for 16f628 available
  • Version 5.4:
    • [hard.] Improve RESET circuit R7+C12