Parallel bus (address 8 bit, data 8 bit) access sample using GPIO pins.

Dependents:   mini_board_PCU9669_demo mini_board_PCU9669

Parallel bus emulation sample code

mbed (LPC1768) does not have parallel bus but it can be emulated by GPIO.
Please find a notebook page for more infomation.

/media/uploads/nxp_ip/parallel-block-diagram.png

/media/uploads/nxp_ip/parallel_access_opt.png

Revision:
0:d6ec2b9171cb
Child:
1:5526d3e04b7a
Child:
2:8f5c7901d52a
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hardware_abs.c	Wed Jul 11 09:37:35 2012 +0000
@@ -0,0 +1,283 @@
+
+/** A sample code for "mini board PCU9669/PCA9665"
+ *
+ *  @author  Akifumi (Tedd) OKANO, NXP Semiconductors
+ *  @version 1.0
+ *  @date    26-Mar-2012
+ *
+ *    ** Parallel bus accessing library version 2.0 (11-Jul-2012)
+ *    ** version 2.0 has been made for speed optimization by register level control
+ *    ** And it makes parallel bus independent from mbed-library (PortOut, PortInOut)
+ *
+ *  Released under the MIT License: http://mbed.org/license/mit
+ *
+ *  An operation sample of PCU9669/PCA9665 I2C bus controller.
+ *  The mbed accesses the bus controller's parallel port (8/2 bit address and 8 bit data) by bit-banging.
+ *  The bit-banging is poerformed by PortInOut function of mbed library.
+ *
+ *    To make the code porting easier, all codes are partitioned into layers to abstract other parts.
+ *    The mbed specific parts are concentrated in lowest layer: "hardware_abs.*".
+ *    This module may need to be modified for the porting.
+ *
+ *    All other upper layers are writen in standard-C.
+ *
+ *    base code is written from 05-Sep-2011 to 09-Sep-2011.
+ *    And demo code has been build on 11-Sep-2011.
+ *    Debug and code adjustment has been done on 08-Sep-2011.
+ *    Small sanitization for main.cpp. All mbed related codes are moved in to "hardware_abs.*". 13-Oct-2011
+ *    hardware_abs are moved into parallel_bus library folder, 3 LED driver operation sample 13-Feb.-2012
+ *    PCU9669 and PCA9665 codes are packed in a project 14-Feb-2012.
+ *
+ *    Before builidng the code, please edit the file mini_board_PCU9669/config.h
+ *    Un-comment the target name what you want to target.
+ */
+
+/*
+ *  "hardware_abs" module has been made to abstract hardware: Hardware abstract layer
+ *  This is file which will be modified when the porting done for other MCUs.
+ */
+
+/*
+ *  This sample code has been made for mbed. The code emulates parallel SRAM bus using the mbed's GPIO ports.
+ *  To maximize the port access speed, PortOut and PortInOut libraly used.
+ */
+
+#include    "mbed.h"
+#include    "hardware_abs.h"
+
+void register_check( LPC_GPIO_TypeDef *p ) {
+    printf( "%p\r\n", p );
+    printf( "  %p->FIODIR  0x%08X\r\n", p, p->FIODIR );
+    printf( "  %p->FIOMASK 0x%08X\r\n", p, p->FIOMASK );
+    printf( "  %p->FIOPIN  0x%08X\r\n", p, p->FIOPIN );
+    printf( "  %p->FIOSET  0x%08X\r\n", p, p->FIOSET );
+    printf( "  %p->FIOCLR  0x%08X\r\n", p, p->FIOCLR );
+}
+
+//  GPIO port setting
+
+#define     ADDR_MASK       0x07878000  //  8 bit address mask on PORT0: Address value will be set into this bit position
+#define     DATA_MASK       0x00000FF0  //  8 bit data mask on PORT0: Data value will be appeared on this bit position
+#define     CONTROL_MASK    0x00000038  //  Control signals CS=bit5(pin21), WR=bit4(pin22), RD=bit3(pin23)
+
+PortOut     addr_port( Port0, ADDR_MASK );
+PortInOut   data_port( Port0, DATA_MASK );
+PortOut     ctrl_port( Port2, CONTROL_MASK );
+InterruptIn int_port( p26 );
+
+//  The very early version of PCU9669 mini board has different configuration.
+//  Following part switches the port configuration for those board versions.
+
+//#define     PROTOTYPE_BREADBOARD
+
+DigitalInOut    reset_port( p20 );
+//DigitalOut      trig_port( p19 );
+
+//  Next two macros defines interface for temporaly interrupt disable/enable functions.
+//  These macros are used to blocking interrupt until a bus access cycle completed.
+//  Because if the interrupt happened in a cycle, the emulated parallel port state will be disturbed.
+//  For the mbed, library routine: __disable_irq() / __enable_irq() can be used.
+
+#define     interrupt_enable()    __enable_irq()
+#define     interrupt_disable()   __disable_irq()
+
+//  "prev_access_was_write" is a variable to keep the previous data directions.
+//  Using this flag, successive write and read addess overhead can be reduced.
+//  This mechanism will not be required if the MCU has parallel port
+
+char        prev_access_was_write;
+
+//  ISR routine installer
+
+void install_ISR( void (*fptr)(void) ) {
+    int_port.fall( fptr );
+}
+
+//  Hardware initialize: it defines initial state of the (emulated) parallel bus
+
+void hardware_initialize( void ) {
+    prev_access_was_write   = 0;
+    ctrl_port               = 0x38;     //  CS, WR and RD are deaserted (HIGH)
+    data_port.input();                  //  data bus set to Hi-Z
+    reset_port.output();
+    reset_port.mode( PullUp );
+}
+
+//  Hardware reset for PCU9669: It asserts RESET signal for 4us and waits 650us after deassert (reset recovery time)
+
+void reset( int reset_pulse_width_us, int reset_recovery_us ) {
+    hardware_reset( ASSERT );            //  Minimum pulse width is 4us for PCU9669
+    hw_wait_us( reset_pulse_width_us );
+    hardware_reset( DEASSERT );          //  deassert hardware /RESET sgnal
+    hw_wait_us( reset_recovery_us );
+}
+
+//  Interface to Control hardware RESET signal
+
+void hardware_reset( char signal ) {
+    reset_port  = signal;
+}
+
+//  Interface to Control hardware TRIGGER signal
+
+void hardware_trigger( char signal ) {
+//    trig_port  = signal;
+}
+
+//  Single write cycle on (emulated) parallel bus
+
+void write_data( char addr, char data ) {
+    unsigned long   addr_data;
+
+    interrupt_disable();    //  disable interrupt first
+
+    addr_data   = (addr << 19) | (addr << 15) | (data << 4);
+
+    LPC_GPIO0->FIOMASK  = ~(ADDR_MASK | DATA_MASK);
+    LPC_GPIO0->FIODIR   = ADDR_MASK;
+    LPC_GPIO0->FIOSET   = addr_data;
+    LPC_GPIO0->FIOCLR   = ~addr_data;
+
+    LPC_GPIO2->FIOCLR   = 0x20; //  Assert CS signal
+
+    LPC_GPIO0->FIODIR   = ADDR_MASK | DATA_MASK;
+
+    LPC_GPIO2->FIOCLR   = 0x30; //  repeating register write to keep pulse width wide :)
+
+    LPC_GPIO0->FIOSET   = addr_data;
+    LPC_GPIO0->FIOCLR   = ~addr_data;
+
+    LPC_GPIO2->FIOCLR   = 0x30; //  to keep timing
+    LPC_GPIO2->FIOCLR   = 0x30; //  to keep timing
+    LPC_GPIO2->FIOCLR   = 0x30; //  to keep timing
+    LPC_GPIO2->FIOCLR   = 0x30; //  to keep timing
+    LPC_GPIO2->FIOSET   = 0x38;
+
+    LPC_GPIO0->FIODIR   = ADDR_MASK;
+
+    interrupt_enable();    //  enable interrupt again
+}
+
+
+char read_data( char addr ) {
+    unsigned long   addr_data;
+    volatile char   tmp;
+
+    interrupt_disable();    //  disable interrupt first
+
+    LPC_GPIO0->FIODIR   = ADDR_MASK;
+
+    LPC_GPIO0->FIOMASK   = ~ADDR_MASK;
+    addr_data   = (addr << 19) | (addr << 15);
+    LPC_GPIO0->FIOSET   = addr_data;
+    LPC_GPIO0->FIOCLR   = ~addr_data;
+
+    LPC_GPIO2->FIOCLR   = 0x28; //  Assert CS and RD signals
+    LPC_GPIO2->FIOCLR   = 0x28; //  to keep timing
+    LPC_GPIO2->FIOCLR   = 0x28; //  to keep timing
+    LPC_GPIO2->FIOCLR   = 0x28; //  to keep timing
+
+    LPC_GPIO0->FIOMASK  = ~DATA_MASK;
+    tmp                 = (LPC_GPIO0->FIOPIN >> 4) & 0xFF;      //  Read data bus into var
+
+    LPC_GPIO2->FIOSET   = 0x38;
+
+    interrupt_enable();    //  enable interrupt again
+
+    return ( tmp );
+}
+
+//  Wait for micro-seconds
+
+void hw_wait_us( int v ) {
+    wait_us( v );
+}
+
+//  Wait for seconds
+
+void wait_sec( float f ) {
+    wait( f );
+}
+
+//  Following part is an optionto accerelate bus access.
+//  If such trick is not required, undefine the "BURST_DATA_ACCESS" and don't touch it.
+//
+//  Next two functions access single address with repeating read/write.
+//  The repeating read/write are used often for PCU9669 like SLATABLE, TRANCONFIG and DATA (buffer accesses).
+//  So this accerelation contributes saving MCU time.
+//
+//  For the porting, it may be good idea to modify those routines to DMA access.
+
+#ifdef  BURST_DATA_ACCESS
+
+void write_data_burst( char addr, char *data, char length ) {
+    unsigned long   addr_data;
+    int             i;
+
+    interrupt_disable();    //  disable interrupt first
+
+    addr_data   = (addr << 19) | (addr << 15);
+
+    LPC_GPIO0->FIOMASK  = ~ADDR_MASK;
+    LPC_GPIO0->FIODIR   = ADDR_MASK;
+    LPC_GPIO0->FIOSET   = addr_data;
+    LPC_GPIO0->FIOCLR   = ~addr_data;
+
+    LPC_GPIO2->FIOCLR   = 0x20; //  Assert CS signal
+
+    LPC_GPIO0->FIODIR   = ADDR_MASK | DATA_MASK;
+    LPC_GPIO0->FIOMASK  = ~DATA_MASK;
+
+    for ( i = 0; i < length; i++ ) {    //  repeat data read access
+
+        addr_data   = *(data + i) << 4;
+
+        LPC_GPIO2->FIOCLR   = 0x30; //  repeating register write to keep pulse width wide :)
+
+        LPC_GPIO0->FIOCLR   = ~addr_data;
+        LPC_GPIO0->FIOSET   = addr_data;
+
+        LPC_GPIO2->FIOCLR   = 0x30; //  to keep timing
+        LPC_GPIO2->FIOCLR   = 0x30; //  to keep timing
+        LPC_GPIO2->FIOCLR   = 0x30; //  to keep timing
+        LPC_GPIO2->FIOSET   = 0x10;
+    }
+        LPC_GPIO2->FIOSET   = 0x38;
+
+    LPC_GPIO0->FIODIR   = ADDR_MASK;
+    interrupt_enable();    //  enable interrupt again
+}
+
+void read_data_burst( char addr, char *data, char length ) {
+    unsigned long   addr_data;
+    int             i;
+
+    interrupt_disable();    //  disable interrupt first
+
+    addr_data   = (addr << 19) | (addr << 15);
+
+    LPC_GPIO0->FIOMASK  = ~ADDR_MASK;
+    LPC_GPIO0->FIODIR   = ADDR_MASK;
+    LPC_GPIO0->FIOSET   = addr_data;
+    LPC_GPIO0->FIOCLR   = ~addr_data;
+
+    LPC_GPIO0->FIOMASK  = ~DATA_MASK;
+
+    for ( i = 0; i < length; i++ ) {    //  repeat data read access
+        LPC_GPIO2->FIOCLR   = 0x28; //  Assert CS and RD signals
+        LPC_GPIO2->FIOCLR   = 0x28; //  to keep timing
+        LPC_GPIO2->FIOCLR   = 0x28; //  to keep timing
+        LPC_GPIO2->FIOCLR   = 0x28; //  to keep timing
+
+        *(data + i)         = (LPC_GPIO0->FIOPIN >> 4) & 0xFF;      //  Read data bus into var
+        LPC_GPIO2->FIOSET   = 0x08;
+    }
+        LPC_GPIO2->FIOSET   = 0x38;
+
+    LPC_GPIO0->FIODIR   = ADDR_MASK;
+    interrupt_enable();    //  enable interrupt again
+}
+
+#endif
+
+