Using the PCIe card EVB/Altera DB4CGX15 and the tool with LCD display and keyboard implement control program for a messaging system resembling Pager (predecessor of SMS). Each keyboard/Altera board is individual pager identified by unique ID in the system. The system is represented by standalone server in the computer network. The pager's ID and server's IP address are passed on command line. When started the pager is in the stand-by state. In this state every 5 seconds it checks if there are any incoming messages on the server. If there is a message, the pager beeps and displays the message. User has to confirm the message by a key. When the key is pressed, the pager sends “read” confirmation to the server and enters stand-by state.
The pager also allows to send a message to other pager in the system. While in stand-by mode, a user can press a designated key to the enter the messaging mode. First he/she has to enter other pager's ID and then enter the message. In easy version - the message consists of a numberic code up to six digits long, in advanced version the message is “text message” of unlimited length. If user do not push any button for 30 seconds, the pager discarts the message and enters stand-by mode.
The keys on the pager has to have acoustic feedback.
To request incoming and send outgoing messages from server you will use TCP/IP protocols. Simple server will be available later, but it's protocol is described later. This server allows numeric codes as messages for simple version. If you want to use advanced version for text messages, you have to implement your own. It will have to handle at least 10 unique pagers and at least 10 unread messages for each pager.
Your solution will consist of: the program, user documentation and technical documentation. On presenting your solution, teacher will check: completeness, functionality and your understanding of the program. The documentation is always mandatory, but you will get points, only if all other parts of your work is complete.
The deadline is on the last week (tutorial) of the semester. You will receive 5 points penalty of every started week after the deadline (starting on Monday midnight).
On presenting your semestral work we will check if your program works correctly and also if you understand your code and documentation. Documentation is always mandatory, but you will get points only if your program works and is complete. You can receive full points only if you present your semestral work before deadline. After that you will get a 5 point fine for every week passed.
lspci -nn -v -d 1172:1f32
(use /proc/bus/pci
) [1pt]
The simple server will be available in source code here. To compile the server, you must use make
.
apo-pagercentral-2015-1.tar.gz
The following command can be used to run the server:
./pagercentral -v
The server by default listens on port 55556. You can verify your server using telnet
program with following command:
telnet localhost 55556
To check new messages in the queue for a pager, you can use following command:
<pager_id> querrymessage 42
Response to this request contains
querrymessage_r <pager_id> <message_id> <sender_id> <message>
If there is no message in the queue, the <message_id>
is text “none”, otherwise it is ID of the message in the system, followed by actual code/text of the message. To check errors/inconsistencies in request/response check the console output.
To confirm that message was read, use:
<pager_id> <message_id> confirmmessage 42 123456
Server then replies with confirmmessage_r
followed by <pager_id> and <message_id>.
Nová zpráva bude centrálnímu systému vyslané příkazem
<pager_id> <recipient_id> <message_text> sendmessage 42 53 1337
Odpověď bude místo textu zprávy obsahovat přiřazené unikátní číslo v rámci systému
<pager_id> <recipient_id> <message_id> sendmessage_r 42 53 123456
Hardware consists of input/output PCI card implementing memory mapped input/output gates and registers of the PCI address space and external hardware tool - matrix keyboard, LCD controller and 8 LED diods.
Card with the FPGA integrated circuit allows to set control and data bits on 8-bit parallel port. This port is used to generate signals on 8bit parallel bus. The card also contains 8-bit output register for data part of the bus (D0 - D7) and also 8-bit input register (used for results of read operation and also as a feedback for write operations).
Control register of the software controlled 8-bit bus.
Address on 8-bit bus | Direction | Abbreviation | Description |
---|---|---|---|
0 | WR | LCD_INST | Write instruction into LCD controller |
1 | RD | LCD_STAT | Read state register of LCD controller |
2 | WR | LCD_WDATA | Write data to display memory or character generator |
3 | RD | LCD_RDATA | Read data from LCD display memory |
1 | WR | LED_WR | Write to LED |
3 | WR | KBD_WR | Write to keyboard scan register |
0 | RD | KBD_RD | Read data from keyboard scan register |
Register programmed on PCIe card EVB/Altera DB4CGX15
As you do not have root access to computers in room KN:E-328 you have to enable direct access to memory for read/write. To do this you have to run
devmemrw
PCI Bus address | Direction | Name | Description |
---|---|---|---|
BAR0+0x0000 | RD/WR | RAM | Local memory 32kB RAM in FPGA |
BAR0+0x8000 | RD/WR | timer_0 | Board build-in timer with IRQ |
BAR0+0x8020 | WR | emul_bus_data_out | Data signals - write data to set value on the bus |
BAR0+0x8040 | RD | emul_bus_data_in | Data signals - read actual data set on the bus |
BAR0+0x8060 | WR | emul_bus_addr | Address - address on the bus |
BAR0+0x8080 | WR | emul_bus_ctrl | Control register of the bus |
BAR0+0x80A0 | WR | Led_Pio | Access to build-in LED on the PCIe card |
8-bit output control register with control signals of emulated bus (emul_bus_ctrl)
Bit | Signal name | Pin IO Modul | Pin of FPGA | Description |
---|---|---|---|---|
0 | RD | IO13 | L9 | Read command (active in L) |
1 | WR | IO14 | K9 | Write command (active in L) |
2 | ||||
3 | ||||
4 | ||||
5 | ||||
6 | CS0 | IO15 | N10 | Chip select (active in L) |
7 | PWR | IO18 | L11 | Turn on the tool |
8-bit output register connected to address wires of the simulated bus
Bit | Signal name | Pin IO Modul | Pin of FPGA | Description |
---|---|---|---|---|
0 | A0 | IO11 | K8 | Address bit 0 (LSB) |
1 | A1 | IO12 | N9 | Address bit 1 |
2 | ||||
3 | ||||
4 | ||||
5 | ||||
6 | ||||
7 |
8-bit output register is connected to simulated data bus (emul_bus_data_out). The same mapping is for the input register (emul_bus_data_in).
Bit | Signal | Module IO Pin | FPGA Pin | Description |
---|---|---|---|---|
0 | D0 | IO1 | L4 | Data bus - bit 0 (LSB) |
1 | D1 | IO2 | M4 | Data bus - bit 1 |
2 | D2 | IO3 | N4 | Data bus - bit 2 |
3 | D3 | IO4 | N5 | Data bus - bit 3 |
4 | D4 | IO5 | L5 | Data bus - bit 4 |
5 | D5 | IO6 | N6 | Data bus - bit 5 |
6 | D6 | IO7 | M6 | Data bus - bit 6 |
7 | D7 | IO8 | L7 | Data bus - bit 7 (MSB) |
More control signals (no important for programmers).
IO10 (M9) = not WR and RD = not IO14 and IO13 IO9 (N9) = (WR and RD and CS0) or not (WR or RD) = (IO14 and IO13 and IO15) or not (IO14 or IO13)
Direction of the data flow (bus operation) is controlled by control register signals RD, WR, CS. The direction is set to output (from FPGA to bus) when (not WR and RD - pin IO14
is set to 1
and pin IO13
is set to 0
).
Other signals of the FPGA are not relevant for your work.
IO19 (N12) = 0 IO20 (K10) = 1
LCD Controller is standard Hitachi HD44780.
To initialize LCD
To write a character to the memory of the controller:
To move cursor to the given position (the next character will be written to this place).
More can be found for example in two PDFs available here http://ozirock.webs.com/hitachihd44780lcd.htm
The code below shows basic first steps you can start with. This code mmap
s the PCI device's memory space to program's address space and turns on and off the hardware tool. The code contains some hints and steps you should implement. To compile the code you can use make
command. The make
uses compile and linking instructions written in makefile. A sample Makefile that can be used to comple the code is in the archive below.
make
command, first open a terminal application. Then use cd
command to change directory to one with the makefile. And then use to make
command (no parameters). This command compiles and links only changed files. If you want to comple whole project, you must remove all intermediate files using make clean
.
#define DEV_ENABLE "/sys/bus/pci/devices/0000:03:00.0/enable" #define DEV_ADDRESS 0xfe8f0000 #define CTRL 0x8020 #include <stdio.h> #include <sys/mman.h> #include <stdlib.h> #include <fcntl.h> int pciEnable(int isEnable) { char cen = isEnable!=0 ? '1' : '0'; int enable = open(DEV_ENABLE,O_WRONLY); //TODO: find the path to DEV_ENABLE by searching through the list of PCI devices. if(enable==-1) return 0; // TODO: Handle errors properly write(enable,&cen,1); close(enable); return 1; } void write_bus(uint8_t address, uint8_t data); //TODO write bus cycle uint8_t read_bus(uint8_t address); //TODO read bus cycle int main() { int soubor= open("/dev/mem",O_RDWR | O_SYNC); if(soubor==-1) return 1; // TODO: Handle errors properly // TODO: Replace DEV_ADDRESS constant and memory size (0x10000) by a search through the PCI devices unsigned char * base = mmap(NULL,0x10000,PROT_WRITE | PROT_READ, MAP_SHARED, soubor, DEV_ADDRESS); if(base==MAP_FAILED) return 2; // TODO: Handle errors properly if(pciEnable(1)) { *(base+CTRL)=0xF0; // Turn on the power sleep(1); // wait a second. For shorter delays use usleep (microseconds) or nanosleep (nanoseconds) // TODO: Your semestral work goes here :). *(base+CTRL)=0x00; // Turn off the power } pciEnable(0); return 0; } //TODO: Podprogram pro zapis/cteni bytu na emulovane PCI sbernici //+TODO: cteni klavesnice, //+TODO zapis na LCD //+TODO: program automatu na jizdenky
Following archive contains header files with display and keyboard register addresses on the emulated bus.
Files /proc/bus/pci/
bb/
dd.
f contains data from PCI headers (a copy of a PCI configuration space) from PCI devices found by OS.
PCI Headrer structure is for example described on Wikipedii
Detailed description of PCI/PCIe bus architecture was given in lectures 5. I/O podsystém 1 and 6. I/O podsystém 2. PCI/PCIe hierarchy is described mainly in following presentation: PCI a PCI Express sběrnice a PCIe.
In the first 4 bytes is encoded product and vendor identification - for our FPGA design is ventor ID set to 0x1172 and product ID is 0x1f32.
Physical memory addresses for access are stored in BAR0 register. Lowest bits in register have to be masked (see eg. PCI BAR Bits table on Wikipedia).
To enable (turn on) the PCI device you must write “1” to file /sys/bus/pci/devices/0000:
bb:
dd.
f/enable
Use O_FSYNC for direct access to avoid OS buffers and disk caches.
Physical address represented /dev/mem
is the mapped to address space of the program and can be accessed in the same way as any other memory region. To map the memory use
To avoid Copy on Write mechanism, you have to use MAP_SHARED option.
To access board registers we will user pointer with type (volatile uint32_t *).
First we will try to read and write memory mapped to FPGA, then we will turn on the HW tool and simulate bus cycles.
Program for direct read and write memory mapped data registers from PCI device (registers have to be mapped via /dev/mem
). (It can also copy and fill memory regions).
To use the program, you have to compile the source code using make
. After compiling the program you can use sudo ./rdwrmem
to run the program. Please note the sudo
- you have to be the superuser to run this program. Run sudo ./rdwrmem -h
to display help and usage information.
./rdwrmem -h
Start address for write is specified by parameters -s
. To start experiments with our HW tool we demonstrate a work with emul_bus_ctrl. This register in on address BAR0 + 0x8040
. (BAR0 is the first Base Address Register). When you write a value with highest bit (bit 7) set to 1, the HW tool is switched on.
# Turn on power ./rdwrmem -s <BAR0+0x8080> -F 0xFF
Now more difficult example - access to KBD_WR register and turn off the speaker.
# set up address of KBD_WR (address part of the bus) ./rdwrmem -s <BAR0+0x8060> -F 0x03 # set up data for write (data part of the bus) ./rdwrmem -s <BAR0+0x8020> -F 0x00 # Set control part of bus (activate WR signal) ./rdwrmem -s <BAR0+0x8080> -F 0xFD # Set control part of bus (activate WR signal, add CS signal) ./rdwrmem -s <BAR0+0x8080> -F 0xBD # wait - at least 10 microseconds sleep 1 # deactivate CS0 ./rdwrmem -s <BAR0+0x8080> -F 0xFD # deactivate WR ./rdwrmem -s <BAR0+0x8080> -F 0xFF
mo_kbd3-minimal-sch.pdf - Simplified schematics of keyboard MO_KBD3
mo_kbd3-sch.pdf - Full schematics of MO_KBD3 including possible MCU connector for CAN bus access
con-db4cgx15-sch.pdf - Schematics of interconnection board CON-DB4CGX15
You can work on your semestral work even without access to HW. Virtual HW for APO course was implemented by Rostislav Lisový. The implementation is based on his diploma thesis Education Material and Environment for PCI Driver Development for GNU/Linux.
Detailed information about APOHW project can be found on APOHW virtual hardware implementation for QEMU
Emulation implements read/write to LED diods and write to the display. Keyboard input, LEDs state and display content is made accessible to user by provision of simple telnet server which listens on TCP port 55555. Next command can be used to monitor hardware state
telnet localhost 55555
Warning: Your semestral work have to work on physical HW. Virtual HW is mainly for testing purposes and to verify basic design of your work. APOHW does not implement timing requirements accurately.
Complete virtual system with APOHW implemented can be downloaded here:
qemu-run-apohw-32.tar.gz (32-bit GNU/Linux verze)
qemu-run-apohw-64.tar.gz (64-bit GNU/Linux verze)
It is implemented using QEMU with HW extension and contains Liux kernel, Busybox and some libraries. The executable is compiled for 32-bit Linux host system. If you have Ubuntu (or Debian) you have to install “qemu-system” and its depandencies (or its equivalents for other Linux systems).