diff options
author | Timothy Pearson <kb9vqf@pearsoncomputing.net> | 2014-02-27 01:00:35 -0600 |
---|---|---|
committer | Timothy Pearson <kb9vqf@pearsoncomputing.net> | 2014-02-27 01:00:35 -0600 |
commit | 6ed57d34cab70cfcada21d3b77014f2e834a0cf9 (patch) | |
tree | 5ea8f7750945b29557ff34ae10147bc61f21fbf3 | |
parent | 1fbfe130665dc4bce56869ed9158531137406129 (diff) | |
download | ulab-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.c | 26 | ||||
-rw-r--r-- | servers/fpga_server_lin/src/bbb-gpmc-init.cpp | 42 | ||||
-rw-r--r-- | servers/fpga_server_lin/src/bbb-gpmc-init.h | 7 | ||||
-rw-r--r-- | servers/fpga_server_lin/src/fpga_conn.cpp | 8 | ||||
-rw-r--r-- | servers/logic_analyzer_server_lin/src/logic_analyzer_server.cpp | 140 |
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("<", "<"); + name.replace(">", ">"); + + 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"); |