LCDInfo.com
http://forum.lcdinfo.com/

Question about 9-bit SPI on an Atmega32
http://forum.lcdinfo.com/viewtopic.php?f=9&t=1514
Page 1 of 1

Author:  jeevan [ Fri Mar 17, 2006 3:37 ]
Post subject:  Question about 9-bit SPI on an Atmega32

Hey all,

I'm trying to parse the SparkFun sample code for the knock-off nokia. I'm using an atmega32 micro, and want to use SPI to talk to the Epson micro. I'm using the board SparkFun is offering.

So there's no real choice but to use the 9-bit serial interface, since the A0 line is not brought out. Anyhow, it looks like the sparkfun sample code (using a philips micro) writes two bytes to the SPI data register (in their case, they are using a 16 bit SSP register (SSPDR) unavailable on the Atmega32) -- the first byte is:

0000 0001 to set up for a command in spi_command()
0000 0000 to set up for data in spi_data()

the second byte is the command, or the data.

So that one bit getting toggled is the first bit of the 9-bit stream, and corresponds to A0. So, the first seven bits of the first byte are basically junk, right?

Their code:

Code:
void spi_command(int dat){
  int temp;
  IOCLR0 |= LCD_CS;
  SSPDR  = dat & ~0x0100;// & ~0x00000100;   // send next SPI channel 0 data
  while ((SSPSR & 0x10)) ;     // wait for transfer completed
  IOSET0 |= LCD_CS;
}



So they basically look like they are hitting chip select, sending two bytes, waiting for xmit to finish and resetting CS.

But that seems weird! The data sheet (p. 13) for the epson says that it reads the first bit at the first clock-edge to set the next byte as command or data. But doesn't writing the first seven bits of the first "dummy" byte get the clock going -- and the epson sees a 0 (the first bit in the dummy byte) at the first clock, every time?

is there something i am missing here? are the sparkfun guys doing some clever timing, such that the clock doesn't start going til the last bit in the first byte gets piped along (seems crazy)? Or will the following C code for the atmega32 work:

Code:

void spi_command(int dat) {

PB4 = 0; //this is the SS (CS) pin on the atmega32 -- just bringing SS low
             // to get the slave (the epson micro) ready

SPDR = 0x01; //dummy byte for command
 while (!(SPSR & (1<<SPIF))); //just wait for the transfer to end
SPDR = dat; //send the actual command
 while (!(SPSR & (1<<SPIF))); //just wait for the transfer to end
PB4 = 1; //all done, bring SS high and exit

}



?

spi_data would be analagous.

any help would be most appreciated. thanks so much!
confused,
jeevan
jeevan [at] media [dot] mit [dott edu

Author:  seulater [ Fri Mar 17, 2006 14:56 ]
Post subject: 

Your in luck, i just finished the code for the same display and processor last night. Unfortunatly i dont have the code here with me at work. When i get home tonight i will reply again with the info you need.

Jimbo

Author:  seulater [ Sat Mar 18, 2006 1:48 ]
Post subject: 

#define LCDCommand 0
#define LCDData 1

Useage:
SendLcd(LCDCommand, [Your Command]);
SendLcd(LCDData, [your data]);

NOTE: i cannot take all credit, jimminy came up with the idea for the function call parameters. i just changed the routine. i used the hardware SPI calls because it was MUCH faster then banging the bits out.

void SendLcd(u_char type, u_char dat)
{

LCD_DATA(type); // set up first bit as command or data
LCD_CS(0); // Enable device CS

LCD_CLK(0); // Pull Clock LOW
LCD_CLK(1); // Pul Clock HIGH

SPCR |=0x50; // Enable Hardware SPI

SPDR = dat; // send data

while(!(SPSR & 0x80)); // wait until send complete

LCD_CS(1); // disable device CS

SPCR &=~0x50;
// Disable Hardware SPI, this releases the SPI pins
// for general IO use. which is used to send the 1'st bit out
}

Author:  Kartman [ Sun Mar 19, 2006 0:52 ]
Post subject: 

For those of you using a micro without hardware support for a 9 bit spi, I knocked up some code for a philips lpc2119 that does 9 bit spi. In the case of an AVR, the calls to spi_delay() should not be necessary - the philips arm devices are mighty quick.

I still haven't got my display operating as I would expect yet, so I'm going to try buying some in from Hong Kong to see if I get better luck!



Code:
void spi_command(int dat)
{
  int temp;
  char bit_count;

  temp = dat & 0x00ff;
  IOCLR0 |= LCD_CS;

   for   (bit_count = 0; bit_count< 9;bit_count++)
      {
      if (temp & 0x0100)
         {
         IOSET0 = LCD_DI;
         }
      else
         {
         IOCLR0 = LCD_DI;
         }
      IOCLR0 = LCD_SCK;      //data valid on falling clock
      spi_delay();
      IOSET0 = LCD_SCK;
      temp<<=1;         //shift next bit
      spi_delay();
      }
  IOSET0 |= LCD_CS;
}

void spi_data(int dat)
{
  int temp;
  char bit_count;

  temp = dat | 0x0100;      //set the data/command bit
     
  IOCLR0 = LCD_CS;

   for   (bit_count = 0; bit_count< 9;bit_count++)
      {
      if (temp & 0x0100)
         {
         IOSET0 = LCD_DI;
         }
      else
         {
         IOCLR0 = LCD_DI;
         }
      IOCLR0 = LCD_SCK;      //data valid on falling clock
      spi_delay();
      IOSET0 = LCD_SCK;
      temp<<=1;         //shift next bit
      spi_delay();
      }
  IOSET0 |= LCD_CS;
}

Author:  jeevan [ Mon Mar 20, 2006 19:19 ]
Post subject: 

hi, thanks!

i've got a few questions about this code, though -- due probably to my inexperience with micro programming.

So, are LCD_DATA, LCD_CS and LCD_CLK #defined somewhere? I take it that LCD_CS and LCD_CLK correspond to the SPI pins for SS and SCK, respectively, which are PORTB4 and PORTB7 on the atmega32.

Is LCD_DATA #defined to be MOSI (PORTB5)? (I guess these aren't really #defines, since they seem to be taking arguments...)

I see otherwise how it works -- you put the command bit "ready" on a pin and then manually flip the clock -- then use SPI for the data byte.

Anyways, I am sure this code works, I would just like to understand the LCD_X a bit better.

thanks for all your help
jeevan



seulater wrote:

#define LCDCommand 0
#define LCDData 1

Useage:
SendLcd(LCDCommand, [Your Command]);
SendLcd(LCDData, [your data]);

NOTE: i cannot take all credit, jimminy came up with the idea for the function call parameters. i just changed the routine. i used the hardware SPI calls because it was MUCH faster then banging the bits out.

void SendtLcd(u_char type, u_char dat)
{

LCD_DATA(type); // set up first bit as command or data
LCD_CS(0); // Enable device CS

LCD_CLK(0); // Pull Clock LOW
LCD_CLK(1); // Pul Clock HIGH

SPCR |=0x50; // Enable Hardware SPI

SPDR = dat; // send data

while(!(SPSR & 0x80)); // wait until send complete

LCD_CS(1); // disable device CS

SPCR &=~0x50;
// Disable Hardware SPI, this releases the SPI pins
// for general IO use. which is used to send the 1'st bit out
}

Author:  jeevan [ Wed Mar 22, 2006 12:32 ]
Post subject:  i figured it out, thanks

hey all,

seulater's/jimminy's code will get you up and running in a flash -- and if any other newbies like me are confused by LCD_CLK, etc., here's what it means:

Code:
/* LCD_CLK
 * -------
 * Function that allows you to pull the SPI SCK clock pin (SCK)
 * high or low.
 */

void LCD_CLK(uint8_t clock) {

   if (clock == 0 ) { //pull clock low
      SPI_PORT &= ~_BV(SPI_SCK);
   } else if (clock == 1) { //pull clock high
      SPI_PORT |= _BV(SPI_SCK);
   }
}


SPI_PORT is just a #define for whatever port your chip uses for SPI (PORTB on the atmega32). SPI_SCK is just the pin that your chip uses for its SPI clock (PORTB7 on the atmega32). So, in my case, I had

Code:

#define SPI_PORT     PORTB
#define SPI_SCK       PORTB7
   


(_BV(blah) is just a macro for (1<<blah); it allows you to target a given bit in a byte. It's included in avrlib-c. for more info, see:

http://www.nongnu.org/avr-libc/user-man ... faq_use_bv)

All the other LCD_X functions are analagous. This is a pretty handy little template for pulling arbitrary pins high and low -- thanks for the tips, all!
jeevan

Author:  seulater [ Fri Mar 31, 2006 4:53 ]
Post subject: 

I would just like to understand the LCD_X a bit better.

Sorry about that...

here is the defines for it.

#define LCD_CS(x) PORTC.2=x;
#define LCD_CLK(x) PORTB.7=x;
#define LCD_DATA(x) PORTB.5=x;
#define LCD_RESET(x) PORTC.0=x;

Page 1 of 1 All times are UTC + 2 hours
Powered by phpBB® Forum Software © phpBB Group
http://www.phpbb.com/