Add GPMC interface to FPGA server

master
Timothy Pearson 10 years ago
parent 4123289a7a
commit 4436bddc8c

@ -3,7 +3,7 @@ KDE_CXXFLAGS = $(USE_EXCEPTIONS)
bin_PROGRAMS = ulab_fpgaserver
ulab_fpgaserver_SOURCES = main.cpp fpga_conn.cpp
ulab_fpgaserver_SOURCES = main.cpp fpga_conn.cpp bbb-gpmc-init.cpp
ulab_fpgaserver_METASOURCES = AUTO
ulab_fpgaserver_LDFLAGS = $(all_libraries) $(KDE_RPATH) $(LIB_QT) -lDCOP $(LIB_TDECORE) $(LIB_TDEUI) -ltdefx $(LIB_TDEIO) -ltdetexteditor -ltdekrbsocket -ltqtrla

@ -0,0 +1,181 @@
/*
* Remote Laboratory FPGA Server GPMC Interface (Beaglebone Black)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* (c) 2012-2014 Timothy Pearson
* Raptor Engineering
* http://www.raptorengineeringinc.com
*/
/** BEGIN: Low-Level I/O Implementation **/
// Beaglebone Black GPMC driver
#include <sys/time.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <fcntl.h>
#define MEMORY_SPACE_ADDRESS_BITS 16
#define GPMC_BASE 0x50000000
#define GPMC_REGLEN 0x10000000
#define GPMC_CHIPSELECTCONFIGDISPLACEMENT (0x30 / 4)
#define GPMC_CONFIG (0x50 / 4)
#define GPMC_CONFIG1 (0x60 / 4)
#define GPMC_CONFIG2 (0x64 / 4)
#define GPMC_CONFIG3 (0x68 / 4)
#define GPMC_CONFIG4 (0x6c / 4)
#define GPMC_CONFIG5 (0x70 / 4)
#define GPMC_CONFIG6 (0x74 / 4)
#define GPMC_CONFIG7 (0x78 / 4)
#define MEMORY_SIZE (1 << MEMORY_SPACE_ADDRESS_BITS)
int mem_fd = 0;
int gpmc_mem_fd = 0;
char *gpio_mem, *gpio_map, *gpmc_map;
// I/O access
volatile unsigned int *gpio = NULL;
volatile unsigned char *gpio_char = NULL;
volatile unsigned int *gpmc = NULL;
void gpmc_mapregisters() {
/* open /dev/mem */
if ((gpmc_mem_fd = open("/dev/mem", O_RDWR|O_SYNC) ) < 0) {
printf("[FATAL] can't open /dev/mem\n");
return;
}
/* mmap GPMC */
gpmc_map = (char *)mmap(
0,
GPMC_REGLEN,
PROT_READ|PROT_WRITE,
MAP_SHARED,
gpmc_mem_fd,
GPMC_BASE
);
if (gpmc_map == MAP_FAILED) {
printf("[FATAL] mmap error %d\n", (int)gpmc_map);
return;
}
// Always use volatile pointer!
gpmc = (volatile unsigned *)gpmc_map;
}
void gpmc_unmapregisters() {
munmap((void*) gpmc, GPMC_REGLEN);
if (gpmc_mem_fd != -1) {
close(gpmc_mem_fd);
}
}
void gpmc_setup(void) {
gpmc_mapregisters();
if (gpmc != NULL) {
int chipselect = 0;
int displacement = GPMC_CHIPSELECTCONFIGDISPLACEMENT * chipselect;
// disable before playing with the registers
*(gpmc + displacement + GPMC_CONFIG7) = 0x00000000;
*(gpmc + displacement + GPMC_CONFIG) = 0x00000000; // Unlimited address space
*(gpmc + displacement + GPMC_CONFIG1) = 0x00000000; // No burst, async, 8-bit, non multiplexed
*(gpmc + displacement + GPMC_CONFIG2) = 0x00001000; // Assert CS on fclk0, deassert CS on fclk16
*(gpmc + displacement + GPMC_CONFIG3) = 0x00000400; // Assert ADV on fclk 0, deassert ADV on fclk 4
*(gpmc + displacement + GPMC_CONFIG4) = 0x0c041004; // Assert WE on fclk4, deassert WE on fclk12, assert OE on fclk4, deassert OE on fclk16
*(gpmc + displacement + GPMC_CONFIG5) = 0x000c1010; // Data valid on fclk 12, cycle time 16 fclks
*(gpmc + displacement + GPMC_CONFIG6) = 0x00000000; // No back to back cycle restrictions
*(gpmc + displacement + GPMC_CONFIG7) = 0x00000e50; // CS0: Set base address 0x10000000, 32MB region, and enable CS
gpmc_unmapregisters();
}
}
int setup_gpmc_bbb(void) {
/* open /dev/mem */
if ((mem_fd = open("/dev/mem", O_RDWR|O_SYNC) ) < 0) {
printf("[FATAL] can't open /dev/mem\n");
return -1;
}
/* mmap GPIO */
gpio_map = (char *)mmap(
0,
MEMORY_SIZE,
PROT_READ|PROT_WRITE,
MAP_SHARED,
mem_fd,
0x10000000
);
if (gpio_map == MAP_FAILED) {
printf("[FATAL] mmap error %d\n", (int)gpio_map);
return -1;
}
// Always use volatile pointers!
gpio = (volatile unsigned *)gpio_map;
gpio_char = (volatile unsigned char *)gpio_map;
return 0;
}
int shutdown_gpmc_bbb(void) {
return 0;
}
void write_gpmc(unsigned int register_offset, unsigned char data) {
*(gpio_char + register_offset) = data;
}
unsigned char read_gpmc(unsigned int register_offset) {
return *(gpio_char + register_offset);
}
void memcpy_from_gpmc(char* destination, unsigned int register_offset, unsigned int length) {
unsigned int i;
for (i=0; i<length; i++) {
*destination = *(gpio_char + register_offset);
destination++;
register_offset++;
}
}
void memcpy_to_gpmc(char* source, unsigned int register_offset, unsigned int length) {
unsigned int i;
for (i=0; i<length; i++) {
*(gpio_char + register_offset) = *source;
source++;
register_offset++;
}
}
/** END: Low-Level I/O Implementation **/

@ -0,0 +1,28 @@
/*
* Remote Laboratory FPGA Server GPMC Interface (Beaglebone Black)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* (c) 2012-2014 Timothy Pearson
* Raptor Engineering
* http://www.raptorengineeringinc.com
*/
int setup_gpmc_bbb();
void write_gpmc(unsigned int register_offset, unsigned char data);
unsigned char read_gpmc(unsigned int register_offset);
void memcpy_from_gpmc(char* destination, unsigned int register_offset, unsigned int length);
void memcpy_to_gpmc(char* source, unsigned int register_offset, unsigned int length);

@ -35,6 +35,7 @@
#include <sys/signal.h>
#include <sys/types.h>
#include <sys/ioctl.h>
#include <math.h>
#include <tqtimer.h>
@ -42,6 +43,8 @@
#include "fpga_conn.h"
#include "bbb-gpmc-init.h"
#define FLUSH_IN 0
#define FLUSH_OUT 1
#define FLUSH_BOTH 2
@ -137,9 +140,29 @@ void FPGASocket::finishKerberosHandshake() {
close();
return;
}
if (setupSerial() != 0) {
m_config->setGroup("FPGA");
m_interfaceType = m_config->readEntry("interface", "serial");
if (m_interfaceType == "serial") {
if (setupSerial() != 0) {
if (enableDebug) {
printf("[DEBUG] Connection from %s closed due to serial port initialization failure\n\r", m_remoteHost.ascii()); fflush(stdout);
}
close();
return;
}
}
else if (m_interfaceType == "gpmc") {
if (setupGPMC() != 0) {
if (enableDebug) {
printf("[DEBUG] Connection from %s closed due to GPMC initialization failure\n\r", m_remoteHost.ascii()); fflush(stdout);
}
close();
return;
}
}
else {
if (enableDebug) {
printf("[DEBUG] Connection from %s closed due to serial port initialization failure\n\r", m_remoteHost.ascii()); fflush(stdout);
printf("[DEBUG] Connection from %s closed due to incorrect interface type specification in configuration file\n\r", m_remoteHost.ascii()); fflush(stdout);
}
close();
return;
@ -212,6 +235,40 @@ int FPGASocket::setupSerial() {
return 0;
}
int FPGASocket::setupGPMC() {
int i;
int ret;
m_stateTXRequested = false;
m_stateImageRXRequested = false;
m_stateImageTXRequested = false;
ret = setup_gpmc_bbb();
if (ret == 0) {
// Verify attached uLab hardware model and version
unsigned char model = read_gpmc(0x00);
unsigned char version = read_gpmc(0x01);
if ((model != 0x42) || (version < 1)) {
printf("A compatible uLab hardware debug interface was not detected! Please verify your configuration.\n");
return -1;
}
printf("[DEBUG] Detected a compatible uLab hardware debug interface (model number 0x%02x, firmware version 0x%02x)\n", model, version);
// Clear out DSP and LCD RAM
unsigned char dsp_ram_bits = read_gpmc(0x0b);
unsigned int dsp_ram_offset = (1 << dsp_ram_bits);
unsigned int dsp_ram_size = (1 << dsp_ram_bits);
for (i=0; i<dsp_ram_size; i++) {
write_gpmc(dsp_ram_offset + i, 0x00);
}
for (i=0; i<32; i++) {
write_gpmc(0x20 + i, 0x00);
}
}
return 0;
}
void FPGASocket::commandLoop() {
int cc;
int ret;
@ -222,39 +279,135 @@ void FPGASocket::commandLoop() {
try {
transferred_data = false;
if (state() == TQSocket::Connected) {
cc = read(m_fd_tty, buffer, 1024);
if (cc > 0) {
writeBlock(buffer, cc);
flush();
transferred_data = true;
if (enableDebug) {
printf("[DEBUG] Got %d bytes from the serial port\n\r", cc); fflush(stdout);
}
}
if (canReadData()) {
cc = readBlock(buffer, 1024);
if (m_interfaceType == "serial") {
cc = read(m_fd_tty, buffer, 1024);
if (cc > 0) {
ret = write(m_fd_tty, buffer, cc);
// HACK
// This works around a buffer overflow on FTDI serial devices
// It may not be sufficient for baudrates less than 115200!
if (cc > 128) {
usleep(100000);
writeBlock(buffer, cc);
flush();
transferred_data = true;
if (enableDebug) {
printf("[DEBUG] Got %d bytes from the serial port\n\r", cc); fflush(stdout);
}
while ((ret < 0) && (errno == EAGAIN)) {
usleep(1000);
}
if (canReadData()) {
cc = readBlock(buffer, 1024);
if (cc > 0) {
ret = write(m_fd_tty, buffer, cc);
// HACK
// This works around a buffer overflow on FTDI serial devices
// It may not be sufficient for baudrates less than 115200!
if (cc > 128) {
usleep(100000);
}
while ((ret < 0) && (errno == EAGAIN)) {
usleep(1000);
ret = write(m_fd_tty, buffer, cc);
}
if (ret < 0) {
// ERROR
printf("[ERROR] Failed to transmit data to serial port (%s, code %d)! Continuing, but data was likely lost\n\r", strerror(errno), errno); fflush(stdout);
}
ioctl(m_fd_tty, TCFLSH, FLUSH_OUT);
transferred_data = true;
if (enableDebug) {
printf("[DEBUG] Got %d bytes from the network interface\n\r", cc); fflush(stdout);
}
}
if (ret < 0) {
// ERROR
printf("[ERROR] Failed to transmit data to serial port (%s, code %d)! Continuing, but data was likely lost\n\r", strerror(errno), errno); fflush(stdout);
}
}
else if (m_interfaceType == "gpmc") {
if (m_stateImageTXRequested) {
if (read_gpmc(0x0a) & 0x02) {
m_stateImageTXRequested = false;
// Transmit image back to client
unsigned char dsp_ram_bits = read_gpmc(0x0b);
unsigned int dsp_ram_size = (1 << dsp_ram_bits);
unsigned int dsp_ram_offset = (1 << dsp_ram_bits);
TQByteArray dataToSend(dsp_ram_size);
memcpy_from_gpmc(dataToSend.data(), dsp_ram_offset, dsp_ram_size);
int offset = 0;
while (offset <= dsp_ram_size) {
writeBlock(dataToSend.data()+offset, 1024);
writeBufferedData();
offset = offset + 1024;
}
}
ioctl(m_fd_tty, TCFLSH, FLUSH_OUT);
transferred_data = true;
if (enableDebug) {
printf("[DEBUG] Got %d bytes from the network interface\n\r", cc); fflush(stdout);
}
else if (m_stateTXRequested) {
m_stateTXRequested = false;
char data[42];
// Read state data from memory map and assemble a reply
memcpy_from_gpmc(data+0, 0x20, 0x1f); // LCD display
data[32] = 1; // Input mode (locked to Remote)
data[33] = read_gpmc(0x0b); // Number of address bits of DSP RAM
data[34] = read_gpmc(0x02); // 4-bit LEDs
data[35] = read_gpmc(0x03); // 8-bit LEDs
data[36] = read_gpmc(0x04); // 16-bit LEDs (upper byte)
data[37] = read_gpmc(0x05); // 16-bit LEDs (lower byte)
memcpy_from_gpmc(data+38, 0x06, 0x04); // 7-segment LED display
writeBlock(data, 42);
writeBufferedData();
}
if (canReadData()) {
int read_offset = 0;
cc = readBlock(buffer, 1024);
if (cc > 0) {
if (m_stateImageRXRequested) {
unsigned char dsp_ram_bits = read_gpmc(0x0b);
unsigned int dsp_ram_offset = (1 << dsp_ram_bits);
unsigned int dsp_ram_size = (1 << dsp_ram_bits);
memcpy_to_gpmc(buffer, (dsp_ram_offset + m_stateImageRXCounter), cc);
m_stateImageRXCounter = m_stateImageRXCounter + cc;
if (m_stateImageRXCounter >= dsp_ram_size) {
m_stateImageRXRequested = false;
m_stateImageTXRequested = true;
}
}
else {
// Parse and write state data to the memory map
while (read_offset < cc) {
if (buffer[read_offset+0] == 'M') {
// Receive image data and store in FPGA memory
m_stateImageRXRequested = true;
m_stateImageTXRequested = false;
m_stateImageRXCounter = 0;
read_offset = read_offset + 2;
}
else if (buffer[read_offset+0] == 'L') {
m_stateTXRequested = true;
read_offset = read_offset + 2;
}
else if (buffer[read_offset+0] == 'I') {
write_gpmc(0x02, buffer[read_offset+2]);
read_offset = read_offset + 4;
}
else if (buffer[read_offset+0] == 'B') {
write_gpmc(0x03, buffer[read_offset+2]);
read_offset = read_offset + 4;
}
else if (buffer[read_offset+0] == 'C') {
write_gpmc(0x04, buffer[read_offset+2]);
write_gpmc(0x05, buffer[read_offset+4]);
read_offset = read_offset + 6;
}
}
if (m_stateImageTXRequested) {
m_stateImageTXRequested = false;
}
}
transferred_data = true;
if (enableDebug) {
printf("[DEBUG] Got %d bytes from the network interface\n\r", cc); fflush(stdout);
}
}
}
}

@ -55,6 +55,7 @@ class FPGASocket : public TDEKerberosServerSocket
void finishKerberosHandshake();
void connectionClosedHandler();
int setupSerial();
int setupGPMC();
void commandLoop();
private:
@ -63,6 +64,11 @@ class FPGASocket : public TDEKerberosServerSocket
int m_pollInterval;
bool enableDebug;
TQString m_remoteHost;
TQString m_interfaceType;
bool m_stateTXRequested;
bool m_stateImageRXRequested;
int m_stateImageRXCounter;
bool m_stateImageTXRequested;
int m_fd_tty;
TQTimer* m_kerberosInitTimer;

Loading…
Cancel
Save