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:
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++;
}
}
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):
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.
Jon Ericson
Juan U.