Finding JTAG on a Canon ELPH100HS (IXUS115)

I’m currently working on a project involving a Canon ELPH100HS point and shoot camera and my first task was to tear it apart and find any low level hardware access that I could. I chose the IXUS115 mainly for it’s full 1080p video recording capabilities and there is a CHDK port for it, which, it was hoped, would make the reversing and hacking process easier. I was hoping to find a serial console port and JTAG access to the processor, to aid programming and debugging.


Before I can start searching for hardware access, I need to get under the covers. The screwdrivers came out and the camera was disassembled with a minimum of fuss.
IMG_9878IMG_9877  IMG_9879 IMG_9880 IMG_9881 IMG_9882 IMG_9883 IMG_9884

Time for some better screwdrivers

On the PCB was a footprint for a connector that wasn’t populated, but most of it’s pins were broken out to test points. This is where it started to get fun.


 Some quick inspection identified a no-connect pin, ground, what looks like two supply rails with one missing a connecting component, and a variety of signals. Thanks to CHDK I knew there was more than likely a serial port on this connector and some quick probing with an oscilloscope revealed that pin 1 was TX and  pin 2 (bottom left) was RX. Objective 1 complete.

Making the camera useful for hacking on

While a serial console on a point and shoot camera was fun (see Event and DryOS shell for what can be done with it) I wanted lower level access. I had to make it easier to hack on the camera as that connector was tiny and impossible to work with for any length of time. I was convinced that there was more to this connector, Canon have to get a bootloader onto the board one way or another, and without code, the serial console doesn’t work.

Using some 0.1mm enamel wire and a magnifying glass, I managed to get all the connections out onto a standard 0.1″ header strip. A bamboo skewer, a takeaway lid and a bit of glue later and I had all the camera parts securely mounted and accessible.


Hooking up the BusPirate in UART bridge mode to the previously identified serial port yielded a console:

=== Dry-shell start ===
Dry> ?
 task  sem  event  mq  mutex  timer  mkobjsize  extask  kill  suspend  resume 
 release  delete  prio  mkcfg  meminfo  xd  xm  memmap  objinfo 
 vers  exit  dminfo 

Dry> meminfo
usage: meminfo [-{l|s|m|L}]
       -l  allocated list
       -s  system memory info
       -m  malloc memory info
       -L  all list (corruption safe)
Dry> meminfo -s
System Memory Information
  Start Address       = 0x00379c08
  End Address         = 0x003ccc00
  Total Size          = 0x00052ff8 (   339960)
  Allocated Size      = 0x000358c8 (   219336)
  Allocated Peak      = 0x000368d8 (   223448)
  Allocated Count     = 0x00000045 (       69)
  Free Size           = 0x0001d730 (   120624)
  Free Block Max Size = 0x0001c6a0 (   116384)
  Free Block Count    = 0x00000004 (        4)
Dry> meminfo -m
Malloc Information (onetime type)
  Start Address       = 0x001745c8
  End Address         = 0x00371de0
  Total Size          = 0x001fd818 (  2086936)
  Allocated Size      = 0x001413c8 (  1315784)
  Allocated Peak      = 0x00147b38 (  1342264)
  Allocated Count     = 0x0000013b (      315)
  Free Size           = 0x000bc450 (   771152)
  Free Block Max Size = 0x000bb330 (   766768)
  Free Block Count    = 0x00000003 (        3)
Dry> memmap
== ITCM ==
00000000 : DRY_VECTOR_ADDR
00001000 : DRY_IRQ_STACK
00001000 : DRY_RESET_STACK
00001000 : ITCM_END_ADDR

== DTCM ==
80000728 : DRY_VECTOR_FUNC
80000b28 : DRY_VECTOR_ARG
80001000 : DTCM_END_ADDR

== ROM  ==
ff810000 : text start
ffc7edd8 : romdata start
ffc8d798 : romdata end

== DRAM ==
00001900 : data start
000102c0 : bss start
001745bc : heap start
00371f80 : DRY_HEAP_END
00379c00 : DRY_SYS_MEM_START
003cd000 : DRY_ERREX_STACK
003ce000 : DRY_EXCEP_STACK
Dry> xd ff810000
           0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f  0123456789abcdef
ff810000: 01 00 00 ea 67 61 6f 6e 69 73 6f 79 50 11 9f e5  ....gaonisoyP...
ff810010: 00 00 a0 e3 00 00 81 e5 78 10 a0 e3 10 1f 01 ee  ........x.......
ff810020: 00 10 a0 e3 9a 1f 07 ee 15 1f 07 ee 16 1f 07 ee  ................
ff810030: 3d 00 a0 e3 10 0f 06 ee bf 01 a0 e3 11 0f 06 ee  =...............
ff810040: 35 00 a0 e3 12 0f 06 ee d5 01 a0 e3 13 0f 06 ee  5...............
ff810050: 5e 01 a0 e3 14 0f 06 ee 08 01 9f e5 15 0f 06 ee  ^...............
ff810060: 34 00 a0 e3 10 0f 02 ee 34 00 a0 e3 30 0f 02 ee  4.......4...0...
ff810070: 34 00 a0 e3 10 0f 03 ee ec 00 9f e5 50 0f 05 ee  4...........P...
ff810080: e4 00 9f e5 70 0f 05 ee 10 0f 11 ee 01 0a 80 e3  ....p...........
ff810090: 04 00 80 e3 01 00 80 e3 10 0f 01 ee 1a 11 a0 e3  ................
ff8100a0: 11 1f 09 ee 06 10 a0 e3 31 1f 09 ee 10 1f 11 ee  ........1.......
ff8100b0: 05 18 81 e3 10 1f 01 ee b0 20 9f e5 01 10 a0 e3  ......... ......
ff8100c0: 0c 11 82 e5 ff 10 a0 e3 0c 10 82 e5 1c 10 82 e5  ................
ff8100d0: 2c 10 82 e5 3c 10 82 e5 4c 10 82 e5 5c 10 82 e5  ,...<...L...\...
ff8100e0: 6c 10 82 e5 7c 10 82 e5 8c 10 82 e5 9c 10 82 e5  l...|...........
ff8100f0: ac 10 82 e5 bc 10 82 e5 cc 10 82 e5 dc 10 82 e5  ................

The memory information shown above will come in handy later when reversing the firmware. I may be able to use the xd/xm commands to query the Flash over CFI and determine what it is, the markings on it bring up no results.

Finding the pin functions

Now that the pins were all nicely accessible and I had a serial console, it was time to figure out what they all did.

Using the oscilloscope (a DMM would have worked too) I looked at the voltages present on all the pins and came up with the following information:

  TX  -  _  RX
 GND  -  _  3.3V
   L  -  _  N/C
 N/C  -  _  L
   L  -  _  L
   L  -  _  L
   H  -  _  H
   H  -  _  L
   H  - 

H = 3.3V, L = 0V

Next, using a 330Ω resistor and a wire I tried to see if I could change the state of any of the pins. If I could change the state they would be either an input or a high-z output, if I couldn’t, the pins would be an output. The resistor is in line to limit current in case the line is being actively driven. From this test I found:

  TX  -  _  RX
 GND  -  _  3.3V
SHDN  -  _  N/C
 N/C  -  _  PD
  PD  -  _  PD
  PD  -  _  PD
  PU  -  _  PU
  PU  -  _  PD
/OFF  - 

PD = Pull Down, PU = Pull Up

Taking SHDN high caused the camera to turn off gracefully, taking /OFF low immediately turned the camera off, no lens retraction. All the rest of the pins were either inputs or high impedance outputs. Having learnt a little more, I thought it was time to hammer on JTAG and see if I could find a chain. Using a STM32F3 development board and a utility of my own making, I hammered on all 9 of the unknown pins to see if JTAG showed up. It didn’t.

Back to the drawing board, I tried to see if any of the pins had special functions on boot. Inverting their state (A pulled up pin taken low, a pulled down pin taken high) one at a time found two interesting pins:

  TX  -  _  RX
 GND  -  _  3.3V
SHDN  -  _  N/C
 N/C  -  _  HALF_BAUD
  PD  -  _  ALT_BOOT
  PD  -  _  PD
  PU  -  _  PU
  PU  -  _  PD
/OFF  - 

PD = Pull Down, PU = Pull Up

When HALF_BAUD is active on boot, it causes the serial port to run at half it’s speed (57600 instead of 115200). I don’t know if this is because the system clock is running at half speed, but it’s interesting. When ALT_BOOT is active on boot a different serial console is shown:

 SiP check start 

Test Case : ?
Test Case : 1
 FROM sum is 0x3CE0C911
Test Case : 2
 Write data is 0x55555555
 Data bus check for all DRAM cell :  [OK] 
Test Case : 3
 Write data is 0xAAAAAAAA
 Data bus check for all DRAM cell :  [OK] 
Test Case : 4
 Write data is 0x00000000
 Data bus check for all DRAM cell :  [OK] 
Test Case : 5
 Write data is 0xFFFFFFFF
 Data bus check for all DRAM cell :  [OK] 
Test Case : 6
 Address bus check for all DRAM cell :  [OK] 
Test Case : 7
 Data bus check (Simple version) :  [OK] 
Test Case : 8
 Address bus check (Simple version) :  [OK] 
Test Case :

It allows for 8 memory and bus checks to be performed. An interesting note about this mode is that the power switch has to be held down, otherwise the board turns off. I’d reduced the candidates, but still hadn’t found a JTAG port. I also tried different combinations of power up modes to see if it was being disabled on startup.


The JTAG finder I was using (dubbed ‘JTAG Knocker’) only looked for TCK, TMS, TDI and TDO, it assumed that the JTAG port was active at all times. Some JTAG ports also come with nTRST pin to reset the chain and if that pin is pulled low, the JTAG port doesn’t work. So I decided the next course of action was to change the state of a pin while looking for a JTAG port on all the other pins.  I started with the ones that were pulled low (more likely to be nTRST) and I hit paydirt:

JTAG Knocker
[!] Potential Chain: TCK: 3 TMS: 5 TDO: 4 TDI: 2
[+] 1 Device(s) found, with total IR Length of 4
[+]  Device 1 - ID CODE 15946009
[!] Potential Chain: TCK: 3 TMS: 5 TDO: 4 TDI: 2
[+] 1 Device(s) found, with total IR Length of 4
[+]  Device 1 - ID CODE 15946009

The two statements with the same result are from the two different methods used to test a pin combination. The manufacturer in the ID code is Fujitsu, I guess they are the ones fabricating the Digic 4 chips for Canon. Updating the pin map:

  TX  -  _  RX
 GND  -  _  3.3V
SHDN  -  _  N/C
 N/C  -  _  HALF_BAUD
  PD  -  _  ALT_BOOT
  PD  -  _  /TRST
 TDI  -  _  TMS
 TCK  -  _  TDO
/OFF  -

Whipping up a quick openocd board definition and giving it a test:


Yup, it’s all working correctly. JTAG found.

So, why the desire for JTAG?

JTAG allows me to debug code (very slowly) on the processor instruction by instruction and gives me runtime information on the firmware, something that a static analysis can’t. I’m also able to program the flash, change things as I see fit, and recover if I brick it.

I rolled my own JTAG finder instead of buying one of the readily available ones (JTAG Enum, JTAGulator, etc) as they are expensive, a dedicated solution and/or require additional hardware I don’t currently have. Rolling my own on a dev board makes it useful, keeps the dev board available for other tasks and taught me a heap about the workings of JTAG. Oh yeah, and all it cost was time, which would have been spent waiting for the post.

Finishing Up

Doing a bit more testing on the pins, I’m fairly certain that /OFF above is actually /SRST (system reset) which promptly disables the power. SHDN above is probably the power switch, as it has similar behavour and if it’s held high on boot, the device won’t turn off. The pin below SHDN is probably a power supply pin (due to the wide trace) for development use, allowing the developers to power, control and debug the board from a single connector.  As it’s not needed for production use, the linking component was not populated, but it can easily be replaced with a solder bridge. This is something for me to try in the near future. Finally the two unidentified PD pins could have something to do with the ARM Embedded Trace Macrocell, possibly an enable and return clock (RTCK).


I’m fairly confident that the same connector would be on all Digic 4 cameras, and it’s probably similar across most of Canon’s range of point and shoot cameras.

The next step is to improve JTAG Knocker to the point where it’s ready for release as a functional JTAG finder and USB based JTAG adapter for OpenOCD. The JTAG adapters I currently have don’t support TRST or SRST and I may be able to roll some other functionality in there too. The board definition file for the camera also needs some work, GDB has a few issues and there are currently no memory regions defined.

Stay Tuned.



, , , ,

  1. #1 by lut on April 20, 2018 - 2:19 am

    Hi, thank you very much for your article. The pinout is the same on my camera for JTAG (PowerShot S100), as for UART I didn’t test it.

(will not be published)