4 Replies Latest reply on Jan 30, 2017 10:10 AM by Intel Corporation

    using the MCU

    nniles

      I am writing an inertial navigation application for my Edison, using the MCU to read the sensors and pass the data to the Atom for high level processing.

       

      There are a number of issues that I'd like to confirm:

      1. mcu_delay() does not have microsecond accuracy? (or time_us() doesn't?)

      In my timing tests (wrapping calls with time_us), mcu_delay() always comes back later than the specified time, and longer requested delays yield higher inaccuracy (i.e., it's not some fixed amount, nor does it appear to be linear).

       

      2. host_send() takes 800+ us to send even a single byte?

      This one is pretty hard to swallow.  Together with the lack of SPI support, this makes 1kHz sample rates unachievable.

       

      3. the Atom only checks the incoming IPC at 50 Hz?

      On top of the amount of time required to send data via the provided IPC channel, the Atom only bothers to read the channel at 50 Hz???  Is there some kernel setting that can change this?  What was the driving factor behind this decision?

       

      Thanks,

        • 1. Re: using the MCU
          Intel Corporation
          This message was posted on behalf of Intel Corporation

          Hi Nniles,


          Thanks for contacting us!


          I appreciate all the information you have provided. I have been working with the Edison MCU in order to test the behavior you have mentioned in your questions, and I got similar results, please take a look at my results:

           

          1. Reading the MCU documentation, the MCU provides a microsecond-level accuracy delay (mcu_delay()), I have ran a simple code that turns a GPIO on/off and set up a delay using the function mcu_delay(). In the tests I have made, I noticed that the MCU takes approximately 16 us more than the specified in the function. See the following pictures:

          Using mcu_delay (1)

          Using mcu_delay (1000)

          Additionally, I ran the code without any delay, and each instruction, to turn on/off the GPIO, takes approximately 9.6 us, so the time that the MCU takes to execute the instructions can affect the execution time. See the picture below.

           

          Without any delay function.

          Regarding the time_us(), the MCU documentation mentions this: “This API returns the number of microseconds since the MCU has booted. This number will overflow (go back to zero) after 71 minutes.”

           

            2. Using the host_send() function, I have sent a single byte and it takes more than 800 us as you have mentioned. See the picture below.

            3. Regarding your last question, please let me investigate a little bit more and as soon as I find useful information I’ll let you know.

           

          Hope this information helps.


          Regards,
          -Yermi

          1 of 1 people found this helpful
          • 2. Re: using the MCU
            nniles

            Yermi,

             

            Thanks for those confirmations.  Your timings are similar to what I've seen.

             

            For the last one, I set up the MCU to send a fixed size message at a certain rate (125 and 250 Hz were tested), and wrote a short Linux program to do nonblocking reads from ttymcu0 in a loop with no delays.  Whenever the Linux program read something (buffer much larger than messages, so the FIFO will be cleared each read), it calculates the time between messages and outputs frequency.

             

            Regardless of the rate at which the messages were sent by the MCU program, the Linux program always reported 50 Hz, and an appropriate multiple of the message size was reported by the read() operation.

             

            #include <iostream>
            #include <iomanip>
            #include <unistd.h>
            #include <fcntl.h>
            #include <cstdint>
            #include <cstdio>
            #include <errno.h>
            #include <time.h>
            #include <signal.h>
            
            int fd = -1;
            
            void sig_handler(int s) {
                if(fd >= 0) {
                    write(fd, "0", 1);
                    close(fd);
                }
                std::cout << "Quitting..." << std::endl;
                exit(1);
            }
            
            int main(void) {
                std::uint8_t buffer[256];
                ssize_t bytesread;
                struct timespec ts_0, ts, ts_prev;
                double dt;
                uint64_t cumbytes=0;
                struct sigaction sigIngHandler;
                
                sigIngHandler.sa_handler = sig_handler;
                sigemptyset(&sigIngHandler.sa_mask);
                sigIngHandler.sa_flags = 0;
                sigaction(SIGINT, &sigIngHandler, NULL);
            
                fd = open("/dev/ttymcu0", O_RDWR | O_NONBLOCK);
                if(fd==-1) {
                    std::cout << "Error opening device." << std::endl;
                    return 1;
                }
            
                if(write(fd, "1", 1) == -1)
                    perror(NULL);
            
                clock_gettime(CLOCK_MONOTONIC_RAW, &ts_0);
            
                while(true) {
                    errno=0;
                    bytesread = read(fd, buffer, 256);
                    if(bytesread == -1) {
                        if(errno != 11)
                            perror(NULL);
                    }
                    else {
                        clock_gettime(CLOCK_MONOTONIC_RAW, &ts);
                        dt = static_cast<double>(ts.tv_sec - ts_prev.tv_sec) + 
                             static_cast<double>(ts.tv_nsec - ts_prev.tv_nsec)*(1E-9);
                        cumbytes += bytesread;
                        std::cout << "Receving " << std::setiosflags(std::ios::fixed) 
                                  << std::setprecision(2) << static_cast<double>(cumbytes)/
                                     (static_cast<double>(ts.tv_sec - ts_0.tv_sec) + 
                                      static_cast<double>(ts.tv_nsec - ts_0.tv_nsec)*(1E-9))
                                  << " bytes/sec -- freq = " << std::setprecision(6) 
                                  <<  1.0/dt << std::endl;
                        ts_prev.tv_sec = ts.tv_sec;
                        ts_prev.tv_nsec = ts.tv_nsec;
                    }
                }
                return 0;
            }
            
            
            
            
            
            
            
            
            
            • 3. Re: using the MCU
              Intel Corporation
              This message was posted on behalf of Intel Corporation

              Hi Nniles,

              Thank you for that extra information, I appreciate that, however, I would like to continue investigating it in order to know if I can find something useful for you. Hope to update you soon.

              Regards,
              -Yermi
               

              • 4. Re: using the MCU
                Intel Corporation
                This message was posted on behalf of Intel Corporation

                Hi Nniles,
                 
                Please accept our apologies for the delay.
                 
                We have been investigating this MCU behavior, and we would like to let you know that our team has this issue in consideration for future release of the Edison Software.
                 
                Regards,
                -Yermi