Volcar memoria flash a través de un solo pin GPIO

Estoy trabajando con el XMC4500 Relax Kit de Infineon y estoy tratando de extraer el firmware a través de un único pin GPIO.

Mi idea muy ingenua es volcar un bit a la vez a través del pin GPIO y de alguna manera “olfatear” los datos con un analizador lógico.

Pseudocódigo

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

¿Estoy en el camino correcto? ¿Alguien tiene una mejor idea de cómo archivar esto?

### EDITAR ###

En realidad, un requisito de mi código (shell) sería que debe ser realmente pequeño. Encontré este ingenioso truco sobre cómo volcar el firmware mediante el parpadeo de los LED.

Sin embargo, estoy luchando para recibir los valores correctos con Saleae Logic Analyzer.

Básicamente lo que estoy haciendo es:

  1. Configurar las direcciones de pines GPIO para la salida
  2. Parpadea LED1 (pin 1.1) con un reloj (reloj serial SPI)
  3. Blink LED2 (pin 1.0) con bits de datos (SPI MOSI)
  4. Olfatea pines con un analizador lógico

Aquí está mi código C:

 #include "XMC4500.h" #define DEL 1260 void init() { // P1.0 output, push pull PORT1->IOCR0 = 0x80UL <IOCR0 |= 0x80UL <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; } 

### 2do EDITAR ###

Dumping memoria flash funciona bien con el siguiente código:

 #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 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++; } } 

El mayor problema con su solución es recuperar la información de tiempo, saber dónde empieza una palabra y dónde termina otra. Sería más sencillo emitir los datos en un pin tx de UART: el UART agrega bits de inicio y parada y administra la temporización para usted, y la salida se puede leer directamente a través de un puerto serie de PC normal.

Si no puede usar un UART, la emulación de un UART pegando un bit al GPIO con temporización de UART aún permitirá que se use un puerto serial convencional para recibir los datos directamente.

Un ejemplo de implementación de software UART se puede encontrar aquí . En su caso, por supuesto, solo necesita la capacidad de transmisión.

Eso podría funcionar decentemente dependiendo de sus necesidades. Algo a tener en cuenta será si hay variaciones de tiempo mientras recorre los datos, como la variación de los tiempos de lectura, la memoria caché, etc., se encontrará con un problema para descubrir dónde comienzan y se detienen los bytes. Es posible que desee echar un vistazo al protocolo 1-Wire:

http://en.wikipedia.org/wiki/1-Wire

No tiene que implementarlo a especificaciones ni nada, solo eche un vistazo para una idea. Si implementas algo así, tu lógica es igual de simple:

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