summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTimothy Pearson <kb9vqf@pearsoncomputing.net>2014-02-27 01:00:35 -0600
committerTimothy Pearson <kb9vqf@pearsoncomputing.net>2014-02-27 01:00:35 -0600
commit6ed57d34cab70cfcada21d3b77014f2e834a0cf9 (patch)
tree5ea8f7750945b29557ff34ae10147bc61f21fbf3
parent1fbfe130665dc4bce56869ed9158531137406129 (diff)
downloadulab-6ed57d34cab70cfcada21d3b77014f2e834a0cf9.tar.gz
ulab-6ed57d34cab70cfcada21d3b77014f2e834a0cf9.zip
First pass of logic analyzer functionality (GPMC interface and server)
-rw-r--r--fpga/interface/beaglebone_black/gpmc/test/bbb-gpmc-test.c26
-rw-r--r--servers/fpga_server_lin/src/bbb-gpmc-init.cpp42
-rw-r--r--servers/fpga_server_lin/src/bbb-gpmc-init.h7
-rw-r--r--servers/fpga_server_lin/src/fpga_conn.cpp8
-rw-r--r--servers/logic_analyzer_server_lin/src/logic_analyzer_server.cpp140
5 files changed, 200 insertions, 23 deletions
diff --git a/fpga/interface/beaglebone_black/gpmc/test/bbb-gpmc-test.c b/fpga/interface/beaglebone_black/gpmc/test/bbb-gpmc-test.c
index ab4eb17..d352348 100644
--- a/fpga/interface/beaglebone_black/gpmc/test/bbb-gpmc-test.c
+++ b/fpga/interface/beaglebone_black/gpmc/test/bbb-gpmc-test.c
@@ -113,6 +113,7 @@ static void gpmc_setup(void)
*(gpmc + displacement + GPMC_CONFIG) = 0x00000000; // Unlimited address space
*(gpmc + displacement + GPMC_CONFIG1) = 0x00000000; // No burst, async, 8-bit, non multiplexed
+// *(gpmc + displacement + GPMC_CONFIG1) = 0x00000010; // No burst, async, 8-bit, non multiplexed, x2 slowed cycle timing
// // 200MHz compatible SRAM device
// *(gpmc + displacement + GPMC_CONFIG2) = 0x00000800; // Assert CS on fclk 0, deassert CS on fclk 8
@@ -139,6 +140,27 @@ static void gpmc_setup(void)
}
}
+void gpmc_dump_registers(void)
+{
+ gpmc_mapregisters();
+
+ if (gpmc != NULL) {
+ int chipselect = 0;
+ int displacement = GPMC_CHIPSELECTCONFIGDISPLACEMENT * chipselect;
+
+ printf("GPMC_CONFIG0: %08x\n", *(gpmc + displacement + GPMC_CONFIG));
+ printf("GPMC_CONFIG1: %08x\n", *(gpmc + displacement + GPMC_CONFIG1));
+ printf("GPMC_CONFIG2: %08x\n", *(gpmc + displacement + GPMC_CONFIG2));
+ printf("GPMC_CONFIG3: %08x\n", *(gpmc + displacement + GPMC_CONFIG3));
+ printf("GPMC_CONFIG4: %08x\n", *(gpmc + displacement + GPMC_CONFIG4));
+ printf("GPMC_CONFIG5: %08x\n", *(gpmc + displacement + GPMC_CONFIG5));
+ printf("GPMC_CONFIG6: %08x\n", *(gpmc + displacement + GPMC_CONFIG6));
+ printf("GPMC_CONFIG7: %08x\n", *(gpmc + displacement + GPMC_CONFIG7));
+ }
+
+ gpmc_unmapregisters();
+}
+
static void io_setup(void)
{
printf("sizeof int:\t%d\n", sizeof(int));
@@ -343,12 +365,14 @@ static void io_setup(void)
// printf("0x%02x\t0x%02x\t0x%02x\t0x%02x\t0x%02x\t0x%02x\t0x%02x\t0x%02x\n\r", *(gpio_char + 0), *(gpio_char + 0), *(gpio_char + 0), *(gpio_char + 0), *(gpio_char + 0), *(gpio_char + 0), *(gpio_char + 0), *(gpio_char + 0));
//
+ gpmc_dump_registers();
+
while (1) {
// printf("0x%02x\t0x%02x\t0x%02x\t0x%02x\t0x%02x\t0x%02x\t0x%02x\t0x%02x\r", *(gpio_char + 0), *(gpio_char + 1), *(gpio_char + 2), *(gpio_char + 3), *(gpio_char + 4), *(gpio_char + 5), *(gpio_char + 6), *(gpio_char + 7));
// printf("0x%02x\t0x%02x\t0x%02x\t0x%02x\t0x%02x\t0x%02x\t0x%02x\t0x%02x\r", *(gpio_char + 0), *(gpio_char + 1), *(gpio_char + 2), *(gpio_char + 3), *(gpio_char + 0x1000), *(gpio_char + 0x1001), *(gpio_char + 0x1002), *(gpio_char + 0x1003));
// printf("0x%02x\t0x%02x\t0x%02x\t0x%02x\t0x%02x\t0x%02x\t0x%02x\t0x%02x\r", *(gpio_char + 0), *(gpio_char + 1), *(gpio_char + 2), *(gpio_char + 3), *(gpio_char + 0x4000), *(gpio_char + 0x4001), *(gpio_char + 0x4002), *(gpio_char + 0x4003));
printf("0x%02x\t0x%02x\t0x%02x\t0x%02x\t0x%02x\t0x%02x\t0x%02x\t0x%02x\r", *(gpio_char + 0), *(gpio_char + 1), *(gpio_char + 2), *(gpio_char + 3), *(gpio_char + 0x0a), *(gpio_char + 0x0b), *(gpio_char + 0x0c), *(gpio_char + 0x0d));
-// printf("0x%02x\t0x%02x\t0x%02x\t0x%02x\t0x%02x\t0x%02x\t0x%02x\t0x%02x\r", *(gpio_char + 0x4000), *(gpio_char + 0x4001), *(gpio_char + 0x4002), *(gpio_char + 0x4003), *(gpio_char + 0x4000), *(gpio_char + 0x4001), *(gpio_char + 0x4002), *(gpio_char + 0x4003));
+// printf("0x%02x\t0x%02x\t0x%02x\t0x%02x\t0x%02x\t0x%02x\t0x%02x\t0x%02x\r", *(gpio_char + 0x4000), *(gpio_char + 0x4001), *(gpio_char + 0x4002), *(gpio_char + 0x4003), *(gpio_char + 0x4004), *(gpio_char + 0x4005), *(gpio_char + 0x4006), *(gpio_char + 0x4007));
usleep(10);
}
}
diff --git a/servers/fpga_server_lin/src/bbb-gpmc-init.cpp b/servers/fpga_server_lin/src/bbb-gpmc-init.cpp
index ac6b1b6..64e8014 100644
--- a/servers/fpga_server_lin/src/bbb-gpmc-init.cpp
+++ b/servers/fpga_server_lin/src/bbb-gpmc-init.cpp
@@ -28,6 +28,7 @@
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
+#include <stdint.h>
#include <stdio.h>
#include <errno.h>
@@ -61,7 +62,6 @@ char *gpio_mem, *gpio_map, *gpmc_map;
// I/O access
volatile unsigned int *gpio = NULL;
volatile unsigned char *gpio_char = NULL;
-volatile unsigned char *gpio_llong = NULL;
volatile unsigned int *gpmc = NULL;
void gpmc_mapregisters() {
@@ -171,12 +171,44 @@ unsigned char read_gpmc(unsigned int register_offset) {
return *(gpio_char + register_offset);
}
-void write_gpmc_llong(unsigned int register_offset, unsigned long long data) {
- *(gpio_char + register_offset) = data;
+void write_gpmc_uint16_t(unsigned int register_offset, uint16_t data) {
+ register_offset = register_offset * 2;
+ *(gpio_char + register_offset + 0) = ((data & 0xff00) >> 8);
+ *(gpio_char + register_offset + 1) = ((data & 0x00ff) >> 0);
}
-unsigned long long read_gpmc_llong(unsigned int register_offset) {
- return *(gpio_char + register_offset);
+uint16_t read_gpmc_uint16_t(unsigned int register_offset) {
+ uint16_t result = 0;
+ register_offset = register_offset * 2;
+ result = result | ((uint16_t)(*(gpio_char + register_offset + 0)) << 8);
+ result = result | ((uint16_t)(*(gpio_char + register_offset + 1)) << 0);
+ return result;
+}
+
+void write_gpmc_uint64_t(unsigned int register_offset, uint64_t data) {
+ register_offset = register_offset * 8;
+ *(gpio_char + register_offset + 0) = ((data & 0xff00000000000000) >> 56);
+ *(gpio_char + register_offset + 1) = ((data & 0x00ff000000000000) >> 48);
+ *(gpio_char + register_offset + 2) = ((data & 0x0000ff0000000000) >> 40);
+ *(gpio_char + register_offset + 3) = ((data & 0x000000ff00000000) >> 32);
+ *(gpio_char + register_offset + 4) = ((data & 0x00000000ff000000) >> 24);
+ *(gpio_char + register_offset + 5) = ((data & 0x0000000000ff0000) >> 16);
+ *(gpio_char + register_offset + 6) = ((data & 0x000000000000ff00) >> 8);
+ *(gpio_char + register_offset + 7) = ((data & 0x00000000000000ff) >> 0);
+}
+
+uint64_t read_gpmc_uint64_t(unsigned int register_offset) {
+ uint64_t result = 0;
+ register_offset = register_offset * 8;
+ result = result | ((uint64_t)(*(gpio_char + register_offset + 0)) << 56);
+ result = result | ((uint64_t)(*(gpio_char + register_offset + 1)) << 48);
+ result = result | ((uint64_t)(*(gpio_char + register_offset + 2)) << 40);
+ result = result | ((uint64_t)(*(gpio_char + register_offset + 3)) << 32);
+ result = result | ((uint64_t)(*(gpio_char + register_offset + 4)) << 24);
+ result = result | ((uint64_t)(*(gpio_char + register_offset + 5)) << 16);
+ result = result | ((uint64_t)(*(gpio_char + register_offset + 6)) << 8);
+ result = result | ((uint64_t)(*(gpio_char + register_offset + 7)) << 0);
+ return result;
}
void memcpy_from_gpmc(char* destination, unsigned int register_offset, unsigned int length) {
diff --git a/servers/fpga_server_lin/src/bbb-gpmc-init.h b/servers/fpga_server_lin/src/bbb-gpmc-init.h
index 7b2bc46..993189f 100644
--- a/servers/fpga_server_lin/src/bbb-gpmc-init.h
+++ b/servers/fpga_server_lin/src/bbb-gpmc-init.h
@@ -25,8 +25,11 @@ int setup_gpmc_bbb();
void write_gpmc(unsigned int register_offset, unsigned char data);
unsigned char read_gpmc(unsigned int register_offset);
-void write_gpmc_llong(unsigned int register_offset, unsigned long long data);
-unsigned long long read_gpmc_llong(unsigned int register_offset);
+void write_gpmc_uint16_t(unsigned int register_offset, uint16_t data);
+uint16_t read_gpmc_uint16_t(unsigned int register_offset);
+
+void write_gpmc_uint64_t(unsigned int register_offset, uint64_t data);
+uint64_t read_gpmc_uint64_t(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); \ No newline at end of file
diff --git a/servers/fpga_server_lin/src/fpga_conn.cpp b/servers/fpga_server_lin/src/fpga_conn.cpp
index 0e1aa17..6ab85a2 100644
--- a/servers/fpga_server_lin/src/fpga_conn.cpp
+++ b/servers/fpga_server_lin/src/fpga_conn.cpp
@@ -235,7 +235,7 @@ int FPGASocket::setupSerial() {
newtio.c_cc[VTIME] = 0; // Inter-character timer unused
newtio.c_cc[VMIN] = 0; // Blocking read unused
-
+
tcflush(m_fd_tty, TCIFLUSH);
tcsetattr(m_fd_tty, TCSANOW, &newtio);
@@ -305,14 +305,14 @@ void FPGASocket::commandLoop() {
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);
@@ -354,7 +354,7 @@ void FPGASocket::commandLoop() {
char data[42];
// Read state data from memory map and assemble a reply
- memcpy_from_gpmc(data+0, 0x20, 0x1f); // LCD display
+ memcpy_from_gpmc(data+0, 0x20, 0x20); // 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
diff --git a/servers/logic_analyzer_server_lin/src/logic_analyzer_server.cpp b/servers/logic_analyzer_server_lin/src/logic_analyzer_server.cpp
index a0f764c..222d685 100644
--- a/servers/logic_analyzer_server_lin/src/logic_analyzer_server.cpp
+++ b/servers/logic_analyzer_server_lin/src/logic_analyzer_server.cpp
@@ -60,6 +60,8 @@ struct exit_exception {
exit_exception(int c):c(c) { }
};
+void gpmc_clear_channel_traces();
+
/*
The LogicAnalyzerSocket class provides a socket that is connected with a client.
For every client that connects to the server, the server creates a new
@@ -166,7 +168,6 @@ void LogicAnalyzerSocket::finishKerberosHandshake() {
}
int LogicAnalyzerSocket::setupGPMC() {
- int i;
int ret;
ret = setup_gpmc_bbb();
@@ -175,10 +176,11 @@ int LogicAnalyzerSocket::setupGPMC() {
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");
+ 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);
+ printf("[DEBUG] Detected a compatible uLab hardware debug interface (model number 0x%02x, firmware version 0x%02x)\n", model, version);
+ gpmc_clear_channel_traces();
}
return 0;
@@ -192,16 +194,65 @@ int gpmc_sample_count() {
return 2048;
}
+double gpmc_timestep() {
+ return ((read_gpmc_uint16_t(0x0e/2))*1e-9);
+}
+
+int gpmc_get_running() {
+ return read_gpmc(0x0d) & 0x1;
+}
+
+void gpmc_set_running(bool running) {
+ if (running) {
+ write_gpmc(0x0d, read_gpmc(0x0d) | 0x1);
+ }
+ else {
+ write_gpmc(0x0d, read_gpmc(0x0d) & ~0x1);
+ }
+}
+
+int gpmc_get_channel_name(TQString &name, unsigned int traceNumber) {
+ int offset;
+ char rawName[32];
+ memcpy_from_gpmc(rawName, 0x800 + (traceNumber * 32), 32);
+ for (offset=0; offset<32; offset++) {
+ if (rawName[offset] != 0) {
+ break;
+ }
+ }
+
+ name = TQString(rawName + offset);
+ name.replace("<", "&lt;");
+ name.replace(">", "&gt;");
+
+ return 0;
+}
+
+void gpmc_clear_channel_traces() {
+ unsigned int i;
+ int traceLength;
+
+ traceLength = gpmc_sample_count();
+ for (i=0; i<traceLength; i++) {
+ write_gpmc_uint64_t(0x800 + i, 0x0);
+ }
+}
+
int gpmc_get_channel_traces(TQDoubleArray& traceData, TQDoubleArray& positionData, unsigned int traceNumber) {
unsigned int i;
int traceLength;
+ double timestep;
+ double position;
traceLength = gpmc_sample_count();
+ timestep = gpmc_timestep();
traceData.resize(traceLength);
positionData.resize(traceLength);
+ position = 0;
for (i=0; i<traceLength; i++) {
- traceData[i] = ((read_gpmc_llong(0x800 + i) & (1 << traceNumber)) >> traceNumber);
- positionData[i] = i;
+ traceData[i] = ((read_gpmc_uint64_t(0x800 + i) & ((uint64_t)1 << traceNumber)) >> traceNumber);
+ positionData[i] = position;
+ position = position + timestep;
}
return traceLength;
@@ -221,7 +272,16 @@ void LogicAnalyzerSocket::commandLoop() {
ds >> instrumentCommand;
if (instrumentCommand != "") {
- if ((instrumentCommand == "GETLOGICTRACES")) { // Want all channel traces
+ if ((instrumentCommand == "LOGICANALYZER")) { // requesting logic analyzer access
+ ds << TQString("ACK");
+ writeEndOfFrame();
+ }
+ else if ((instrumentCommand == "RESET")) { // requesting reset
+ // Nothing to reset...
+ ds << TQString("ACK");
+ writeEndOfFrame();
+ }
+ else if ((instrumentCommand == "GETLOGICTRACES")) { // Want all channel traces
ds << TQString("ACK");
int i;
int channels = gpmc_channel_count();
@@ -234,11 +294,12 @@ void LogicAnalyzerSocket::commandLoop() {
}
writeEndOfFrame();
}
- else if (instrumentCommand == "GETTRACESAMPLECOUNT") { // Want to get number of samples in a trace
- TQ_INT32 samples = gpmc_sample_count();
- if (samples > 0) {
+ else if (instrumentCommand == "GETHORIZONTALDIVCOUNT") { // Want the number of horizontal divisions available
+ // One horizontal division per sample
+ TQ_INT16 divisions = gpmc_sample_count();
+ if (divisions >= 0) {
ds << TQString("ACK");
- ds << samples;
+ ds << divisions;
writeEndOfFrame();
}
else {
@@ -246,7 +307,17 @@ void LogicAnalyzerSocket::commandLoop() {
writeEndOfFrame();
}
}
- else if (instrumentCommand == "GETNUMBEROFCHANNELS") { // Want the number of channels available
+ else if (instrumentCommand == "GETTRACESAMPLECOUNT") { // Want to get number of samples in a trace
+ int i;
+ int channels = gpmc_channel_count();
+ TQ_INT32 samples = gpmc_sample_count();
+ ds << TQString("ACK");
+ for (i=0; i<channels; i++) {
+ ds << samples;
+ }
+ writeEndOfFrame();
+ }
+ else if (instrumentCommand == "GETNUMBEROFCHANNELS") { // Want the number of channels available
TQ_INT32 channels = gpmc_channel_count();
if (channels > 0) {
ds << TQString("ACK");
@@ -258,6 +329,53 @@ void LogicAnalyzerSocket::commandLoop() {
writeEndOfFrame();
}
}
+ else if (instrumentCommand == "GETCHANNELNAME") { // Want to get channel name
+ TQString name;
+ int i;
+ int channels = gpmc_channel_count();
+ ds << TQString("ACK");
+ for (i=0; i<channels; i++) {
+ gpmc_get_channel_name(name, i);
+ ds << name;
+ }
+ writeEndOfFrame();
+ }
+ else if (instrumentCommand == "GETCHANNELACTIVE") { // Want to get channel activity
+ TQ_INT16 state;
+ int i;
+ int channels = gpmc_channel_count();
+ ds << TQString("ACK");
+ for (i=0; i<channels; i++) {
+ // All channels are always active
+ state = 1;
+ ds << state;
+ }
+ writeEndOfFrame();
+ }
+ else if (instrumentCommand == "GETSECONDSSDIV") { // Want to get seconds per division
+ double secondsdiv;
+ int i;
+ int channels = gpmc_channel_count();
+ ds << TQString("ACK");
+ for (i=0; i<channels; i++) {
+ secondsdiv = gpmc_timestep();
+ ds << secondsdiv;
+ }
+ writeEndOfFrame();
+ }
+ else if (instrumentCommand == "GETRUNNING") { // Want to get run status
+ TQ_INT16 running = gpmc_get_running();
+ ds << TQString("ACK");
+ ds << running;
+ writeEndOfFrame();
+ }
+ else if (instrumentCommand == "SETRUNNING") { // Want to change run status
+ TQ_INT16 value;
+ ds >> value;
+ gpmc_set_running(value);
+ ds << TQString("ACK");
+ writeEndOfFrame();
+ }
else {
printf("[WARNING] Received unknown command %s from host %s\n\r", instrumentCommand.ascii(), m_remoteHost.ascii()); fflush(stdout);
ds << TQString("NCK");