# Dump Flash Memory through a single GPIO pin

I'm working with Infineon's XMC4500 Relax Kit and I'm trying to extract the firmware through a single GPIO pin.

My very naive idea is to dump one bit at a time through the GPIO pin and somehow "sniff" the data with a logic analyzer.

Pseudocode:

while(word by word memory copy hasn't finished)
...
register = value;
temp_value = value AND 0x1;
pin = temp_value;
value = value >> 1;
...


Am I on the right track? Does anybody have a better/nicer idea how to archive this?

### EDIT ###

Actually a requirement of my (shell)code would be that it needs to be really tiny. I found this nifty trick on how to dump firmware by blinking the LEDs.

However I'm struggling to receive correct values with Saleae Logic Analyzer.

Basically what I'm doing is:

1. Setup the GPIO pin directions to output
2. Blink LED1 (pin 1.1) with a clock (SPI serial clock)
3. Blink LED2 (pin 1.0) with data bits (SPI MOSI)
4. Sniff pins with a logic analyzer

Here's my C code:

#include "XMC4500.h"

#define DEL 1260

void init()
{
// P1.0 output, push pull
PORT1->IOCR0 = 0x80UL << 0;
// P1.1 output, push pull
PORT1->IOCR0 |= 0x80UL << 8;
}

void delay(int i) {
while(--i) {
asm("nop\n");
asm("nop\n");
}
}

// Sets a pin to high
// P1.0 = SPI MOSI
// P1.1 = SPI CLOCK
void output_high(int i) {
// P1.0 high
if(i == 0) {
PORT1->OUT |= 0x1UL;
}

// P1.1 high
if(i == 1) {
PORT1->OUT |= 0x2UL;
}
}

// Sets a pin to low
// P1.0 = SPI MOSI
// P1.1 = SPI CLOCK
void output_low(int i) {
// P1.0 low
if(i == 0) {
PORT1->OUT &= (~0x1UL);
}

// P1.1 low
if(i == 1) {
PORT1->OUT &= (~0x2UL);
}
}

// SPI bit banging
void spi_send_byte(unsigned char data)
{
int i;

// Send bits 7..0
for (i = 0; i < 8; i++)
{
// Sets P1.1 to low (serial clock)
output_low(1);

// Consider leftmost bit
// Set line high if bit is 1, low if bit is 0
if (data & 0x80)
// Sets P1.0 to high (MOSI)
output_high(0);
else
// Sets P1.0 to low (MOSI)
output_low(0);

delay(DEL);

// Sets P1.1 to high (Serial Clock)
output_high(1);

// Shift byte left so next bit will be leftmost
data <<= 1;
}
}

int main() {
init();

while(1) {
spi_send_byte('t');
spi_send_byte('e');
spi_send_byte('s');
spi_send_byte('t');
}

return 0;
}


### 2nd EDIT ###

Finally sorted it out. Dumping flash memory is working fine with the following code:

#include "XMC4500.h"

// SPI bit banging
void spi_send_word(uint32_t data)
{
int i;

// LSB first, 32 bits per transfer
for (i = 0; i < 32; i++)
{
// set pin 1.1 to low (SPI clock)
PORT1->OUT &= (~0x2UL);

// set line high if bit is 1, low if bit is 0
if (data & 0x1) {
// set pin 1.0 to high (SPI MOSI)
PORT1->OUT |= 0x1UL;
}
else {
// set pin 1.0 to low (SPI MOSI)
PORT1->OUT &= (~0x1UL);
}

// set pin 1.1 to high (SPI clock)
PORT1->OUT |= 0x2UL;

data >>= 1;
}
}

int main() {
// start dumping at memory address 0x08000000
unsigned int *p;
p = (uint32_t *)(0x08000000u);

// configure pin 1.0 and pin 1.1 as output (push-pull)
PORT1->IOCR0 = 0x8080UL;

while(1) {
spi_send_word(*p);
p++;
}
}

• I migrated this from our recently closed Embedded site. I've been adding an [embedded] tag when possible, but this question already has 5 tags. Any suggestions about which to (if any) to replace? (Also, please follow this proposal if interested in rebooting that site. – Jon Ericson Jun 9 '14 at 21:03
• I'd suggest you could ditch [arm] as this is not a processor-specific operation. – John U Jun 10 '14 at 19:00

The biggest issue I see with your current plan is tat long series of 0s or 1's (multiple 0x00 or oxFF bytes) will be difficult to differentiate. Here are some other ideas for consideration.

Bitbanged UART TX

Bit banging a UART TX line isn't terribly hard. Pick a a slower baud rate that is easily divides your system clock. You'll still be transmitting bytes in a similar fashion as your code sample, just with a set delay between each bit and a leading start and trailing stop bit for each byte. This has the advantage of being able to be directly connected to a computer to receive all the data. Alternatively, newer logic analyzers can usually decode the transmission directly into bytes without you needing to do anything by hand.

UNI/O

Microchip has a single line communication scheme called UNI/O. It runs at a range of clock rates where the master basically toggle the line at a given rate a few times and then all communication takes place at that rate.

A bit value is then transmitted by the rising or falling edge taking place in the middle of the clock period. A High to low transition would be a zero bit and a low to high transition would be a one bit. You can read more about UNI/O here

Look at the various ways data can be transmitted over a single line (or channel). The basic problem is timing: how does the receiver know where the boundary between two bits is. Some simple solutions for this problem are (there are many more):

• asynchronous (aka NRZ start-stop, aka UART, somtimes - wrongly - called RS232): send only a limited number of bits in a chunk, seperate chunks by start + stop bits
• NRZI: encode each bit as a change or non-change of the signal at the center of the bit cell
• manchester: encode each bit as a low-to-high or high-to-low edge at the center of the bit cell
• pulse length: encode 1 and 0 as pulses of different length
• Did you mean "send only a limited number of bits in a chunk" ? – Rocketmagnet Jun 1 '14 at 21:09
• I meant bits, corrected. The reason is that after a limited (e.g. 8) bit cells the 'dead reckoning' timing can still be accurate without excessively costly clocks. – Wouter van Ooijen Jun 1 '14 at 21:11

If you have or buy a Bus Pirate you'll have a wide range of protocols to choose from which should be easier get get data out of than your typical logic analyzer. There are other answers on protocol and the bus pirate supports 1-wire protocols, but if you can grab second GPIO, SPI might be nice as it goes fairly fast, you can bit-bang in the processor, and with a bus pirate, you don't need to worry as much about matching up logic voltage levels vs trying to get RS232 lined up. Other than that, the bus pirate documentation and open-hardware community is pretty extensive in how to get setup.