INTEGRATED CIRCUITS Abstract PCA9564 evaluation board description, features and operation modes are discussed. Source code in C language, containing communication routines between an 80C51-core microcontroller and the PCA9564 is provided. AN10149 PCA9564 Evaluation Board Jean-Marc Irazabal Paul Boogaards Bauke Siderius PCA Technical Marketing Manager Sr. Field Application Engineer Application Engineer Philips Semiconductors 1 2004 Aug 19 TABLE OF CONTENTS OVERVIEW...........................................................................................................................................................................................3 DESCRIPTION ........................................................................................................................................................................................3 ORDERING INFORMATION ......................................................................................................................................................................4 TECHNICAL INFORMATION – HARDWARE ...............................................................................................................................4 BLOCK DIAGRAM ..................................................................................................................................................................................4 I2C DEVICE ADDRESSES .........................................................................................................................................................................4 SCHEMATIC ..........................................................................................................................................................................................5 PCA9564 EVALUATION BOARD TOP VIEW............................................................................................................................................6 JUMPERS AND HEADERS ........................................................................................................................................................................6 PUSHBUTTONS – USER INTERFACE AND RESET ......................................................................................................................................8 IN-SYSTEM PROGRAMMING MODE ........................................................................................................................................................8 P89LV51RD2 ISP programming ...................................................................................................................................................9 P89LPC932 ISP programming......................................................................................................................................................9 OTHER FEATURES .................................................................................................................................................................................9 Write Protect PCF85116...............................................................................................................................................................9 Use of other 80C51 type Philips microcontrollers ......................................................................................................................10 Use of any other non 80C51 type master devices ........................................................................................................................10 Communication between the 2 microcontrollers .........................................................................................................................10 Miscellaneous..............................................................................................................................................................................11 TECHNICAL INFORMATION – EMBEDDED FIRMWARE ......................................................................................................12 OVERVIEW..........................................................................................................................................................................................12 EMBEDDED PROGRAMS FLOWCHARTS ..................................................................................................................................................14 Program Selection.......................................................................................................................................................................14 Program 1: P89LV51RD2–PCA9564–PCA9531; PCA9531 dynamic programming..................................................................15 Program 2: P89LV51RD2–PCA9564–PCA9531–PCF85116–P89LPC932; Predefined blinking patterns ................................16 Program 3: P89LV51RD2–PCA9564–PCA9531–P89LPC932; P89LPC932 LED programming..............................................16 2 Program 4: P89LV51RD2–PCA9564–PCA9531–P89LPC932; I C address search ..................................................................17 SOURCE CODE P89LV51RD2 – REV 1.0 ............................................................................................................................................18 SOURCE CODE P89LPC932 – REV 1.0................................................................................................................................................18 DOWNLOAD SOFTWARE, PROGRAMS AND DOCUMENTATION .......................................................................................19 PCA9564 EVALUATION BOARD WEB PAGE..............................................................................................................................19 APPENDIX 1: P89LV51RD2 MICROCONTROLLER SOURCE CODE – REV 1.0...................................................................20 I2CEXPRT.H ....................................................................................................................................................................................20 MAINLOOP.C.......................................................................................................................................................................................21 I2C_ROUTINES.H ................................................................................................................................................................................23 I2C_ROUTINES.C ................................................................................................................................................................................23 I2CDRIVR.H.....................................................................................................................................................................................36 I2CDRIVR.C.....................................................................................................................................................................................36 I2CMASTR.H ....................................................................................................................................................................................37 I2CMASTR.C ...................................................................................................................................................................................38 I2CINTFC.C......................................................................................................................................................................................41 PCA9564SYS.H ..................................................................................................................................................................................43 PCA9564SYS.C ..................................................................................................................................................................................43 INTERRUPTS.C .....................................................................................................................................................................................44 APPENDIX 2: P89LPC932 MICROCONTROLLER SOURCE CODE – REV 1.0 ......................................................................45 MAIN.C...............................................................................................................................................................................................45 I2CSLAVE.C .........................................................................................................................................................................................46 UA_EXPRT.H .......................................................................................................................................................................................48 APPENDIX 3: PCA9564 EVALUATION BOARD BILL OF MATERIAL...................................................................................49 REVISION HISTORY ........................................................................................................................................................................51 DISCLAIMERS......................................................................................................................................................................................52 2 OVERVIEW Description The PCA9564 Evaluation Board demonstrates the Philips PCA9564 I2C-bus controller’s ability to interface between a master (connected to its parallel bus and its control signals) and any master and slave devices connected to its I2C-bus. The evaluation board is populated with the following devices and functions: - Philips P89LV51RD2 microcontroller connected to the PCA9564 8-bit parallel port and control signals. It is used as the master controlling the other devices on the board with the embedded firmware. It can also be used as a slave device with an appropriate program loaded. - Philips PCA9564 I2C-bus controller interfacing between the P89LV51RD2 and the I2C-bus. - Philips PCA9531 I2C 8-bit LED dimmer used as an I2C target slave device for the P89LV51RD2/PCA9564. - Philips P89LPC932 microcontroller connected to the I2C-bus. It can act as either a target slave device with the default P89LV51RD2 firmware programs or as a master connected to the I2C-bus through some stored user definable routines. - Philips PCF85116 16 kbits (2KB) I2C EEPROM used to store information that can be used by the evaluation board firmware. - Philips PCA9554A I2C 8-bit GPIO acting as interface / keyboard between the user and the P89LV51RD2 - Sipex SP3223 RS-232 transceiver allows the P89LV51RD2 and the P89LPC932 devices to be in-system programmed through a personal computer’s serial port. An external 9 V DC power supply is used to provide power to the 3.3 V on-board voltage regulator. The P89LPC932 and P89LV51 are both limited to a 3.3 V supply voltage. The evaluation board can be used in different ways: 1. Stand-alone mode: 4 default firmware programs are stored in the P89LV51RD2 (master) and the P89LPC932 (slave). No external hardware or software is required. The firmware allows the user to execute some applications where data and control traffic is automatically generated in both directions between the P89LV51RD2 and the PCA9564 on one side and the PCA9564 and the I2C devices on the other side (PCA9531, PCF85116, P89LPC932 and PCA9554A). The user, through an 8-switch interface, can control the routines and the execution of the commands. The embedded firmware provides master mode examples (transmitter and receiver). Code is written in C language and can be used with any 80C51-type microcontroller. The embedded firmware can be downloaded from the www.standardproducts.philips.com website which the user can modify as required. 2. Program the microcontroller(s) with compiled files (“Hex” files) through the ISP (In-System Programming) interface. This mode allows a user to program the microcontroller(s) with additional applications and programs. Code programming is not required and the “Hex” file(s) can be loaded to the microcontroller(s) by using Flash Magic, Windows based free software from the Embedded Systems Academy, sponsored by Philips Semiconductors “Hex” files can be downloaded from the (http://www.esacademy.com/software/flashmagic/). www.standardproducts.philips.com website. “Hex” files can be the manufacturing default embedded program (explained above) or any evaluation/demo program that will be developed for this specific board. 3. Use the full flow using 8051 software development tools: C code generation or Assembler code generation, program debugging, compilation and program loading the targeted microcontroller to develop specific applications using the PCA9564 evaluation board and optional I2C devices daughter cards. Free evaluation software from American Raisonance allowing up to 4 kbits of code can be used. 4. Use any emulator, microcontroller, microprocessor or DSP instead of the Philips P89LV51RD2. To do that, the new master needs to be connected to the 8-bit parallel port and control signals headers and the P89LV51RD2 needs to be removed from its socket. For more information about program files and software that is required, refer to the paragraphs “Download software, programs and documentation” and “PCA9564 evaluation board web page”. 3 Ordering information The complete PCA9564 evaluation board Kit consists of the: • PCA9564 evaluation board • 9 V DC power supply • DB-9 connector Kit can be obtained through your local Philips Semiconductors Sales organization. It can also be obtained via email at [email protected]. TECHNICAL INFORMATION – HARDWARE Block diagram VDD GND I2C-bus 1 SDA P89LV51 RD2 PCA9531 PCA9564 DATA I2C Connector SCL CONTROL PCF85116 8 LEDs INT PCA9554A 8 LEDs P89LPC932 DB-9 connector 8 PUSHBUTTONS I2C Connector VDD GND SP3223 RS-232 9 V external power supply VOLTAGE REGULATOR 3.3 V I2C-bus 2 Figure 1. Evaluation board block diagram I2C device addresses Device type P89LV51RD2 / PCA9564 P89LPC932 PCA9531 PCF85116 PCA9554A I2C Address (Hexadecimal) User definable when microcontroller used as slave Microcontroller User definable when microcontroller used as slave 0xE0 to 0xE8 with the embedded programs 8-bit I2C LED Dimmer 0xC8 16kbits I2C EEPROM 0xA0 to 0xA8 (function of the addressed memory) 8-bit I2C GPIO 0x7E Table 1. I2C device addresses Description Microcontroller / I2C-bus controller 4 Schematic Figure 2. PCA9564 Evaluation Board Schematic 5 PCA9564 Evaluation Board Top view JP16 JP14 PCF85116 PCA9564 PORT1LV51 VDDMCU + EEWP – JP1 PCA9531 RESET VDDISP – JP15 LD1 to LD8 (bottom to top) RSTISP – JP10 LD9 to LD12 (top to bottom) I2C-bus 1 Connector 1 – 9564 JP4 P89LV51RD2 I2C Connect – JP7 JP6 LD21 to LD23 (right to left) JP12 – SCLLV JP13 – SDALV JP9 – PSEN\ I2C-bus 2 Connector 2 – LV/LPC JP5 SP3223 JP11 P89LPC932 VDD Conn – J P8 PORT0LPC JP17 JP18 JP2 JP3 PCA9554A JP19 – A2 JP20 – A1 JP21 – A0 LD13 to LD20 (right to left) Figure 3. PCA9564 Evaluation Board Top View Jumpers and Headers Label Purpose JP1 (EEWP) PCF85116 Write Protect JP2 Selection of the microcontroller to be programmed through ISP (TxD) JP3 Selection of the microcontroller to be programmed through ISP (RxD) JP4 (9564) I2C-bus connector 1 JP5 (LV/LPC) I2C-bus connector 2 Jumper position Description Open WP pin connected to VDD – Write not permitted Closed WP pin connect to GND – Write permitted Open No ISP programming can be performed Closed between 1 and 2 (PRGLPC) Closed between 2 and 3 (PRGLV) Open ISP programming of P89LPC932 can be performed TxD pin of P89LPC932 connected to T1IN of SP3223 ISP programming of P89LV51RD2 can be performed TxD pin of P89LV51RD2 connected to T1IN of SP3223 No ISP programming can be performed Closed between 1 and 2 (PRGLPC) Closed between 2 and 3 (PRGLV) ISP programming of P89LPC932 can be performed RxD pin of P89LPC932 connected to R1OUT of SP3223 ISP programming of P89LV51RD2 can be performed TxD pin of P89LV51RD2 connected to R1OUT of SP3223 I2C-bus 1 – Bus connected to the PCA9564, PCA9531, PCF85116 and PCA9554A Note: I2C-bus 1 and I2C-bus 2 can be connected together through jumpers JP6 and JP7 I2C-bus 2 – Bus connected to the P89LPC932. It is also connected to the I2C-bus of a P89C51Rx+/Rx2/66x with I2C-bus (SCL = P1.6, SDA = P1.7) when JP12 and JP13 closed Note: I2C-bus 1 and I2C-bus 2 can be connected together through jumpers JP6 and JP7 6 JP6 (I2C Connect) JP7 (I2C Connect) JP8 (VDD Conn) Connect I2C-bus 1 and I2C-bus 2 2 Connect I C-bus 1 and I2C-bus 2 Power supply for the I2C-bus connectors Open SCL I2C-bus 1 and SCL I2C-bus 2 are not connected together Closed SCL I2C-bus 1 and SCL I2C-bus 2 are connected together Open SDA I2C-bus 1 and SDA I2C-bus 2 are not connected together Closed SDA I2C-bus 1 and SDAI2C-bus 2 are connected together Open VDD pin of connectors not connected to the internal 3.3 V power supply VDD pin of connectors connected to the internal 3.3 V power supply Closed JP9 (PSEN\) 89C51Rx+/Rx2/66x ISP mode (Not applicable to P89LV51RD2, only to 5 V devices) Open ISP mode not entered Closed JP10 (RSTISP) P89LPC932 ISP mode Open ISP mode entered Note: More information can be found on the Philips Application Notes AN461: “In-circuit and In-application programming of the 89C51Rx+/Rx2/66x microcontrollers” Normal mode Closed P89LPC932 ISP mode JP11 PCA9554A Interrupt output monitoring Open PCA9554A INT pin not monitored Closed between 1 and 2 (INTLPC) Closed between 2 and 3 (INTLV) Open PCA9554A INT pin can be monitored by P89LPC932 JP12 (SCLLV) P89x51 with I2C-bus connection to I2C-bus 2 PCA9554A INT pin can be monitored by P89LV51RD2 P89C51Rx+/Rx2/66x with I2C-bus (SCL = P1.6) not connected to SCL I2C-bus 2 P89C51Rx+/Rx2/66x with I2C-bus (SCL = P1.6) connected to SCL I2C-bus 2 P89C51Rx+/Rx2/66x with I2C-bus (SDA = P1.7) not connected to SDA I2C-bus 2 P89C51Rx+/Rx2/66x with I2C-bus (SDA = P1.7) connected to SDA I2C-bus 2 Probing of PCA9564 control signals Closed JP13 (SDALV) P89x51 with I2C-bus connection to I2C-bus 2 Open Closed JP14 PCA9564 control signals JP15 (VDDISP) JP16 PCA9564 parallel bus JP17 (Tx ↔Rx) Connection TxD P89LV51RD2 to RxD P89LPC932 JP18 (Rx ↔Tx) Connection RxD P89LV51RD2 to TxD P89LPC932 JP19 (A0) P89LPC932 I2C slave address input 0 2 JP20 (A1) P89LPC932 I C slave address input 1 JP21 (A2) P89LPC932 I2C slave address input 2 VDDMCU+ P89xx51 Power supply selection Open P89LPC932 ISP mode Closed Normal mode Probing of PCA9564 8-bit parallel bus Open Pins not connected together Closed Pins connected together Note: JP2 and JP3 must be open when JP17 is closed Pins not connected together Open Closed Open Pins connected together Note: JP2 and JP3 must be open when JP18 is closed Address Input 0 connected to VDD – A0 = 1 Closed Address Input 0 connected to GND – A0 = 0 Open Address Input 1 connected to VDD Closed Address Input 1 connected to GND – A1 = 0 Open Address Input 2 connected to VDD Closed Address Input 2 connected to GND – A2 = 0 Open – A1 = 1 – A2 = 1 PORT1LV51 Port 1 P89LV51 External power supply can be applied to the P89xx51 microcontroller (Voltage applied to pin VDDMCU+, on the left side of the jumper) Internal regulated 3.3 V power supply applied to the P89xx51 microcontroller General purpose 8-bit Input/Output port (Port 1 P89LV51RD2) PORT0LPC Port 0 P89LPC932 General purpose 8-bit Input/Output port (Port 0 P89LPC932) Closed Table 2. PCA9564 Evaluation Jumpers and Headers 7 Pushbuttons – User interface and Reset • Pushbuttons S1 to S8: They are connected to the 8 inputs of the PCA9554A, I2C General Purpose Input Output device and can be used as an interface between the user and the microcontroller(s) to perform actions such as program selection, user definable events … The microcontroller(s) can either: - Poll the PCA9554A in order to read the input register and the state of the switches. Reading of the input port is performed by: 1. Sending the PCA9554A I2C address with a Write command followed by 0x00 (Input register pointer). 2. A Re-Start Command followed by the PCA9554A I2C address with a Read command. 3. Reading the input port register byte from the PCA9554A. - Monitor the PCA9554A Interrupt output pin in order to detect change(s) in the switches. When one or more input change states: 1. The PCA9554A Interrupt output will go LOW, thus indicating to the microcontroller that a switch has been pressed and the Interrupt service routine needs to be initiated. 2. The microcontroller can then perform the same reading sequence as explained above in order to determine which input changes state. Reading the PCA9554A will automatically clear its interrupt. Pushbuttons can be used in 2 different modes with the embedded programs: - Single shot mode: a single push then release is detected. The action associated with the pushbutton is executed once. 1. An Interrupt is detected by the master (P89LV51RD2) when a pushbutton is pressed. 2. P89LV51RD2 initiates a read of the PCA9554A input register (first snapshot). 3. P89LV51RD2 initiates a second reading of the PCA9554A input register (second snapshot) about 750 ms later. If the second reading indicates a pushbutton idle condition, then the action read the first time is performed once. - Permanent push mode: the user keeps the pushbutton pushed and the master executes the associated command until the pushbutton is released again. 1. An Interrupt is detected by the master (P89LV51RD2) when a pushbutton is pressed 2. P89LV51RD2 initiates a read of the PCA9554A input register (first snapshot) 3. P89LV51RD2 initiates a second read of the PCA9554A input register (second snapshot) about 750 ms after If the second read is the same as the first one, then the master will continue to poll the PCA9554A input register and execute the associated command until the user releases the pushbutton. Notes: Connection of the PCA9554A Interrupt pin to the P89LV51RD2 or to the P89LPC932 is done through jumper JP11. a) JP11 between 1 and 2 connects the PCA9554A Interrupt pin to the P89LPC932 device b) JP11 between 2 and 3 connects the PCA9554A Interrupt pin to the P89LV51 device - Polling or interrupt monitoring of the PCA9554A by the P89LPC932 microcontroller requires having jumpers JP6 and JP7 closed. I2C-bus 1 and I2C-bus 2 need to be connected together since the PCA9554A is located on I2C-bus 1. • Pushbutton S9: Pushbutton S9 (RESET), when pressed, performs a reset to both P89LV51RD2 and PCA9531 devices to their power up default states. It is also used to enter and exit the P89LV51RD2 ISP mode (for more detail, refer to the paragraph “In-System Programming Mode”. In-System Programming Mode P89LV51RD2 and P89LPC932 devices have a built-in ISP (In-System Programming) algorithm allowing them to be programmed without the need to remove them from the application. Also, a previously programmed device can be erased and reprogrammed without removal from the circuit board. In order to perform ISP operations, the microcontroller is powered up in a special “ISP mode”. ISP mode allows the microcontroller to communicate with an external host device through the serial port, such as a PC or terminal. The microcontroller receives commands and data from the host, erases and reprograms code memory, etc. Once the ISP operations have been completed, the device is reconfigured so that it will operate normally the next time it is either reset or power cycled. 8 ISP programming for both devices can be done using Flash Magic. Flash Magic is a free, powerful, feature-rich Windows application that allows easy programming of Philips Flash microcontrollers. Flash Magic uses Intel Hex files as input to program the targeted device. For download information, refer to the paragraph “Download software, programs and documentation”. P89LV51RD2 ISP programming a) Set jumpers JP2 and JP3 to target P89LV51RD2 device: both jumpers connected between 2 and 3 b) Connect the DB-9 cable between the PC serial port and the PCA9564 evaluation board DB-9 connector c) Enter the P89LV51RD2 ISP mode as requested in the Flash Magic pop up window: This is done by pushing the RESET pushbutton (S9) one time. d) Open Flash Magic and go through the five following steps: Step 1: Set the connection status and the type of microcontroller to be programmed: COM port, Baud Rate (9600), Device = 89LV51RD2 Step 2: Flash erasing (part or all) Step 3: Select the Hex file to be loaded in the microcontroller Step 4: Options to be set (Memory verification, Security bits…) Step 5: Perform the operations described in the steps above (click on “START” button) Programming of the blocks is displayed at the bottom of the Flash Magic window. e) Exit the P89LV51RD2 ISP mode when programming done (“Finished” displayed at the bottom of the Flash Magic window): This is done by pushing the RESET pushbutton one time again (S9) f) Once device programming has successfully been executed, the microcontroller can run the new program. P89LPC932 ISP programming a) Set jumpers JP2 and JP3 to target P89LPC932 device: both jumpers connected between 1 and 2 b) Connect the DB-9 cable between the PC serial port and the PCA9564 evaluation board DB-9 connector c) Enter the P89LPC932 ISP mode: This is done by setting the following jumpers: - JP10 (RSTISP) closed - JP15 (VDDISP) open - JP6 and JP7 (I2CConnect) open - JP12 (SCLLV) and JP13 (SDALV) open d) Open Flash Magic and go through the 6 following steps: Step 1: Set the connection status and the type of microcontroller to be programmed: COM port, Baud Rate (9600), Device = 89LPC932 Step 2: Go to: Options → Advanced Options → Hardware Config Check the box “Use DTR and RTX to enter ISP mode” Step 3: Flash erasing (part or all) Step 4: Select the Hex file to be loaded in the microcontroller Step 5: Options to be set (Memory verification, Security bits…) Step 6: Perform the operations described in the steps above (click on “START” button). Programming of the blocks is displayed at the bottom of the Flash Magic window. e) Exit the P89LV51RD2 ISP mode when programming done (“Finished” displayed at the bottom of the Flash Magic window): This is done by setting: - JP10 (RSTISP) open - JP15 (VDDISP) closed - State of JP6, JP7, JP12 and JP13 are function of the program requirements f) Once device programming has successfully completed, exit from the ISP. The microcontroller is now ready to run the new program. Other features Write Protect PCF85116 JP1 allows data protection in the PCF85116 EEPROM: - JP1 open: data in the EEPROM is write protected - JP1 closed: writing to the EEPROM is allowed – memory is not protected 9 Use of other 80C51 type Philips microcontrollers Any Philips 80C51 microcontroller pin to pin compatible with the P89LV51Rx2 device can be used as to interface with the PCA9564. • Power supply: It can be chosen from: - The internal 3.3 V regulated voltage: Jumper VDDMCU+ closed - An external regulated voltage: Jumper VDDMCU+ open, external voltage applied to VCCMCU+ If an external voltage is applied to the microcontroller, digital signals interfacing with the PCA9564 will be pulled up to this external voltage value. Caution: Since the PCA9564 is 5.5 V tolerant, no voltage greater than 5.5 V must be applied to the VDDMCU+ pin. • Microcontroller with built-in I2C interface: Port P1.6 (SCL) and P1.7 (SDA) can be connected to the internal I2C-bus 2 (connector JP5) through jumpers JP12 and JP13. - JP12 open: P1.6 not connected to SCL2 - JP12 closed:P1.6 connected to SCL2 - JP13 open: P1.7 not connected to SDA2 - JP13 closed:P1.7 connected to SDA2 • ISP mode: ISP mode for P89C51Rx+/Rx2/66x devices can also be entered by forcing the /PSEN pin to LOW. This is performed through the jumper JP9. - JP9 open: PSEN floating - JP9 closed: PSEN forced to ground Use of any other non 80C51 type master devices Any other non-80C51 type microprocessor, DSP, ASIC or emulator can be used with the PCA9564 evaluation board. When an external device is used: 1) Remove the P89LV51RD2 microcontroller from its socket 2) Apply the 8-bit parallel bus data on connector JP16. Built-in pull up resistors can be disconnected by opening the jumper VDDMCU+. Note: RESET pushbutton (S9) cannot longer be used when VDDMCU+ is open 3) Apply PCA9564 control signals and monitor Interrupt pin (open drain output) on connector JP14 Caution: Since the PCA9564 is 5.5 V tolerant, no voltage greater than 5.5 V must be applied to the parallel bus data and the control signals Communication between the 2 microcontrollers • Communication through the I2C-bus: Jumpers JP6 and JP7 allow to connect or split the I2C-bus in one same bus or 2 different buses. I2C-bus 1 contains the following devices: P89LV51RD2/ PCA9564, PCA9531, PCF85116 and PCA9554A I2C-bus 2 contains the following devices: P89LPC932, P89xx51 with built-in SCL/SDA (when jumpers JP12 and JP13 are closed). - JP6 open: SCL Bus 1 and SCL Bus 2 are not connected together - JP6 closed: SCL Bus 1 and SCL Bus 2 are connected together - JP7 open: SDA Bus 1 and SDA Bus 2 are not connected together - JP7 closed: SDA Bus 1 and SDA Bus 2 are connected together Since the PCA9564 is a multi-master capable device, both microcontrollers can be a master in the same bus (when JP6 and JP7 closed). If both masters try to take control of the I2C-bus at the same time, an arbitration procedure will be performed between the P89LV51RD2/PCA9564 and the P89LPC932. • Communication through RxD and TxD pins: An additional non-I2C communication channel between the 2 microcontrollers is available through their RxD and TxD pins. P89LV51 TxD pin can be connected to the P89LPC932 RxD pin through jumper JP17 - JP17 open: pins are not connected together - JP17 closed: pins are connected together 10 P89LV51 RxD pin can be connected to the P89LPC932 TxD pin through jumper JP18 - JP18 open: pins are not connected together - JP18 closed: pins are connected together Note: Jumpers JP2 and JP3 must be open when JP17 and JP18 need to be closed. Miscellaneous • Power supply for daughter cards connected to the I2C-bus connectors: Jumper JP8 (VDD Conn), when closed, connect the VDD pins in the two I2C-bus connectors (JP4 and JP5) to the internal 3.3 V regulated voltage, thus allowing daughter cards to be supplied directly by the main board - JP8 open: VDD pin in the two I2C-bus connectors is floating - JP8 closed: VDD pin in the two I2C-bus connectors is connected to the internal 3.3 V regulated voltage • General purpose LEDs: Several LEDs are connected to the P89LV51RD2 and the P89LPC932 for debugging or general-purpose use. LD1 to LD8 are accessible by both microcontrollers through I2C by programming the PCA9531. LED Pin Device LED Pin Device LD1 LD2 LD3 LD4 LD5 LD5 LD7 LD8 LD9 LD10 LD11 LD12 LED0 LED1 LED2 LED3 LED4 LED5 LED6 LED7 P2.2 P2.3 P2.4 P2.5 PCA9531 PCA9531 PCA9531 PCA9531 PCA9531 PCA9531 PCA9531 PCA9531 P89LV51RD2 P89LV51RD2 P89LV51RD2 P89LV51RD2 LD13 LD14 LD15 LD16 LD17 LD18 LD19 LD20 LD21 LD22 LD23 P2.0 P2.1 P2.2 P2.3 P2.4 P2.5 P2.6 P2.7 P1.4 P1.6 P1.7 P89LPC932 P89LPC932 P89LPC932 P89LPC932 P89LPC932 P89LPC932 P89LPC932 P89LPC932 P89LPC932 P89LPC932 P89LPC932 Table 3. Evaluation board LEDs • • General Purpose jumpers for P89LPC932: Jumpers JP19, JP20 and JP21 allows to force HIGH or LOW logic levels respectively on pins P0.0, P0.1 and P0.2 of the P89LPC932. - JPxx open: the corresponding port is set to HIGH - JPxx closed: the corresponding input port is set to LOW General purpose headers for both microcontrollers: PORT1LV51 and PORT0LPC headers allow to easily access to Port 0 of each device for monitoring or external control. VDD and GND pins are also available. Note: Header labeled “3v3” on PORT0LV51 is actually connected to VDDMCU+ pin. The voltage on this node can be externally supplied and is limited to 5.5 V. 11 TECHNICAL INFORMATION – EMBEDDED FIRMWARE Overview PCA9564 evaluation board is delivered with 4 different embedded firmware programs (Program 1 to Program 4) allowing the user to run simple applications in order to evaluate the PCA9564’s capabilities, to monitor data and control signals with the P89LV51RD2 master, and the I2C slave devices present in the evaluation board. Besides the external power supply, no external hardware or software is required to run those applications. Embedded programs are erased as soon as the microcontroller is reprogrammed with a different code. The embedded programs require programming of both P89LV51RD2 and P89LPC932 and “Hex” files can be downloaded from www.standardproducts.philips.com website. “Hex” files can be loaded to the microcontrollers by using their ISP mode with Flash Magic software. For more information about ISP mode and file downloading, refer to the paragraphs “InSystem Programming mode” and “Download software, programs and documentation”. - Pushbuttons S1 to S8 allow program selection (S8) and initiate specific actions for each program (S1 to S7). PCA9554A is used to collect actions performed on the pushbuttons and inform the P89LV51RD2 that a reading routine to determine the nature of the action is requested. Pushing S8 does jump from one program to another (from Program 1 to Program 4, then again Program 1…). - LD9 and LD10 display the number of the selected program - LD11 and LD12 display program specific information • Program 1 (LD9 = OFF, LD10 = OFF): PCA9531 dynamic programming Program 1 uses the P89LV51RD2/PCA9564 as an I2C master, the PCA9531 (with LD1 to LD8) as an I2C slave to dynamically change blinking rates and output states. LD1 to LD4 are programmed to blink at Blinking rate 0 (BR0), while LD5 to LD8 are programmed to blink at Blinking Rate 1 (BR1). Actions on the pushbuttons: - S1: Decrease blinking frequency for both BR0 and BR1 (single shot or permanent push modes) - S2: Decrease duty cycle for both BR0 and BR1 (single shot or permanent push modes) - S3: Select the Blinking Rate (BR0 or BR1) to be programmed through S1, S2, S5, S6 and S7 - S4: Reset the programming and program the LEDs to their default blinking frequency - S5: Increase blinking frequency for both BR0 and BR1 (single shot or permanent push modes) - S6: Increase duty cycle for both BR0 and BR1 (single shot or permanent push modes) - S7: Program the LEDs to be OFF or blinking at BR0 or BR1 - S8: Jump to the next program (Program 2) LD11 and LD12 provide the following information: - LD11 = OFF → BR0 programming selected (LD1 to LD4) - LD11 = ON → BR1 programming selected (LD5 to LD8) - LD12 = ON → Default blinking rate set to the PCA9531 - LD12 = OFF → PCA9531 has been programmed by the user and blinking is different from default values • Program 2 (LD9 = ON, LD10 = OFF): Preprogrammed blinking patterns Program 2 uses the P89LV51RD2/PCA9564 as an I2C master, the PCF85116, the PCA9531 (with LD1 to LD8) and the P89LPC932 (with LD13 to LD20) as I2C slaves to display preprogrammed blinking patterns stored in the EEPROM. For a specific selected pattern: a) Data used to program the PCA9531is read from the EEPROM. Data organization is shown in Figure 4. b) The PCA9531 is then programmed with the data previously read. Action on the pushbuttons: - S4: Scans the EEPROM in order to determine location of the different patterns (first and last cell numbers for each programmed pattern). - S5: Select the pattern to be read from the EEPROM and to be programmed in the PCA9531. Scan of the EEPROM must be performed first before being able to select between the different patterns. - S8: Jump to the next program (Program 3) 12 LD12 provides the following information: - LD12 = OFF → Scan of the EEPROM not performed - LD12 = ON → Scan of the EEPROM performed LD13 to LD20 display the number of the pattern currently selected. COMMAND 1.1 P A T T E R N 1 COMMAND 1.2 N1 bytes COMMAND 1.N COMMAND 2.1 P A T T E R N 2 COMMAND 2.2 COMMAND 2.M COMMAND X.1 P A T T E R N X E N D COMMAND X.2 N2 bytes C O M M A N D 1.1 C O M M A N D 1.2 Memory location Data 00 Number of bytes = N1 01 Function Number 1 = 0x01 02 Delay between commands 03 I2C Address 04 Data (1) 05 Data (2) N1-1 Data (N1-4) N1 Number of bytes = N2 N1+1 Function Number 1 = 0x01 N1+2 Delay between commands N1+3 I2C Address N1+4 Data (1) N1+5 Data (2) N1+ N2-1 Data (N2-4) N1-1 Number of bytes = 2 N1 Function End = 0x99 Total umber of bytes for this command Function (Pattern) identifier Programmable delay between commands COMMAND X.Y END INSTRUCTION End of data identifier Figure 4. PCF85116 memory organization • Program 3 (LD9 = OFF, LD10 = ON): P89LPC932 LED programming Program 3 uses P89LV51RD2/PCA9564 as an I2C master, the PCA9531 (with LD1 to LD8) and the P89LPC932 (with LD13 to LD20) as I2C slaves to display a user definable byte on LD13 to LD20. Value of the byte to be programmed is displayed with LD1 (bit 0, LSB) to LD8 (bit 7, MSB) Once P89LPC932 has been programmed, the value is displayed with LD13 (bit 0, LSB) to LD20 (bit 7, MSB). Action on the pushbuttons: S1: Decrease position of the bit to be programmed: 7 → 6 → 5 → 4 → 3 → 2 → 1 → 0 → 7 → … S2: Invert the polarity of the logic value of the current bit, programmed logic value is displayed on LD1 to LD8: 0 → 1 → 0 → 1 … 0: corresponding LED is OFF 1: corresponding LED is ON S3: Send the programmed byte to the P89LPC932 when programming has been done. LD13 to LD20 display the programmed byte value when command has been sent 0: corresponding LED is OFF 1: corresponding LED is ON S4: Reset the programming and the value sent to the P89LPC932. LD1 to LD8, LD13 to LD20 are OFF. S5: Increase position of the bit to be programmed: 0 → 1 → 2 → 3 → 4 → 5 → 6 → 7 → 0 → … S8: Jump to the next program (Program 4) 13 • Program 4 (LD9 = ON, LD10 = ON): I2C address search Program 4 uses the P89LV51RD2/PCA9564 as an I2C master and the P89LPC932 (with jumpers JP19 to JP21) as an I2C slave. In this mode, the PCA9564 searches for the P89LPC932’s I2C slave address (JP19 to JP21 programs the 3 LSB’s of the P89LPC932 I2C slave address, the 4 MSB’s of the address are fixed. The address is unknown to the P89LV51RD2) Action on the pushbuttons: - S1: Initiates the P89LPC932’s I2C address search routine - S2: Resets the P89LV51RD2 search routine algorithm and initiates a P89LPC932 I2C address scanning and memorization. The P89LPC932 scans its GPIO’s in order to memorize logic values associated with jumpers JP19 to JP21. - S8: Jump to the next program (Program 1) LD11 and LD12 provide the following information: - LD11 = OFF → I2C address not found or search routine not performed yet - LD11 = ON → I2C address search routine successful - LD12 = OFF → search routine not performed yet - LD12 = ON → search routine performed and I2C address not found Embedded programs flowcharts Program Selection Power – up or RESET pushbutton (S9) pushed NO PROGRAM SELECTED NO S8 pushed? YES PROGRAM 1 NO S8 pushed? YES PROGRAM 2 NO PROGRAM 3 S8 pushed? YES PROGRAM 4 NO LD9 LD10 LD11 LD12 LD[1:8] LD[13:20] LD[21:23] = ON = ON = ON = ON = OFF = OFF = OFF LD9 LD10 LD[1:8] LD11 LD12 LD[13:20] LD[21:23] = OFF = OFF = default blinking rate = OFF = OFF = OFF = OFF LD9 LD10 LD[1:8] LD11 LD12 LD[13:20] LD[21:23] = ON = OFF = OFF = OFF = OFF = OFF = OFF LD9 LD10 LD[1:8] LD11 LD12 LD[13:20] LD[21:23] = OFF = ON = OFF = OFF = OFF = OFF = OFF LD9 LD10 LD[1:8] LD11 LD12 LD[13:20] LD[21:23] = ON = ON = OFF = OFF = OFF = OFF = OFF S8 pushed? YES NO STATES of LEDs when entering the programs S8 pushed? Note: At power up or when an action on the RESET pushbutton is performed, no program is selected and LD9 to LD12 are ON. YES Figure 5. Program selection 14 Program 1: P89LV51RD2–PCA9564–PCA9531; PCA9531 dynamic programming LD1 to LD4 blinking at 0.5 s, 50 % LD5 to LD8 blinking at 0.5 s, 50 % LD11 = OFF, LD12 = ON LD11 = OFF YES S4 pushed? NO YES S3 pushed? Notes: - Increment is blocked when Value = 0xFF - Decrement is blocked when Value = 0x00 - Increment/Decrement pushbuttons have 2 modes: a) One shot: Single Increment/Decrement when a single push and then release done b) Continuous Increment/Decrement until Value = 0xFF/0x00 when the corresponding pushbutton is kept pressed NO S1 pushed? YES LD12 = OFF New PSC0 = Programmed PSC0 + 1 YES LD12 = OFF New PSC0 = Programmed PSC0 – 1 YES LD12 = OFF New PWM0 = Programmed PWM0 + 1 YES LD12 = OFF New PWM0 = Programmed PWM0 - 1 YES LD12 = OFF - Read LS0 If LED at BR0, then OFF If LED OFF, then LED at BR0 YES LD12 = OFF New PSC1 = Programmed PSC1 + 1 YES LD12 = OFF New PSC1 = Programmed PSC1 – 1 YES LD12 = OFF New PWM1 = Programmed PWM1 + 1 YES LD12 = OFF New PWM1 = Programmed PWM1 – 1 YES LD12 = OFF - Read LS1 If LED at BR1, then OFF If LED OFF, then LED at BR1 NO S5 pushed? NO S2 pushed? NO S6 pushed? NO S7 pushed? NO NO LD11 = ON YES S4 pushed? NO YES NO PUSHBUTTONS S1 PSC - S3 pushed? S5 PSC + S1 pushed? NO S5 pushed? S2 PWM - S6 PWM + S3 BR0 BR1 S7 OFF BRx S4 INIT S8 CHGE PRG NO S2 pushed? NO S6 pushed? NO S7 pushed? NO Figure 6. Program 1 – PCA9531 dynamic programming 15 Program 2: P89LV51RD2–PCA9564–PCA9531–PCF85116–P89LPC932; Predefined blinking patterns LD1 to LD8 = OFF LD13 to LD20 = OFF LD11 = OFF, LD12 = OFF Scan_Done = 0 Pattern_Number = 1 NO PUSHBUTTONS S1 NOT USED S5 PRG CHGE S2 NOT USED S6 NOT USED S3 NOT USED S7 NOT USED S4 EE CHK S8 CHGE PRG Scan the PCF85116 EEPROM First and last cell number for each preprogrammed pattern are memorized by the P89LV51RD2 Min and Max for each pattern Scan_Done = 1 YES S4 pushed? NO YES S5 pushed? Scan_Done =1 ? NO NO YES 1. 2. 3. 4. 5. If Pattern_Number ≠ 4 then Increase Pattern_Number If Pattern_Number = 4 then Pattern_Number = 1 Display Pattern_Number using LD13 to LD20 Read each I2C command in the EEPROM between Min [Pattern_Number] and Max[Pattern_Number] Send data read from EEPROM Loop between 3) and 4) until S5 pushed again Figure 7. Program 2 – Preprogrammed blinking patterns Program 3: P89LV51RD2–PCA9564–PCA9531–P89LPC932; P89LPC932 LED programming LD1 to LD8 = OFF LD13 to LD20 = OFF LD11 = OFF, LD12 = OFF Bit_Position = 0 Bit_Value = 0 Data[7:0] = 0 YES NO PUSHBUTTONS S1 BIT - S2 0/1 S4 pushed? S5 BIT + S6 NOT USED YES If Bit_Position = 0, then Bit_Position = 7 Else Decrement Bit_Position YES If Bit_Position = 7, then Bit_Position = 0 Else Increment Bit_Position YES If Data[Bit_Position] = 0 then Data[Bit_Position] = 1 If Data[Bit_Position] = 1 then Data[Bit_Position] = 0 LD[Bit_Position+1] = Data[Bit_Position] YES Program P89LPC932 with the programmed byte Sequence = Start – Address+W – 0x00 – Data[7:0] – Stop LD13 to LD20 display the programmed byte S1 pushed? NO S5 pushed? NO S2 pushed? S3 SND DATA S7 NOT USED NO S3 pushed? S4 RST S8 CHGE PRG NO Figure 8. Program 3 – P89LPC932 LED programming 16 Program 4: P89LV51RD2–PCA9564–PCA9531–P89LPC932; I2C address search LD1 to LD8 = OFF LD13 to LD20 = OFF LD11 = OFF, LD12 = OFF I2C_Address = 0x00 S1 pushed? YES NO NO S2 pushed? YES LD11 = OFF, LD12 = OFF Switch off LED[13:20]: S – Address+W – 0x00 – 0xFF – P Scan and reprogram I2C Address: S – Address+W – 0xEE – P I2C_Address = I2C_Address + 1 Send: S – I2C_Address + W YES ACK? PUSHBUTTONS Send: 0xFF – Sr – I2C_Address + R Read Data from slave device – P NO S1 STRT S2 RST S3 NOT USED S5 NOT USED NO S6 NOT USED YES LD11 = ON (search successful), LD12 = OFF LD14 to LD20 display I2C_Address (7 bits) LD13 = OFF S – I2C_Address+W – 0x00 – I2C_Address – P S7 NOT USED NO S4 NOT USED S8 CHGE PRG Data = I2C_Address? YES I2C_Address = 0xFF? LD12 = ON (search failed), LD11 = OFF Figure 9. Program 4 – I2C address search 17 Source Code P89LV51RD2 – Rev 1.0 P89LV51RD2/PCA9564 source code of the embedded software is organized in several files written in C language. Modularity of the files allows building applications using an 8051-core microcontroller and a PCA9564 in an easy and intuitive way. Most of the files are core independent and can be used with different types of microcontrollers. Only the file generating the control signals and receiving/transmitting data is subject to modification depending on the type of microcontroller used. The code in C language is divided in several files, organized as following: 1. I2CEXPRT.H: 2. Contains the definition of the different structures and functions used in the code. 3. Mainloop.c: Contains the main running loop: - Initialization at power up or reset - Call to the function handling the program selection 4. I2C_Routines.c and I2C_Routines.h: Contain the different programs selectable by the user. These files are generally those that need to be modified in order to develop specific programs or functions. Main functions are: - void Blinker_Up_Down(void): Function for Program 1 - void ReadEEprom(short int MinEEPtr, short int MaxEEPtr, int Operation_EEprom, int Operation_Function) and void Preset_Patterns_PCA9532(void): Functions for Program 2 - void LV51_LPC932(void): Function for Program 3 - unsigned char Search_Routine(unsigned char min, unsigned char max) and void I2C_Address_Search(void): Functions for Program 4 - void GPIO_Interrupt_Handler(void): Function handling actions on pushbuttons S1 to S8 5. I2CDRIVR.C and I2CDRIVR.H: Handle the selection between master and slave mode. 6. I2CMASTR.C and I2CMASTR.h: Contain the functions handling the Master Transmitter and Master Receiver modes. Handle the different states of the state machine and generate the sequencing of the commands based upon the previous command and the status information. Interface directly with the PCA9564 (read and write in a specific register) 7. I2CINTFC.C: Contains the description of the top functions used to send and receive I2C messages: - Start, Write, Stop - Start, Read, Stop - Start, Write, Repeated Start, Read, Stop - Start, Write, Repeated Start, Write, Stop 8. PCA9564sys.c and PCA9564sys.h: Contain the actual interface between the microcontroller and the PCA9564: control signal generation, data writing and reading. This file is specific to an 8051-type microcontroller and needs to be changed if another type of microcontroller is used to interface with the PCA9564. 9. Interrupts.c: Contains the definition of the Interrupts – Not used in this program – For future reference Complete source code can be found in Appendix 1 “P89LV51RD2 Microcontroller Source Code – Rev1.0”. Source Code P89LPC932 – Rev 1.0 P89LPC932 microcontroller is used as a slave device with the default embedded programs and use only the slave part of the I2C core. 1. main.c: Contains the instructions to interface with the P89LV51RD2/PCA9564 default embedded program: a) Instruction controlling LD[13:20]: S – Address+W – 0x00 – Data[7:0] – P - Data[0] = state LD13 - Data[7] = state LD20 b) Instruction controlling the “I2C address Scan and Memorize” procedure: S – Address+W – 0xEE – P c) Instruction allowing reading back the I2C slave address: S – Address+W – 0xFF – Sr – Address+R – Data – P with Data = I2C slave address 18 2. i2cslave.c: Contains the source code of the I2C slave core 3. ua_exprt.h: Contains the definition of variables used in the I2C slave core Complete source code can be found in Appendix 2 “P89LPC932 Microcontroller Source Code – Rev1.0”. Download software, programs and documentation • The Raisonance free evaluation development kit can be downloaded from: http://www.amrai.com/amrai.htm 1. In the “Software” yellow box, select 8051 2. Fill the form 3. Download the “kit51.exe” file and the “GettingStartedManual.pdf” 4. Install the software by running “kit51.exe” The Raisonance 8051 Development Kit is a complete solution to creating software for the 8051 family family of microcontroller. The Development Kit comprises many different tools that allow projects ranging from simple to highly complex to be developed with relative ease. The free evaluation version can be used to develop up to 4 kbits of code that can be loaded into the P89LV51 or P89LPC932 by using Flash Magic software. • Flash Magic software from Embedded Systems Academy can be downloaded from: http://www.esacademy.com/software/flashmagic/ 1. In the download section (bottom of the page), download the file using http or ftp 2. Install the software using the downloaded “.exe” file Flash Magic is a free, powerful, feature-rich Windows application that allows easy programming of Philips Flash Microcontrollers. • All the information about Philips microcontrollers (Datasheets, Application Notes, Support Tools…) can be found in the Philips microcontroller homepage at: http://www.semiconductors.philips.com/markets/mms/products/microcontrollers/ PCA9564 evaluation board web page PCA9564 evaluation board homepage that can be found at: http://www.standardproducts.philips.com/support/boards/pca9564 It contains the following: - Source code in C-language for the manufacturing default firmware used in the P89LV51RD2 and P89LPC932 - Application Note AN10148 and AN10149 - Datasheet of the different I2C slave devices and µcontrollers used in the PCA9564 evaluation board - Links to the 3rd party tools (Flash Magic, Raisonance) - IBIS model - How to order the PCA9564 Evaluation Board - … 19 Appendix 1: P89LV51RD2 Microcontroller Source Code – Rev 1.0 I2CEXPRT.H //************************************************************************* // // P H I L I P S P R O P R I E T A R Y // // COPYRIGHT (c) 2003 BY PHILIPS SEMICONDUCTORS // -- ALL RIGHTS RESERVED -// // File Name: i2cexpert.h // Created: June 2, 2003 // Modified: June 4, 2003 // Revision: 1.00 // //************************************************************************* #include <REG51RX.H> typedef unsigned char typedef unsigned short typedef unsigned long BYTE; WORD; LONG; typedef struct { BYTE address; BYTE nrBytes; BYTE *buf; } I2C_MESSAGE; // each message is configured as follows: typedef struct { BYTE nrMessages; I2C_MESSAGE **p_message; } I2C_TRANSFER; // // // // // slave address to sent/receive message // number of bytes in message buffer // pointer to application message buffer structure of a complete transfer made up of a number of messages and pointers to the messages number of message in one transfer pointer to pointer to message /******************************************************************/ /* E X P O R T E D D A T A D E C L A R A T I O N S /******************************************************************/ #define FALSE #define TRUE 0 1 #define I2C_WR #define I2C_RD 0 1 #define #define #define #define PCA9531_WR PCA9531_RD PCA9554_WR PCA9554_RD 0xC8 0xC9 0x7E 0x7F // // // // i2c i2c i2c i2c address address address address LED LED i/o i/o Dimmer Dimmer expander expander Write operation Read operation - Write operation - Read operation // // // // // // // // // // // // transfer ended No Errors transfer busy err: general error err: No data in block err: No ack on data err: No ack on address err: Device not present err: Arbitration lost err: Time out occurred err: Slave mode error err: Initialization (not done) err: Initialization (not done) /**** Status Errors ****/ #define #define #define #define #define #define #define #define #define #define #define #define I2C_OK I2C_BUSY I2C_ERROR I2C_NO_DATA I2C_NACK_ON_DATA I2C_NACK_ON_ADDRESS I2C_DEVICE_NOT_PRESENT I2C_ARBITRATION_LOST I2C_TIME_OUT I2C_SLAVE_ERROR \ I2C_INIT_ERROR I2C_RETRIES 0 1 2 3 4 5 6 7 8 9 10 11 /******************************************************************/ /* I N T E R F A C E F U N C T I O N P R O T O T Y P E S /******************************************************************/ extern extern extern extern void void void void I2C_InitializeMaster(BYTE speed); I2C_InitializeSlave(BYTE slv, BYTE *buf, BYTE size, BYTE speed); I2C_InstallInterrupt(BYTE vector); I2C_Interrupt(void); extern void I2C_Write(I2C_MESSAGE *msg); extern void I2C_WriteRepWrite(I2C_MESSAGE *msg1, I2C_MESSAGE *msg2); 20 extern extern extern extern void void void void I2C_WriteRepRead(I2C_MESSAGE *msg1, I2C_MESSAGE *msg2); I2C_Read(I2C_MESSAGE *msg); I2C_ReadRepRead(I2C_MESSAGE *msg1, I2C_MESSAGE *msg2); I2C_ReadRepWrite(I2C_MESSAGE *msg1, I2C_MESSAGE *msg2); extern extern extern extern extern extern extern extern extern extern void Blinker_Up_Down(void); void LV51_LPC932(void); void ReadEEprom(short int MinEEPtr, short int MaxEEPtr, int Operation_EEprom, int Operation_Function); void Preset_Patterns_PCA9532(void); void I2C_Address_Search(void); void Init_Slaves(void); void Init_LPC932(void); unsigned char Search_Routine(unsigned char min, unsigned char max); void GPIO_Interrupt_Handler(void); void InsertDelay(unsigned char delayTime); static static static static sbit sbit sbit sbit LED0 LED1 LED2 LED3 = = = = P2^2; P2^3; P2^4; P2^5; static sbit PCA9554_Int = P3^2; sbit PCA9564_Reset = P3^4; // LD[9:12] mapped with LV51's P2[2:5] // Interrupt PCA9554 mapped with LV51's P3[2] // Reset PCA9564 mapped with LV51's P3[4] Mainloop.c //************************************************************************* // // P H I L I P S P R O P R I E T A R Y // // COPYRIGHT (c) 2003 BY PHILIPS SEMICONDUCTORS // -- ALL RIGHTS RESERVED -// // File Name: mainloop.c // Created: June 2, 2003 // Modified: November 07, 2003 // Revision: 1.00 // //************************************************************************* #include #include #include #include <REG51RX.H> "i2cexprt.h" "PCA9564sys.h" "I2C_Routines.h" idata idata idata idata BYTE BYTE BYTE BYTE Buffer1[32]; Buffer2[32]; Buffer3[16]; Buffer4[16]; idata idata idata idata I2C_MESSAGE Message1; I2C_MESSAGE Message2; I2C_MESSAGE Message3; I2C_MESSAGE Message4; static short int ProgramCounter = 0; //**************************************************************************** // Initialization Functions at power up, Reset or program change //**************************************************************************** static void Init_PCA9564(void) { PCA9564_Reset = 1; PCA9564_Reset = 0; InsertDelay(1); PCA9564_Reset = 1; AUXR = 2; I2C_InitializeMaster(0x00); } static void Init_Slaves(void) { Message1.address = PCA9531_WR; Message1.buf = Buffer1; Message1.nrBytes = 7; Buffer1[0] = 0x11; Buffer1[1] = 0x80; Buffer1[2] = 0x80; Buffer1[3] = 0x80; Buffer1[4] = 0x80; // PCA9564 reset time = 1 ms // External memory space // 330 kHz // // // // // autoincrement + register 1 default prescaler pwm0 default duty cycle for pwm0 default prescaler pwm1 default duty cycle for pwm1 21 Buffer1[5] Buffer1[6] = 0x00; = 0x00; // LD1 to LD4 off // LD5 to LD8 off I2C_Write(&Message1); // LD[1:8] off Message2.address Message2.buf Message2.nrBytes Buffer2[0] = = = = // subaddress = 0 Message3.address Message3.buf Message3.nrBytes = PCA9554_RD; = Buffer3; = 1; PCA9554_WR; Buffer2; 1; 0; // read one byte } //**************************************************************************** // Delay time in milliseconds // Insert a wait into the program flow // Use Timer 1 // Do not use an interrupt // Oscillator running at 11.0592 MHz // 6 clock cycles per clock tick // Therefore, we need 1843 cycles for 1msec //**************************************************************************** void InsertDelay(unsigned char delayTime) { unsigned char i; TMOD = (TMOD & 0x0F) | 0x01; TR1 = 0; for (i=0;i<delayTime;i++) { TF1 = 0; TH1 = 0xF8; TL1 = 0xCD; TR1 = 1; while(TF1==0); } // 16-bit timer // // // // set timer1 to 1843 since it's an up-timer, use Start timer wait until Timer1 overflows (65536-1843) = 63693 = F8CD } //************************************************************************************* // Toggles pushbutton S8 in order to determine which program the user wants to run //************************************************************************************* static void Program_Selection(void) { if (Buffer3[0] == 0x7F) { if (ProgramCounter < 4) { ProgramCounter++; } else { ProgramCounter = 1; } } switch (ProgramCounter) { case 1 : LED0 = 1; LED1 = 1; Buffer3[0] = 0xFF; Blinker_Up_Down(); break; case 2 : LED0 = 0; LED1 = 1; Buffer3[0] = 0xFF; Preset_Patterns_PCA9531(); break; case 3 : LED0 = 1; LED1 = 0; Buffer3[0] = 0xFF; LV51_LPC932(); break; case 4 : LED0 = 0; LED1 = 0; Buffer3[0] = 0xFF; I2C_Address_Search(); break; // Push on S8 detected // Program selection incremented // Program selection back to 1 // LD9 off // LD10 off // Blinker PSC and PWM Up/down program is selected // LD9 on // LD10 off // PCA9531 preset patterns program selected // LD9 off // LD10 on // LPC932 LED programming program is selected // LD9 on // LD10 on // LPC932 I2C address search program selected 22 } } //**************************************************************************** // Main program //**************************************************************************** void main(void) { Init_PCA9564(); Init_Slaves(); Init_LPC932(); LED0 = 0; LED1 = 0; LED2 = 0; LED3 = 0; while (1) { GPIO_Interrupt_Handler(); Program_Selection(); } // // // // // // // Initialization PCA9564 Initialization slave devices Initialization LPC932 LD9 on at power up or after reset LD10 on at power up or after reset LD11 on at power up or after reset LD12 on at power up or after reset // Toggles S8 in order to determine which program is selected by the user } I2C_Routines.h //************************************************************************* // // P H I L I P S P R O P R I E T A R Y // // COPYRIGHT (c) 2003 BY PHILIPS SEMICONDUCTORS // -- ALL RIGHTS RESERVED -// // File Name: I2C_Routines.c // Created: June 2, 2003 // Modified: November 07, 2003 // Revision: 1.00 // //************************************************************************* unsigned char Search_Routine(unsigned char min, unsigned char max); void GPIO_Interrupt_Handler(void); void Blinker_Up_Down(void); void ReadEEprom(short int MinEEPtr, short int MaxEEPtr, int Operation_EEprom, int Operation_Function); void Preset_Patterns_PCA9531(void); void LV51_LPC932(void); void I2C_Address_Search(void); I2C_Routines.c //************************************************************************* // // P H I L I P S P R O P R I E T A R Y // // COPYRIGHT (c) 2003 BY PHILIPS SEMICONDUCTORS // -- ALL RIGHTS RESERVED -// // File Name: I2C_Routines.c // Created: June 2, 2003 // Modified: November 07, 2003 // Revision: 1.00 // //************************************************************************* #include <REG51RX.H> #include "i2cexprt.h" #include "PCA9564sys.h" idata BYTE Snapshot_1 = 0x0F; idata BYTE Snapshot_2 = 0x00; int Trigger_GPIO_Polling; int Search_Successful = 0; unsigned char Data_Received; unsigned char LPC932_WR; unsigned char LPC932_RD; extern unsigned char LPC932_WR; extern unsigned char LPC932_RD; 23 extern unsigned char CRX; extern extern extern extern idata idata idata idata BYTE BYTE BYTE BYTE Buffer1[32]; Buffer2[32]; Buffer3[16]; Buffer4[16]; extern extern extern extern idata idata idata idata I2C_MESSAGE I2C_MESSAGE I2C_MESSAGE I2C_MESSAGE Message1; Message2; Message3; Message4; //**************************************************************************** // I2C Address Search Routine // Make the search between min and max // Return the I2C Address and set the Search_Successful bit // to 1 when search has been successful //**************************************************************************** unsigned char Search_Routine(unsigned char min, unsigned char max) { unsigned char I2C_Address_Write; unsigned char I2C_Address_Read; unsigned char Address_Sent_Status; unsigned char Command_Sent_Status; unsigned char Counter_I2C_Address_Write = min; unsigned char Counter_I2C_Address_Read = min+1; int i; Search_Successful = 0; while (Counter_I2C_Address_Write != max & Search_Successful == 0) // Search routine starts { Counter_I2C_Address_Write++; Counter_I2C_Address_Write++; // Increment I2C Address Write (+2) Counter_I2C_Address_Read++; Counter_I2C_Address_Read++; // Increment I2C Address Read (+2) I2C_Address_Write = Counter_I2C_Address_Write; I2C_Address_Read = Counter_I2C_Address_Read; PCA9564_Write(I2CCON,0xE0 | CRX); // 1110 0xxx -> generate Start for (i=0; i < 200;i++); PCA9564_Write(I2CDAT,I2C_Address_Write); // Send Address Byte + W for (i=0; i < 200;i++); PCA9564_Write(I2CCON,0xC0 | CRX); // I2CCON=11000xxx for (i=0; i < 200;i++); Address_Sent_Status = PCA9564_Read(I2CSTA); // Read status Register switch (Address_Sent_Status) { case 0x18 : //Ack received PCA9564_Write(I2CDAT,0xFF); // send Command byte (0xFF) for (i=0; i < 200;i++); PCA9564_Write(I2CCON,0xC0 | CRX); // I2CCON=11000xxx for (i=0; i < 200;i++); Command_Sent_Status = PCA9564_Read(I2CSTA); PCA9564_Write(I2CCON,0xD0 | CRX); // send Stop for (i=0; i < 200;i++); if (Command_Sent_Status == 0x28) // Command byte has been ack'ed { PCA9564_Write(I2CCON,0xE0 | CRX); // 1110 0xxx -> generate Start for (i=0; i < 200;i++); Command_Sent_Status = PCA9564_Read(I2CSTA); if (Command_Sent_Status == 0x08) // Start = OK { PCA9564_Write(I2CDAT,I2C_Address_Read); // send Address Byte + R for (i=0; i < 200;i++); PCA9564_Write(I2CCON,0xC0 | CRX); // I2CCON=11000xxx for (i=0; i < 200;i++); Command_Sent_Status = PCA9564_Read(I2CSTA); if (Command_Sent_Status == 0x40) // Addr + R = OK { PCA9564_Write(I2CCON,0x40 | CRX); // Read Data and NACK for (i=0; i < 200;i++); Data_Received = PCA9564_Read(I2CDAT); } } } PCA9564_Write(I2CCON,0xD0 | CRX); // send Stop if (Data_Received == I2C_Address_Write) { Search_Successful = 1; // Search successful if Read Data = Address 24 } else { Search_Successful = 0; } break; case 0x20 : // no Ack received PCA9564_Write(I2CCON,0xD0 | CRX); break; } // Search unsuccessful if Read Data != Address // I2CCON=11010xxx -> Stop condition Address_Sent_Status = 0x00; Command_Sent_Status = 0x00; } return I2C_Address_Write; } //**************************************************************************** // GPIO Interrupt Handling function // One shot mode (through /INT) or // permanent action detection (then Input PCA9554 Reg# polling) //**************************************************************************** void GPIO_Interrupt_Handler(void) { Message2.address = PCA9554_WR; Message2.buf = Buffer2; Message2.nrBytes = 1; Buffer2[0] = 0; Message3.address Message3.buf Message3.nrBytes // subaddress = 0 = PCA9554_RD; = Buffer3; = 1; // read one byte if (PCA9554_Int==0) { I2C_WriteRepRead(&Message2,&Message3); if (Buffer3[0] != 0xFF) { Snapshot_1 = Buffer3[0]; } InsertDelay(255); InsertDelay(255); InsertDelay(255); I2C_WriteRepRead(&Message2,&Message3); Snapshot_2 = Buffer3[0]; if (Snapshot_1 == Snapshot_2) { Trigger_GPIO_Polling = 1; } else { Trigger_GPIO_Polling = 0; Buffer3[0] = Snapshot_1; } } if (Trigger_GPIO_Polling == 1) { I2C_WriteRepRead(&Message2,&Message3); } // Action on pushbutton detected // 1st read the PCA9554 // load the 1st read data in a temp memory // Delay between 2 snapshots to detect if pushbutton is // still pressed or has been released // 2nd read the PCA9554 // load the 2nd read data in a temp memory // Compare the 2 read data in the temp memories // permanent push detected when 1st and 2nd readings equal // single shot action when 1st and 2nd readings different // Buffer loaded again with the initial push value // Start Polling PCA9554 when permanent push detected } /**************************************************************************** // Program 1: P89LV51 <--> PCA9564 <--> PCA9531 // Through Pushbuttons, BR0 and BR1 can be selected // Once BR selected, PSC and PWM registers // can be incremented / decremented //**************************************************************************** static int BR_Select = 0; void Blinker_Up_Down(void) { idata BYTE Frequency_0; idata BYTE DutyCycle_0; idata BYTE Frequency_1; idata BYTE DutyCycle_1; LED2 = 1; LED3 = 0; // LD11 // LD12 off on --> PCA9531 programmed with default blinking rate 25 Message1.nrBytes = 7; Buffer1[0] = 0x11; Buffer1[1] = 0x80; Buffer1[2] = 0x80; Buffer1[3] = 0x80; Buffer1[4] = 0x80; Buffer1[5] = 0xAA; Buffer1[6] = 0xFF; I2C_Write(&Message1); Frequency_0 DutyCycle_0 Frequency_1 DutyCycle_1 = = = = // // // // // // // // // Reset the PCA9531 to its default programmed values subaddress = 0x01 default prescaler pwm0 default duty cycle for pwm0 default prescaler pwm1 default duty cycle for pwm1 LD1 to LD4 blinking at BR0 LD5 to LD8 blinking at BR1 Program PCA9531 with default values (7 bytes) Buffer1[1]; Buffer1[2]; Buffer1[3]; Buffer1[4]; while (Buffer3[0]!=0x7F) { GPIO_Interrupt_Handler(); InsertDelay(100); // Main loop as long as S8 (exit Program) has not been pushed // Check if an action on pushbutton happened // Small delay for LED dimmer visual purpose (wait between device programming) Message1.nrBytes = 2; // 2 bytes will be sent to the PCA9531 (pointer + register to be modified) if (Buffer3[0]!=0xFF) // Execute the command associated with the action on pushbutton { switch (Buffer3[0]) { case 0x7F : break; // Exit Program 1- Push on S8 detected case 0xFB : if (BR_Select == 0) // Action on pushbutton selecting Blinking Rate to be programmed { BR_Select = 1; // Blinking Rate 1 selected to be modified - LD[4:8] LED2 = 0; // LD11 on Buffer3[0] = 0xFF; break; } else { BR_Select = 0 // Blinking Rate 0 selected to be modified - LD[1:4] LED2 = 1; // LD11 off Buffer3[0] = 0xFF; } break; case 0xBF : LED3 = 1; // LD12 = off --> Default programming overwritten Message2.address = PCA9531_WR; // Action on pushbutton - outputs to be either off or blinking Message2.buf = Buffer2; Message2.nrBytes = 1; Buffer2[0] = 0x15; // subaddress = 15 Message3.address = PCA9531_RD; Message3.buf = Buffer3; Message3.nrBytes = 2; // read 2 bytes I2C_WriteRepRead(&Message2,&Message3); // read output states of the PCA9531 if (BR_Select == 0) { if (Buffer3[0] == 0x00) { Buffer1[0]= 0x05; // subaddress = 0x05 Buffer1[1] = 0xAA; // LD[1:4] blinking at BR0 I2C_Write(&Message1); // send new data to PCA9531 (2 bytes) } if (Buffer3[0] == 0xAA) { Buffer1[0]= 0x05; // subaddress = 0x05 Buffer1[1] = 0x00; // LD[1:4] off I2C_Write(&Message1); // send new data to PCA9531 (2 bytes) } } if (BR_Select == 1) { if (Buffer3[1] == 0x00) { Buffer1[0]= 0x06; // subaddress = 0x05 Buffer1[1] = 0xFF; // LD[4:8] blinking at BR1 I2C_Write(&Message1); // send new data to PCA9531 (2 bytes) } if (Buffer3[1] == 0xFF) { Buffer1[0]= 0x06; // subaddress = 0x05 Buffer1[1] = 0x00; // LD[4:8] off I2C_Write(&Message1); // send new data to PCA9531 (2 bytes) } } break; 26 case 0xFE : LED3 = 1; if (BR_Select == 0 & Frequency_0 { Buffer1[0] = 0x01; Frequency_0++; Buffer1[1] = Frequency_0; I2C_Write(&Message1); Buffer3[0] = 0xFF; } if (BR_Select == 1 & Frequency_1 { Buffer1[0] = 0x03; Frequency_1++; Buffer1[1] = Frequency_1; I2C_Write(&Message1); Buffer3[0] = 0xFF; } break; case 0xEF : LED3 = 1; if (BR_Select == 0 & Frequency_0 { Buffer1[0] = 0x01; Frequency_0--; Buffer1[1] = Frequency_0; I2C_Write(&Message1); Buffer3[0] = 0xFF; } if (BR_Select == 1 & Frequency_1 { Buffer1[0] = 0x03; Frequency_1--; Buffer1[1] = Frequency_1; I2C_Write(&Message1); Buffer3[0] = 0xFF; } break; case 0xDF : LED3 = 1; if (BR_Select == 0 & DutyCycle_0 { Buffer1[0] = 0x02; DutyCycle_0++; Buffer1[1] = DutyCycle_0; I2C_Write(&Message1); Buffer3[0] = 0xFF; } if (BR_Select == 1 & DutyCycle_1 { Buffer1[0] = 0x04; DutyCycle_1++; Buffer1[1] = DutyCycle_1; I2C_Write(&Message1); Buffer3[0] = 0xFF; } break; case 0xFD : LED3 = 1; if (BR_Select == 0 & DutyCycle_0 { Buffer1[0] = 0x02; DutyCycle_0--; Buffer1[1] = DutyCycle_0; I2C_Write(&Message1); Buffer3[0] = 0xFF; } if (BR_Select == 1 & DutyCycle_1 { Buffer1[0] = 0x04; DutyCycle_1--; Buffer1[1] = DutyCycle_1; I2C_Write(&Message1); Buffer3[0] = 0xFF; } break; case 0xF7 : LED3 = 0; Message1.nrBytes = 7; Buffer1[0] = 0x11; Buffer1[1] = 0x80; Buffer1[2] = 0x80; Buffer1[3] = 0x80; Buffer1[4] = 0x80; Buffer1[5] = 0xAA; Buffer1[6] = 0xFF; // LD12 = off --> Default programming overwritten < 0xFF) // subaddress = 0x01 // increment prescaler 0 // send new data to PCA9531 (2 bytes) < 0xFF) // subaddress = 0x03 // increment prescaler 1 // send new data to PCA9531 (2 bytes) // LD12 = off --> Default programming overwritten > 0x00) // subaddress = 0x01 // decrement prescaler 0 // send new data to PCA9531 (2 bytes) > 0x00) // subaddress = 0x03 // decrement prescaler 1 // send new data to PCA9531 (2 bytes) // LD12 = off --> Default programming overwritten < 0xFF) // subaddress = 0x02 // increment pwm 0 // send new data to PCA9531 (2 bytes) < 0xFF) // subaddress = 0x04 // increment pwm 1 // send new data to PCA9531 (2 bytes) // LD12 = off --> Default programming overwritten > 0x00) // subaddress = 0x02 // decrement pwm 0 // send new data to PCA9531 (2 bytes) > 0x00) // subaddress = 0x04 // decrement pwm 1 // send new data to PCA9531 (2 bytes) // // // // // // // // // 27 LD12 = on --> PCA9531 with default blinking rate Reset the PCA9531 to its default programmed values subaddress = 0x01 default prescaler pwm0 default duty cycle for pwm0 default prescaler pwm1 default duty cycle for pwm1 LD1 to LD4 blinking at BR0 LD5 to LD8 blinking at BR1 I2C_Write(&Message1); Buffer3[0] = 0xFF; BR_Select = 0; LED2 = 1; break; // send new data to PCA9531 (7 bytes) } } } Message1.nrBytes = 3; Buffer1[0] = 0x15; Buffer1[1] = 0x00; Buffer1[2] = 0x00; I2C_Write(&Message1); // subaddress = 0x15 // PCA9531 all LEDs off when leaving Program 1 // send new data to PCA9531 (3 bytes) } //****************************************************************************************************** // Program 2 : P89LV51 <--> PCA9564 <--> PCF85116 <--> PCA9531 // Predefined blinking patterns are stored in the EEPROM (3 for this specific code) // For each of them, command to be written are read from the EEPROM by the P89LV51 and PCA9531 is programmed // // Read the EEprom // In order to get the data from the EE, read five bytes. // Buffer4[0]: Length // Buffer4[1]: Function // if Function=0 (function 0): // Buffer4[2]: Delay // Buffer4[3]: Address // Buffer4[4]: Data0 // Buffer4[n]: Data... // if Function=1 (function 1): // Buffer4[2]: Delay // Buffer4[3]: Address // Buffer4[4]: Data0 // Buffer4[n]: Data... // if Function=0x99 then end // // ReadEEprom function can be used im 2 different ways: // Operation_EEprom = 0: determine the different functions by reading the full memory and storing // the 1st and last memory cell for each function // Operation_EEprom = 1: for a specified function stored in the EEPROM, a specific operation is performed // - Operation_Function = 0: a write operation is performed // - Operation_Function = 1: not defined // - Operation_Function = 2: not defined //******************************************************************************************************** short short short short short short short short short short short short short int int int int int int int int int int int int int EEPROM_Scan_Done; MinPtrFound_0 = 0; MinPtr_0; MaxPtr_0; MinPtrFound_1 = 0; MinPtr_1; MaxPtr_1; MinPtrFound_2 = 0; MinPtr_2; MaxPtr_2; MinPtrFound_3 = 0; MinPtr_3; MaxPtr_3; // If more than 3 patterns in EEPROM, declare the additional PtrFound, MinPtr and void ReadEEprom(short int MinEEPtr, short int MaxEEPtr, { short int NextEEaddress; short int EndEEaddress; bit EndofMessages; int ExitLoop = 0; EndofMessages NextEEaddress EndEEaddress = 0; = MinEEPtr; = MaxEEPtr; int Operation_EEprom, MaxPtr here int Operation_Function) // initialization of the min subaddress within the 2kB eeprom // initialization of the max subaddress within the 2kB eeprom while (EndofMessages==0 & ExitLoop==0 & NextEEaddress <= MaxEEPtr) { // First we need to retrieve the data from the eeprom Message3.address = 0xA0 | ((NextEEaddress & 0x0700)>>7); // Upper byte of NextEEaddress Buffer3[0] = NextEEaddress & 0xFF; // Lower byte of NextEEaddress = subaddress Message4.address = Message3.address | 0x01; // Message 4 address is a read so set lsb Message3.nrBytes = 1; 28 // We're going to write one byte (subaddress) if (Operation_EEprom == 0) // EEPROM reading - Function (search min and max / function) { EEPROM_Scan_Done = 0; Message4.nrBytes = 2; // We're going to read 2 bytes (length of descriptor + Function) I2C_Write(&Message3); InsertDelay(2); I2C_Read(&Message4); switch (Buffer4[1]) { case 0x00 : if (MinPtrFound_0 == 0) // Min and Max search for function 0 { MinPtr_0 = NextEEaddress; MinPtrFound_0 = 1; } if (MinPtrFound_0 == 1) { MaxPtr_0 = NextEEaddress; } break; case 0x01 : if (MinPtrFound_1 == 0) // Min and Max search for function 1 { MinPtr_1 = NextEEaddress; MinPtrFound_1 = 1; } if (MinPtrFound_1 == 1) { MaxPtr_1 = NextEEaddress; } break; case 0x02 : if (MinPtrFound_2 == 0) // Min and Max search for function 2 { MinPtr_2 = NextEEaddress; MinPtrFound_2 = 1; } if (MinPtrFound_2 == 1) { MaxPtr_2 = NextEEaddress; } break; case 0x03 : if (MinPtrFound_3 == 0) // Min and Max search for function 3 (not defined in the EEPROM) { MinPtr_3 = NextEEaddress; MinPtrFound_3 = 1; } if (MinPtrFound_3 == 1) { MaxPtr_3 = NextEEaddress; } break; // If more patterns, add the additional “case” here case 0x99 : EndofMessages = 1; // End of data in the EEPROM break; } EEPROM_Scan_Done = 1; } if (Operation_EEprom == 1) // EEPROM reading - Data in a specified function { Message4.nrBytes = 1; // We're going to read one byte (length of descriptor) //I2C_WriteRepRead(&Message3,&Message4); I2C_Write(&Message3); // Read the EEPROM InsertDelay(2); I2C_Read(&Message4); // Buffer4[0] contains the length of the descriptor InsertDelay(2); Message4.nrBytes = Buffer4[0]; // First byte of data is the descriptor length //I2C_WriteRepRead(&Message3,&Message4); I2C_Write(&Message3); // Read the entire descriptor from the eeprom InsertDelay(2); I2C_Read(&Message4); InsertDelay(2); // Buffer4 contains the data from the eeprom // ---------------------------------------------------------// At this point we have the data from the eeprom in Buffer4 29 switch(Operation_Function) { case 0x00 : Message1.address = Buffer4[3]; // Write operation performed with the data read from EEPROM Message1.nrBytes = Buffer4[0] - 4; Message1.buf = Buffer4 + 4; I2C_Write(&Message1); InsertDelay(Buffer4[2]); // Programmable delay in ms (up to 255 ms i.e. 0xFF) break; case 0x01 : break; case 0x02 : break; } } NextEEaddress = NextEEaddress + Buffer4[0]; // Not defined // Not defined // // GPIO_Interrupt_Handler(); // Check if an action on if (Buffer3[0]==0x7F | Buffer3[0]==0xEF) // { ExitLoop = 1; } // } // The length of the descriptor is in Buffer4[0] so we can calculate the next eeprom address+subaddress S8 happened (to exit the program)or S5 (to change program) Leave the loop when S5 or S8 pushed switch while(EndofMessage or exit program) } void Preset_Patterns_PCA9531(void) { short int PatternCounter = 0; LED2 = 1; LED3 = 1; EEPROM_Scan_Done = 0; // LD11 off // LD12 off // EEPROM scan not done when entering the program while (Buffer3[0]!=0x7F) { GPIO_Interrupt_Handler(); // Main loop as long as S8 (exit Program) has not been pushed // Check if an action on pushbutton happened if (Buffer3[0]!=0xFF) // execute the command associated with the action on pushbutton { switch (Buffer3[0]) { case 0x7F : break; // Exit Program 3 - S8 pushed case 0xF7 : ReadEEprom(0x000,0x7FF,0,0); // Read EEPROM structure (function organization) LED3 = 0; // LD12 on when the EEPROM structure has been analyzed Buffer3[0] = 0xFF; break; case 0xEF : if ( EEPROM_Scan_Done == 0) break; // Nothing can be done until the EEPROM SCAN has been done if (PatternCounter < 3) // Pattern change pushbutton activated { // If more than 3 patterns, increase the number above to the adequate number PatternCounter++; // Program selection incremented } else { PatternCounter = 1; // Program selection back to 1 } Message4.address = LPC932_WR; Message4.buf = Buffer4; Message4.nrBytes = 2; Buffer4[0] = 0x00; // Command byte to program LEDs if (PatternCounter ==1) Buffer4[1] = 0xFE; // LD13 on (Pattern 1) if (PatternCounter ==2) Buffer4[1] = 0xFD; // LD14 on (Pattern 2) if (PatternCounter ==3) Buffer4[1] = 0xFB; // LD15 on (Pattern 3) // If more than 3 patterns, add the required "if" I2C_Write(&Message4); // Program LPC932 to display the pattern number Buffer3[0] = 0xFF; break; } GPIO_Interrupt_Handler(); // Check if an action on pushbutton happened if (PatternCounter == 1 & EEPROM_Scan_Done == 1)ReadEEprom(MinPtr_0,MaxPtr_0,1,0); if (PatternCounter == 2 & EEPROM_Scan_Done == 1)ReadEEprom(MinPtr_1,MaxPtr_1,1,0); if (PatternCounter == 3 & EEPROM_Scan_Done == 1)ReadEEprom(MinPtr_2,MaxPtr_2,1,0); // If more than 3 patterns, add the required "if" } } Message1.address = PCA9531_WR; Message1.nrBytes = 3; Buffer1[0] = 0x15; Buffer1[1] = 0x00; Buffer1[2] = 0x00; // subaddress = 0x15 // PCA9531 all LEDs off when leaving Program 1 30 I2C_Write(&Message1); Buffer4[0] = 0x00; Buffer4[1] = 0xFF; I2C_Write(&Message4); // send new data to PCA9531 (3 bytes) // Command to program LEDs // LPC932 all LEDs off when leaving Program 3 } //**************************************************************************** // Program 3 : P89LV51 <--> PCA9564 <--> P89LPC932 // Through Pushbuttons, Byte to be sent to LPC932 can be programmed // Once done, a pushbutton sends the LPC932 I2C address + programmed byte //**************************************************************************** static bdata sbit LS0_0 = sbit LS0_1 = sbit LS0_2 = sbit LS0_3 = sbit LS0_4 = sbit LS0_5 = sbit LS0_6 = sbit LS0_7 = BYTE LS0 = 0; LS0^0; LS0^1; LS0^2; LS0^3; LS0^4; LS0^5; LS0^6; LS0^7; static bdata sbit LS1_0 = sbit LS1_1 = sbit LS1_2 = sbit LS1_3 = sbit LS1_4 = sbit LS1_5 = sbit LS1_6 = sbit LS1_7 = BYTE LS1 = 0; LS1^0; LS1^1; LS1^2; LS1^3; LS1^4; LS1^5; LS1^6; LS1^7; static bdata BYTE DataByteLPC932 = 0xFF; sbit DataByteLPC932_0 = DataByteLPC932^0; sbit DataByteLPC932_1 = DataByteLPC932^1; sbit DataByteLPC932_2 = DataByteLPC932^2; sbit DataByteLPC932_3 = DataByteLPC932^3; sbit DataByteLPC932_4 = DataByteLPC932^4; sbit DataByteLPC932_5 = DataByteLPC932^5; sbit DataByteLPC932_6 = DataByteLPC932^6; sbit DataByteLPC932_7 = DataByteLPC932^7; void LV51_LPC932(void) { int BitCounter = 1; int ValueToBeChanged = 0; Init_LPC932(); Message1.address = PCA9531_WR; Message1.buf = Buffer1; Message1.nrBytes = 7; Buffer1[0] = 0x11; Buffer1[1] = 0x80; Buffer1[2] = 0x80; Buffer1[3] = 0x80; Buffer1[4] = 0x80; Buffer1[5] = 0x00; Buffer1[6] = 0x00; I2C_Write(&Message1); LED2 = 1; LED3 = 1; DataByteLPC932 = 0xFF; LS0 = 0; LS1 = 0; while (Buffer3[0]!=0x7F) { GPIO_Interrupt_Handler(); if (Buffer3[0]!=0xFF) { switch (Buffer3[0]) { case 0x7F : break; case 0xF7 : BitCounter = 1; LS0 = 0x00; LS1 = 0x00; Message1.nrBytes = 3; Buffer1[0] = 0x15; Buffer1[1] = 0x00; Buffer1[2] = 0x00; // Initialization of LPC932 (narrowed search address + LEDs off // Initialization of PCA9531 // // // // // // // // // // autoincrement + register 1 default prescaler pwm0 default duty cycle for pwm0 default prescaler pwm1 default duty cycle for pwm1 LD1 to LD4 off LD5 to LD8 off LD[1:8] off LD11 is off LD12 is off // Main loop as long as S8 (exit Program) has not been pushed // Check if an action on pushbutton happened // execute the command associated with the action on pushbutton // Exit Program 3 - S8 pushed // Reset programming (all LEDs are off) - S4 pushed // subaddress = 0x05 // LS0 = 0x00 - All LEDs off // LS1 = 0x00 - All LEDs off 31 I2C_Write(&Message1); // Program PCA9531 (3 bytes) DataByteLPC932 = 0xFF; Buffer4[0] = 0x00; // Command byte to program LEDs Buffer4[1] = DataByteLPC932; // LPC932 all LEDs off I2C_Write(&Message4); // Program LPC932 (2 bytes) Buffer3[0] = 0xFF; break; case 0xEF : if (BitCounter < 8) // increment programming position - S1 pushed { BitCounter++; } else { BitCounter = 1; } Buffer3[0] = 0xFF; break; case 0xFE : if (BitCounter != 1) // decrement programming position - S5 pushed { BitCounter--; } else { BitCounter = 8; } Buffer3[0] = 0xFF; break; case 0xFD : ValueToBeChanged = 1; // S2 pushed - Change polarity of the current position switch (BitCounter) { Message1.nrBytes = 2; case 1 : if (ValueToBeChanged == 1) // Bit 0 { if (DataByteLPC932_0 == 0) { LS0_0 = 0; LS0_1 = 0; DataByteLPC932_0 = 1; ValueToBeChanged = 0; } else { LS0_0 = 1; LS0_1 = 0; DataByteLPC932_0 = 0; ValueToBeChanged = 0; } Message1.nrBytes = 2; Buffer1[0] = 0x15; // subaddress = 0x05 Buffer1[1] = LS0; // LED Selector programming I2C_Write(&Message1); } break; case 2 : if (ValueToBeChanged == 1) // Bit 1 { if (DataByteLPC932_1 == 0) { LS0_2 = 0; LS0_3 = 0; DataByteLPC932_1 = 1; ValueToBeChanged = 0; } else { LS0_2 = 1; LS0_3 = 0; DataByteLPC932_1 = 0; ValueToBeChanged = 0; } Message1.nrBytes = 2; Buffer1[0] = 0x15; // subaddress = 0x05 Buffer1[1] = LS0; // LED Selector programming I2C_Write(&Message1); } break; 32 case 3 : if (ValueToBeChanged == 1) { if (DataByteLPC932_2 == 0) { LS0_4 = 0; LS0_5 = 0; DataByteLPC932_2 = 1; ValueToBeChanged = 0; } else { LS0_4 = 1; LS0_5 = 0; DataByteLPC932_2 = 0; ValueToBeChanged = 0; } Message1.nrBytes = 2; Buffer1[0] = 0x15; Buffer1[1] = LS0; I2C_Write(&Message1); } break; case 4 : if (ValueToBeChanged == 1) { if (DataByteLPC932_3 == 0) { LS0_6 = 0; LS0_7 = 0; DataByteLPC932_3 = 1; ValueToBeChanged = 0; } else { LS0_6 = 1; LS0_7 = 0; DataByteLPC932_3 = 0; ValueToBeChanged = 0; } Message1.nrBytes = 2; Buffer1[0] = 0x15; Buffer1[1] = LS0; I2C_Write(&Message1); } break; case 5 : if (ValueToBeChanged == 1) { if (DataByteLPC932_4 == 0) { LS1_0 = 0; LS1_1 = 0; DataByteLPC932_4 = 1; ValueToBeChanged = 0; } else { LS1_0 = 1; LS1_1 = 0; DataByteLPC932_4 = 0; ValueToBeChanged = 0; } Message1.nrBytes = 2; Buffer1[0] = 0x16; Buffer1[1] = LS1; I2C_Write(&Message1); } break; case 6 : if (ValueToBeChanged == 1) { if (DataByteLPC932_5 == 0) { LS1_2 = 0; LS1_3 = 0; DataByteLPC932_5 = 1; ValueToBeChanged = 0; } else { LS1_2 = 1; LS1_3 = 0; DataByteLPC932_5 = 0; 33 // Bit 2 // subaddress = 0x05 // LED Selector programming // Bit 3 // subaddress = 0x05 // LED Selector programming // Bit 4 // subaddress = 0x06 // LED Selector programming // Bit 5 ValueToBeChanged = 0; } Message1.nrBytes = 2; Buffer1[0] = 0x16; Buffer1[1] = LS1; I2C_Write(&Message1); // subaddress = 0x06 // LED Selector programming } break; case 7 : if (ValueToBeChanged == 1) { if (DataByteLPC932_6 == 0) { LS1_4 = 0; LS1_5 = 0; DataByteLPC932_6 = 1; ValueToBeChanged = 0; } else { LS1_4 = 1; LS1_5 = 0; DataByteLPC932_6 = 0; ValueToBeChanged = 0; } Message1.nrBytes = 2; Buffer1[0] = 0x16; Buffer1[1] = LS1; I2C_Write(&Message1); } break; case 8 : if (ValueToBeChanged == 1) { if (DataByteLPC932_7 == 0) { LS1_6 = 0; LS1_7 = 0; DataByteLPC932_7 = 1; ValueToBeChanged = 0; } else { LS1_6 = 1; LS1_7 = 0; DataByteLPC932_7 = 0; ValueToBeChanged = 0; } Message1.nrBytes = 2; Buffer1[0] = 0x16; Buffer1[1] = LS1; I2C_Write(&Message1); } break; } Buffer3[0] = 0xFF; break; case 0xFB : Buffer4[0] = 0x00; Buffer4[1] = DataByteLPC932; I2C_Write(&Message4); Buffer3[0] = 0xFF; break; // Bit 6 // subaddress = 0x06 // LED Selector programming // Bit 7 // subaddress = 0x06 // LED Selector programming // Command byte to program LEDS // Program LPC932 with the programmed byte - S3 pushed // LPC932 programmed (2 bytes) } } } Message1.nrBytes = 3; Buffer1[0] = 0x15; Buffer1[1] = 0x00; Buffer1[2] = 0x00; I2C_Write(&Message1); Buffer4[0] = 0x00; Buffer4[1] = 0xFF; I2C_Write(&Message4); // subaddress = 0x15 // PCA9531 all LEDs off when leaving Program 3 // Program PCA9531 (3 bytes) // Command to program LEDs // LPC932 all LEDs off when leaving Program 3 } 34 //**************************************************************************** // Program 4:P89LV51 <--> PCA9564 <--> P89LPC932 // Initiates an automatic I2C slave address search in order // to find P89LPC932's I2C slave address //**************************************************************************** void I2C_Address_Search(void) { bdata BYTE I2C_Address; LED2 = 1; LED3 = 1; // LD11 is // LD12 is while (Buffer3[0]!=0x7F) { GPIO_Interrupt_Handler(); // Main loop as long as S8 (exit Program) has not been pushed off off // Check if an action on pushbutton happened if (Buffer3[0]!=0xFF) // execute the command associated with the action on pushbutton { switch (Buffer3[0]) { case 0x7F : break; // Exit Program 3 - S8 pushed case 0xFE : I2C_Address = Search_Routine(0x00,0xFE); if (Search_Successful == 0) { LED2 = 1; LED3 = 0; // Search failed (the all I2C address range has been checked } Buffer3[0] = 0xFF; if (Search_Successful == 1) { LED2 = 0; // Search successful LED3 = 1; LPC932_WR = I2C_Address; LPC932_RD = LPC932_WR + 1; Message4.address = LPC932_WR; Message4.buf = Buffer4; Message4.nrBytes = 2; Buffer4[0] = 0x00; // Command byte to program the LEDs Buffer4[1] = ~LPC932_WR; // LD[13:20] display the found address I2C_Write(&Message4); // Program LPC932 (2 bytes) } break; case 0xFD : Search_Successful = 0; // Reset of the previous search, LPC932 scans and stores its I2C address LED2 = 1; LED3 = 1; Message4.address = LPC932_WR; Message4.buf = Buffer4; Message4.nrBytes = 2; Buffer4[0] = 0x00; // Command byte to program the LEDs Buffer4[1] = 0xFF; // LD[13:20] off I2C_Write(&Message4); // Program LPC932 (2 bytes) Message4.nrBytes = 1; Buffer4[0] = 0xEE; // Command byte to scan and store the new I2C address I2C_Write(&Message4); // Program LPC932 (1 byte) Buffer3[0] = 0xFF; break; } } } Message4.nrBytes = 2; Buffer4[0] = 0x00; Buffer4[1] = 0xFF; I2C_Write(&Message4); // Command to program LEDs // LPC932 all LEDs off when leaving Program 3 } void Init_LPC932(void) { LPC932_WR = Search_Routine(0xDE,0xEE); LPC932_RD = LPC932_WR + 1; Message4.address = LPC932_WR; Message4.buf = Buffer4; Message4.nrBytes = 2; Buffer4[0] = 0x00; // Command byte to program LEDs Buffer4[1] = 0xFF; // LPC932 all LEDs off I2C_Write(&Message4); // LD[13:20] off } 35 I2CDRIVR.H //************************************************************************* // // P H I L I P S P R O P R I E T A R Y // // COPYRIGHT (c) 2003 BY PHILIPS SEMICONDUCTORS // -- ALL RIGHTS RESERVED -// // File Name: i2cdriver.h // Created: June 2, 2003 // Modified: June 9, 2003 // Revision: 1.00 // //************************************************************************* #define #define #define #define #define ST_IDLE ST_SENDING ST_AWAIT_ACK ST_RECEIVING ST_RECV_LAST //#define //#define //#define //#define //#define //#define //#define //#define 0 1 2 3 4 CR0_MASK 0x01 CR1_MASK 0x02 CR2_MASK 0x04 SI_MASK 0x08 STO_MASK 0x10 STA_MASK 0x20 ENSIO_MASK 0x40 AA_MASK 0x80 extern BYTE master; extern BYTE intMask; void MainStateHandler(void); I2CDRIVR.C //************************************************************************* // // P H I L I P S P R O P R I E T A R Y // // COPYRIGHT (c) 2003 BY PHILIPS SEMICONDUCTORS // -- ALL RIGHTS RESERVED -// // File Name: i2cdriver.c // Created: June 2, 2003 // Modified: June 10, 2003 // Revision: 1.00 // //************************************************************************* #include #include #include #include "i2cexprt.h" "i2cdrivr.h" <REG51RX.H> "PCA9564sys.h" static void NoInitErrorProc(void); void (*masterProc)(void) = NoInitErrorProc; void (*slaveProc)(void) = NoInitErrorProc; BYTE master; BYTE intMask; 36 /* ************************************************************************* * Input(s): none. * Output(s): none. * Returns: none. * Description: ERROR: Master or slave handler called while not initialized ***************************************************************************/ static void NoInitErrorProc(void) { PCA9564_Write(I2CCON, 0x40); } /*************************************************************************** * Input(s): none. * Output(s): none. * Returns: none. * Description: Main event handler for I2C. ***************************************************************************/ void MainStateHandler(void) { if (master) masterProc(); else slaveProc(); } // Master Mode // Slave Mode /* ************************************************************************* * Input(s): none. * Output(s): none. * Returns: none. * Description: Interrupt handler for I2C. ***************************************************************************/ void I2C_Interrupt(void) interrupt 5 { MainStateHandler(); } I2CMASTR.h //************************************************************************* // // P H I L I P S P R O P R I E T A R Y // // COPYRIGHT (c) 2003 BY PHILIPS SEMICONDUCTORS // -- ALL RIGHTS RESERVED -// // File Name: i2cmaster.h // Created: June 2, 2003 // Modified: June 9, 2003 // Revision: 1.00 // //************************************************************************* void I2C_Transfer(I2C_TRANSFER *p, void (*proc)(BYTE, BYTE)); 37 I2CMASTR.C //************************************************************************* // // P H I L I P S P R O P R I E T A R Y // // COPYRIGHT (c) 2003 BY PHILIPS SEMICONDUCTORS // -- ALL RIGHTS RESERVED -// // File Name: i2cmaster.c // Created: June 2, 2003 // Modified: June 10, 2003 // Revision: 1.00 // //************************************************************************* #include #include #include #include #include <REG51RX.H> "i2cexprt.h" "i2cdrivr.h" "i2cmastr.h" "PCA9564sys.h" extern void (*masterProc)(); //extern void (*slaveProc)(); // Handle Master Transfer action // Handle Slave Transfer action static I2C_TRANSFER *tfr; static I2C_MESSAGE *msg; // Pointer to active transfer block // Pointer to active message block static void (code *readyProc)(BYTE status,BYTE); static BYTE msgCount; static BYTE dataCount; static BYTE state; extern BYTE drvStatus; unsigned char CRX; // proc. to call if transfer ended // Number of messages sent // nr of bytes of current message // state of the I2C driver // I2C frequency selector /*************************************************************************** * Input(s): status -> status of the driver. * Output(s): None. * Returns: None. * Description: Generate a stop condition. ***************************************************************************/ /*static void GenerateStop(BYTE status) { PCA9564_Write(I2CCON,0xD0 | CR); master = FALSE; state = ST_IDLE; readyProc(status, msgCount); }*/ // Signal driver is finished /*************************************************************************** * Input(s): None. * Output(s): None. * Returns: None. * Description: Master mode state handler for I2C-bus. ***************************************************************************/ // // // +---------------------------------------------------------+ | I2CCON | AA | ENSIO | STA | STO | SI | CR2 | CR1 | CR0 | +---------------------------------------------------------+ static void HandleMasterState(void) { unsigned char PCA9564_Status; PCA9564_Status = PCA9564_Read(I2CSTA); switch (PCA9564_Status) { case 0x08 : // (re)start condition case 0x10 : PCA9564_Write(I2CDAT,msg->address); PCA9564_Write(I2CCON,0xC0 | CRX); break; case 0x18 : PCA9564_Write(I2CDAT,msg->buf[dataCount++]); PCA9564_Write(I2CCON,0xC0 | CRX); break; 38 // clear SI bit to send address // send next data byte // I2CCON=11000xxx case 0x20 : // no Ack received PCA9564_Write(I2CCON,0xD0 | CRX); drvStatus = I2C_ERROR; break; case 0x28 : // ack received if (dataCount < msg->nrBytes) { PCA9564_Write(I2CDAT,msg->buf[dataCount++]); PCA9564_Write(I2CCON,0xC0 | CRX); } else { if (msgCount < tfr->nrMessages) { dataCount = 0; msg = tfr->p_message[msgCount++]; PCA9564_Write(I2CDAT,msg->address); PCA9564_Write(I2CCON,0xE0 | CRX); } else { PCA9564_Write(I2CCON,0xD0 | CRX); drvStatus = I2C_OK; } } // if break; case 0x30 : // no ACK for data byte PCA9564_Write(I2CCON,0xD0 | CRX); drvStatus = I2C_ERROR; break; case 0x38 : // arbitration lost -> not addressed as slave PCA9564_Write(I2CCON,0xE0 | CRX); drvStatus = I2C_ARBITRATION_LOST; break; // MASTER RECEIVER FUNCTIONS case 0x40 : // ACK for slave address + R if (msg->nrBytes>1) { PCA9564_Write(I2CCON,0xC0 | CRX); } else { PCA9564_Write(I2CCON,0x40 | CRX); } // if break; case 0x48 : // no ACK for slave address + R PCA9564_Write(I2CCON,0xD0 | CRX); drvStatus = I2C_ERROR; break; case 0x50 : // ACK for data byte msg->buf[dataCount++] = PCA9564_Read(I2CDAT); if (dataCount + 1 < msg->nrBytes) { PCA9564_Write(I2CCON,0xC0 | CRX); } else { PCA9564_Write(I2CCON,0x40 | CRX); } break; case 0x58 : // no ACK for data byte msg->buf[dataCount++] = PCA9564_Read(I2CDAT); PCA9564_Write(I2CCON,0xD0 | CRX); drvStatus = I2C_OK; break; default : // undefined error PCA9564_Write(I2CCON,0xD0 | CRX); drvStatus = I2C_ERROR; break; } // switch - PCA9564_Status } // i2c_isr 39 // I2CCON=11010xxx -> Stop condition // I2CCON=11000xxx -> release interrupt // I2CCON=11100xxx = start // I2CCON=11010xxx // I2CCON=11010xxx -> stop condition // I2CCON=11100xxx -> send start again // I2CCON=11000xxx -> acknowledge byte // I2CCON=01000xxx -> return NACK // I2CCON=11010xxx -> send stop // I2CCON=11000xxx // I2CCON=01000xxx // I2CCON=11010xxx -> send Stop // I2CCON=11000xxx -> send stop /************************************************************************************ * Input(s): p address of I2C transfer parameter block. * proc procedure to call when transfer completed, * with the driver status passed as parameter. * Output(s): None. * Returns: None. * Description: Start an I2C transfer, containing 1 or more messages. The application must * leave the transfer parameter block untouched until the ready procedure is called. *************************************************************************************/ void I2C_Transfer(I2C_TRANSFER *p, void (*proc)(BYTE status, BYTE msgsDone)) { tfr = p; readyProc = proc; msgCount = 0; dataCount = 0; master = TRUE; msg = tfr->p_message[msgCount++]; state = (msg->address & 1) ? ST_AWAIT_ACK : ST_SENDING; PCA9564_Write(I2CCON,0xE0 | CRX); // 1110 0xxx -> generate Start } /* ******************************************************************** * Input(s): speed clock register value for bus speed. * Output(s): None. * Returns: None. * Description: Initialize the PCA9564 as I2C-bus master. **********************************************************************/ void I2C_InitializeMaster(BYTE speed) { int i; state = ST_IDLE; readyProc = 0; masterProc = HandleMasterState; PCA9564_Write(I2CADR,0xFE); CRX = speed; PCA9564_Write(I2CCON,0xC0 | CRX); for (i=0;i<1000;i++) ; master = FALSE; // // // // // Null pointer Set pointer to correct proc. own slave address I2C Frequency 1100 0xxx -> Set to slave receiver } 40 I2CINTFC.C //************************************************************************* // // P H I L I P S P R O P R I E T A R Y // // COPYRIGHT (c) 2003 BY PHILIPS SEMICONDUCTORS // -- ALL RIGHTS RESERVED -// // File Name: i2cintfc.c // Created: June 2, 2003 // Modified: June 10, 2003 // Revision: 1.00 // //************************************************************************* #include #include #include #include #include <REG51RX.H> "i2cexprt.h" "i2cdrivr.h" "i2cmastr.h" "PCA9564sys.h" BYTE drvStatus; static I2C_MESSAGE static I2C_TRANSFER // Status returned by driver *p_iicMsg[2]; iicTfr; // pointer to an array of (2) I2C messages /************************************************************************** * Input(s): status Status of the driver at completion time * msgsDone Number of messages completed by the driver * Output(s): None. * Returns: None. * Description: Signal the completion of an I2C transfer. This function is * passed (as parameter) to the driver and called by the * drivers state handler (!). ***************************************************************************/ static void I2cReady(BYTE status, BYTE msgsDone) { drvStatus = status; } /* *************************************************************************** * Input(s): None. * Output(s): status field of I2C_TRANSFER contains the driver status: * I2C_OK Transfer was successful. * I2C_TIME_OUT Timeout occurred * Otherwise Some error occurred. * Returns: None. * Description: Start I2C transfer and wait (with timeout) until the * driver has completed the transfer(s). ************************************************************************** */ static void StartTransfer(void) { LONG timeOut; BYTE retries = 0; do { drvStatus = I2C_BUSY; I2C_Transfer(&iicTfr, I2cReady); timeOut = 0; while (drvStatus == I2C_BUSY) { if (++timeOut > 60000) drvStatus = I2C_TIME_OUT; if (PCA9564_Read(I2CCON) & 0x08) // wait until SI bit is set MainStateHandler(); } if (retries == 6) { drvStatus = I2C_RETRIES; // too many retries } else retries++; } while ((drvStatus != I2C_OK) & (drvStatus!=I2C_RETRIES)); } 41 /*************************************************************************** * Input(s): msg I2C message * Returns: None. * Description: Read a message from a slave device. * PROTOCOL: <S><SlvA><R><A><D1><A> ... <Dnum><N><P> ***************************************************************************/ void I2C_Read(I2C_MESSAGE *msg) { iicTfr.nrMessages = 1; iicTfr.p_message = p_iicMsg; p_iicMsg[0] = msg; StartTransfer(); } /*************************************************************************** * Input(s): msg I2C message * Returns: None. * Description: Write a message to a slave device. * PROTOCOL: <S><SlvA><W><A><D1><A> ... <Dnum><N><P> ***************************************************************************/ void I2C_Write(I2C_MESSAGE *msg) { iicTfr.nrMessages = 1; iicTfr.p_message = p_iicMsg; p_iicMsg[0] = msg; StartTransfer(); } /*************************************************************************** * Input(s): msg1 first I2C message * msg2 second I2C message * Returns: None. * Description: A message is sent and received to/from two different * slave devices, separated by a repeat start condition. * PROTOCOL: <S><Slv1A><W><A><D1><A>...<Dnum1><A> * <S><Slv2A><R><A><D1><A>...<Dnum2><N><P> ***************************************************************************/ void I2C_WriteRepRead(I2C_MESSAGE *msg1, I2C_MESSAGE *msg2) { iicTfr.nrMessages = 2; iicTfr.p_message = p_iicMsg; p_iicMsg[0] = msg1; p_iicMsg[1] = msg2; StartTransfer(); } /*************************************************************************** * Input(s): msg1 first I2C message * msg2 second I2C message * Returns: None. * Description: Writes two messages to different slave devices separated * by a repeated start condition. * PROTOCOL: <S><Slv1A><W><A><D1><A>...<Dnum1><A> * <S><Slv2A><W><A><D1><A>...<Dnum2><A><P> ***************************************************************************/ void I2C_WriteRepWrite(I2C_MESSAGE *msg1, I2C_MESSAGE *msg2) { iicTfr.nrMessages = 2; iicTfr.p_message = p_iicMsg; p_iicMsg[0] = msg1; p_iicMsg[1] = msg2; StartTransfer(); } 42 PCA9564sys.h //************************************************************************* // // P H I L I P S P R O P R I E T A R Y // // COPYRIGHT (c) 2003 BY PHILIPS SEMICONDUCTORS // -- ALL RIGHTS RESERVED -// // File Name: PCA9564sys.h // Created: June 2, 2003 // Modified: June 4, 2003 // Revision: 1.00 // //************************************************************************* #ifndef __PCA9564SYS_H__ #define __PCA9564SYS_H__ #define #define #define #define #define #define MCU_COMMAND 0xFF I2CSTA 0x00 I2CTO 0x00 I2CDAT 0x01 I2CADR 0x02 I2CCON 0x03 // // // // // // dummy address PCA9564 Status Register PCA9564 Timeout Register PCA9564 Data Register PCA9564 Address Register PCA9564 Control Register // I2CCON = AA + ENSIO + STA + STO + SI + CR2 + CR1 + CR0 #define AA_ENSIO_STA_NOTSTO_NOTSI 0xE0 // Generate Start #define AA_ENSIO_NOTSTA_STO_NOTSI 0xD0 // Generate Stop #define AA_ENSIO_NOTSTA_NOTSTO_NOTSI 0xC0 // Release bus and Ack + set to slave receiver #define NOTAA_ENSIO_NOTSTA_NOTSTO_NOTSI 0x40 // Release bus and NOT Ack void PCA9564_Write(unsigned char Reg, unsigned char val); unsigned char PCA9564_Read(unsigned char Reg); #endif PCA9564sys.c //************************************************************************* // // P H I L I P S P R O P R I E T A R Y // // COPYRIGHT (c) 2003 BY PHILIPS SEMICONDUCTORS // -- ALL RIGHTS RESERVED -// // File Name: PCA9564sys.C // Created: June 2, 2003 // Modified: June 10, 2003 // Revision: 1.00 // //************************************************************************* #include <REG51RX.H> //#include "BasicTyp.h" #include "PCA9564sys.h" sbit A0 sbit A1 // special function register declarations = P2^0; = P2^1; sbit Reset9564 = P3^4; // +---------------------------------------------+ // | PCA9564 register commands // +---------------------------------------------+ void PCA9564_Write(unsigned char Reg, unsigned char val) { A0 = Reg & 0x01; A1 = Reg & 0x02; AUXR = 0x02; // Access external memory, emit/don't emit ALE --> emit when using emulator *((unsigned char pdata *)MCU_COMMAND) = val; AUXR = 0x00; // Access internal memory, emit ALE when using emulator } 43 unsigned char PCA9564_Read(unsigned char Reg) { unsigned char RegData; int i; A0 = Reg & 0x01; A1 = Reg & 0x02; AUXR = 0x02; // Access external memory, emit ALE when using emulator for (i=0;i<10;i++); // add small delay due to rise time issues on demoboard RegData = *((unsigned char pdata *)MCU_COMMAND); AUXR = 0x00; // Access internal memory, emit ALE when using emulator return RegData; } Interrupts.c //************************************************************************* // // P H I L I P S P R O P R I E T A R Y // // COPYRIGHT (c) 2003 BY PHILIPS SEMICONDUCTORS // -- ALL RIGHTS RESERVED -// // File Name: Interrupts.c -- Only for reference (not used) // Created: June 2, 2003 // Modified: November 07, 2003 // Revision: 1.00 // //************************************************************************* void ExternalInt0(void) interrupt 0 { } void Timer0(void) interrupt 1 { } void ExternalInt1(void) interrupt 2 { } void Timer1(void) interrupt 3 { } 44 Appendix 2: P89LPC932 Microcontroller Source Code – Rev 1.0 Main.c //*************************************************************************** //* main.c //* Date : July 2003 //* Discription : Using I2Cslave code to interact with the //* PCA9564 on the I2C-bus //*************************************************************************** #include <Reg932.h> #include "ua_exprt.h" //*************************************************************************** //* Definitions //*************************************************************************** typedef unsigned char BYTE; typedef unsigned short WORD; //*************************************************************************** //* Functions //*************************************************************************** void init(void); //*************************************************************************** //* init() //* Input(s) : none. //* Returns : none. //* Description : initialization of P89LPC903 //*************************************************************************** void init(void) { P0M1 = 0x00; // P0 in Quasi bi mode P1M1 = 0x0C; // P1 in Quasi bi mode P1M2 = 0x0C; // P1.2 P13 open drain P2M1 = 0x00; // P2 in Quasi bi mode } //*************************************************************************** //* main() //* Input(s) : none. //* Returns : none. //* Description : main loop //*************************************************************************** void main(void) { har temp; init(); // initialize P89LPC932 I2C_Init(); // initialize I2C block EA = 1; // enable interrupts while(1) // main loop { switch(slaveBuf[0]) // switch on first byte received { case(0x00): // Command 00, write byte to P2 { P2 = slaveBuf[1]; } break; case(0xEE): // command EE, change address { // according jumper settings temp = P0; temp &= 0x07; // mask out non address bits temp <<= 1; // shift left one I2ADR = (0xE0 | temp); // generate I2C address depending on P0 } break; case(0xFF): // command FF, send back I2C slave address { slaveBuf[0] = I2ADR; } break; default: { } break; } } } 45 i2cslave.c /************************************************************** /* Name of module: I2CSLAVE.C /* Creation date: 12 March 2003 /* Program language : C /* /* (C) Copyright 2003 Philips Semiconductors B.V. /* /************************************************************** #include <Reg932.H> #include "ua_exprt.h" typedef unsigned char BYTE; typedef unsigned short WORD; #define #define #define #define #define SLAVE_IDLE SLAVE_BUSY SLAVE_READY SLAVE_TRX_ERROR SLAVE_RCV_ERROR 0 1 2 3 4 #define #define #define #define GENERATE_STOP RELEASE_BUS_ACK RELEASE_BUS_NOACK RELEASE_BUS_STA 0x54 0x44 0x40 0x64 static BYTE count; char slaveBuf[3]; static BYTE size; static BYTE slaveStatus; void I2C_Interrupt(void) interrupt 6 using 1 { switch(I2STAT) { case 0x60: case 0x68: case 0x70: case 0x78: slaveStatus = SLAVE_BUSY; count = 0; if (size > 1) I2CON = RELEASE_BUS_ACK; else I2CON = RELEASE_BUS_NOACK; break; case 0x80: case 0x90: slaveBuf[count++] = I2DAT; if (count == size) I2CON = RELEASE_BUS_NOACK; else I2CON = RELEASE_BUS_ACK; break; case 0x88: case 0x98: slaveStatus = SLAVE_RCV_ERROR; I2CON = RELEASE_BUS_ACK; break; case 0xA0: slaveStatus = SLAVE_READY; I2CON = RELEASE_BUS_ACK; break; case 0xB0: slaveStatus = SLAVE_BUSY; count = 0; I2DAT = slaveBuf[count++]; I2CON = RELEASE_BUS_STA; break; case 0xA8: slaveStatus = SLAVE_BUSY; count = 0; case 0xB8: I2DAT = slaveBuf[count++]; I2CON = RELEASE_BUS_ACK; break; case 0xC0: slaveStatus = SLAVE_TRX_ERROR; case 0xC8: I2CON = RELEASE_BUS_ACK; // // // // set STO, clear STA and SI clear STO,STA,SI and set AA (ack) clear STO, STA, SI and AA (noack) generate (rep)START, set STA // bytes send/received of current message // size of slave mode buffer // status of the slave // own SLA+W received, Ack returned // Addressed as slave // General call received, Ack returned // Data will be received // return ACK on first byte // return NACK on first byte // Data received, ACK returned // read data // return NACK on next byte // return ACK on next byte // received, NACK returned // clr SI, set AA // STOP or REP.START received, addressed as slave // clr SI, set AA // Arb. lost as MST, addressed as slave transmitter // Transmit next data, restart // MST mode if bus is free again // Addressed as slave transmitter // Data transmitted, ACK received // Transmit next data // clr SI, set AA // Data transmitted, NOT ACK received // clr SI, set AA 46 break; default: break; } } //void I2C_Init(BYTE *buf, BYTE size) void I2C_Init(void) { unsigned char temp; slaveStatus = SLAVE_IDLE; slaveBuf[0] = 0xA5; slaveBuf[1] = 0x55; slaveBuf[2] = 0x99; size = 3; P1M1 P1M2 |= 0x0C; |= 0x0C; // Configure P1.2 and P1.3 to open drain //***************************************************************************** //* Modified from Paul's code to select an address depending on the jumper //* settings of A2, A1 and A0 //***************************************************************************** temp = P0; temp &= 0x07; // mask out non address bits temp <<= 1; // shift left one I2ADR = (0xE0 | temp); // generate I2C address depending on P0 //***************************************************************************** //* End modification //***************************************************************************** I2SCLH = 0x05; I2SCLL = 0x04; I2CON = RELEASE_BUS_ACK; EI2C = 1; // enable I2C hardware // enable I2C interrupt } void I2C_ProcessSlave(void) ***************************************************************************/ * Input(s) : None. * Output(s) : None. * Returns : None. * Description: Process the slave. * This function must be called by the application to check * the slave status. The USER should adapt this function to * his personal needs (take the right action at a certain * status). ***************************************************************************/ { switch(slaveStatus) { case SLAVE_IDLE : /* do nothing or fill transmit buffer for transfer */ break; case SLAVE_BUSY : /* do nothing if interrupt driven */ break; case SLAVE_READY : /* read or fill buffer for next transfer, signal application */ slaveStatus = SLAVE_IDLE; break; case SLAVE_TRX_ERROR : /* generate error message */ slaveStatus = SLAVE_IDLE; break; case SLAVE_RCV_ERROR : /* generate error message */ slaveStatus = SLAVE_IDLE; break; } } 47 ua_exprt.h /**************************************************************************** /* /* (C) Copyright 1993 Philips Semiconductors B.V. /* /**************************************************************************** /* /* Description: /* /* This module consists a number of exported declarations of the I2C /* driver package. Include this module in your source file if you want /* to make use of one of the interface functions of the package. /* /**************************************************************************** /**** Status Errors ****/ #define #define #define #define #define #define #define #define #define #define #define I2C_OK I2C_BUSY I2C_ERR I2C_NO_DATA I2C_NACK_ON_DATA I2C_NACK_ON_ADDRESS I2C_DEVICE_NOT_PRESENT I2C_ARBITRATION_LOST I2C_TIME_OUT I2C_SLAVE_ERROR I2C_INIT_ERROR extern char slaveBuf[]; 0 1 2 3 4 5 6 7 8 9 10 /* /* /* /* /* /* /* /* /* /* /* transfer ended No Errors */ transfer busy */ err: general error */ err: No data in block */ err: No ack on data */ err: No ack on address */ err: Device not present */ err: Arbitration lost */ err: Time out occurred */ err: slave mode error */ err: Initialization (not done)*/ // ptr to rec/trm data into/from if slave /***************************************************************************/ /* I N T E R F A C E F U N C T I O N P R O T O T Y P E S */ /***************************************************************************/ extern void I2C_Init(void); 48 Appendix 3: PCA9564 evaluation Board Bill Of Material Part C1 C2 C3 C4 C5 C6 C7 C8 C9 C10 C11 C12 C13 C14 C15 C16 C17 C18 C19 C20 DB9 IC1 IC3 JP1 JP2 JP3 JP4 JP5 JP6 JP7 JP8 JP9 JP10 JP11 JP12 JP13 JP14 JP15 JP16 JP17 JP18 JP19 JP20 JP21 LD1 to LD8 LD9 to LD12 LD13 to LD20 LD21 to LD23 LD24 PCA9564 PCF85116 PORT0LPC PORT1LV51 Q1 Q2 R1 R2 R3 R4 R5 R6 R7 R8 R9 Value 100 nF 100 nF 100 nF 100 nF 100 nF 100 nF 1 µF 100 nF 100 nF 100 nF 100 nF 100 nF 100 nF 22 pF 22 pF 22 pF 22 pF 100 µF 100 nF 100 nF F09HP 7402PW LM317TL Package Description C0603 C0603 C0603 C0603 C0603 C0603 C0603 C0603 C0603 C0603 C0603 C0603 C0603 C0603 C0603 C0603 C0603 085CS_1AR C0603 C0603 CAPACITOR CAPACITOR CAPACITOR CAPACITOR CAPACITOR CAPACITOR CAPACITOR CAPACITOR CAPACITOR CAPACITOR CAPACITOR CAPACITOR CAPACITOR CAPACITOR CAPACITOR CAPACITOR CAPACITOR POLARIZED CAPACITOR CAPACITOR CAPACITOR SUB-D Connector Quad 2-input NOR gate VOLTAGE REGULATOR JUMPER JUMPER JUMPER FEMALE 90 DEGREES CONNECTOR FEMALE 90 DEGREES CONNECTOR JUMPER JUMPER JUMPER JUMPER JUMPER JUMPER JUMPER JUMPER PIN HEADER JUMPER PIN HEADER JUMPER JUMPER JUMPER JUMPER JUMPER Red LED Green LED Red LED Green LED Red LED I2C-bus Controller 256 x 8 bits I2C EEPROM PIN HEADER PIN HEADER CRYSTAL CRYSTAL RESISTOR RESISTOR RESISTOR RESISTOR RESISTOR RESISTOR RESISTOR RESISTOR RESISTOR TSSOP14 317TL 1X06 1X08 PCA9564PW PCF85116 11.0592 MHz 12 MHz 1 kΩ 1.5 kΩ 10 kΩ 1 kΩ 1 kΩ 10 kΩ 10 kΩ 10 kΩ 270 Ω PLCC2 PLCC2 PLCC2 PLCC2 PLCC2 TSSOP20 SO8 2X04 2X05 QS QS R0603 R0603 R0603 R0603 R0603 R0603 R0603 R0603 R0603 49 Part Value R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 R22 R23 R24 R25 R26 R27 R28 R29 R30 R31 R32 R33 R34 R35 R36 R37 R38 R39 R40 R42 R43 RN1 S1 S2 S3 S4 S5 S6 S7 S8 S9 U$1 270 Ω 270 Ω 270 Ω 10 kΩ 270 Ω 270 Ω 270 Ω 270 Ω 270 Ω 270 Ω 270 Ω 270 Ω 10 kΩ 10 kΩ 270 Ω 270 Ω 270 Ω 270 Ω 270 Ω 270 Ω 270 Ω 270 Ω 10 kΩ 10 kΩ 270 Ω 270 Ω 270 Ω 47 kΩ 47 kΩ 4.7 kΩ 4.7 kΩ 47 kΩ 47 kΩ 4.7 kΩ Package P89LV51RD2 R0603 R0603 R0603 R0603 R0603 R0603 R0603 R0603 R0603 R0603 R0603 R0603 R0603 R0603 R0603 R0603 R0603 R0603 R0603 R0603 R0603 R0603 R0603 R0603 R0603 R0603 R0603 R0603 R0603 R0603 R0603 R0603 R0603 SIL9 B3F-10XX B3F-10XX B3F-10XX B3F-10XX B3F-10XX B3F-10XX B3F-10XX B3F-10XX B3F-10XX PLCC44SOCKET Description U$3 U$4 U$5 U$6 74LVC1G04GW PMBTA92 SK14 P89LPC932 SOT753 SOT23 DO214AC PLCC28SOCKET U$7 U$8 U$9 U2 VDDMCU+ 9VDCJACK PCA9531PW PCA9554PW SP3223EY TSSOP16 TSSOP16 TSSOP20 RESISTOR RESISTOR RESISTOR RESISTOR RESISTOR RESISTOR RESISTOR RESISTOR RESISTOR RESISTOR RESISTOR RESISTOR RESISTOR RESISTOR RESISTOR RESISTOR RESISTOR RESISTOR RESISTOR RESISTOR RESISTOR RESISTOR RESISTOR RESISTOR RESISTOR RESISTOR RESISTOR RESISTOR RESISTOR RESISTOR RESISTOR RESISTOR RESISTOR SIL RESISTOR PUSHBUTTON PUSHBUTTON PUSHBUTTON PUSHBUTTON PUSHBUTTON PUSHBUTTON PUSHBUTTON PUSHBUTTON PUSHBUTTON 8-bit 8kB Flash 512 B RAM Low Voltage Microcontroller 80C51 8-bit microcontroller with two-clock core 8-bit LED Dimmer 8-bit I2C GPIO with Interrupt JUMPER 50 REVISION HISTORY Revision _2 Date 20040819 _1 20031211 Description Application note (9397 750 13956). Modifications: - Added “PCA9564 evaluation board web page” paragraph - Replaced www.philipslogic.com by www.standardproducts.philips.com Application note, initial version (9397 750 12508). 51 Purchase of Philips I2C components conveys a license under the Philips I2C patent to use the components in the I2C system provided the system conforms to the I2C specifications defined by Philips. This specification can be ordered using the code 9398 393 40011. Disclaimers Application information – Applications that are described herein for any of these products are for illustrative purposes only. Philips Semiconductors make no representation or warranty that such applications will be suitable for the specified use without further testing or modification. Life support – These products are not designed for use in life support appliances, devices or systems where malfunction of these products can reasonably be expected to result in personal injury. Philips Semiconductors customers using or selling these products for use in such applications do so at their own risk and agree to fully indemnify Philips Semiconductors for any damages resulting from such application. Right to make changes – Philips Semiconductors reserves the right to make changes, without notice, in the products, including circuits, standard cells, and/or software, described or contained herein in order to improve design and/or performance. Philips Semiconductors assumes no responsibility or liability for the use of any of these products, conveys no license or title under any patent, copyright, or mask work right to these products, and makes no representations or warranties that these products are free from patent, copyright, or mask work right infringement, unless otherwise specified. © Koninklijke Philips Electronics N.V. 2004 All rights reserved. Published in the U.S.A. Contact information For additional information please visit http://www.semiconductors.philips.com Date of release: 08-04 Document order number: 9397 750 13956 Fax: +31 40 27 24825 For sales offices addresses send e-mail to: [email protected] 52