Archive for the Chapter 5 Category

Chapter 5 Excercises

The exercises assigned in Chapter 5 are actually quite advanced and are mostly meant to give you ideas of the kind of powerful things you can do in C using interrupts (and simple state machines). The following chapters, in particular in the third part of the book, will cover several such examples. The NTSC composite video generator (Exercise 5.3) is well described in Chapter 12, but you will be able to find the solution to the other two exercises in other (perhaps unexpected) places.

Excercise 5.2 is perhaps my favourite as you will find an example of (interrupt based) radio receiving routines (for a very special protocol) in the code attached to application note AN745, available for download as part of the vast collection of application notes available on Microchip’s web site.

Check the “rxi.c” module in particular. The code was written to be compatible with the HiTech C  compiler and the CCS compiler for the PIC16  architecture, but you should find it easy to port for the PIC24 and compile it with MPLAB C30.

The solution to Exercise 5.1 is not going to be very dissimilar…

More on Chapter 5 Tips and Tricks and builtin functions

If after yesterday’s posting you though things were getting ugly (I agree), you will be pleased to learn that since the introduction of MPLAB C30 v3.02 things have improved considerably. After all, performing the unlock sequences should not be an “impossible” task in C requiring super advanced inline assembly programming skills!

Four new builtin functions of the compiler come to our rescue:

  • __builtin_write_RTCWEN( void)
  • __builtin_write_NVM( void);
  • __builtin_write_OSCCONL( unsigned char value);
  • __builtin_write_OSCCONH( unsigned char value);

[Note: a double underscore preceeds each function name]
They give us complete access to the RCFGCAL, NVM and OSCCON control registers by performing the proper unlock sequences.

You will find a complete (long) list of builtin functions well documented in Appendix B of the MPLAB C30 compiler.

Chapter 5 Tips and Tricks

It is in Chapter 5 that we present for the first time the use of inline assembly. As a general rule in the book, this is a compromise accepted only in cases where we need to perform a task otherwise “impossible” if using only the C language, in this case: the unlock sequences of the OSCCON register and the RTCC register.

Both unlock sequences require the use of inline assembly because they must be performed in a very strict order, something we cannot “count” on the compiler to respect. Compilers are somewhat rebellious, they like to be in control of things and to be free to accomplish their tasks in the way THEY judge to be the most appropriate!

The inline assembly codes presented in the Tips and Tricks section works, but as I learned recently they are not optimal, especially when using the latest version of the MPLAB C30 compiler. A better way to do things is to still use inline assembly but, thanks to a special notation, let the compiler choose at least the registers to be used.

Here is an example showing the RTCC unlock sequence (and RTCWREN bit set) as recommended to me by the true MPLAB C30 gurus:

{int *nvmkey = &NVMKEY;
int v1 = 0×55;
asm volatile(”mov %0,[%1]\n\t”
“com %0,%0\n\t”
“mov %0,[%1]\n\t”
“bset RCFGCAL,#13″ : “+r”(v1) : “r”(nvmkey));
}

First of all notice how two parameters (%0 and %1) are replacing what before was the explicit use of processor registers. Now the choice is left to the compiler so that there is no interference/limitation whatsoever with the compiler register optimization algorithms.

Notice how the four assembly statements are passed inside a single inline assembly statement using a special escape sequence to terminate each line (\n\t) and concatenate with the next one.

Finally notice how the statement contains two additional parameters separated by “:”. They inform the compiler of what kind of registers will be required and what kind of use we will make of them.

You will find more details on this special notation inside the MPLAB C30 compiler User Guide chapter 8. Some pretty advanced stuff!

Updating Chapter 5

A lot of work has been done in MPLAB C30 rev 3.02 to perfect the management of interrupts and it affects the examples presented in the book in a number of ways.

A) Let’s start with the simplest change, the processor interrupt level (represented by 3 bits in the status register) and defined as a bit-field in the “p24fj128ga010.h” include file, has changed name, it is now spelled “_IPL” rather than just “_IP”. I am not sure where, but they tell me it was causing a possible name conflict. The fix is quick and does not require further explanation.

B) More worrisome, but not as critical as you might think, is a new warning that is generated now for every new interrupt service routine defined in the code examples:
Interrupts.c: xx: warning:  PSV model not specified for ‘_xxInterrupt’;
This is due to some changes implemented in the compiler to facilitate the implementation of the CodeGuard(tm) technology. Nothing special, really, all that happens is that the compiler does NOT assume that the “PSV window” (unfortunately this is a feature we learn about only in the next Chapter 6)  is under his control. It actually assumes the opposite now (that our application is managing it ), and therefore it takes preventive actions to make sure it is not corrupted during the ISR execution (saving the PSV value on the stack before the ISR and restoring its value after it).  And it tells us about it:
assuming ‘auto_psv’ this may affect latency

as it warns us that this “precautionary” push and pop require a few extra instructions, that affect the overall interrupt latency.
The fact is that none of the examples in the book makes any attempt at modifying the PSV and the default value (assigned by the compiler) is used throughout.

Unfortunately there is no global switch (compiler option) that can change the compiler assumptions and we have to either accept the (redundant)  warning and the increased latency (just a couple of cycles) or remember to add an attribute to each and every interrupt routine we define:
__attribute__((no_auto_psv)) 

Did I ever mention before how I  don’t care for the quadruple underscore and double parenthesis required by all GNU compilers to extend the C syntax?

For example:

void _ISR  __attribute__((no_auto_psv))  _T1Interrupt( void)
{
A less distracting option would be to define a new macro:

#define _NOPSV  __attribute__((no_auto_psv))

and use it as in the following example:

void _ISR  _NOPSV  _T1Interrupt( void)
{
We could be tempted to modify directly the definition of the _ISR macro to include the additional no_auto_psv attribute. But the _ISR macro is defined inside the device “p24fj128ga010.h” include file, and it is not considered a safe practice to modify standard include files, actually that is a VERY bad idea…

For now, since this is the first chapter were we learn to declare and use interrupt service routines, I will propose we use the _NOPSV macro explicitly.

Here are the three source codes used alternatively in the interrupt.mcp project:

1- Interrupts.c

2- Interrupts 32kHz

3- Interrupts RTCC

|