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/ |