Du hast zwei Probleme und die solltest du getrennt lösen. Das erste ist dein SPI Controler, das zweite das Display. Ich hab, wie ich gerade rausgefunden hab, auch mal was mit diesem Display gemacht. Bei für mich neuen Bausteinen mit simplem synchronen seriellen Protokoll, fange ich mit Bitbanging an. Ich programmiere einfach direkt das Timingdiagramm nach. Wenn der Baustein dann zuckt, kann man ja immer noch die HW im µC einsetzen. Meist bleibt es aber bei dieser Lösung, so auch bei diesem Display.

Ich kann meine Sachen im Augenblick nicht nachvollziehen, hab keine HW lauffähig. Ich pack aber trotzdem hier mal den wesentlichen Teil des Codes rein. Passt natürlich nicht für deinen Prozessor, ist aber plain C. Mein Prozessor ist ein PIC24 mit 16MHz Befehlstakt,
Code:
//uint8_t LCD_InitTab[] = {0x39,0x14,0x55,0x6d,0x78,0x38,0x0f,0x06,0x01};
const uint8_t LCD_InitTab[] = {0x29,0x14,0x56,0x6d,0x70,0x38,0x0f};

#define _____ 0x00
#define ____X 0x01
#define ___X_ 0x02
#define ___XX 0x03
#define __X__ 0x04
#define __X_X 0x05
#define __XX_ 0x06
#define __XXX 0x07
#define _X___ 0x08
#define _X__X 0x09
#define _X_X_ 0x0A
#define _X_XX 0x0B
#define _XX__ 0x0C
#define _XX_X 0x0D
#define _XXX_ 0x0E
#define _XXXX 0x0F
#define X____ 0x10
#define X___X 0x11
#define X__X_ 0x12
#define X__XX 0x13
#define X_X__ 0x14
#define X_X_X 0x15
#define X_XX_ 0x16
#define X_XXX 0x17
#define XX___ 0x18
#define XX__X 0x19
#define XX_X_ 0x1A
#define XX_XX 0x1B
#define XXX__ 0x1C
#define XXX_X 0x1D
#define XXXX_ 0x1E
#define XXXXX 0x1F

const uint8_t Chargen[] = {
#ifdef ARROWS
    // left arrow
    _____,
    __X__,
    _X___,
    XXXXX,
    _X___,
    __X__,
    _____,
    _____,
    // top left arrow
    XXX__,
    XX___,
    X_X__,
    ___X_,
    ____X,
    _____,
    _____,
    _____,
    // up arrow
    __X__,
    _XXX_,
    X_X_X,
    __X__,
    __X__,
    __X__,
    _____,
    _____,
    // top right arrow
    __XXX,
    ___XX,
    __X_X,
    _X___,
    X____,
    _____,
    _____,
    _____,
    // right arrow
    _____,
    __X__,
    ___X_,
    XXXXX,
    ___X_,
    __X__,
    _____,
    _____,
    // bottom right arrow
    _____,
    _____,
    _____,
    X____,
    _X___,
    __X_X,
    ___XX,
    __XXX,
     // down arrow
    _____,
    _____,
    __X__,
    __X__,
    __X__,
    X_X_X,
    _XXX_,
    __X__,
    // bottom left arrow
    _____,
    _____,
    _____,
    ____X,
    ___X_,
    X_X__,
    XX___,
    XXX__,
#else
    // bottom row
    _____,
    _____,
    _____,
    _____,
    _____,
    _____,
    _____,
    XXXXX,
    // two rows
    _____,
    _____,
    _____,
    _____,
    _____,
    _____,
    XXXXX,
    XXXXX,
    // three rows
    _____,
    _____,
    _____,
    _____,
    _____,
    XXXXX,
    XXXXX,
    XXXXX,
    // four rows
    _____,
    _____,
    _____,
    _____,
    XXXXX,
    XXXXX,
    XXXXX,
    XXXXX,
    // five rows
    _____,
    _____,
    _____,
    XXXXX,
    XXXXX,
    XXXXX,
    XXXXX,
    XXXXX,
    // six rows
    _____,
    _____,
    XXXXX,
    XXXXX,
    XXXXX,
    XXXXX,
    XXXXX,
    XXXXX,
     // seven rows
    _____,
    XXXXX,
    XXXXX,
    XXXXX,
    XXXXX,
    XXXXX,
    XXXXX,
    XXXXX,
    // full block
    XXXXX,
    XXXXX,
    XXXXX,
    XXXXX,
    XXXXX,
    XXXXX,
    XXXXX,
    XXXXX,
#endif
};

void SPI_WriteByte(uint8_t data) {
    uint8_t mask = 0x80;
    while (mask) {
        SCKout = 0;
        if (data & mask) {
            SDOout = 1;
        } else {
            SDOout = 0;
        }
        SCKout = 1;
        mask >>= 1;
    }
}

void LCD_SendCMD(uint8_t command){
    RSout = 0;
    CSBout = 0;
    SPI_WriteByte(command);
    CSBout = 1;
    __delay_us(28);
}

void LCD_SendData(uint8_t data){
    RSout = 1;
    CSBout = 0;
    SPI_WriteByte(data);
    CSBout = 1;
    __delay_us(28);
}

void LCD_SendCMDBlock(const uint8_t* commands, int length) {
    while (length) {
        LCD_SendCMD(*commands++);
        length--;
    }
}

void LCD_SendDataBlock(const uint8_t* data, int length) {
    RSout = 1;
    CSBout = 0;
    while (length) {
        LCD_SendData(*data++);
        length--;
    }
    CSBout = 1;
}

void LCD_ClearDisplay(void){
    LCD_SendCMD(0x01);
    __delay_us(1500);
}

void LCD_SetCursor(int mode){
    LCD_SendCMD(0b00001100 | (mode & 0b00000011));
}

void LCD_SetDisplayAddress(int address){
    LCD_SendCMD(0b10000000 | (address & 0b01111111));
}

void LCD_SetCharGenAddress(int address){
    LCD_SendCMD(0b01000000 | (address & 0b00111111));
}

void LCD_Init(void){
    LCD_SendCMDBlock(LCD_InitTab, sizeof(LCD_InitTab));
    LCD_ClearDisplay();
}

int LCD_SetExtraChars(const uint8_t* BitPattern, int length) {
    if(*BitPattern == 0xFF){    // unprogrammed EEPROM data
        return -1;
    }
    if(length > 64){
        length = 64;
    }
    LCD_SetCharGenAddress(0);
    LCD_SendDataBlock((uint8_t*) BitPattern, length);
    return 0;
}

void LCD_SetBacklight(int intensity) {
    int tmp;
    if (intensity > 15) {
        intensity = 15;
    }
    tmp = 0x01 << intensity;
    OC2R = tmp;
}
Ist schon eine Weile her, daß ich das geschrieben hab, daher weiß ich nicht mehr, was der Unterschied der beiden Initialisierungssquenzen am Anfang ist. Da sind auch noch zusätzliche Zeichen drin, die auf die freien Plätze programmiert werden können und ein paar #defines, die das besser "lesbar" machen. Das Backlight hatte ich wohl an einem PWM Ausgang.

Achso noch was:

RSout = 0;
CSBout = 0;

hier werden Portbits PIC-typisch (auf 0) gesetzt, da gibts irgendwo an anderer Stelle die #defines dazu, es gibt noch SCKout und SDOout, also 4 Ports.

Ich hoffe, es hilft dir etwas

MfG Klebwax