Dump Flash-Speicher über einen einzigen GPIO-Pin

Ich arbeite mit dem XMC4500 Relax Kit von Infineon und versuche, die Firmware über einen einzelnen GPIO-Pin zu extrahieren.

Meine sehr naive Idee ist, ein Bit nach dem anderen durch den GPIO-Pin zu leiten und die Daten irgendwie mit einem Logikanalysator zu "schnüffeln".

Pseudocode:

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

Bin ich auf dem richtigen Weg? Hat jemand eine bessere/schönere Idee, wie man das archiviert?

### BEARBEITEN ###

Eigentlich wäre eine Anforderung an meinen (Shell-)Code, dass er wirklich winzig sein muss. Ich habe diesen raffinierten Trick gefunden, wie man Firmware durch Blinken der LEDs ausgibt.

Ich habe jedoch Probleme, mit Saleae Logic Analyzer korrekte Werte zu erhalten.

Grundsätzlich mache ich folgendes:

  1. Richten Sie die GPIO-Pin-Richtungen für die Ausgabe ein
  2. LED1 (Pin 1.1) mit einer Uhr blinken (serielle SPI-Uhr)
  3. Blink LED2 (Pin 1.0) mit Datenbits (SPI MOSI)
  4. Schnüffeln Sie Pins mit einem Logikanalysator

Hier ist mein 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;
}

### 2. BEARBEITUNG ###

Endlich geklärt. Das Dumping des Flash-Speichers funktioniert gut mit dem folgenden 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++;
  }
}
Ich habe dies von unserer kürzlich geschlossenen eingebetteten Site migriert. Ich habe nach Möglichkeit ein [eingebettetes] Tag hinzugefügt, aber diese Frage hat bereits 5 Tags. Irgendwelche Vorschläge, welche (falls vorhanden) zu ersetzen sind? (Bitte folgen Sie auch diesem Vorschlag, wenn Sie daran interessiert sind, diese Site neu zu starten.
Ich würde vorschlagen, dass Sie [arm] fallen lassen könnten, da dies keine prozessorspezifische Operation ist.

Antworten (3)

Das größte Problem, das ich bei Ihrem aktuellen Plan sehe, ist, dass lange Reihen von Nullen oder Einsen (mehrere 0x00- oder oxFF-Bytes) schwer zu unterscheiden sind. Hier sind einige andere Ideen zur Überlegung.

Bitbanged UART TX

Das Bit-Banging einer UART-TX-Leitung ist nicht besonders schwer. Wählen Sie eine langsamere Baudrate, die Ihre Systemuhr leicht teilt. Sie übertragen Bytes weiterhin auf ähnliche Weise wie Ihr Codebeispiel, nur mit einer festgelegten Verzögerung zwischen jedem Bit und einem führenden Start- und einem abschließenden Stoppbit für jedes Byte. Dies hat den Vorteil, dass es direkt mit einem Computer verbunden werden kann, um alle Daten zu erhalten. Alternativ können neuere Logikanalysatoren die Übertragung normalerweise direkt in Bytes decodieren, ohne dass Sie etwas von Hand tun müssen.

UNI/O

Microchip hat ein einzeiliges Kommunikationsschema namens UNI/O. Es läuft mit einer Reihe von Taktraten, bei denen der Master die Leitung im Grunde einige Male mit einer bestimmten Rate umschaltet und dann die gesamte Kommunikation mit dieser Rate stattfindet.

Durch die in der Mitte der Taktperiode stattfindende steigende oder fallende Flanke wird dann ein Bitwert übertragen. Ein Übergang von High nach Low wäre ein Null-Bit und ein Übergang von Low nach High wäre ein Bit Eins. Hier können Sie mehr über UNI/O lesen

Sehen Sie sich die verschiedenen Möglichkeiten an, wie Daten über eine einzige Leitung (oder einen einzigen Kanal) übertragen werden können. Das grundlegende Problem ist das Timing: Woher weiß der Empfänger, wo die Grenze zwischen zwei Bits ist. Einige einfache Lösungen für dieses Problem sind (es gibt noch viele mehr):

  • asynchron (auch bekannt als NRZ Start-Stop, auch bekannt als UART, manchmal - fälschlicherweise - RS232 genannt): Senden Sie nur eine begrenzte Anzahl von Bits in einem Chunk, trennen Sie Chunks durch Start- und Stoppbits
  • NRZI: jedes Bit als Änderung oder Nichtänderung des Signals in der Mitte der Bitzelle codieren
  • Manchester: Codieren Sie jedes Bit als eine Low-to-High- oder High-to-Low-Flanke in der Mitte der Bitzelle
  • Impulslänge: Codieren Sie 1 und 0 als Impulse unterschiedlicher Länge
Meinten Sie "nur eine begrenzte Anzahl von Bits in einem Chunk senden" ?
Ich meinte Bits, korrigiert. Der Grund dafür ist, dass nach begrenzten (z. B. 8) Bitzellen die Zeitsteuerung der „Koppelnavigation“ immer noch genau sein kann, ohne übermäßig kostspielige Uhren.

Wenn Sie einen Bus Pirate haben oder kaufen , haben Sie eine große Auswahl an Protokollen zur Auswahl, mit denen Sie leichter Daten abrufen können als mit Ihrem typischen Logikanalysator. Es gibt andere Antworten zum Protokoll, und der Buspirat unterstützt 1-Draht-Protokolle, aber wenn Sie ein zweites GPIO greifen können, ist SPI möglicherweise nett, da es ziemlich schnell geht, Sie können den Prozessor und mit einem Buspiraten Bit-Bang einschalten Sie Sie müssen sich nicht so viele Gedanken über das Anpassen der Logikspannungspegel machen, anstatt zu versuchen, RS232 in eine Reihe zu bringen. Abgesehen davon ist die Buspiraten-Dokumentation und die Open-Hardware-Community ziemlich umfangreich in der Einrichtung.