Parallel bus access

Controlling parallel bus peripheral device

mbed (LPC1768) does not have parallel bus but it can be emulated by GPIO.
This sample shows that operation with bus 2MHz(random access) and 6MHz(burst access: continuous access to same address). This sample bus timing is tuned for PCU9669 (This library has been made for the demo of the PCU9669).

A picture below shows the logic analyzer waveform. Red is 8 bit address, Yellow is 8 bit data and others are sinal for the bus controls.

/media/uploads/nxp_ip/parallel_access_opt.png

The parallel bus library version 2 access cycle is independent from mbed-library. The version 2 is accessing to GPIO registers directly.

Want to use parallel bus!

mbed is an ideal device to try controlling peripheral devices but it doesn't have parallel bus.
This note describes how the 8bit/8bit (address/data) parallel bus can be accessed by GPIO port of the mbed.

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

Using GPIO

"BusInOut" class in mbed library in may be easiest way to operate the GPIO as address and data lines.
But the performance is not ideal for the fast operation.

mbed providing another interface for controlling several GPIO pins together. It's PortInOut.
With this interface, the GPIO can be operated much faster but need to match internal bit assignment of GPIO port registers.

Here is a sample of how the bits are assigned for the operation.

Signal mapping (into GPIO registers)

Next table shows the GPIO registers of LPC1768. The port 0, 1 and 2 can be used for GPIO control.
The address and the data are assigned in port 0. The address and the data are gathered in one port (register) to minimize the port access time.

For the parallel bus access, it requires three control signals to read/write data from/to specified address.
Those are "Read(RD)", "Write(WR)" and "ChipSelect(CS)" signals. Those signals are assigned in other port (port 2 register). Because those are not required to be in the same register of address/data. Those are controlled separately to make signal timing of parallel bus.

"CS1" and "CS2" are optional signals for when the system requires more ChipSelect. This sample code is not using those.

"INT(interrupt)" (on port 2) and "TRG(trigger)", "RS(reset)" (on port 1) are signals for interrupt, trigger and reset, respectively. Those are not the parallel port signals but it can be used for controlling the peripheral device.

/media/uploads/nxp_ip/bit-assign_ports.png

A picture above is the mapping of the signals and the GPIO registers.
As a result of those, the "ports" can be defined as below.

#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 );

Since the address, RD, WR and CS signals are uni-directional signal from MCU to the peripheral device, those are defined as "PortOut". The data lines are defined as "PortInOut" should be bi-directional.

Signal mapping (onto pins)

Pin assignment can be find as a result of the signal mapping to the register bits.
Next table shows the pin assigns. Physical signal connection to the peripheral device should be done with this information.

/media/uploads/nxp_ip/bit-assign_pins.png

Signals on pins.

/media/uploads/nxp_ip/parallel-pins.png

Using code

This parallel bus sample code was intentionally written in C (not C++) because this code is intended to port other environment that can not use C++.

Import libraryparallel_bus

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

The library works as a abstraction layer for hardware i.e. mbed. All mbed dependent code is inside of this library and user can have access to the parallel bus, interrupt and "wait" functions.

Usage sample is available here.

Import programParallel_bus_HelloWorld

Parallel bus emulation by GPIO ports

#include "mbed.h"
#include "hardware_abs.h"

#define ADDR    0xC3

char    data[]  =   { 0xFE, 0xFD, 0xFC, 0xFB, 0xFA, 0xF9, 0xF8, 0xF7, 0xF6, 0xF5, 0xF4, 0xF3, 0xF2, 0xF1, 0xF0, 0xEF };
char    v;

int main() {
    hardware_initialize();
    reset( 10, 1000 );

    write_data( 0xCA, 0x55 );
    write_data( 0xDA, 0xAA );
    v   = read_data( 0xCA );
    v   = read_data( 0xDA );

    write_data_burst( 0xC3, data, sizeof( data ) );

    while (1)
        ;
}

Library interface

Parallel bus access

Parallel data bus access can be done by functions read_data() and write_data().
read_data() takes 1 byte argument as address and returns 1 byte read value.
write_data() takes 2 byes parameters. First is address and second is data to be written.

hardware_abs.h

/** Write data
 *
 *  Writes 1 byte  
 *
 *  @param addr 8 bit address where the data should be written to 
 *  @param data 8 bit data which will be written
 *  @see read_data()
 */
void    write_data( char addr, char data );

/** Read data
 *
 *  Reads 1 byte  
 *
 *  @return 8 bit data which is read from bus
 *  @param addr 8 bit address where the data should be read from 
 *  @see write_data()
 */
char    read_data( char addr );

Signal timing (between address, data, RD, WR and CS) may needed to be adjusted for the peripheral device. For the timing adjustment, edit inside of functions in "hardware_abs.c".

Before calling read_data() and write_data() functions, the parallel bus state must be initialized. The initialization can be done by calling hardware_initialize().

hardware_abs.h

/** Hardware initialization
 *
 *  MCU side initialization should be done in this function. 
 *  For the mbed, it set the initial state of parallel bus control signal. 
 */
void    hardware_initialize( void );

Burst bus access

Consecutive access to same address can be done by burst access function. This accelerates the read/write speed.
Burst read/write can be disabled by undefining BURST_DATA_ACCESS. Undefining can be done to minimize the code porting effort when it is not necessary.

hardware_abs.h

/** @def BURST_DATA_ACCESS
 *
 *  To accelerate multiple bus access on same addess, use BURST_DATA_ACCESS
 *  On the mbed emvironment, this burst access enables 3 times faster read/write compare to single access.
 *  For code porting, the BURST_DATA_ACCESS code part is not neccesary if the hardware is fast enough. 
 */
#define     BURST_DATA_ACCESS

hardware_abs.h

/** BURST_DATA_ACCESS option code
 *
 *  This code is option to accelerate the bus access
 */
#ifdef  BURST_DATA_ACCESS

/** Write data
 *
 *  Writes multiple bytes to same address. 
 *  This function suitable to use for the registers like SLATABLE, TRANCONFIG and data buffers (through DATA register).
 *  While this access is going, the interrupt will be tempolary disabled (ISR execution will be postponed)
 *
 *  @param addr   8 bit address where the data should be written to 
 *  @param *data  pointer to char array. The data in this array will be written
 *  @param length length of the data (bytes)
 *  @see read_data_burst()
 */
void    write_data_burst( char addr, char *data, char length );

/** Read data
 *
 *  Reads multiple bytes from same address. 
 *  This function suitable to use for the registers like SLATABLE, TRANCONFIG and data buffers (through DATA register).
 *  While this access is going, the interrupt will be tempolary disabled (ISR execution will be postponed)
 *
 *  @param addr   8 bit address where the data should be written to 
 *  @param *data  pointer to char array. The read data will be written to this
 *  @param length length of the data (bytes)
 *  @see write_data_burst()
 */
void    read_data_burst( char addr, char *data, char length );
#endif

Reset signal

Since this library made for hardware abstraction, the reset signal interface available also. The reset pin is defined in hardware_abs.c.

There are two types of functions.
hardware_reset() is for manual pin state control. It drives Low(ASSERT) or High(DEASSERT) by calling this function. reset() asserts the reset signal for specified period. It also manages "reset recovery time". That means the function will not be returned for specified time after the reset signal de-asserted.

hardware_abs.h

/** Reset signal control
 *
 *  This function drives the RESET signal line with given state.  
 *
 *  @param signal the state of RESET signal: ASSERT | DEASSERT
 */
void    hardware_reset( char signal );

/** Hardware reset
 *
 *  Asserts the RESET signal with required pulse width and waits its recovery time
 *  
 *  @param reset_pulse_width_us RESET pulse width in micro-seconds
 *  @param reset_recovery_us RESET  recovery time in micro-seconds (wait time after RESET de-assertion)
 */
void reset( int reset_pulse_width_us, int reset_recovery_us );

Interrupt

To abstract mbed specific interface, interrupt interface also provided. The definition is similar to mbed InterruptIn interface but no pin

hardware_abs.h

/** Install an ISR
 *
 *  Registering function as ISR. 
 *  The function will be called when the interrupt asserted.
 *
 *  @param fptr a pointer to a function
 */
void    install_ISR( void (*fptr)(void) );

Note

version 2

Version 2 has improved bus access cycle and the speed is independent from mbed-library difference.
Bus timing is tuned for PCU9669.
The frequency is about 2MHz(random access) and 6MHz(burst access: continuous access to same address).

/media/uploads/nxp_ip/parallel_access_opt.png

version 1

Bus access cycles may be different by mbed library revisions.
The revision 28 shows 1MHz(random access) and 2.75MHz(burst access).

/media/uploads/nxp_ip/parallel_access_rev28.png

But when the library is updated to 43 (latest as of 10-July-2012), it becomes 0.78MHz and 1.4MHz.

/media/uploads/nxp_ip/parallel_access.png

So user need to be careful about library revision difference.


Please log in to post comments.