From ddb7c1fc29b3805280a42841f2a9ba34db32d76a Mon Sep 17 00:00:00 2001 From: Marc Majoral Date: Tue, 14 Aug 2018 14:04:00 +0200 Subject: [PATCH] added control of the FPGA PL counter interrupt (using a level interrupt). --- .../libs/gnss_sdr_fpga_sample_counter.cc | 140 +++++++++++++++++- .../libs/gnss_sdr_fpga_sample_counter.h | 12 +- 2 files changed, 147 insertions(+), 5 deletions(-) diff --git a/src/algorithms/libs/gnss_sdr_fpga_sample_counter.cc b/src/algorithms/libs/gnss_sdr_fpga_sample_counter.cc index 234367318..727de7521 100644 --- a/src/algorithms/libs/gnss_sdr_fpga_sample_counter.cc +++ b/src/algorithms/libs/gnss_sdr_fpga_sample_counter.cc @@ -35,6 +35,14 @@ #include #include #include +#include +#include // libraries used by the GIPO +#include // libraries used by the GIPO + +#include + +#define PAGE_SIZE 0x10000 // default page size for the multicorrelator memory map +#define TEST_REG_SANITY_CHECK 0x55AA // value to check the presence of the test register (to detect the hw) gnss_sdr_fpga_sample_counter::gnss_sdr_fpga_sample_counter(double _fs, int32_t _interval_ms) : gr::block("fpga_fpga_sample_counter", gr::io_signature::make(0, 0, 0), @@ -44,11 +52,15 @@ gnss_sdr_fpga_sample_counter::gnss_sdr_fpga_sample_counter(double _fs, int32_t _ set_max_noutput_items(1); interval_ms = _interval_ms; fs = _fs; + //printf("CREATOR fs = %f\n", fs); + //printf("CREATOR interval_ms = %" PRIu32 "\n", interval_ms); samples_per_output = std::round(fs * static_cast(interval_ms) / 1e3); + //printf("CREATOR samples_per_output = %" PRIu32 "\n", samples_per_output); //todo: Load here the hardware counter register with this amount of samples. It should produce an //interrupt every samples_per_output count. //The hardware timer must keep always interrupting the PS. It must not wait for the interrupt to //be served. + open_device(); sample_counter = 0ULL; current_T_rx_ms = 0; @@ -75,7 +87,11 @@ gnss_sdr_fpga_sample_counter_sptr gnss_sdr_make_fpga_sample_counter(double _fs, bool gnss_sdr_fpga_sample_counter::start() { //todo: place here the RE-INITIALIZATION routines. This function will be called by GNURadio at every start of the flowgraph. - // return true if everything is ok. + + // configure the number of samples per output in the FPGA and enable the interrupts + configure_samples_per_output(samples_per_output); + + // return true if everything is ok. return true; } @@ -85,6 +101,8 @@ bool gnss_sdr_fpga_sample_counter::stop() { //todo: place here the routines to stop the associated hardware (if needed).This function will be called by GNURadio at every stop of the flowgraph. // return true if everything is ok. + close_device(); + return true; } @@ -101,6 +119,15 @@ int gnss_sdr_fpga_sample_counter::general_work(int noutput_items __attribute__(( // Possible problem: what happen if the PS is overloaded and gnuradio does not call this function // with the sufficient rate to catch all the interrupts in the counter. To be evaluated later. + uint32_t counter = wait_for_interrupt_and_read_counter(); + uint64_t samples_passed = 2*static_cast(samples_per_output) - static_cast(counter); // ellapsed samples + //printf("============================================ interrupter : samples_passed = %" PRIu64 "\n", samples_passed); + // Note: at this moment the sample counter is implemented as a sample counter that decreases to zero and then it is automatically + // reloaded again and keeps counter. It is done in this way to minimize the logic in the FPGA and maximize the FPGA clock performance + // (it takes less resources and latency in the FPGA to compare a number against a fixed value like zero than to compare it to a programmable + // variable number). + + sample_counter = sample_counter + samples_passed; //samples_per_output; Gnss_Synchro *out = reinterpret_cast(output_items[0]); out[0] = Gnss_Synchro(); out[0].Flag_valid_symbol_output = false; @@ -109,7 +136,11 @@ int gnss_sdr_fpga_sample_counter::general_work(int noutput_items __attribute__(( out[0].fs = fs; if ((current_T_rx_ms % report_interval_ms) == 0) { - current_s++; + //printf("time to print sample_counter = %" PRIu64 "\n", sample_counter); + //printf("time to print current Tx ms : %" PRIu64 "\n", current_T_rx_ms); + //printf("time to print report_interval_ms : %" PRIu32 "\n", report_interval_ms); + //printf("time to print %f\n", (current_T_rx_ms % report_interval_ms)); + current_s++; if ((current_s % 60) == 0) { current_s = 0; @@ -166,6 +197,109 @@ int gnss_sdr_fpga_sample_counter::general_work(int noutput_items __attribute__(( } } out[0].Tracking_sample_counter = sample_counter; - current_T_rx_ms = (sample_counter * 1000) / samples_per_output; + //current_T_rx_ms = (sample_counter * 1000) / samples_per_output; + current_T_rx_ms = interval_ms*(sample_counter) / samples_per_output; return 1; } + +uint32_t gnss_sdr_fpga_sample_counter::test_register(uint32_t writeval) +{ + uint32_t readval; + // write value to test register + map_base[3] = writeval; + // read value from test register + readval = map_base[3]; + // return read value + return readval; +} + +void gnss_sdr_fpga_sample_counter::configure_samples_per_output(uint32_t interval) +{ + // note : the counter is a 48-bit value in the HW. + //printf("============================================ total counter - interrupted interval : %" PRIu32 "\n", interval); + //uint64_t temp_interval; + //temp_interval = (interval & static_cast(0xFFFFFFFF)); + //printf("LSW counter - interrupted interval : %" PRIu32 "\n", static_cast(temp_interval)); + //map_base[0] = static_cast(temp_interval); + map_base[0] = interval - 1; + //temp_interval = (interval >> 32) & static_cast(0xFFFFFFFF); + //printf("MSbits counter - interrupted interval : %" PRIu32 "\n", static_cast(temp_interval)); + //map_base[1] = static_cast(temp_interval); // writing the most significant bits also enables the interrupts +} + +void gnss_sdr_fpga_sample_counter::open_device() +{ + // open communication with HW accelerator + if ((fd = open(device_name.c_str(), O_RDWR | O_SYNC)) == -1) + { + LOG(WARNING) << "Cannot open deviceio" << device_name; + std::cout << "Counter-Intr: cannot open deviceio" << device_name << std::endl; + } + map_base = reinterpret_cast(mmap(NULL, PAGE_SIZE, + PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0)); + + if (map_base == reinterpret_cast(-1)) + { + LOG(WARNING) << "Cannot map the FPGA acquisition module into user memory"; + std::cout << "Counter-Intr: cannot map deviceio" << device_name << std::endl; + } + + // sanity check : check test register + uint32_t writeval = TEST_REG_SANITY_CHECK; + uint32_t readval; + readval = gnss_sdr_fpga_sample_counter::test_register(writeval); + if (writeval != readval) + { + LOG(WARNING) << "Acquisition test register sanity check failed"; + } + else + { + LOG(INFO) << "Acquisition test register sanity check success!"; + //std::cout << "Acquisition test register sanity check success!" << std::endl; + } +} + +void gnss_sdr_fpga_sample_counter::close_device() +{ + //printf("=========================================== NOW closing device ...\n"); + map_base[2] = 0; // disable the generation of the interrupt in the device + + uint32_t *aux = const_cast(map_base); + if (munmap(static_cast(aux), PAGE_SIZE) == -1) + { + printf("Failed to unmap memory uio\n"); + } + close(fd); +} + +uint32_t gnss_sdr_fpga_sample_counter::wait_for_interrupt_and_read_counter() +{ + int32_t irq_count; + ssize_t nb; + int32_t counter; + + // enable interrupts + int32_t reenable = 1; + write(fd, reinterpret_cast(&reenable), sizeof(int32_t)); + + // wait for interrupt + //printf("============================================ interrupter : going to wait for interupt\n"); + nb = read(fd, &irq_count, sizeof(irq_count)); + //printf("============================================ interrupter : interrupt received\n"); + //printf("interrupt received\n"); + if (nb != sizeof(irq_count)) + { + printf("acquisition module Read failed to retrieve 4 bytes!\n"); + printf("acquisition module Interrupt number %d\n", irq_count); + } + + // acknowledge the interrupt + map_base[1] = 0; // writing anything to reg 1 acknowledges the interrupt + + // add number of passed samples or read the current counter value for more accuracy + counter = samples_per_output; //map_base[0]; + return counter; + +} + + diff --git a/src/algorithms/libs/gnss_sdr_fpga_sample_counter.h b/src/algorithms/libs/gnss_sdr_fpga_sample_counter.h index 4ea9397ae..e02320afc 100644 --- a/src/algorithms/libs/gnss_sdr_fpga_sample_counter.h +++ b/src/algorithms/libs/gnss_sdr_fpga_sample_counter.h @@ -45,13 +45,18 @@ class gnss_sdr_fpga_sample_counter : public gr::block { private: gnss_sdr_fpga_sample_counter(double _fs, int32_t _interval_ms); + uint32_t test_register(uint32_t writeval); + void configure_samples_per_output(uint32_t interval); + void close_device(void); + void open_device(void); bool start(); bool stop(); + uint32_t wait_for_interrupt_and_read_counter(void); uint32_t samples_per_output; double fs; uint64_t sample_counter; - int32_t interval_ms; - int64_t current_T_rx_ms; // Receiver time in ms since the beginning of the run + uint32_t interval_ms; + uint64_t current_T_rx_ms; // Receiver time in ms since the beginning of the run uint32_t current_s; // Receiver time in seconds, modulo 60 bool flag_m; // True if the receiver has been running for at least 1 minute uint32_t current_m; // Receiver time in minutes, modulo 60 @@ -61,6 +66,9 @@ private: uint32_t current_days; // Receiver time in days since the beginning of the run int32_t report_interval_ms; bool flag_enable_send_msg; + int32_t fd; // driver descriptor + volatile uint32_t *map_base; // driver memory map + std::string device_name = "/dev/uio26"; // HW device name public: friend gnss_sdr_fpga_sample_counter_sptr gnss_sdr_make_fpga_sample_counter(double _fs, int32_t _interval_ms);