chipKIT® Development Platform

Inspired by Arduino™

3 IDEs have different timings for core timer service callback; also service stops!

Created Thu, 16 Jun 2016 11:35:59 +0000 by shirleyc


shirleyc

Thu, 16 Jun 2016 11:35:59 +0000

I have been testing a new Wifire board with Digilent's Analog Shield (16 bit ADCs and DACs at 100kHz, with SPI interface). I was using the Core timer service to cause a small routine to execute every 100uS and checking the times for the my callback routine to execute. I found that 3 different IDEs (Arduino 1.6.9+chipKit core, MPIDE 0023, and UECIDE 0.8.8alpha21) produce code with varying execution times. Moreover, only the code generated by MPIDE continues to give interrupts; code produced by the other 2 IDEs works for a few seconds to a minute or so and then there are no more interrupts, i.e., my callback routine is never called again, since I see no more pulses on my oscilloscope. Here is the code in question, which is for a digital feedback loop: uint32_t MyCallback(uint32_t currentTime) { digitalWrite(4, HIGH); // Start pulse on pin 4 to check interrupt service routine timing Input = analog.read(0); //call to Analog Shield 16 bit A/D myPID.Compute(); //floating point computation, PID library modified for interrupts analog.write(0,Output); //call to Analog Shield 16 bit D/A digitalWrite(4, LOW); // End pulse return (currentTime + CORE_TICK_RATE/10); // asks for callback in 100uS }

The interrupts that do occur happen every 100uS, as requested. The pulse lengths measured on pin 4 are as follows: Arduino IDE 15.7uS, MPIDE 19.2 uS, UECIDE 16.2uS. When I tried to check the timing of the 3 separate instructions (the call to analog.read, the computation, and then the call to analog.write), they are reasonable except for the UECIDE version, for which the call to analog.read alone takes 70uS! The computation alone takes 4.1 or 4.3 uS for code from any of the IDEs.

Are the different IDEs using different compilers or versions? Could they be doing different optimizations or using different versions of the SPI library? How do I find out what they are doing? Also, I have the impression that the interrupts only stop if the calls to the Analog Shield are included in the code. The problems also seem to be specific to the Wifire board, as I used the uC32 and the Analog Shield last summer with the same callback routine, and I did not have any troubles with the interrupts stopping. However, I only used MPIDE under Windows then.

By the way, myPID.Compute takes 14.1 to 15 uS on the uC32 board. Thus the Wifire is faster by slightly more than the multiple of the 200MHz vs 80MHz clock speeds. Is the floating point unit on the Wifire's Pic32MZ processor actually being used? UECIDE won't upload to the Wifire if I select the board as Chipkit Wifire Rev C+; it returns error message "avrdude: AVR part '32MZ2048EFG100' not found." I don't know whether the other IDEs compile code that use the FPU, or whether UECIDE produces code that uses it when the board is selected just as "Chipkit Wi-fire". Also, is there any way to use the DSP instructions for the MZ processor from any of these IDEs?

Finally, I want to put some additional code under interrupt control, but much slower, perhaps every 20mS. Should I try to use the core timer service for that also, or set another timer and use interrupts as described in [url]http://chipkit.net/interrupts-made-easy-with-chipkit/[/url] Is the priority of the core timer service higher than for other interrupts? Does the core timer service get turned off or delayed if interrupts are disabled?

I don't understand what could be causing the problems described above. Any help is welcome! --Shirley


majenko

Thu, 16 Jun 2016 16:05:15 +0000

The interrupts that do occur happen every 100uS, as requested. The pulse lengths measured on pin 4 are as follows: Arduino IDE 15.7uS, MPIDE 19.2 uS, UECIDE 16.2uS. When I tried to check the timing of the 3 separate instructions (the call to analog.read, the computation, and then the call to analog.write), they are reasonable except for the UECIDE version, for which the call to analog.read alone takes 70uS! The computation alone takes 4.1 or 4.3 uS for code from any of the IDEs. Are the different IDEs using different compilers or versions? Could they be doing different optimizations or using different versions of the SPI library? How do I find out what they are doing? Also, I have the impression that the interrupts only stop if the calls to the Analog Shield are included in the code. The problems also seem to be specific to the Wifire board, as I used the uC32 and the Analog Shield last summer with the same callback routine, and I did not have any troubles with the interrupts stopping. However, I only used MPIDE under Windows then.

MPIDE most likely is using old code and compiler. MPIDE has been deprecated. UECIDE and chipKIT-core should both be on the latest compiler and the same code base. The UECIDE packages are generated from the chipKIT-core repository. Make sure all your UECIDE packages are up to date and that you are using the very latest chipKIT-core in the Arduino IDE.

You might want to check what speed the SPI is running at by default, unless you are specifically requesting a certain speed. That is really the only factor that can affect how long it takes to do an SPI transaction. I am not familiar with the analog shield in question, so I don't know if the library is using SPI or DSPI. Ideally it should be using DSPI since it has much better facilities in it.

By the way, myPID.Compute takes 14.1 to 15 uS on the uC32 board. Thus the Wifire is faster by slightly more than the multiple of the 200MHz vs 80MHz clock speeds. Is the floating point unit on the Wifire's Pic32MZ processor actually being used? UECIDE won't upload to the Wifire if I select the board as Chipkit Wifire Rev C+; it returns error message "avrdude: AVR part '32MZ2048EFG100' not found." I don't know whether the other IDEs compile code that use the FPU, or whether UECIDE produces code that uses it when the board is selected just as "Chipkit Wi-fire". Also, is there any way to use the DSP instructions for the MZ processor from any of these IDEs?

Avrdude is a pain in that it has to have a separate chip entry in the config file for each possible chip you ever want to use (well, there are ways around it but they have only been used by me in the very latest version of UECIDE pre-release so far). You should be using pic32prog not avrdude for uploading. Avrdude has been deprecated and new chips don't get added to it.

You only get FPU instructions from the WiFire Rev C+ board in UECIDE, or the latest WiFire (not Rev A / B variant) board in the chipKIT core. MPIDE has never had any support for the FPU variant. It's only in the past few weeks that FPU support has been added to chipKIT core.

Finally, I want to put some additional code under interrupt control, but much slower, perhaps every 20mS. Should I try to use the core timer service for that also, or set another timer and use interrupts as described in [url]http://chipkit.net/interrupts-made-easy-with-chipkit/[/url] Is the priority of the core timer service higher than for other interrupts? Does the core timer service get turned off or delayed if interrupts are disabled?

I'd say use a separate timer for that. The priority is up to you - you can set it with setIntPriority(). That said, you'll have to go some to get higher than the core timer - that runs at IPL 7 / SPL 0 so you can only use the sub-priorities to get any higher than CT.

The CT interrupt, as with all interrupts, will be delayed if interrupts are disabled globally. If two interrupts would have fired you'll only get one - there is no queue, just a flag.


shirleyc

Tue, 21 Jun 2016 17:58:03 +0000

Majenko, thank you very much for your help! I made progress but still have some problems and questions.

I found the menu item in UECIDE to use pic32prog instead of avrdude to upload programs to the Wifire. I also updated my Linux desktop's version of the Arduino program to 1.6.9 and downloaded the latest Chipkit Core v. 1.2.0 from June 7, 2016. Now both UECIDE and Arduino programs have a board selection corresponding to the Wifire Rev C with floating point. The computation subroutine now only takes 0.7uS, instead of 4.1uS; thus the FPU clearly works! Also, both programs seem to continue responding to the core timer interrupts now, i.e., no more program hangs. The timings are now the same for the code compiled under UECIDE and Arduino+Chipkit Core: 12.5uS for the sequence of analog.read, PID.Compute, and analog.write. But having the core timer service routine execute only analog.read still takes 70uS! Does this indicate a problem with the Analog Shield's SPI interface routines? Perhaps this relates to the problems described below.

Then I tried the example HTTPServer, called deWebIOServer, for the Wifire. Under UECIDE, I got compilation errors from SoftSPI.h and DSDVOL.h libraries, even though I told UECIDE to update all of the libraries. Under Arduino+Chipkit Core 1.2.0, everything compiled successfully and ran, with the Wifire successfully serving up a webpage from the SD card on the board. So is there another setting that I need to update in UECIDE? In UECIDE's PlugIn Manager under Libraries, I was ignoring all of the libraries labeled "Harmony testing"; by the way, how are those supposed to be used? I had previously found a library for MPLAB Harmony that says it supports the DSP functions of the PIC32MZ processor. Would there be a way to port it or modify it to work with UECIDE or Arduino with Chipkit-core?

I then spent most of the weekend testing my program with the uC32 board and the Analog Shield (100kHz A/Ds and D/As with SPI interface). (I have an I2C LCD text display that runs at 5V, and I didn't want to burn up the unprotected pins on the Wifire board in case of error. I've since wired up a 3.3V level shifter for those lines and now could try the Wifire again.) Recall that my core timer service routine, which executes every 100uS, makes 2 calls to the Analog Shield, one to read an A/D and the other to write a DAC. Digilent's Analog Shield library uses the SPI library, not DSPI. I found out that I could hang my program by executing calls to the Analog Shield in the main program loop, and the problems occurred more often if I was trying to write even 2 or 3 DAC signals in a tight loop, but less likely if I tried to write the DAC only once per Arduino loop(). This suggests to me that maybe the Analog Shield/SPI library is not checking status correctly before trying to execute an instruction; maybe the processor is sitting in a loop waiting for the device to be ready but never comes out because the main program and the interrupt service routine are interfering. These tests were compiled with Arduino 1.6.9 and Chipkit Core 1.1.0 (version from Jan. 10, 2016) because I forgot to upgrade the Chipkit Core on my Window laptop. I haven't looked carefully at the Analog Shield library, but I suppose that is the next thing to do. Should I try to modify it to use DSPI instead of SPI? I also didn't check the default speed setting for the SPI bus yet. Do I need to worry about executing instructions for other SPI devices (e.g., Wifi, SD card on the Wifire) while my core timer service routine is running? Or is that not an issue for those 2 devices because they use separate SPI controllers from the Pic32MZ processor? The reference manual for the Wifire says that the usual SPI interface (Arduino pins 11,12,13) uses SPI2, SD card uses SPI3, and Wifi module uses SPI4. So maybe this is only an issue if I am using the uC32 board and then try to add another SPI peripheral? Should I be asking these questions on the Digilent Forum for the Analog Shield or the Wifire?

I didn't try to add another interrupt service routine to the program yet. --Shirley


majenko

Tue, 21 Jun 2016 19:24:38 +0000

You should never use the same SPI bus from both the main loop and an interrupt handler. It's just asking for trouble. The only possible way it could work would be to abstract the SPI accesses into a single set of routines used in both contexts and add a mutex to those routines - and if the mutex is locked, instead of blocking waiting for it to unlock (at least in the ISR context), abort the attempt - after all, if you block in the ISR there's no way for the SPI transaction to finish and thus never release the mutex, so you get a deadlock.

In the main loop it's possible to block, of course, however you would never be trying to run the SPI from main loop during an ISR context transfer since the main loop isn't running at that point.

So no, you can't really use the same SPI bus from two different contexts and get away with it.

But you should be able to use two separate buses in the different contexts, of course, since they are two completely separate entities.

For the HTTPServer example you may need to just add a few extra libraries to the main sketch. The libraries used there are very fragile and do some dodgy inclusions that don't work too well on UECIDE. They do that to get around the fact that MPIDE and Arduino IDE can't recurse the library requirements, so they include things with relative paths and such like, which UECIDE doesn't much like. Adding the libraries they reference manually to the sketch tells UECIDE that they are used and to compile them.

The main culpret is needing to add DFATFS.h to get DSDVOL.h to work.