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.
Diff: hardware_abs.c
- Revision:
- 0:d6ec2b9171cb
- Child:
- 1:5526d3e04b7a
- Child:
- 2:8f5c7901d52a
diff -r 000000000000 -r d6ec2b9171cb hardware_abs.c --- /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 + +