1.59k likes | 1.86k Views
The C - Language ready MCU. Introduction. The C Programming Language is a powerful, flexible and potentially portable high-level programming language.
E N D
Introduction • The C Programming Language is a powerful, flexible and potentially portable high-level programming language. • The C language may be used successfully to create a program for an 8-bit MCU, but to produce the most efficient machine code, the programmer must carefully construct the C Language program. • The programmer must not only create an efficient high level design, but also pay attention to the detailed implementation.
C Language • Facts about the C language • C is a HLL that deeply interacts with the underlaying computer hardware • C is an easily understood language • Is a programming language widely standardized • Is very productive • Allows code re-use and code borrowing • Allows hardware abstraction maintainability • Excellent programming tool for Microcontrollers
Assembly vs.C • A compiler is no more efficient than a good assembly programmer. • It is much easier to write good code in C which can be converted in to efficient assembly code than it is to write efficient assembly code by hand. • C is a means to an end and not an end itself.
One should use standard C as much as possible... However, when it interferes with solving the problem at hand, do not hesitate to bypass it. - Nigel Jones ANSI C for 8-Bits MCUs • Pure ANSI C is not always convenient for embedded systems because: • Embedded systems interact with hardware. ANSI C provides extremely crude tools for addressing registers at fixed memory locations. • Almost all embedded systems use interrupts • ANSI C has various type promotion rules that are absolute performance killers to an eight-bit machine. • Some microcontroller architectures don’t have hardware support for a C stack. • Many microcontrollers have multiple memory spaces
Embedded vs. Desktop Programming Main characteristics of an Embedded progamming environment: • Limited RAM • Limited ROM • Limited stack space • Hardware oriented programming • Critical Timing (ISR, tasks, ...) • Many different pointer kinds (far/near/rom/uni/paged/...) • Special keywords/tokens (@, interrupt, tiny, ...)
Compiler Requirements • ROM-able code • Optimized code • Re-entrant code • Support for Different Member in CPU Family • Support for different memory models • Non Obvious optimization .h .o .c Compiler listing .cpp
Compiler’s little Details While choosing a compiler, you must remember that the Devil is in the details • Nice features that can make a huge difference: • Inline Assembly • Interrupt Functions • Assembly Language Generation • Standard Libraries • Startup code
C Example for Embedded Systems • The Hello World Application for the HC08 #include <stdio.h> void main(void){ printf (“Hello World!\n”); while(1); } • Startup code • Standard libraries - Startup code is an extra piece of software that executes prior to main(). - A standard set of function libraries. These include various routines like printf, memcpy, strcmp, scanf and so on. Example #1
Startup Routine • The startup code is generally written in assembly language and linked with any executable that you build. It prepares the way for the execution of programs written in a high-level language. • Disable interrupts • Copy any initialized data from ROM to RAM • Zero the uninitialized data area • Allocate space for and initialize the stack • Create and initialize the heap (if available) • Enable interrupts • Call main()
Performing Input/Output using the C library functions getchar gets printf putchar puts scanf sprintf sscanf. Standard Library #include <stdio.h> void main(void){ printf (“Hello World!\n”); while (1); } All input/output performed by C library functions is supported by underlying calls to getchar and putchar. The C source code for these and all other C library functions are commonly included
C for Embedded Systems October 24, 2014
Some natural Questions... After seeing the previous code, some natural questions may arise: • Where is my code? • Where are my variables? • How do I access I/O Registers? • How do I handle interrupts?
Where is my code? In the PRM file, you can define where you want to allocate each segments you have defined in your source code. In order to place a segment into a specific memory area; just add the segment name in the PLACEMENT block of your PRM file.
Where are my variables? • The variables are placed into the Default_RAM PLACEMENT unless otherwise stated with a #pragma... • It is important to define a segment into the Zero Page RAM ($40 -$FF) to place the most frequently used variables. • This way, the compiler will optimize the code using direct addressing mode (8-bit address) instead of extended mode (16-bit address).
How to access I/O Registers? • Many I/O and control registers are located in the direct page and they should be declared as such, so the compiler can use the direct addressing mode where possible. One of the first questions that arises when programming embedded is: How do I access I/O Registers? The answer is as simple or complicated as you want...
This makes PortA a variable of type char at address 0x0000 This is a compiler-specific syntax... It is more readable, but we pay the price loosing portability. Defining I/O Registers • One common and very useful form is: #definePortA( * (volatile unsigned char* ) 0x0000 ) • An easier way to do this is: volatile unsigned charPortA @0x0000;
How do I handle interrupts? • The CodeWarrior compiler provides a non-ANSI compliant way to specify directly the interrupt vector number in the source: interrupt 17 voidTBM_ISR (void){ /* Timebase Module Handler*/ }
Introduction to CodeWarrior Let’s see how to... • Create empty project from stationary • Add and remove files from a project • Startup Code • Default.prm Settings • Use of file editor • Compiling (successful and unsuccessful) • Enable debugging and debugging a project • Setting a breakpoint • Viewing variables in debugger Example #2
Useful ANSI-C Standards October 24, 2014
Data types Facts • The greatest savings in code size and execution time can be madeby choosing the most appropriate data type for variables. • The natural internal datasize for 8-bit MCU is 8-bits (one byte), whereas the C preferred data type is‘int’. • 8-bit machines can process 8-bit data types more efficiently than 16-bit types. • “int” and larger data types should only be used where required by the size of data to be represented. • Double precision and floating point operations are particularly inefficient and should be avoided wherever efficiency is important.
All scalar types (exceptchar) are signed by default Example: ‘int’ = ‘signed int’ Scalar Types for the HC08 TheANSI standard does not precisely define the size of its native types, but CodeWarrior does... 0 255
Default CodeWarrior Data Types All basic types can be changed...
Data Type Selection There are 3 Rules for Data Type Selection on 8-bit MCUs: • Use the smallest possible type to get the job done. • Use unsignedtype if posibble. • Use casts within expressions to reduce data types to the minimum required.
Modifiers Three key words, together, allow us to write not only better code, but also tighter code: • static • volatile • const
Note: These variables won’t be stored in the Stack. Static Variables • The variable doesn’t disappear between successive invocations of a function. • When declared at the module level, it is accessible by all functions in all the module, but by no one else. • When applied to variables, static has two primary fuctions:
Before entering to MyFunctionthe first time, myVar =0 The static Variable keeps its value even thoughmyVaris local Before entering to MyFunctionfor the second time: myVar =1 Static variable Example FILE1.c #include <FILE2.h> includes functions contained in file FILE2.c void main (void){ MyFunction();included in FILE2.c MyFunction();included in FILE2.c } FILE2.c void MyFunction (void){ Definition of MyFunction in FILE2.C static charmyVar = 0; local variable declared static myVar = myVar + 1; }
Static Functions • Features: • Only callable by other functions within its module. • Good structured programming practice. • Can result in smaller and/or faster code. • Advantages: Since the compiler knows at compile time exactly what functions can call a given static function, it may strategically place the static function such that may be called using a short version of the call or jump instruction.
It is very good practice to declare volatile all Peripheral Registers in embedded devices. Volatile Variables • In embedded systems, there are two ways this can happen: • Via an interrupt service routine • As a consequence of hardware action A volatile variable is one whose value may be changed outside the normal program flow.
Without Volatile keyword MOV #5,PORTA LDA #10 STA @value With Volatile keyword MOV #5,PORTA MOV #5,PORTA LDA SCS1 LDX #10 STX @value Volatile variables are never Optimized • Access to variables defined as volatile are never optimized by the compiler !!! volatile unsigned charPORTA @0x00; volatile unsigned charSCS1@0x16; unsigned charvalue; void main(void){ PORTA = 0x05; /* PORTA = 00000101 */ PORTA = 0x05; /* PORTA = 00000101 */ SCS1; value= 10; } volatile volatile
Volatile variable Example /* MC68HC908GP20/32 Official Peripheral Register Names */ volatile unsigned char PORTA @0x0000; /* Ports and data direction */ volatile unsigned char PORTB @0x0001; volatile unsigned char PORTC @0x0002; volatile unsigned char PORTD @0x0003; volatile unsigned char PORTE @0x0008; volatile unsigned char DDRA @0x0004;/* Data Direction Registers */ volatile unsigned char DDRB @0x0005; volatile unsigned char DDRC @0x0006; volatile unsigned char DDRD @0x0007; volatile unsigned char DDRE @0x000C; volatile unsigned char PTAPUE @0x000D;/* Port pull-up enables */ volatile unsigned char PTCPUE @0x000E; volatile unsigned char PTDPUE @0x000F;
Const variables The Declaration constis applied to any variable, and it tells the compiler to store it in ROM code. The compiler keeps the program memory address of that location. Since it is in ROM, its value cannot be changed. An initialization value must be declared. Example: const double PI = 3.14159265;
Const constrains • Some compilers create a genuine variable in RAM to hold the const variable. On RAM-limited systems, this can be a significant penalty. • Some compilers, like CodeWarrior, store the variable in ROM. However, the “read only” variable is still treated as a variable and accessed as such, typically using some form of indexed addressing (16-bit). Compared to immediate addressing (8-bit), this method is normally much slower.
Const volatile variables Can a variable be both, const and volatile? Yes! This modifier form should be use on any memory location that can change unexpectedly (volatile) and that is read-only (const). The most obvious example of this is a hardware status register: /* SCI Status Register */ const volatile unsigned charSCS1 @0x0016
Architecture October 24, 2014
8 Keyboard Interrupts Upward HC05 Object Code Compatible CPU08 KBI PORTA 8 512 Bytes RAM RAM 8 Channel / 8-Bit Analog-to-Digital Converter 32,292 Bytes Flash Flash Single-Wire Development Interface MON ADC PORTB 8 Address-Match Hardware Breakpoints BRK Reset / Interrupt Priority Control SIM PORTC 7 External Interrupt IRQ Watchdog COP Low-Voltage Inhibit LVI PORTD 8 CGMC PORTE 2 MC68HC908GP32 • 33 Bi-directional I/O • All Ports Pins Rated for • 10mA Sink • 10mA Source TIM1 • Dual 2 Channel 16-Bit Timers • Input Capture • Output Compare • Pulse Width Modulation TIM2 32kHz Clock Generator Module SPI Time Base Module TBM SCI Synchronous Serial Peripheral Interface Asynchronous Serial Communications Interface DIP 40, QFP 44
Memory-Mapped Registers & Peripherals! (No Special I/O Instructions!) Direct Bit Manipulation in Page 0 Memory (Fast and Code Space Efficient!) 512B RAM Program and Data Memory ALL Addressable from Same Memory Map! (Easy to Use!) No Special Memory Pages! (Easy to Use!) 32K FLASH Can Perform Data Operations on Program Memory! (No Special I/O Instructions!) HC08GP32 Memory Organization $0000 Peripheral Registers $003F $0040 RAM $023F $0240 Unimplemented ROM or FLASH $7FFF $8000 $FE00 Control Registers $FE10 Monitor ROM $FF80 Vectors $FFFF
CPU October 24, 2014
7 0 15 H X Index Register (HX) 7 0 Two’s Compliment Overflow CPU08 Register Model Accumulator (A) 16-bit 16-bit 16-bit Easier Signed Arithmetic Index Register (X) 0 0 0 0 0 1 1 Stack Pointer (SP) X X X X X Program Counter (PC) V 1 1 H I N Z C Condition Code Register (CCR) Carry/Borrow (MSB) Zero Negative (MSB = 1) Interrupt Mask Half-Carry (for BCD)
CPU08 Registers The CPU08 has 5 registers which are not part of thememory map Accumulator The accumulator is a general purpose 8-bit register. The CPU uses theaccumulator to hold the operands and results of operations. Index Register The 16-bit index register is called H:X and is used by indexed addressingmodes to determine the effective address of an operand. The indexregister can access a 64K byte address space in this mode. The lowerbyte X is used to hold the operand for the MUL and DIV instructions. H:Xcan also serve as a temporary data storage location.
CPU08 Registers Stack Pointer The 16-bit stack pointer is used to hold the address of the next available location on the stack. The CPU uses the contents of the stack pointer register as an index to access operands on the stack in stack pointer offset addressing modes. The stack can be located anywhere where there is RAM in the 64K byte address space. The SP can also be used as an index like HX
CPU08 Registers Program Counter The 16-bit program counter contains the address of the next instruction or operand to be fetched. The program counter can access a 64K byte address space. Condition Code Register The 8-bit condition code register contains the global interrupt mask bit and five flags that indicate the results of the instruction just executed. Bits 5 and 6 are permanently set to logic 1.
HC08 Addressing Modes The CPU08 has 16 different addressing modes Inherent This instructions have no operand to fetch and require no operandaddress. Most are one byte long. Immediate The operand for immediate instructions is contained in the bytesimmediately following the opcode. Immediateinstructions thereforehave constant operands.
HC08 Addressing Modes Direct Direct instructions are used to access operands in the direct page, i.e. inthe address range $0000 to $00FF. The high-order byte of the addressis not included in the instruction, thus saving one byte and one executioncycle compared to extended addressing. Extended Extended instructions can access operands at any address in a64K byte memory map. All extended instructions are 3 bytes long. Relative All conditional branch instructions use relative addressing to evaluate theeffective address. If the branch condition is true, the CPU evaluates thebranch destination by adding the signed byte following the opcode to theprogram counter. The branch range is –128 to +127 bytes from theaddress after the branch instruction.
HC08 Addressing Modes Indexed • Indexed instructions use the contents of the 16-bit index register HX toaccess operands with variable addresses, such as variables accessedthrough a pointer. • There are five modes of indexed addressing: • No offset • 8-bit offset • 16-bit offset • No offset w/ post increment • 8-bit offset w/ post increment
HC08 Addressing Modes Stackpointer • Stack pointer instructions are similar to indexed instructions only theyuse the contents of the stack pointer as an address of the operandinstead of the index register. • There are two modes of stack pointeraddressing: • 8-bit offset • 16-bit offset • Stack pointer instructions require one extra byte and one extra executioncycle compared to the equivalent indexed instruction.
Assembly: foo: B00BA7FBAIS #-3 B00D 9EE701 STA 1,SP B010 A707 AIS #3 B012 81 RTS The Stack Pointer Importance typedef struct{ unsigned charID; unsigned short Time; } ObjectType; voidfoo(unsigned charvalue) { volatileObjectType instance; instance.ID = value; } A Stack Pointer Register supports very key features of C: • Passing variables to subroutines • Allows the use of recursion • Is the base of Automatic variables
HC08 Addressing Modes Memory to Memory • Memory to memory instructions copy data from one location to another. One of the locations is always in the direct page. • There are four modes of memory to memory instructions: • Move immediate to direct • Move direct to direct • Move indexed to direct with post increment • Move direct to indexed with post increment
Time Reference Program October 24, 2014