ADVANCED INDUSTRIAL LEVEL TRAINING IN LINUX BASED EMBEDDED SYSTEMS

ADVANCED INDUSTRIAL LEVEL TRAINING IN LINUX BASED EMBEDDED SYSTEMS
ADMISSIONS OPEN

Search This Blog

Thursday, 4 July 2013

THE CONCEPT OF PORTS


A port can be thought of as a data channel that comes into or goes out of the uC. There can be parallel ports (all data bits present on their own lines) and serial ports (data bits passed serially along one or more lines). A number of types of serial ports will be discussed in later chapters of this tutorial, but for now we'll just talk about GPIO ports. A GPIO port is a set of GPIO pins which are organized into a single N-bit (8/16/32 bit) word, and are thus written out and read in as operations on a single word. A uC can have one or more GPIO ports, and given port may be a full N-bits wide, or a given port may be fewer than N-bits. A shortened port (fewer than N-bits wide) usually exists because the chip designers simply ran out of pins for the extra GPIO bits. For example, a 28-pin, 8-bit microcontroller may dedicate 5 pins to power and GND, and all other pins are available as GPIO. That means 23 GPIO pins, which could be organized as two 8-bit ports and one 7-bit port.
A shortened port will still appear as a full N-bit value to the CPU, it is just that the bit positions that are not brought out to pins are unused, since they can never transmit or receive valid data. and must be ignored. Depending on the CPU design these unused bits may always read as 0s or they may read as undetermined values. The datasheet will give the details, and in any case, the unused bits should be masked out before using the port data.
You will also see this phenomenon of missing or unused bits in configuration registers. It is very common for a configuration register to have unused bits - sometimes a configuration register will only use a single bit in the register! Again, these unused bits may read as 0s or they may be indeterminate. When writing to a configuration register that has unused bits, the datasheet will tell you what values to write to those bits. Usually you are required to write 0s to the unused bits. One reason for this is that unused bit positions may become used in a future version of the device, and writing a 1 to a configuration bit is more likely to enable some feature - some feature you didn't intend, since the bit and the feature didn't even exist when you wrote the software. Just be safe and write the unused bits of any configuration register according to the datasheet. To sum up, mask out unused bits when reading ports or configuration registers, and set unused bits as per the datasheet when writing to ports or configuration registers.
Each GPIO port will have a number of data and configuration registers associated with it. These registers will access data read as inputs, hold data written as outputs, and will allow configuration settings (often for each individual GPIO pin) such as (depending on the device) data direction (input or output), built-in pullup/pulldowns, input hysteresis, output drive strength, and so on. All GPIO register information will be found in the datasheet.

A NOTE ON THE EXAMPLE PROGRAMS


Each tutorial section will include a number of short example programs. The examples will start with the simplest concepts and add some concepts in each succeeding program. Along the way, some comments will be trimmed to try and help keep the visual clutter down and keep the focus on the newer concepts being presented. As an example, comments to the effect that "this bit/port/address needs to be adjusted for your particular hardware" will eventually disappear, because by then you should know that e.g. if I am discussing an LED output on PORTA bit 0 and on your hardware you are using an LED on PORTB bit 7 then you'll make that change accordingly. Or when I mention in the first programs that after a "ret" instruction that you'd better have set up the stack first, after a while that comment and others like it will disappear.

ONES AND ZEROS,HIGHS AND LOWS


As you should already know, a computer program manipulates data in the form of binary digits, 1s and 0s. This data may represent characters, times, temperatures, button pushes, alarm signals, screen pixels, the list is almost endless. But in the computer it's all 1s and 0s. When any computer, and in particular a microcontroller, interfaces with the real world as it must, there must be a translation between these 1s and 0s and external voltages on the device pins. It is enough now to know that externally a 1 will be represented to and from the uC by a high voltage (we'll talk later about how high is high) and a 0 will be represented by a low voltage (again, details will follow). Like every other rule there can be exceptions, but for now just remember 1=high, 0=low. We will try to use "1" and "0" when talking about logical states (the data in the program) and "high" and "low" when talking about signals external to the uC, but we may fuzz up that dividing line now and then.

HOW DOES AN EMBEDDED PROGRAM RUN ??


Before talking much more about embedded programming, this is a good place to give a brief overview of how an embedded program starts up and runs.  Assuming that you have generated a program file and have loaded it into the μC program memory (all steps that we will talk about later), the good stuff happens when you either turn on the device or you push the RESET button.  When the μC comes out of reset it will always go to a particular memory location, as defined by the manufacturer, to begin executing whatever code is found there.  Sometimes this memory location is defined directly, e.g. “upon coming out of reset, program execution begins at program address 0”.  Other times the fixed memory location is a vector, a location that holds the actual address of the beginning of the program, e.g. “upon coming out of reset, the controller will load its program counter with the value found at program address 0xFFFE”.  In the first instance you will have to make sure that your program has loaded at the specified startup address, while in the second instance you will load your program wherever the program memory has been placed in the controller address space, and you will have to make sure that you then load that startup address into the reset address vector.
When an embedded program starts to run, there is usually a fair amount of initialization and housekeeping that must be done before the “meat” of the program begins.  Most of this initialization is something that the average desktop programmer never sees, since it is handled by the computer boot code and operating system.  But in an embedded system, it is just as likely as not that there is no operating system, and all boot code and other startup code must be explicitly provided.  Some very critical hardware may need to be initialized first e.g. hardware that controls memory access times and address maps, as well as system clock hardware.  Then some software initialization may need to happen, such as setting up a stack pointer and perhaps copying data from nonvolatile memory to volatile memory where it can be accessed and perhaps modified.  After that will usually come another round of hardware initialization, setting up any peripheral devices that the system requires, and setting initial output states.  Finally, yet another round of software initialization may occur.
This initialization is usually broken up into two sections, with the first hardware and software initialization steps often being done in what is known as the startup code, and the later hardware and software steps being done in the user program.  This delineation is more distinct in a C program, where the startup code is invisible to the C program, being the code that happens before main() is run, and ending in a jump or call to main() where the “visible” C program begins.  In an assembler program all the initialization steps may be equally visible in the user code, although even then the first steps may reside in a separate startup source file.

WHICH PROGRAMMING LANGUAGE ??


This is a good time to talk about the various programming languages that one can use to write embedded software.  The two languages I will use in this tutorial are C and assembly language.  The first thing I want to point out is that these are not the only two languages available to embedded programmers, and that in many cases other languages may be a better choice.  That being said, both C and assembly language are useful not only for learning about embedded programming, but also for actually doing productive embedded programming.  They are also ubiquitous in that no matter what microcontroller you choose, it will almost certainly have available both an assembler (for converting assembly language code) and a C compiler (for converting C code).  The same is definitely not the case for other languages.  But I would encourage you to consider other languages if you are so inclined and, big IF, if they are available for your device family.
On the subject of assembly language, even if you don’t plan on using assembly language in your embedded programming, I would strongly suggest that you become at least somewhat familiar with the concepts, and with the instruction set of your uC.  The reason for this is that, even if you don’t end up writing any assembly language, you will find yourself at some point needing to examine the output of your compiler and/or your compiler-supplied startup files written or output in assembly language.
Also note that the term "assembly language" will often be shortened, in this tutorial and elsewhere, to "asm" or "ASM."

WHAT ELSE IS REQUIRED FOR THIS TUTORIAL ??

While you could, I suppose, work through this tutorial using just a microcontroller simulator, I strongly recommend that you have either a microcontroller training/development board, or even just a bare μC chip, assorted components and a powered breadboard.  In addition you will need an assembler for your device, and optionally a C compiler that targets your device.  You should have no trouble finding a free assembler for your chip, and you should also be able to find a free C compiler, even if it is a reduced-functionality version of a commercial compiler.  You will also need a method of downloading your programs into your μC.  The details of this download process will depend intimately on the particular μC.
These are the details of the hardware and tools used for each of the processor families:

8051-

keil microvision 4 IDE
flash magic flasher software

PIC-

mplab IDE
PIC kit2 programmer
Mikro c 

ARM-

keil microvision IDE 3 for ARM
HTAG V6.0
Philips flash utility

WHAT MICROCONTROLLER FAMILIES ARE USED IN THIS TUTORIAL ??


To give a good overview of the different “flavors” of microcontrollers available, this tutorial will be written around 2 8-bit family (the 8051 and PIC ) and one 32-bit family (the ARM7TDMI architecture in the form of the NXP LPC2xxx family).  These families were chosen to give a broad picture of the devices and approaches found in the world of microcontrollers.  Most software examples will be written in embedded C for each of these families, as well as in assembly language.