roger430 12 Posted November 18, 2011 Share Posted November 18, 2011 Does anyone on this board have any experience in using the PCF8566 to drive glass LCD displays? It uses I2C for communications with a Master. I'm getting acknowledgments back from the PCF8566 after selecting its address and also from sending a command to it, however, subsequent data bytes display incorrectly. Any help would be greatly appreciated. Thanks, Roger430 anissof 1 Quote Link to post Share on other sites
roger430 12 Posted November 19, 2011 Author Share Posted November 19, 2011 :oops: :oops: My bad! Turns out my Raw LCD display segment map was totally different than what I expected. I got the 4 backplane pins right but the segment pins were way off. Everything is working just fine now. I modified the I2c code in TI's example code "msp430g2x21_usi_12.c" to communicate with the PCF8566. Quote Link to post Share on other sites
bluehash 1,581 Posted November 19, 2011 Share Posted November 19, 2011 Awesome.. could we see what your working on? Quote Link to post Share on other sites
roger430 12 Posted November 19, 2011 Author Share Posted November 19, 2011 Awesome.. could we see what your working on? Sure, it's just an experiment with a raw LCD display that I salvaged from a digital device. I did this to get familiar with I2C and the PFC8566 was pretty cheap. I'll get a picture and clean up my code a bit and post it here shortly. Thanks for asking! Roger Quote Link to post Share on other sites
roger430 12 Posted November 19, 2011 Author Share Posted November 19, 2011 Well here it is in all its glory! If only I could find a use for it. . . The toughest part was trying to figure out the configuration of the Raw LCD display. This one happened to have 4 back planes and used only 2 pins for each character for a total of 20 pins. It has a few graphics and a low battery indicator. It also has a small 7 segment character in the upper right hand corner as seen in the photo. The PCF8566 plays nicely with the MSP420G2231 and works very well with 3.3v. and here is the code: //****************************************************************************** // MSP430G2x21/G2x31 Demo - I2C Master Transmitter / Reciever, multiple bytes // // Description: I2C Master communicates with I2C Slave using // the USI. Master data should increment from 0x55 with each transmitted byte // and Master determines the number of bytes recieved, set by // the Number_of_Bytes value. LED off for address or data Ack; // LED on for address or data NAck. // ACLK = n/a, MCLK = SMCLK = Calibrated 1MHz // // // ***THIS IS THE MASTER CODE*** // // Slave Master // (msp430g2x21_usi_15.c) // MSP430G2x21/G2x31 MSP430G2x21/G2x31 // ----------------- ----------------- // /|\| XIN|- /|\| XIN|- // | | | | | | // --|RST XOUT|- --|RST XOUT|- // | | | | // LED <-|P1.0 | | | // | | | P1.0|-> LED // | SDA/P1.7|------->|P1.6/SDA | // | SCL/P1.6|<-------|P1.7/SCL | // // Note: internal pull-ups are used in this example for SDA & SCL // // D. Dang // Texas Instruments Inc. // October 2010 // Built with CCS Version 4.2.0 and IAR Embedded Workbench Version: 5.10 //****************************************************************************** #include #define number_of_bytes 10 // How many bytes? void Master_Transmit(void); //void Master_Recieve(void); void Setup_USI_Master_TX(void); //void Setup_USI_Master_RX(void); // First two bytes are PCF8566 commands static char MST_Data[10] = {0xC8, 0x00, 0xBE, 0x06, 0x7C, 0x5E, 0xC6, 0xDA, 0xBE, 0x00}; //character segment map char SLV_Addr = 0x7C; int I2C_State = 0; int Bytecount = 0; int Transmit = 0; // State variable void Data_TX (void); void main(void) { volatile unsigned int i; // Use volatile to prevent removal WDTCTL = WDTPW + WDTHOLD; // Stop watchdog if (CALBC1_1MHZ ==0xFF || CALDCO_1MHZ == 0xFF) { while(1); // If calibration constants erased // do not load, trap CPU!! } BCSCTL1 = CALBC1_1MHZ; // Set DCO DCOCTL = CALDCO_1MHZ; P1OUT = 0xC0; // P1.6 & P1.7 Pullups, others to 0 P1REN |= 0xC0; // P1.6 & P1.7 Pullups P1DIR = 0xFF; // Unused pins as outputs P2OUT = 0; P2DIR = 0xFF; while(1) { Master_Transmit(); //_NOP(); // Used for IAR } } /****************************************************** // USI interrupt service routine // Data Transmit : state 0 -> 2 -> 4 -> 10 -> 12 -> 14 ******************************************************/ #pragma vector = USI_VECTOR __interrupt void USI_TXRX (void) { switch(__even_in_range(I2C_State,14)) { case 0: // Generate Start Condition & send address to slave P1OUT |= 0x01; // LED on: sequence start Bytecount = 0; USISRL = 0x00; // Generate Start Condition... USICTL0 |= USIGE+USIOE; USICTL0 &= ~USIGE; if (Transmit == 1){ USISRL = 0x7C; // Address is 0x48 << 1 bit + 0 (rw) } if (Transmit == 0){ USISRL = 0x91; // 0x91 Address is 0x48 << 1 bit // + 1 for Read } USICNT = (USICNT & 0xE0) + 0x08; // Bit counter = 8, TX Address I2C_State = 2; // next state: rcv address (N)Ack break; case 2: // Receive Address Ack/Nack bit USICTL0 &= ~USIOE; // SDA = input USICNT |= 0x01; // Bit counter=1, receive (N)Ack bit I2C_State = 4; // Go to next state: check (N)Ack break; case 4: // Process Address Ack/Nack & handle data TX USICTL0 |= USIOE; // SDA = output if (USISRL & 0x01) // If Nack received... { // Send stop... USISRL = 0x00; USICNT |= 0x01; // Bit counter=1, SCL high, SDA low I2C_State = 14; // Go to next state: generate Stop P1OUT |= 0x01; // Turn on LED: error } else { // Ack received, TX data to slave... USISRL = MST_Data[bytecount]; // Load data byte USICNT |= 0x08; // Bit counter = 8, start TX I2C_State = 10; // next state: receive data (N)Ack //Bytecount++; P1OUT &= ~0x01; // Turn off LED break; } case 10: // Receive Data Ack/Nack bit USICTL0 &= ~USIOE; // SDA = input USICNT |= 0x01; // Bit counter = 1, receive (N)Ack bit I2C_State = 12; // Go to next state: check (N)Ack break; case 12: // Process Data Ack/Nack & send Stop USICTL0 |= USIOE; if (Bytecount == number_of_bytes){// If last byte USISRL = 0x00; I2C_State = 14; // Go to next state: generate Stop P1OUT |= 0x01; USICNT |= 0x01; } // set count=1 to trigger next state else{ P1OUT &= ~0x01; // Turn off LED Data_TX(); // TX byte } break; case 14:// Generate Stop Condition USISRL = 0x0FF; // USISRL = 1 to release SDA USICTL0 |= USIGE; // Transparent latch enabled USICTL0 &= ~(USIGE+USIOE); // Latch/SDA output disabled I2C_State = 0; // Reset state machine for next xmt LPM0_EXIT; // Exit active for next transfer break; } USICTL1 &= ~USIIFG; // Clear pending flag } void Data_TX (void){ USISRL = MST_Data[bytecount]; // Load data byte USICNT |= 0x08; // Bit counter = 8, start TX I2C_State = 10; // next state: receive data (N)Ack Bytecount++; } void Setup_USI_Master_TX (void) { _DINT(); Bytecount = 0; Transmit = 1; USICTL0 = USIPE6+USIPE7+USIMST+USISWRST; // Port & USI mode setup USICTL1 = USII2C+USIIE; // Enable I2C mode & USI interrupt USICKCTL = USIDIV_7+USISSEL_2+USICKPL; // USI clk: SCL = SMCLK/128 USICNT |= USIIFGCC; // Disable automatic clear control USICTL0 &= ~USISWRST; // Enable USI USICTL1 &= ~USIIFG; // Clear pending flag _EINT(); } void Master_Transmit(void){ Setup_USI_Master_TX(); USICTL1 |= USIIFG; // Set flag and start communication LPM0; // CPU off, await USI interrupt __delay_cycles(10000); // Delay between comm cycles } anissof, oPossum and pine 3 Quote Link to post Share on other sites
zeke 693 Posted November 19, 2011 Share Posted November 19, 2011 That's nice. Good job! There's plenty of applications for something like this: - Outside Thermometer - Tachometer - Clock - Voltmeter - CPU load monitor Personally, I would build an outside thermometer with some 1-Wire temp sensors because it's flipping cold up here today. It's -20'C or 0'F. Brrr!!! Quote Link to post Share on other sites
bluehash 1,581 Posted November 19, 2011 Share Posted November 19, 2011 Awesome work.. nice and crisp.. You know where this needs to go: POTM I would use it as a: -Clock -Calendar -Temp display -Maybe check if you have new mail PC->Launchpad->display Quote Link to post Share on other sites
roger430 12 Posted November 19, 2011 Author Share Posted November 19, 2011 Thanks for the ideas! :clap: :clap: I came across this offer from "The Electronic Goldmine": http://www.goldmine-elec-products.com/prodinfo.asp?number=G17892 3 LCD displays for $0.99! I wonder what treasure could be hidden in those! Now that I have a way of checking them out, I may just get a bunch! Quote Link to post Share on other sites
roger430 12 Posted November 22, 2011 Author Share Posted November 22, 2011 I managed to cobble together a workable temperature display of the internal MSP430 temperature sensor. I used the small character in the upper right hand corner of the display as a degree symbol (actually the character 0). I used a table lookup for the characters 0 - 9. Right now it only displays the temp in two digits. I need to display 3 digits here in Texas - temps last summer were mostly in the 100's. Here's a picture followed by the code if anyone is interested (the schematic has been updated above): //****************************************************************************** // This project is a simple display of the internal temperature sensor // of the MSP430G2231 utilizing a raw (no logic) LCD panel and a PCF8566 // display driver. The MSP430 communicates with the PCF8566 using 2 wires // via I2C. Temperatures up to 199F will be displayed, however, no provision // has been made for negative temperatures. (Rarely gets that cold if at all // in this part of Texas.) I2c code came directly from the example code TI // has provided. // Roger430 - December, 2011 // // MSP430G2x21/G2x31 Demo - I2C Master Transmitter / Receiver, multiple bytes // // Description: I2C Master communicates with I2C Slave using // the USI. Master data should increment from 0x55 with each transmitted byte // and Master determines the number of bytes received, set by // the Number_of_Bytes value. LED off for address or data Ack; // LED on for address or data NAck. // ACLK = n/a, MCLK = SMCLK = Calibrated 1MHz // // // ***THIS IS THE MASTER CODE*** // // Slave Master // PCF8566 MSP430G2x31 // ----------------- ----------------- // | | /|\| XIN|- // | Address: | | | | // | 0x7C | --|RST XOUT|- // | 0111 1100 | | | // | | | | // | | | P1.0|-> LED // | Pin 2 SDA |<-------|P1.6/SDA | // | Pin 1 SCL |<-------|P1.7/SCL | // // Note: internal pull-ups are used in this example for SDA & SCL // // D. Dang // Texas Instruments Inc. // October 2010 // Built with CCS Version 4.2.0 and IAR Embedded Workbench Version: 5.10 // //****************************************************************************** #include void Master_Transmit(void); void Setup_USI_Master_TX(void); // Initialize data: static char MST_DataInit[10] = {0xC8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xBE, 0x00}; // LCD segment array: static const char Digits[10] = {0xBE, 0x06, 0x7C, 0x5E, 0xC6, 0xDA, 0xFA, 0x0E, 0xFE, 0xCE}; // Transmit array: static char MST_DataT[7] = {0xC8, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00}; int number_of_bytes = 0; int digit1 = 0; int digit2 = 0; long temp; long IntDegF; long IntDegC; char *MST_Data; char SLV_Addr = 0x7C; int I2C_State = 0; int Bytecount = 0; int Transmit = 0; // State variable int FCflag = 1; //Fahrenheit/Celsius flag void Data_TX (void); void GetDigits(int); void main(void) { volatile unsigned int i; // Use volatile to prevent removal WDTCTL = WDTPW + WDTHOLD; // Stop watchdog if (CALBC1_1MHZ ==0xFF || CALDCO_1MHZ == 0xFF) { while(1); // If calibration constants erased // do not load, trap CPU!! } ADC10CTL1 = INCH_10 + ADC10DIV_3; // Temp Sensor ADC10CLK/4 ADC10CTL0 = SREF_1 + ADC10SHT_3 + REFON + ADC10ON + ADC10IE; __enable_interrupt(); // Enable interrupts. TACCR0 = 30; // Delay to allow Ref to settle TACCTL0 |= CCIE; // Compare-mode interrupt. TACTL = TASSEL_2 | MC_1; // TACLK = SMCLK, Up mode. LPM0; // Wait for delay. TACCTL0 &= ~CCIE; // Disable timer Interrupt __disable_interrupt(); BCSCTL1 = CALBC1_1MHZ; // Set DCO DCOCTL = CALDCO_1MHZ; P1OUT = 0xC0; // P1.6 & P1.7 Pullups, others to 0 P1REN |= 0xC0; // P1.6 & P1.7 Pullups P1DIR = 0xFF; // Unused pins as outputs P2OUT = 0; P2DIR = 0xFF; _delay_cycles(100000); MST_Data = MST_DataInit; // Load initialize data number_of_bytes = 10; Master_Transmit(); // Initialize PCF8566 while(1) { ADC10CTL0 |= ENC + ADC10SC; // Sampling and conversion start __bis_SR_register(CPUOFF + GIE); // LPM0 with interrupts enabled __disable_interrupt(); temp = ADC10MEM; // IntDegF = ((temp - 630) * 761) / 1024; // Calculate Fahrenheit IntDegF = ((temp - 623) * 761) / 1024; // Calculate Fahrenheit //IntDegC = ((temp - 673) * 423) / 1024; // Calculate Celsius IntDegC = ((temp - 666) * 423) / 1024; // Calculate Celsius if (FCflag == 1) { GetDigits(IntDegF); MST_DataT[6] = 0xE8; // set small character to "F" FCflag = 0; // celsius on the next go-around } else { GetDigits(IntDegC); MST_DataT[6] = 0xB8; // set small character to "C" FCflag = 1; // fahrenheit on the next go-around } MST_DataT[3] = Digits[digit1]; // put 10's digit in array MST_DataT[4] = Digits[digit2]; // put units digit in array MST_Data = MST_DataT; // get data to xmit number_of_bytes = 7; Master_Transmit(); // transmit data to PCF8566 __enable_interrupt(); } } /****************************************************** // USI interrupt service routine // Data Transmit : state 0 -> 2 -> 4 -> 10 -> 12 -> 14 // Data Recieve : state 0 -> 2 -> 4 -> 6 -> 8 -> 14 ******************************************************/ #pragma vector = USI_VECTOR __interrupt void USI_TXRX (void) { switch(__even_in_range(I2C_State,14)) { case 0: // Generate Start Condition & send address to slave P1OUT |= 0x01; // LED on: sequence start Bytecount = 0; USISRL = 0x00; // Generate Start Condition... USICTL0 |= USIGE+USIOE; USICTL0 &= ~USIGE; if (Transmit == 1){ USISRL = 0x7C; // Address is 0x48 << 1 bit + 0 (rw) } if (Transmit == 0){ USISRL = 0x91; // 0x91 Address is 0x48 << 1 bit // + 1 for Read } USICNT = (USICNT & 0xE0) + 0x08; // Bit counter = 8, TX Address I2C_State = 2; // next state: rcv address (N)Ack break; case 2: // Receive Address Ack/Nack bit USICTL0 &= ~USIOE; // SDA = input USICNT |= 0x01; // Bit counter=1, receive (N)Ack bit I2C_State = 4; // Go to next state: check (N)Ack break; case 4: // Process Address Ack/Nack & handle data TX USICTL0 |= USIOE; // SDA = output if (USISRL & 0x01) // If Nack received... { // Send stop... USISRL = 0x00; USICNT |= 0x01; // Bit counter=1, SCL high, SDA low I2C_State = 14; // Go to next state: generate Stop P1OUT |= 0x01; // Turn on LED: error } else { // Ack received, TX data to slave... USISRL = MST_Data[bytecount]; // Load data byte USICNT |= 0x08; // Bit counter = 8, start TX I2C_State = 10; // next state: receive data (N)Ack //Bytecount++; P1OUT &= ~0x01; // Turn off LED break; } case 10: // Receive Data Ack/Nack bit USICTL0 &= ~USIOE; // SDA = input USICNT |= 0x01; // Bit counter = 1, receive (N)Ack bit I2C_State = 12; // Go to next state: check (N)Ack break; case 12: // Process Data Ack/Nack & send Stop USICTL0 |= USIOE; if (Bytecount == number_of_bytes){// If last byte USISRL = 0x00; I2C_State = 14; // Go to next state: generate Stop P1OUT |= 0x01; USICNT |= 0x01; } // set count=1 to trigger next state else{ P1OUT &= ~0x01; // Turn off LED Data_TX(); // TX byte } break; case 14:// Generate Stop Condition USISRL = 0x0FF; // USISRL = 1 to release SDA USICTL0 |= USIGE; // Transparent latch enabled USICTL0 &= ~(USIGE+USIOE); // Latch/SDA output disabled I2C_State = 0; // Reset state machine for next xmt LPM0_EXIT; // Exit active for next transfer break; } USICTL1 &= ~USIIFG; // Clear pending flag } void Data_TX (void){ USISRL = MST_Data[bytecount]; // Load data byte USICNT |= 0x08; // Bit counter = 8, start TX I2C_State = 10; // next state: receive data (N)Ack Bytecount++; } void Setup_USI_Master_TX (void) { _DINT(); Bytecount = 0; Transmit = 1; USICTL0 = USIPE6+USIPE7+USIMST+USISWRST; // Port & USI mode setup USICTL1 = USII2C+USIIE; // Enable I2C mode & USI interrupt USICKCTL = USIDIV_7+USISSEL_2+USICKPL; // USI clk: SCL = SMCLK/128 USICNT |= USIIFGCC; // Disable automatic clear control USICTL0 &= ~USISWRST; // Enable USI USICTL1 &= ~USIIFG; // Clear pending flag _EINT(); } void Master_Transmit(void){ Setup_USI_Master_TX(); USICTL1 |= USIIFG; // Set flag and start communication LPM0; // CPU off, await USI interrupt __delay_cycles(2000000); // Delay between comm cycles } // ADC10 interrupt service routine #pragma vector=ADC10_VECTOR __interrupt void ADC10_ISR (void) { __bic_SR_register_on_exit(CPUOFF); // Clear CPUOFF bit from 0(SR) } #pragma vector=TIMERA0_VECTOR __interrupt void ta0_isr(void) { TACTL = 0; LPM0_EXIT; // Exit LPM0 on return } void GetDigits(tempVal) { if (tempVal >= 100 ) { tempVal -= 100; MST_DataT[2] = 0x06; // set 100's digit to "1" (no provision for > 199) } else { MST_DataT[2] = 0x00; // or not } digit1 = tempVal/10; // separate 10's digit digit2 = tempVal%10; // separate units digit } ** Added code to alternately display the temperature in Fahrenheit and Celsius. The symbol in the upper right hand corner will change from F to C accordingly. ** Added display of 100's digit - Dec. 2011 Quote Link to post Share on other sites
bluehash 1,581 Posted November 22, 2011 Share Posted November 22, 2011 Love the degree symbol. Good use. POTM submission please. Quote Link to post Share on other sites
roger430 12 Posted November 22, 2011 Author Share Posted November 22, 2011 Love the degree symbol. Good use. POTM submission please. Thanks for the invitation to submit this to POTM, however, I don't feel that this experiment would qualify as a candidate for POTM. I believe this project is too specific in nature as it contains an LCD display that most likely cannot be purchased anywhere. It was salvaged from a scrapped digital blood pressure device. The code could possibly be used with other raw LCD displays - don't know for sure. Thanks, Roger Quote Link to post Share on other sites
bluehash 1,581 Posted November 22, 2011 Share Posted November 22, 2011 At the same time, submit your project, even if it is a simple one It does not matter whether it is a one time project. Quote Link to post Share on other sites
roger430 12 Posted December 15, 2011 Author Share Posted December 15, 2011 Tweaked code to display 100's digit and to alternately display the temperature in Fahrenheit and Celsius. Quote Link to post Share on other sites
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.