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.
hardware_abs.c
- Committer:
- nxp_ip
- Date:
- 2012-07-12
- Revision:
- 4:2b277209c3e6
- Parent:
- 3:a3e71822a7a3
- Parent:
- 1:5526d3e04b7a
- Child:
- 5:8b54fb7ecfff
File content as of revision 4:2b277209c3e6:
/** A sample code for "mini board PCU9669/PCA9665" * * @author Akifumi (Tedd) OKANO, NXP Semiconductors * @version 1.1 * @date 11-Jul-2012 * * ** Parallel bus accessing library version 2.0 (12-Jul-2012) * ** version 2.0 has been made for speed optimization by register level control * ** And it makes parallel bus speed 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