Chapter 6 Under the Hood
Di Jasio – Programming 16-bit Microcontrollers in C (Second Edition) Checklist The following tools will be used in this lesson: MPLAB X, Integrated Development Environment (v1.8 or later, free) MPLAB XC16, C compiler (v1.11 or later, free) The following pieces of documentation will be used during this lesson: PIC24FJ128GA010 Datasheet –DS39747 (latest rev.) Make sure they are available and/or installed and ready to use on your computer. You can download them from Microchip web site at: And
Di Jasio – Programming 16-bit Microcontrollers in C (Second Edition) Characters and Strings The declaration of a variable containing a single character: char c; An 8-bit integer (character), that is treated as a signed value ( ) by default. We can declare and initialize it with a numerical value: char c = 0x41; Or, we can declare and initialize it with an ASCII value: char c = ’a’; Note: use single quotes for ASCII character constants Note: characters are numbers! We can declare and initialize a string as an array of 8-bit integers (characters): char s[5] = { ’H’, ’E’, ’L’, ’L’, ’O’};
Di Jasio – Programming 16-bit Microcontrollers in C (Second Edition) Strings Proper For short use: char s[5] = "HELLO"; Or let the C compiler determine the number of characters required to store the string: char s[] = "HELLO"; Note: This automatically adds a termination character (zero). The example above is, in truth, equivalent to the following declaration: char s[6] = { ’H’, ’E’, ’L’, ’L’, ’O’, ’\0’ };
Di Jasio – Programming 16-bit Microcontrollers in C (Second Edition) Assigning a value to a char Assigning a value to a char (8-bit integer) variable and performing arithmetic upon it is no different to performing the same operation on any integer type: char c; // declare c as an 8-bit signed integer c = ’a’; // assign value ’a’ from the ASCII table c++; // increment, c == ’b’ now!
Di Jasio – Programming 16-bit Microcontrollers in C (Second Edition) Assigning a value to a String char s[15]; // declare s as an array of 15 char A string can be initialized during definition but cannot be assigned a value at run time using the same notation: s = ”Hello!”; // Error! This does not work!
Di Jasio – Programming 16-bit Microcontrollers in C (Second Edition) Using string.h By including the string.h, gain access to numerous useful functions to: copy the content of a string into another... strcpy( s, "HELLO"); // s : "HELLO" append (or concatenate) two strings... strcat( s, " WORLD"); // s : "HELLO WORLD" determine the length of a string... i = strlen( s); // i : 11 and many more …
Di Jasio – Programming 16-bit Microcontrollers in C (Second Edition) Memory Space Allocation Every time a string variable is declared and initialized as in: char s[] = "Flying with the PIC24"; Three things happen: 1. The MPLAB XC linker reserves a contiguous set of (22) memory locations in RAM (data space). This space is part of the ndata (near) data section 2. The MPLAB XC linker stores the initialization value in a 22 byte long table (in program memory). This space is part of the init code section. 3. The MPLAB XC compiler creates a small routine that will be called before the main program (part of the crt0 code) to copy the values, thereby initializing the variable.
Di Jasio – Programming 16-bit Microcontrollers in C (Second Edition) Constant Strings If a string is not supposed to be manipulated during the program, but is only used “as is”, consider declaring the string as a constant. This will save RAM space and initialization code/time: const char s[] = ”Flying with the PIC24”; The XC linker will only allocate space in program memory, in the const code section, (it will be accessible via the Program Space Visibility window) The string will be treated by the XC compiler as a direct pointer into program memory and, as a consequence, there will be no RAM space used.
Di Jasio – Programming 16-bit Microcontrollers in C (Second Edition) Program Space Visibility
Di Jasio – Programming 16-bit Microcontrollers in C (Second Edition) Notes for the PIC MCU Experts Notice that the PIC24 uses a 24-bit wide program memory bus, but operates only on a 16-bit wide data bus. The PSV connects only the lower 16-bits of the program memory bus to the data memory bus. The upper portion (8-bit) of each program memory word is not accessible using the PSV window. However, when using the table access instructions, all parts of the program memory word become accessible, but at the cost of having to differentiate the manipulation of data in RAM (using direct addressing) from the manipulation of data in program memory (using the special table access instructions).
Di Jasio – Programming 16-bit Microcontrollers in C (Second Edition) Notes for PIC Experts Since the PIC24 program memory is implemented using single supply Flash technology: it is possible to design boot-loaders which are applications that automatically update part or all of their own code. It is also possible to utilize sections of the Flash program memory as a Non Volatile Memory storage area, To write to the Flash program memory: Memory can only be written in complete rows (64 words at a time) Must be first erased in blocks of 8 rows (512 words) each. NOTE: This can make frequent updates impractical if single words or, as is more usual, small data structures are being managed.
Di Jasio – Programming 16-bit Microcontrollers in C (Second Edition) Notes for the PIC MCU Experts The PIC24 programmer can therefore choose between the more convenient, but relatively memory inefficient, method for transferring data between the two buses of the PSV, or the more memory efficient, but less transparent, solution offered by the table access instructions. The designers of the MPLAB XC compiler considered the trade offs and chose to use both mechanisms albeit using them to solve different problems at different times: The PSV is used to manage constant arrays (numeric and strings) so that a single type of pointer (to the data memory bus) can be used uniformly for constants and variables. The table access mechanism is used to perform the variable initializations (limited to the crt0 segment) for maximum compactness and efficiency.
Di Jasio – Programming 16-bit Microcontrollers in C (Second Edition) Investigating Memory Allocation /* ** Strings */ #include // 1. variable declarations const char a[] = "Learn to fly with the PIC24"; char b[100] = ””; // 2. main program main() { strcpy( b, "MPLAB C compiler"); // assign new content to b } //main
Di Jasio – Programming 16-bit Microcontrollers in C (Second Edition) Watches
Before and After strcpy()
Di Jasio – Programming 16-bit Microcontrollers in C (Second Edition) Looking at the.map section address length (PC units) length (bytes) (dec) text 0x200 0x90 0xd8 (216).const 0x290 0x38 0x54 (84).dinit 0x2c8 0x4c 0x72 (114).text 0x314 0x16 0x21 (33).isr 0x32a 0x2 0x3 (3) Total program memory used (bytes): 0x1c2 (450) <1%
Di Jasio – Programming 16-bit Microcontrollers in C (Second Edition) Sections of the.map Most section names are pretty intuitive, other are historical: .text section - is where all the code generated by the MPLAB XC compiler from your source files will be placed .const section - is where the constants (integers and strings) will be placed for access via the PSV . dinit section - is where RAM variable's initialization data (used by the crt0 code) will be found .isr - is where the Interrupt Service Routine (in this case a default one) will be found
Di Jasio – Programming 16-bit Microcontrollers in C (Second Edition) Embedded Memory Editor
Di Jasio – Programming 16-bit Microcontrollers in C (Second Edition) Data Memory Usage Section section address alignment gaps total length (dec) icd 0x800 0x50 0x50 (80).ndata 0x x64 (100) Total data memory used (bytes): 0xb4 (180) 2% .icd, a small area of 80 bytes reserved for the In Circuit Debugger use starting at address 0x800, the first location available in the PIC24 RAM. .ndata, containing only one variable: b for which 100 bytes are reserved immediately following.icd
Di Jasio – Programming 16-bit Microcontrollers in C (Second Edition) Pointers Sequential access to an array of integers: int *pi; // define a pointer to an integer int i; // index/counter int a[10]; // an array of integers // 1. sequential access using array indexing for( i=0; i<10; i++) a[ i] = i; // 2. sequential access using a pointer pi = a; for( i=0; i<10; i++) { *pi = i; pi++; }
Di Jasio – Programming 16-bit Microcontrollers in C (Second Edition) Pointer (cont) The previous code is more often reduced to the following: // 2. sequential access to array using pointers for( i=0, pi=a; i<10; i++) *pi++ = i; Note: an “empty” pointer,, is assigned a special value NULL, which is implementation specific and defined in stddef.h.
Di Jasio – Programming 16-bit Microcontrollers in C (Second Edition) The Heap The heap is an area of data memory reserved for dynamic use The standard C library stdlib.h, provide the tools to allocate and free the memory blocks. void *malloc(size_t size); Takes a block of memory of requested size from the heap, and returns a pointer to it. void free(void *ptr); Returns the block of memory pointed to by ptr to the heap.
Di Jasio – Programming 16-bit Microcontrollers in C (Second Edition) PIC24 NEAR and FAR space The PIC24 architecture allows for a very efficient (compact) instruction encoding for all operations performed on data memory within the first 8k byte of addressing space. This is referred to as the “near” memory. Access to memory beyond the 8k byte limit, “far”, requires the use of indirect addressing methods (pointers). The stack (and with it all the local variables used by C functions) and the heap (used for dynamic memory allocation) are naturally accessed via pointers and are correspondingly ideal candidates to be placed in the far RAM space.
Di Jasio – Programming 16-bit Microcontrollers in C (Second Edition) MPLAB XC Data Memory Models Small Data Model: The linker will attempt to place all the global variables defined in a project in the near memory space for maximum efficiency. If a variable cannot be placed within the near memory space it has to be “manually” declared with a far attribute, so that the compiler will generate the appropriate access code. Large Data model: Each variable is assumed to be far unless the near attribute is manually specified. In practice, while using the PIC24FJ128GA010, you will use almost uniquely the default Small Memory Model and in rare occasions you will find it necessary to identify a variable with the far attribute. Since access to elements of an array (explicitly via pointers or by indexing) is performed via indirect addressing anyway, there is typically no performance or code size penalty in declaring an array far.
Di Jasio – Programming 16-bit Microcontrollers in C (Second Edition) MPLAB XC Program Memory Models Similarly the PIC24 architecture allows for maximum efficiency when functions are called within a +/-32K byte (near) range. Small Program model: MPLAB XC attempts to place all functions compiled in a module within the near range (+/-32K). Large Program model: All functions are considered as far unless manually specified otherwise
Di Jasio – Programming 16-bit Microcontrollers in C (Second Edition) Notes for C Experts The const attribute is normally used in C language together with most other variable types only to assist the compiler in catching common parameters usage errors. When a parameter is passed to a function as a const or a variable is declared as a const, the compiler can in fact help flag any following attempt to modify it. The MPLAB XC extends the const semantic in a very natural way by ensuring that the variable is placed in Flash memory space.
Di Jasio – Programming 16-bit Microcontrollers in C (Second Edition) Notes for the Assembly Experts The string.h library contains many useful block manipulation functions that can be useful, via the use of pointers, to perform operations on any type of data array, not just strings, like memcpy(), memcmp(), memset() and memmove(). The ctype.h library, on the other hand, contains functions that help discriminate individual characters according to their position in the ASCII table, to discriminate lower case from upper case, and or convert between the two cases.
Di Jasio – Programming 16-bit Microcontrollers in C (Second Edition) Tips and Tricks Copying zero terminated strings can be dangerous: void mycpy( char *dest, char * src) { while( *dest++ = *src++); } Problems: There is no limit to how many characters could be copied. There is no check as to whether the dest pointer is pointing to a buffer that is large enough What would happen should the src string be missing the termination character? It would be very easy for this code to continue beyond the allocated variable spaces and to corrupt the entire contents of the data RAM including the all precious SFRs. To Do: Try at least to verify that pointers passed to your functions have been initialized before use. Compare them with the NULL value (declared in stdlib.h and/or stddef.h) to catch the error. Add a limit to the number of bytes to be copied. If you don’t know the size of the strings/arrays used, use the sizeof() operator. A better implementation of mycpy() could be the following: void mycpy( char *dest, char *src, int max) { if ((dest != NULL) && ( src != NULL)) while (( max-- > 0) && ( *src)) *dest++ = *src++; }
Di Jasio – Programming 16-bit Microcontrollers in C (Second Edition) Suggested Excercises 1. Search for a string in an array of strings sequentially 2. Implement a Binary search 3. Develop a simple Hash Table management library
Di Jasio – Programming 16-bit Microcontrollers in C (Second Edition) Recommended Readings Wirth, N. (1976), Algorithms + Data Structures = Programs, Prentice-Hall, Englewood Cliffs, NJ. With un-paralleled simplicity Wirth (the father of the Pascal programming language) takes you from the basics of programming all the way up to writing your own compiler.
Di Jasio – Programming 16-bit Microcontrollers in C (Second Edition) Online Resources ous_programming_languages Learn more about pointers and see how they are managed in various programming languages. ous_programming_languages