I know I can speed it up a little by not having spi_wr call the spi_bit_out function and put that function into spr_wr, but it's still pretty slow.

Bassically, everytime spi_bit_out is called, the register is rotated 7 times to get the MSB, is there a quicker and less costly way of doing this.

As 'data' in the bit_out function is an unsigned char, could I simply subtract 127 from it and leave myself with either 1 or 0 in the data register?

It currently takes about 0.4s to clear the screen on my Nokia 5110 LCD module running at 4MHz. I need to get a quicker routine, as I want to play around with a 1.8" 128x160 colour TTF module. This needs 2 bytes sent to it for every pixel whereas the Nokia 5110 module uses a bit for each pixel.

Hi Papabravo, that has certainly sped things up. That instruction takes 6uS at 8Mhz to complete, rather than the 56uS the rotate one did, but still this seems slow. In assembly, a couple of simple bit test functions would take so much less time to complete.

This function now takes 130uS (at 8MHz) to send 1 Byte out over SPI:

Code ( (Unknown Language)):

void spi_wr(unsigned char data, unsigned char com_data)

{

unsigned char i; // loop counter

DC = com_data; // set the data/command pin

for (i = 0; i < 8; i++) // loop through each bit

{

SDAT = (data & 0x80) ? 1 : 0 ; // output the MSB

SCLK = 1; // clock high

SCLK = 0; // clock low

data = data << 1; // shift left for next bit

}

}

Even at 8MHz, just clearing the display of a 160x128 TTF display would take 160 * 128 * 2 bytes per pixel * 130uS = 5.32 seconds.

Is there any quicker way to send SPI apart from a quicker processor and using the PICs hardware SPI port?

OK, I just tried this (obviously only outputs 1 bit, but it's just a test):

Code ( (Unknown Language)):

#asm

_asm

btfss data,7

bcf PORTC,3 // SDAT

btfsc data,7

bsf PORTC,4

bsf PORTC,4 // SCLK

bcf PORTC,4

_endasm

#endasm

Not sure why I need to use #asm, then _asm, but it's the only thing that worked and others on the internet suggested it.

Only problem is, an error saying 'data' is not defined. Obviously is assembly I need to give it an address not a variable from my C code. Is there a sneaky way to get the address of where 'data' is stored to be able to use it in the asm part of the code?

At 8MHz clock, the function takes 29uS to send a byte, way better than before. It takes 34uS in total to complete a byte send, as I have to get the byte I want to send from an array, then call the spi_out function.

So, to display an image on my Nokia 5110 LCD module, it only takes 28mS. Way quicker than before.

Should compile down to the same assembler you are using. It's good practice with really speed ciritcal C code to compile it and check the compiler output which should be in an autogenerated .asm or .lst file.

Then you get to know how badly the compiler mangles your nice C code.

But seriously with the right C code your compiler will probably make the same asm output that you have above, without the need to use inline asm in your code which can have its own problems.

I'll have a bit more of a play with the compiler to test what it outputs, but am pretty happy to use assembly within my C code.

Do you know much about using fonts on GLCDs. I have the basic system font 5x7 which I use on my Nokia 5110 module, but when I get my 1.8" 160x128 I will need larger fonts. I've downloaded a few from Adafruit, but I don't understand how they work. Any help would be great.

Cheers ErnieM. I just downloaded LCD Font Creator which I'm running on a virtual machine on the Mac. I can sort of see how it's working. Pretty similar to my basic LCD Creator I wrote.

At present I am using the standard 5x7 font array which works well with the Nokia 5110 module as the characters are not proportionally spaced. They each take 5 columns with a blank column added at the start.

I'll just keep playing about with the font creator until I get what I need.

I started using software because I was programming in assembly and it looked very complicated using the built in hardware. But now I'm using C it may be easier for me to set it up.

You say about processing time. But surely most of the time, even with hardware SPI, you are still sitting there waiting for it to send a byte and then loading another byte etc. until everything you want to send is sent.

Well, it can look intimidating, but it's actually very easy. Here is the setup procedure from a project I did using the PIC16F690 and the CCS compiler, though this part is probably the same for any other compiler. CCS likes to give you a function to do everything, and I usually write things out explicitly--that's my way of buying a dog and barking myself!

Code ( (Unknown Language)):

sspstat = 0b01000000;

sspcon = 0b00100000; // Master mode, Fosc/4 (1MHz)

Then here is the way I drive the SPI port; in this case I'm only sending data, not receiving anything. What I'm operating is two MAX7219 display drivers, which each take 2 bytes of data in series, and there's one of them on the output of the other. Then in addition, there's a 74HC595 shift register between the processor and the display drivers, so it gets the last data byte. It's a peculiar feature of the CCS compiler that they call a single byte an "int", so where you see "int" just pretend it's "unsigned char". Finally, note the use of portc_shadow, which is there to ensure that I don't get tripped up by Microchip's absurd read-modify-write nonsense with port pins. Maybe I don't need that, but I just wasn't in the mood to figure it out.

What I recall about this was that I looked at the time taken to send each byte, and at 1MHz it would be 8 instruction times or a little longer, and I thought, will waiting for each byte delay the program enough to cause problems? And for 5 bytes, I just decided it was OK to wait, for the sake of having a simple routine. Probably if I'd done some kind of polling routine to let the processor do some other work and then send another byte, it would have taken at least as long to decide what to do next, but it's the kind of decision you have to make all the time with these processors.

The while (!BF) doesn't seem to work on the 18F PIC I'm using, so here I clear the 'transmit finished' interrupt flag, load the buffer, then wait for the flag to set before continuing. Then clear it again.