microcontroller doesn't work with Nokia 5110 LCD (PCD8544)
are those the same commands that the other working examples used?  My working examples (this one the raspberry pi is driving the display) have a few more commands/settings.

    spi_command(0x21); //extended commands
//    spi_command(0xB0); //vop
    spi_command(0xBF); //vop
    spi_command(0x04); //temp coef
    spi_command(0x14); //bias mode 1:48
    spi_command(0x20); //extended off
    spi_command(0x0C); //display on

//experiment 1
if(1)
{
    spi_command(0x80); //column
    spi_command(0x40); //row
    for(ra=0;ra&lt;504;ra++) spi_data(ra);
}


You are probably running slow enough you dont need any delays, but you could sprinkle some more in, between everything basically the D/C change to the spi select to the first data change and so on.

Do you have a scope to examine the bus?  You can feed the signals into the raspberry pi and sample very fast and save the data to use it as a logic analyzer (bare metal is easier/better but can possibly do it on linux as well).  Or use any other microcontroller so long as it is faster than what you think you are bit banging.

You could also put leds on the lines and make the delays massive, slow enough for you to visually see what is happening in what order.

If the display works when using off the shelf code, but not with yours then clearly it is not the display.  It is something your code is or isnt doing.  It is a fairly easy spi target to mess with, no reading back is required just blasting stuff out. 

You probably dont have the storage in the microcontroller, but do in the pi, you can also take another approach, take your bit bang code, simulate the gpio and make a log file of every state change.  Then make the real program just blast those out.  At least you can visually see

#include &lt;stdio.h&gt;

unsigned char port;

static void spi_delay ( void )
{
}

static void spi_dc ( unsigned int x )
{
    if(x) port|=(1&lt;&lt;0);
    else  port&amp;=~(1&lt;&lt;0);
    printf("0x%02X,\n",port);
}
static void spi_cs ( unsigned int x )
{
    if(x) port|=(1&lt;&lt;1);
    else  port&amp;=~(1&lt;&lt;1);
    printf("0x%02X,\n",port);
}
static void spi_clk ( unsigned int x )
{
    if(x) port|=(1&lt;&lt;2);
    else  port&amp;=~(1&lt;&lt;2);
    printf("0x%02X,\n",port);
}
static void spi_mosi ( unsigned int x )
{
    if(x) port|=(1&lt;&lt;3);
    else  port&amp;=~(1&lt;&lt;3);
    printf("0x%02X,\n",port);
}

static void spi_command ( unsigned int cmd )
{
    unsigned int ra;
    unsigned int rb;

    spi_dc(0);
    spi_cs(0);
    spi_delay();
    for(rb=cmd,ra=0;ra&lt;8;ra++,rb&lt;&lt;=1)
    {
        spi_mosi((rb&gt;&gt;7)&amp;1);
        spi_delay();
        spi_clk(1);
        spi_delay();
        spi_clk(0);
        spi_delay();
    }
    spi_cs(1);
}

static void spi_data ( unsigned int data )
{
    unsigned int ra;
    unsigned int rb;

    spi_dc(1);
    spi_cs(0);
    spi_delay();
    for(rb=data,ra=0;ra&lt;8;ra++,rb&lt;&lt;=1)
    {
        spi_mosi((rb&gt;&gt;7)&amp;1);
        spi_delay();
        spi_clk(1);
        spi_delay();
        spi_clk(0);
        spi_delay();
    }
    spi_cs(1);
}

int main ( void )
{
    port=0;

    spi_clk(0);
    spi_data(0);
    spi_cs(0);
    spi_cs(1);

    spi_command(0x21); //extended commands
...


for that init and command giving this output:

0x00,
0x01,
0x01,
0x01,
0x05,
0x01,
0x01,
0x05,
0x01,
0x01,
0x05,
0x01,
0x01,
0x05,
0x01,
0x01,
0x05,
0x01,
0x01,
0x05,
0x01,
0x01,
0x05,
0x01,
0x01,
0x05,
0x01,
0x03,
0x01,
0x03,
0x02,
0x00,
0x00,
0x04,
0x00,
0x00,
0x04,
0x00,
0x08,
0x0C,
0x08,
0x00,
0x04,
0x00,
0x00,
0x04,
0x00,
0x00,
0x04,
0x00,
0x00,
0x04,
0x00,
0x08,
0x0C,
0x08,
0x0A,


Note from the code I have bit 0 as D/C, bit 1 is cs, 2 is clk, and 3 mosi.  didnt do reset in this code, this one just tied reset to power I think, you can easily adjust those.

You could take that output then feed it into some code you run on the pi or microcontroller (if you have the space).

for(x=0;x&lt;datalen;x++)
{
  PORT = data[x];
  delay();
}


You can create some tools to visually see the waveforms (I recommend looking at the very simple vcd format and using gtkwave).  or even better just print them out as binary and turn your head sideways.

You can at least get a feel that you have things wired up right and you are bit banging right, once that works then you replace the set/clear functions for each bit with direct access to the gpio and move the code into the microcontroller.  can even write it such that it compiles both ways with an abstraction layer.

If you have a multi channel scope you can save yourself a ton of work.  Bit banging spi or i2c or mdio, etc you really really need a scope or need to build a logic analyzer out of a microcontroller or something.  Scope is preferred, esp for things like i2c and mdio where you can see when the busses change directions and how fast/slow the pull ups are.