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.
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.
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.
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.
Signals on pins.
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).
version 1
Bus access cycles may be different by mbed library revisions.
The revision 28 shows 1MHz(random access) and 2.75MHz(burst access).
But when the library is updated to 43 (latest as of 10-July-2012), it becomes 0.78MHz and 1.4MHz.
So user need to be careful about library revision difference.
Please log in to post comments.