Monday, June 23, 2014

PIC32MX250F128B ipl7: odd shadow register set behavior and observations

This issue has now been solved. Scroll to the bottom for the update.

I started working on a pure sine wave inverter based on the PIC32MX250F128B. The first stage was to just get the SPWM working and test that before proceeding to add the power stage, feedback and other control, etc.

This led me to some interesting observations regarding the PIC32MX250F128B interrupts, especially the use of the shadow register set and a related problem.

I set up Timer 2 to be the time base for sine wave generation (DDS/SPWM) using OC1. In the Timer 2 interrupt, the duty cycle update request is performed (OC1RS is updated). Timer 2 interrupt priority was set to 7.
This all worked fine. The initial ISR definition was:

void __ISR(_TIMER_2_VECTOR, ipl7) T2int(void) {
.....
}


However, when I used the ADC (input from potentiometer for amplitude control - a start at implementing feedback), accessing any of the ADC registers in the while (1) loop in main stopped the PIC32 from working. 

I then added a line of code in main to continuously toggle RA0 (PORTA bit 0). This would stop when trying to access the ADC registers as well. (It worked fine if I removed the code that accessed the ADC.) This meant that the core was being stopped. So, I thought that it might be some kind of exception being thrown (?).
However, changing the timer 2 interrupt priority from 7 (which I had initially) to anything else fixes the problem. My guess was that something went wrong when the shadow register set was being used for interrupt priority level 7 (?).

So I did some more tests and came up with this:

The way I have the ISR defined initially selects the "AUTO" mode of selection where, I believe, the compiler decides whether to use the shadow register set or software for context save/restore.
Forcing the compiler to use the software context save/restore instead of the shadow register set seems to fix it:

void __ISR(_TIMER_2_VECTOR, ipl7SOFT) T2int(void) {
.....
}


I forced the shadow register set just to confirm:

void __ISR(_TIMER_2_VECTOR, ipl7SRS) T2int(void) {
.....
}
and sure enough it didn't work.

So, since it worked with ipl6, my guess was that for ipl6 (and for any ipl except 7), the compiler chooses software for AUTO, whereas for ipl7, the compiler chooses SRS.

So, I forced the shadow register set on ipl6:

void __ISR(_TIMER_2_VECTOR, ipl6SRS) T2int(void) {
.....
}
and sure enough, it didn't work.

Forcing software for ipl6 fixes it (as does AUTO).

I looked through the errata of the chip and couldn't find anything. (The errata is an interesting read.)  I am also a little surprised since I did have ipl7 running fine previously. Maybe something weird happens with a certain combination of peripherals (?) that I unfortunately happened to use. I'll still see if I can find this documented, and I'll have to check whether an exception is thrown and if so, what type. If nothing else, at least it was a nice, albeit frustrating, lesson. Hopefully, it'll help someone else who might run into a similar problem.

UPDATE/SOLUTION: It turns out that the PIC32MX250F128B does not have a shadow register set, as mentioned in the datasheet. I seemed to have missed that while concentrating on the reference manual which talks about the shadow register set for the PIC32 series. Thus, from the point of view of my 'experiments', the lesson learnt could very well just be that when using ipl7, force the compiler to use software instead of the default AUTO mode (which may make the compiler try to use the shadow register set, which doesn't exist - explaining the problem I faced earlier).

---------------------------------------------------
DDS = direct digital synthesis
ipl = interrupt priority level
ISR = interrupt service routine 
SPWM = sinusoidal pulse width modulation
SRS = shadow register set

Tuesday, June 17, 2014

Simple AC voltmeter

I had long been thinking of designing a simple AC voltmeter but had somehow never gotten to it. However, with school just ending, and me going back to electronics, this was a neat simple yet useful circuit that I felt I could just get done with in a day or two.

The concept is fairly straight forward. Since I needed this only to measure the mains AC voltage and the output voltage of the sine wave inverter I was working on (based on the PIC32MX250F128B - more on this later), I didn't need to do any "true RMS" measurement. All I had to do was to convert the mains AC to DC, filter it and measure the peak voltage. Of course this had to be scaled down to a safe range for the microcontroller. The RMS voltage for a sine wave is equal to 0.707 (to 3 decimal places) the peak voltage.

The design was based on the Microchip PIC16F676. However I realized that I didn't have any in stock with me. So, I just used the pin-compatible PIC16F684. On the software side of things, the difference between the code for PIC16F676 and PIC16F684 is just one line. (See source file attached below.)

The variable resistor is adjusted so that the reading of my AC voltmeter matches that of a commercial voltmeter (Extech MA640 DMM). This is a sort of calibration.

CAUTION: THIS CIRCUIT IS NOT ISOLATED FROM THE MAINS AC AND HAS THE POTENTIAL TO BE LETHAL. YOU MUST BE VERY CAREFUL IF YOU ARE GOING TO USE THIS DESIGN. DO NOT ATTEMPT IF INEXPERIENCED. I CANNOT AND WILL NOT BE HELD RESPONSIBLE FOR ANY DAMAGE DONE WHILE USING THIS CIRCUIT.

Here's the schematic:

 Fig. 1 - Voltmeter

Here are some pictures:

 Fig. 2 - The PCB without (above) and with (below) the transformer


Fig. 3 - The test setup


Fig. 4 - Measuring voltage set with the variac


 Fig. 5 - Measuring voltage set with the variac


 Fig. 6 - Measuring voltage set with the variac

Fig. 7 - Measuring voltage set with the variac


C source file:
https://drive.google.com/file/d/0B4SoPFPRNziHdDB6cDdzNGZPdXc/edit?usp=sharing

http://www.4shared.com/file/Cz56s9Zlba/ACvoltmeter.html

mikroC project file:
https://drive.google.com/file/d/0B4SoPFPRNziHN2MydDRDalRWS1k/edit?usp=sharing
http://www.4shared.com/file/JwW3bpJNce/ACvoltmeter.html

Parts list (Excel XLSX file):
https://drive.google.com/file/d/0B4SoPFPRNziHb2ZCcnFNVnNpc2s/edit?usp=sharing
http://www.4shared.com/file/b_NcW4vdce/parts_list.html

Schematic (ARES DSN file):
https://drive.google.com/file/d/0B4SoPFPRNziHb1NFWDdwcWpJV2M/edit?usp=sharing
http://www.4shared.com/file/U6kPQH_rce/schematic.html

PCB (ARES LYT file):
https://drive.google.com/file/d/0B4SoPFPRNziHNDhhMDBkNFlnWW8/edit?usp=sharing
http://www.4shared.com/file/ZVczMJ7Wba/schematic.html

PCB (PDF files):
https://drive.google.com/file/d/0B4SoPFPRNziHMV9LdTBab1BXeDg/edit?usp=sharing
Mirrored:  https://drive.google.com/file/d/0B4SoPFPRNziHSmxvT1pSbXBWOTA/edit?usp=sharing

It's a fun simple yet useful project that you can build pretty easily if you want. Let me know what you think in the comments section below!