Attempting to sniff the SPI bus

General

Sorunome

6 years ago

So.....I'm attempting to sniff the SPI bus for a possible HDMI out using a raspberry pi.....the problem is, that my code only works well for clock speeds up to 2MHz, and our display is clocked at 24MHz. I thought maybe one of you has more experience with the raspberry pi and its GPIOs, as this is literally the first time i worked with that!

#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <unistd.h>

#define PAGE_SIZE (4*1024)
#define BLOCK_SIZE (4*1024)

#define BCM2708_PERI_BASE        0x20000000
#define GPIO_BASE                (BCM2708_PERI_BASE + 0x200000) /* GPIO controller */


int  mem_fd;
void *gpio_map;

// I/O access
volatile unsigned *gpio;


// GPIO setup macros. Always use INP_GPIO(x) before using OUT_GPIO(x) or SET_GPIO_ALT(x,y)
#define INP_GPIO(g) *(gpio+((g)/10)) &= ~(7<<(((g)%10)*3))
#define OUT_GPIO(g) *(gpio+((g)/10)) |=  (1<<(((g)%10)*3))
#define SET_GPIO_ALT(g,a) *(gpio+(((g)/10))) |= (((a)<=3?(a)+4:(a)==4?3:2)<<(((g)%10)*3))

#define GPIO_SET *(gpio+7)  // sets   bits which are 1 ignores bits which are 0
#define GPIO_CLR *(gpio+10) // clears bits which are 1 ignores bits which are 0

#define GET_GPIO(g) (*(gpio+13)&(1<<g)) // 0 if LOW, (1<<g) if HIGH

#define GPIO_PULL *(gpio+37) // Pull up/pull down
#define GPIO_PULLCLK0 *(gpio+38) // Pull up/pull down clock

void setup_io();

const int pin_clock = 11;
const int pin_input = 9;

const int frame_threashold = 107058;

typedef unsigned char BYTE;

BYTE get_byte() {
        BYTE b = 0;
        int i;
        for (i = 0; i < 8; i++) {
                while(!GET_GPIO(pin_clock));
                b <<= 1;
                b |= (GET_GPIO(pin_input)?1:0);
                while(GET_GPIO(pin_clock));
        }
        return b;
}

void find_start() {
        int max = 0;
        while(!GET_GPIO(pin_clock));
        while(GET_GPIO(pin_clock));
        unsigned start_time = (unsigned)time(NULL);
        int i;
        do {
                i = 0;
                while(!GET_GPIO(pin_clock))i++;
                if (i > max) max = i;
                while(GET_GPIO(pin_clock));
        } while (start_time + 2 >= (unsigned)time(NULL));
        max -= (max/10);

        do {
                i = 0;
                while(!GET_GPIO(pin_clock))i++;
                while(GET_GPIO(pin_clock));
        } while (i < max);
        for (i = 0; i < 7; i++) { // read the remaining byte
                while(!GET_GPIO(pin_clock));
                while(GET_GPIO(pin_clock));
        }
}

int main(int argc, char **argv) {
        setup_io();

        INP_GPIO(pin_input);
        INP_GPIO(pin_clock);

        find_start();

        BYTE data[10];
/*
        while(1) {
                if(get_byte() != 0x2A) continue;
                if (get_byte() != 0) continue;
                if (get_byte() != (160-1)) continue;
                data[0] = 0x2A;
                data[1] = 0;
                data[2] = 160-1;
                break;
        }
*/
        int i;
        for (i = 0; i < 10; i++) {
                data[i] = get_byte();
        }

        for (i = 0; i < 10; i++) {
                printf("%02x ", data[i]);
        }
        printf("\n");
        return 0;
}

void setup_io() {
        if ((mem_fd = open("/dev/mem", O_RDWR|O_SYNC) ) < 0) {
                printf("can't open /dev/mem \n");
                exit(-1);
        }

        /* mmap GPIO */
        gpio_map = mmap(
                NULL,             //Any adddress in our space will do
                BLOCK_SIZE,       //Map length
                PROT_READ|PROT_WRITE,// Enable reading & writting to mapped memory
                MAP_SHARED,       //Shared with other processes
                mem_fd,           //File to map
                GPIO_BASE         //Offset to GPIO peripheral
        );

        close(mem_fd); //No need to keep mem_fd open after mmap

        if (gpio_map == MAP_FAILED) {
                printf("mmap error %d\n", (int)gpio_map);//errno also set!
                exit(-1);
        }

        // Always use volatile pointer!
        gpio = (volatile unsigned *)gpio_map;
}


find_start is for finding the start of a byte, as what if we start the program in the middle of a byte being sent? It is based on that on some byte eventually there will be a longer pause than between bytes, which is true, as we aren't using the SPI bus 100% of the time in any sketches.

As test sketch i used the following with the METAs library custom yeild function disabled (as that would cause delay() to sometimes do SPI stuff):

#include <Gamebuino-Meta.h>

static SPISettings mySPISettings;

void setup() {
    gb.begin();
    mySPISettings = SPISettings(2000000, MSBFIRST, SPI_MODE0);
    SPI.beginTransaction(mySPISettings);
    while(1) {
        SPI.transfer(0x12);
        SPI.transfer(0x34);
        delay(1);
    }
    SPI.endTransaction();
}

void loop() {
    
}


So yeah, as I already said, I'm basically stuck currently as the receiving part on the raspberry pi only works well up to 2MHz but the screen is at 24MHz

ripper121

NEW 6 years ago

Sorunome

6 years ago

Thank you for the links, i'll look more into it once i have time. Me having a gen 1 raspberry pi probably doesn't help this, then >.<

Sorunome

NEW 6 years ago

ripper121 ripper121

Thank you for the links, i'll look more into it once i have time. Me having a gen 1 raspberry pi probably doesn't help this, then >.<

ripper121

6 years ago

But I dont think you need to use SoftSPI, the HW spi goes up to 125MHz:

 cdiv    speed

    2      125.0 MHz

https://www.raspberrypi.org/documentation/hardware/raspberrypi/spi/README.md

ripper121

NEW 6 years ago

Sorunome Sorunome

But I dont think you need to use SoftSPI, the HW spi goes up to 125MHz:

 cdiv    speed

    2      125.0 MHz

https://www.raspberrypi.org/documentation/hardware/raspberrypi/spi/README.md