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

Estoy trabajando con XMC4500 Relax Kit de Infineon y estoy tratando de extraer el firmware a través de un solo 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/mejor idea de cómo archivar esto?

### EDITAR ###

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

Sin embargo, tengo problemas para recibir los valores correctos con Saleae Logic Analyzer.

Básicamente lo que estoy haciendo es:

  1. Configure las direcciones de los pines GPIO para la salida
  2. Parpadeo LED1 (pin 1.1) con un reloj (reloj serie SPI)
  3. Parpadeo LED2 (pin 1.0) con bits de datos (SPI MOSI)
  4. Olfatear 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 << 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;
}

### 2ª EDICIÓN ###

Finalmente lo arreglé. Volcar la 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 < 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++;
  }
}
Migré esto de nuestro sitio integrado recientemente cerrado. He estado agregando una etiqueta [incrustada] cuando es posible, pero esta pregunta ya tiene 5 etiquetas. ¿Alguna sugerencia sobre cuál (si corresponde) reemplazar? (Además, siga esta propuesta si está interesado en reiniciar ese sitio.
Te sugiero que te deshagas de [arm] ya que esta no es una operación específica del procesador.

Respuestas (3)

El mayor problema que veo con su plan actual es que será difícil diferenciar largas series de 0 o 1 (múltiples 0x00 u oxFF bytes). Aquí hay algunas otras ideas para su consideración.

Bitbanged UART TX

Bit banging una línea UART TX no es terriblemente difícil. Elija una velocidad en baudios más lenta que divida fácilmente el reloj de su sistema. Seguirá transmitiendo bytes de manera similar a su ejemplo de código, solo con un retraso establecido entre cada bit y un comienzo inicial y un bit final final para cada byte. Esto tiene la ventaja de poder conectarse directamente a una computadora para recibir todos los datos. Alternativamente, los analizadores lógicos más nuevos generalmente pueden decodificar la transmisión directamente en bytes sin necesidad de hacer nada a mano.

UN/O

Microchip tiene un esquema de comunicación de una sola línea llamado UNI/O. Se ejecuta en un rango de frecuencias de reloj en las que el maestro básicamente cambia la línea a una frecuencia determinada varias veces y luego toda la comunicación se lleva a cabo a esa frecuencia.

A continuación, se transmite un valor de bit por el flanco ascendente o descendente que tiene lugar en la mitad del período del reloj. Una transición de alto a bajo sería un bit cero y una transición de bajo a alto sería un bit. Puedes leer más sobre UNI/O aquí

Mire las diversas formas en que los datos se pueden transmitir a través de una sola línea (o canal). El problema básico es el tiempo: ¿cómo sabe el receptor dónde está el límite entre dos bits? Algunas soluciones simples para este problema son (hay muchas más):

  • asíncrono (también conocido como NRZ start-stop, también conocido como UART, a veces, incorrectamente, llamado RS232): envíe solo una cantidad limitada de bits en un fragmento, separe los fragmentos por bits de inicio + parada
  • NRZI: codifica cada bit como un cambio o no cambio de la señal en el centro de la celda de bit
  • Manchester: codifique cada bit como un borde de menor a mayor o de mayor a menor en el centro de la celda de bit
  • longitud de pulso: codifica 1 y 0 como pulsos de diferente longitud
¿Quiso decir "enviar solo un número limitado de bits en un fragmento"?
Quise decir bits, corregido. La razón es que después de unas celdas de bits limitadas (por ejemplo, 8), la temporización de "estimación muerta" todavía puede ser precisa sin relojes excesivamente costosos.

Si tiene o compra un Bus Pirate , tendrá una amplia gama de protocolos para elegir, de los cuales debería ser más fácil obtener datos que su analizador lógico típico. Hay otras respuestas sobre el protocolo y el pirata de bus admite protocolos de 1 cable, pero si puede obtener un segundo GPIO, SPI podría ser bueno, ya que va bastante rápido, puede hacer un bit-bang en el procesador, y con un pirata de bus, usted no necesita preocuparse tanto por hacer coincidir los niveles de voltaje lógico con tratar de alinear RS232. Aparte de eso, la documentación de piratas de autobuses y la comunidad de hardware abierto es bastante extensa en cuanto a cómo configurarlo.