Sample program to demonstrate using the Mega103 analog to digital converter (ADC) in conjunction with the Idle sleep mode during sampling and Power Save sleep mode between samples for lowest possible power when the cpu must restart itself. Note that if the cpu can be interrupted by an external event, you could use the Power Down mode for even lower power.

For demonstration purposes, the high 8 bits of channel 3 (10-2) are written to PORTB, the set of LEDs on an STK300.

//-----------------------------------------------------------------------------// The current AtoD conversion has completed. Copy the value (in ADCH and ADCL)// to the current array location.//SIGNAL(SIG_ADC){ // Read the ADC into the current entry // Sample[Index] = inp(ADCL) | inp(ADCH)&lt;&lt;8;}

The first ADC control example uses the Idle sleep mode and a simpledelay loop between samples, and the use of a pointer to write to theoutput array. The latter is hardly warranted in this case, but if theoutput array was two-dimensional it would make sense. Note the use of sbi/cbi instructions setting bits on PORTA. This is a very good debug tool if you have access to an oscilloscope.

//---------------------------------------------------------------------// Control the ADC for an eight channel sample using the inbuilt noise// cancelling capability.//void AtoDconverter(void){ sbi(PORTA, 1); // for scoping

This example will show how to configure and use the Analog toDigital Converter (ADC) in the Atmel Mega103 micro. It will also showhow to use the sleep instruction in conjunction with the ADC tominimise digital noise from the cpu. I will start with the simplestnon-interrupt code and progress to using interrupts and power savingtechniques. I assume you have the Mega103 Manual open at the section onthe ADC for reference.

The '103 has a ten bit analog to digital converter (ADC) as part ofits peripheral equipment. It includes simple multiplexer control andconfiguration and there is no specific initialisation required.Starting a reading consists of selecting the channel and setting theADSC bit in the ADCSR control register:

outp(channel, ADMUX); outp(ADC_CONTROL | 1&lt;&lt;ADSC, ADCSR);

The ADC_CONTROL is a local define that combines the specific ADCSR bits I am using here.

#define ADC_CONTROL (1&lt;&lt;ADEN | 1&lt;&lt;ADPS2 | 1&lt;&lt;ADPS0)

This enables the ADC and selects a divide by 32 clock which, with a4 Mhz cpu clock, gives an ADC clock of 125 Khz. The specificationquotes 2 bits accuracy at 200 Khz, so there is little advantage in aslower clock. Note that constants like ADEN are defined as a bitposition (ADEN=7), whereas I am going to use this define in an outpinstruction where the same bit is represented by the unsigned byte0x80. If you shift 1 left 7 times you get 0x80. Hence the strangelooking 1&lt;&lt;ADEN.

When the conversion is complete the ADIF bit will go high. Thus the wait-until-done code is:

while (!(inp(ADCSR) & 1&lt;&lt;ADIF)) {;} sbi(ADCSR, ADIF);

This loop will exit when the conversion is complete. The last lineclears the ADIF bit by setting it (Atmel weird!). Note that aninstruction like sbirequires the bit position, so thereis no need for funny shifts. All that is then required is to read theresult into an integer variable. Because this is 10-bits, it requires atwo stage read. You must first read the low byte, then the high byte:

This works well but does not take advantage of the low noisecapability of the '103 where the cpu can be turned off during theconversion. However, to use this mode requires enabling interrupts.

Using interrupts actually makes for simpler code once you decide tobite the bullet. The following code snippet assumes you have enabledglobal interrupts elsewhere. The ADC uses the sleep instruction in Idlemode (see Using the Sleep Instruction)as the clocks must still run but the cpu can be turned off. Note that Ihave re-defined the ADC_CONTROL variable to include the interruptenable.

You need to be sure that no other interrupt can occur during the conversion other than the ADC itself, as anyinterrupt will wake up the processor and the current sample will belost. In a complex system where perhaps internal timers and/or externalevents are using interrupts for response, it is very difficult toensure an asynchronous interrupt will not occur during a conversion.Designing around this can be very difficult where low noise isparamount. Because you must use the Idle sleep mode to ensurenoise from the cpu does not interfere, you must run the ADC underinterrupt control. Thus you need to come up with a system that disablesinterrupts from any peripheral where they could occur asynchronously,before starting the ADC sample sequence. The multi module version ofthese ADC examples that uses TaskR for task management shows onepossible solution.

In most cases the results captured in the ADC handler must be storedelsewhere for subsequent processing. Most likely a mathematicalconversion will be required to present the results in SI units. Theseconversions and transfers are usually done after the sample set istaken to ensure the measurements themselves are as close together intime as possible. Where speed or storage are at a premium, you coulduse global pointers to manage the storage task. It is also possible tostore the data by channel (rather than by sample data set) using anarray of pointers. For example the ADC control loop would remain thesame, but the interrupt routine would look something like:

SIGNAL(SIG_ADC){ *Pointer[Index]++ = inp(ADCL) | inp(ADCH)&lt;&lt;8;}

where Pointer[0] points at the data storage area for channel 0,Pointer[1] for channel 1, etc. By incrementing the pointer in each casethe data for each channel will go into contiguous arrays. Of coursethere would need to be some test that the arrays had eventually filledand the pointers reset to the start of the buffers.

The following two examples provide a convenient way to test thesealgorithms on your STK300 or similar board. Simply cut and past fromthe browser into your favourite editor. Note that it assumes the files below are called main.c.

Tuesday, February 19, 2008

The attiny2313 has a built in UART for serial communication. You
need a few outside parts to allow it to communicate with a PC over a
serial connection. The attiny2313 uses TTL signals. You have to convert
them to true RS232 signals using an external converter. For this
example I will use a MAX232.

The AVR has an internal RC oscillator. The Atmel data sheet says
this oscillator is calibrated to within +- 10%. You may be able to get
a serial connection to work, but because of the margin of error it is
best to have your chip use an external watch crystal instead of the
internal RC oscillator. I have been successful in getting serial
communication to work using only the internal RC oscillator but your
mileage may vary.

Parts list:

1 MAX232IN ( mouser 595-MAX232IN)

4 16V 10uF capacitors ( mouser 140-MLRL16V10-RC)

1 3.6846 cyrstal

2 20pf capacitors

1 DB9 female serial connector

Below is the wireing schematic:

To get the AVR to use the external 3.6846 crystal instead of the
internal RC oscillator I had to burn the fuses. I am using linux and
avrdude, so I ran this command:

avrdude -p attiny2313 -P /dev/parport0 -c dt006 -u -U lfuse:w:0xed:m

Now the avr will only run with the external crystal.

First we look at the data sheet see what UBRRL needs to be set for
our baud rate and crystal. We will be transmitting at 2400 baud.

On the PC side I will be using minicom on a linux PC. Set minicom
(or hyperterminal on windows) to 2400 baud, 8N1. Minicom gave me a few
problems when it would first connect to the AVR. To get around this, I
would start minicom, then AFTER minicom was running, I would power up
the AVR. I am not sure why this happened. If I started minicom after
the AVR was powered up, I would get some garbage characters only.

This sample program will have the Avr listen for a character, then
transmit back the next highest character. So if you type in the letter
“B”, the avr will send be the letter “C”. (This program is written C
and should would with the gcc compiler)

NOTE : - This document was last found on the avrfreaks website. This got deleted from there for some reason. I have had updated this document for better understanding. In case if you have any update [correction] on this please leave the feedback.

Monday, February 18, 2008

WinAVR comes withProgrammers Notepad UI by default. It is very powerful editor, but ifyou want more robust UI with better project management abilities youcan try Java based EclipseIDE. It is universal open source IDE which supports almost any compilerby using plugins. Eclipse has some nice features that makes itattractive, like Subversion integration, code completion in editor.

Thomas Hollandhas been working on AVR plugin for Eclipse which allows to use Eclipsefeatures with AVR-GCC compiler. The newest release has nice set offeatures and updates like: automatic makefile generation, MCU type andclock frequency can be selected during project creation, project can becompiled for debug only or as complete release with flashable hexfiles, tool-chain has integrated assembler, nice viewer showinginformation about processor used where you can find all registers,ports, interrupts in one convenient place for quick pick-up.

Eclipsedoesn't require installation, just extract to some directory. You justneed to set path to projects folder during first run. AVR Pluginalso doesn't need any special installations, just extract to Eclipsedirectory and thats it. Also plugin can be installed remotely by usingEclipse Software update feature.

Ijust tried to compile one of my project with this environment – itworked without problems. Lets go through how to compile your firstAVR-GCC project in Eclipse IDE. First of all make sure you have latest WinAVR tools installed. Then download Eclipse for C/C++ for Windows platform:

Extract it to some directory. Then download plugin and extract it to Eclipse directory(just follow original explanation).When its all set, we can start new project. I am using project filescreated so I will need to add then to Eclipse project only. But firstof all... In Eclipse select New-&gt;Project and then select C Project.

Select AVR Cross Target Application In Toolchain section you can see WinAVR Toolchainselected. Enter project name and click Next. In next window you willhave to select build configurations that include various settings thathave to be included in makefile. Settings can be saved separately fordebug and release configurations. Lets say wee select Releaseconfiguration.

By pressing advanced settings you may change additional makefile settings. But lets leave then by default. Press Next button.

Here you must select AVR microcontroller and its clock frequency. After selections are done click Finishbutton to prepare new project. To add files to project you can createnew or add existing source files. I just used drag and drop feature toadd files to project tree. Files also are copied to project folderphysically.

Imade IDE window smaller to show how all workspace look like. In theleft you can see project tree where source files are added. Next windowis for file contents. Then goes project outline. And the bottom are hasseveral tabs for displaying problems, properties, console and earliermentioned AVR device explorer. I really like the way Eclipse extractsoutline from source file. It is easy to find and navigate by selectingvariables, functions and defines. Source code outlining is alsopleasing. Even things like #ifdef ...#endif areas are greyed if notdefined.

Compiledrelease is placed in different folder where all object, hex and othercompilation products are saved – this way it keeps source folder clean.

Myfirst impression with AVR Plugin for Eclipse is very good. I would saythis is must try tool. As it is quite new plugin, I would expect bugsor problems appearing. I think main problems may appear with makefilegeneration, so you can always use external makefile if needed. As faras I tested this plugin with basic AVR programs it worked withoutproblems.

Some good news for thosewho are tired of writing same program parts every time. Most timeconsumption is during initial code writing. The guy named tcg inavrfreaks have decided to write code generating tool which could robustmost common tasks.

Currentversion of program is v0.009 (early beta stage of program) but italready support baud calculator, timer calculator, multitaskinggenerator, interrupts, ports and more. But there are several thing tobe done like TWI, USI. As Author states there is lots of testing to bedone. Project is open for new ideas and suggestions.

Nicething I like about it that program is capable to generate codeinstantly. It can be saved as single file or whole Avr Studio projectwith makefile which is ready to compile instantly.

Because AVRmicrocontrollers are Harvard architecture they have separate addressspaces for different memory types: SRAM, FLASH and EEPROM. Each ofthese memories have their own purposes. If data will not change duringall time of program execution, then it should be stored as one type ofmemory like EEPROM otherwise if data will be used frequently and willchange during program execution, then it should be stored in SRAMmemory. Where to store data decides program developer. One thing youshould note, that working with different types of memories requiredifferent operations how they are accessed.

Usually when define variables in C language like int a – compiler automatically stores it in to the SRAM. But if you want you can place constants in EEPROM or even FLASH memories.

AsI mentioned no specific operations aren't needed to work with variablessored in SRAM. Lets go through other two memory types FLASH and EEPROM.

Lets say we decide to store some information to FLASH in order to save space in SRAM. Then we

need to show compiler to store this information to FLASH memory. For this wee will need additionally library: #include &lt;avr/pgmspace.h&gt;. Now wee can declare data to be stored in FLASH memory:

For reading from FLASH usually use pgm_read_byte() function like in this example:

uint8_t a, i;

for(i=0;pgm_read_byte(&backslash[i]);i++)

{

a=pgm_read_byte(&backslash[i]);

}

this way you can store and read bytes, words and double words by using commands:

pgm_read_byte()

pgm_read_word()

pgm_read_dword()

If you will read pgmspace library documentation you will see that instead const uint8_t backslash[] PROGMEM you can use const prog_uint8_t backslash[]

Here is a working example of program:

#include &lt;avr\io.h&gt;

#include &lt;avr\iom8.h&gt;

#include &lt;avr\pgmspace.h&gt;

const prog_uint8_t backslash[]=

{

0b00000000,//back slash

0b00010000,

0b00001000,

0b00000100,

0b00000010,

0b00000001,

0b00000000,

0b00000000

};

int main(void) {

uint8_t a, i;

for(i=0;pgm_read_byte(&backslash[i]);i++)

{

a=pgm_read_byte(&backslash[i]);

}

while(1) {

}

}

Char types

As it is important to understand variable types in AVR-GCC lest take a deeper look at this.

Choosingproper variable type sometimes may be crucial in designing embeddedsoftware as microcontroller resources are limited. Choice of propervariable type may save lots of time and space of your program.

Whatis common variable type in 8 bit system? Of course byte or so calledchar type. Char name comes from word “character” because char typeusually is used to store character symbols (ASCII). Char type can havevalues from -128 to +127 while unsigned char may have values from 0 to256. Some compilers may use byte type instead of unsigned char.

All AVR ports haveRead-modify-write functionality when used as genera I/O ports.Direction of separate port pin can be changed. Each pin buffer hassymmetric capability to drive and sink source. Pin driver is strongenough to drive LED directly , but it is not recommended. All port pinshave selectable pull-up resistors. All pins have protection diodes toboth VCC and GND.

Eachport consists of three registers DDRx, PORTx and PINx (where x meansport letter). DDRx register selects direction of port pins. If logicone is written to DDRx then port is configured to be as output. Zeromeans that port is configured as input. If DDRx is written zero andPORTx is written logic “1” then port is configured as input withinternal pull-up resistor. Otherwise if PORTx is written to zero, thenport is configured as input but pins are set to tri-state and you mightneed to connect external pull-up resistors.

If PORTx is written to logic “1” and DDRx is set to “1”, then port pin is driven high. And if PORTx=0, then port is driven low.

Letsmove to C. How we can control AVR port pins? When using WinAVR GCCfirst we need to set up proper library where PORT register names havetheir addresses defined. Main library where general purpose registersare defined is io.h located in avr directory of WINAVR installationlocation.

#include &lt;avr/io.h&gt;

Nowwe can use port names instead of their addresses. For instance if wewant to set all pins of PORTD as output we simply write:

DDRD=0xFF; //set port D pins as outputs

Now we can output a number to port D:

PORTD=0x0F; //port pins will be set to 00001111

if we have 8 bit variable i we can assign this variable to port register like this:

uint8_t i=0x54;

PORTD=i;

Lets read port D pins:

DDRD=0; //set all port D pins as input

i=PIND; //read all 8 pin bits of port Dand store to variable i

There is ability to access separate port pins. So all eight port pins can be used for multiple purposes.

Some of the pins may be configured as outputs and some as inputs and performs different functions.

Lets say we need 0,2,4,6 pins to be as input and 1,3,5,7 as output. Then we do like this:

DDRD=0; //reset all bits to zero

DDRD|=(1&lt;&lt;1)|(1&lt;&lt;3)|(1&lt;&lt;5)|(1&lt;&lt;7); //using bitshift “&lt;&lt;”operation and logical OR to set bits 1,3,5,7 to “1”

Youcan read 1 and 3 bits by using masks or simply shift i value by 1 ar 3positions to compare LSB with 1. Of course there are some functions insfr_defs.h library like bit_is_set() or bit_is_clear() to check particular bits and make these tasks little easier.

Following example should clarify some issues:

#include "avr\io.h"

#include "avr\iom8.h"

int main(void) {

DDRD&=~_BV(0);//set PORTD pin0 to zero as input

PORTD|=_BV(0);//Enable pull up

PORTD|=_BV(1);//led OFF

DDRD|=_BV(1);//set PORTD pin1 to one as output

while(1) {

if (bit_is_clear(PIND, 0))//if button is pressed

{

PORTD&=~_BV(1);//led ON

loop_until_bit_is_set(PIND, 0);//LED ON while Button is pressd

PORTD|=_BV(1);//led OFF

}

}

}

Microcontrollers without interrupts are almostworthless. Interrupt is called what interrupts normal program flow.Interrupts are nothing more than subroutines that put on hold normalprogram flow while they are executed. After interrupt subroutines arefinished they return to normal from last point. Those subroutines arecalled interrupt handlers that are called by some event like toggleexternal pin or some register value overfilled like timer overflow andso on.Why interrupts are so important? For instance withoutinterrupts you would have to do loops in order to check if one oranother event occurred. This operation is called polling. But poolinghas many disadvantages like program have do loops taking resources fromother task may be done. This is why microcontroller comes with multipleinterrupt sources. Instead of checking events microcontroller hasability to interrupt normal program flow on event and jump to interruptservice subroutine and then get back to normal program flow.

Whathappens when interrupt occurs? After interrupt event microcontrollerstops the task at current point, saves current information to stack andgives its resources to interrupt subroutine. When interrupt subroutineis finished last program point is restored and program flow continues.

In assembly language your program usually would start with interrupt table:

Thistable indicates where all interrupt subroutines are located. Afterparticular interrupt occurs, program pointer jumps to interrupt tablewhere it is directed to interrupt subroutine location.

Forinstance every time you power up microcontroller program pointer jumpsto location $000 where it is directed to (RESET) location. With Cprogram this would be location of main() function.

CCompiler creates this table while compiling the source code. But how todescribe interrupts handling routines in C language using WinAVRtoolset. All time when compilers are improving, there is no agreementhow to handle interrupt code. As compilers tries to stay away frommachine dependant details, each compiler is designed with their ownmethods. AVR-GCCisn’t exception. There each interrupt is pointed with predefined names– you will find in microcontroller definition header file like iniom8.h.

Defining the interrupt routines is ease…

First of all include desired library that compiler could understand interrupt macro commands:

#include &lt;avr/interrupt.h&gt;

All interrupts then can be described using macro command: ISR(), for instance:

ISR(ADC_vect)

{

//Your code here

}

Thissubroutine is for ADC conversion complete handler. Macro command ISR()is convenient for handling all unexpected interrupts. Just createroutine like this;

ISR(_vector_default)

{

//your code here;

}

If you want to describe an empty interrupt for particular event (puts “reti” command in interrupt table) just use:

In earlier versions of WINAVR there were SIGNAL() macro used. Now this is the same as ISR() and not used anymore.

Anotherinteresting interrupt handling macro is ISR_ALIAS(vector,target_vector). This is used when you need to pint one vector o anothervector. This way you may handle multiple interrupts with singleimplementation, for instance:

Monday, February 11, 2008

execute the following when the external ISP stimuli (such as a UART string, switch press or whatever) occur:

mov a,#2

mov r5,#1

mov R7,#3

lcall 0ff00h

Then the program hums happily till the next power-on-reset after which it is in 'virgin chip boot mode' i.e. it will expect and accept FlashMagic input.

This can be automated further by engaging the watchdog after the code above and let it time out generating the reset. By that, in combination with a 'unique serial string activate', you can create a system that requires nothing more than connect the serial cable and run the PC.

This way a simple Rxd/Txd 232 chip (externally) connected to the PC is all that is required as opposed to the 'cut the power, bang the reset' etc that a pure hardware ISP entry require.

It is recommended that, during development, you include the above very early in the code activated by e.g. TXD held low. This will allow simple ISP activation when your code has a bug that does not let it reach the ‘customer activation’.

NOTE: when the chip comes from the factory it will automatically go to ISP, so no ‘first time mode’ is required.

The Philips P89C51Rx2 and P89C66x both have a modifiable “boot vector”.

This is a problem in the case where the bootvector (accidentially) get changed because changing the bootvector makes it impossible to do IAP (in application programming)

This article covers providing a back door for IAP when the boot vector is lost (I still consider it the only bad thing about these chips that the vector is not fixed)

NOTE:

nothing here will work after the fact, this MUST be done before you lose the bootvector.

The page numbers refer to AN461 2002 jun 24.

The NoTouch should still be included as described in my article for regular program maintenance; however, to be able to rescue the chip when a mistake in the just uploaded code does not allow the program to get to the NoTouch upload an emergency exit should be provided. This "emergency exit" also allow you to lose the boot vector and still provide ISP.

To provide this "emergency exit" include the following the very first time you boot, after that you can forget about bootvectors and the other stuff

where your program looks like

org 0

ljmp xxxyyy

...

xxxyyy:

change to

org 0

ljmp bootck

bootck:

jbP3.1,xxxyyy ;TxD always high without cliplead

movAUXR1,#020h;enable boot

!!insert parametres for set bootvector as in AN 461 pg 14

call 0fff0h

!! insert parametres for setstatus byte as in AN 461 pg 14

call 0fff0h

jmp$;wait for reset

xxxyyy:as in your original code

Now when emergency strikes, just use a cliplead to hold TxD to ground, reset, remove the

cliplead, reset again and you are booting.

Of course, this only works if you have Vpp at +5 (where it should be as !EA anyhow) and P2.6, P2.7 allowed high.

“Touchless” ISP/IAP of the Philips 89C51Rx2 and 89C66x

Programming the Philips 89C51Rx2 without access to the circuit board using FlashMagic.

Many 8051 derivatives from several manufacturers have the ability to enter “boot mode” by applying certain voltage levels to certain pins, usually during reset. A study found that for our purpose (“touchless” ISP/IAP) the only solution would be the Philips 89C51Rx2 or the Philips 89C66x. Since we occasionally experience very high levels of EMI a secondary reason to chose the Philips 89C51RD2 was that the built-in bootloader is in ROM and thus can not be destroyed by EMI which may scramble flash memory. While the “touchless” ISP/IAP will not function in case of a scrambled flash the Philips 89C51Rx2 can still be programmed in the circuit. While it is a fact that an EMI caused scramble of a specific flash location ( boot vector ) would disable this the statistical likelihood of being unable to perform ISP is greatly reduced. I do not understand why Philips when they did the right thing by using ROM rather than flash for the bootloader did not hard code the boot vector to avoid this problem.

The built in ROM code for Flash programming in the Philips 89C51Rx2 microcontrollers allow several means of Programming, AN-461 describes them in some detail. AN-461 may leave you with the impression that you need switches or latches on the board to accomplish this, that, however, is not necessarily the case. This document assumes you are familiar with the concepts described in AN-461 and the operation of FlashMagic. Figure 2 and figure 3 in AN-461 show the basis for this process. An absolute condition for achieving “touchless” ISP/IAP is that you do not use external code memory which, in most cases, should not be necessary since the Philips 89C51RD2 gives you 64k of internal code space. Also, if you employ bank switching, FlashMagic will not serve your programming needs. To achieve “touchless” ISP/IAP it is necessary to tie !EA/Vpp directly to the 5V supply, thus no external code memory can be used. It is also a condition that nothing pulls P2.6 and P2.7 down after reset is applied when the application code is not running. I suggest tying these 2 pins to Vcc through each a 10k resistor as an extra safety. A RS-232 port is required as well, but that will be the case whether the ISP/IAP is “touchless” or not. The process is simpler if the application uses the watchdog, if not, an additional power off, power on step will be required.

To initiate “touchless” ISP/IAP some action, such as a signal on the serial port, a special keyboard sequence or a command from the PC mentioned below, must cause the application code to call the GoToBoot assembly code shown below. During program development it may be advisable to also activate this if a specific port pin is held low.

It is suggested that the minimal code shown below is written as an entire program with e.g. p1.0 low as the trigger. This can then be loaded using a few clip leads using “standard logic level based ISP”. Once this is accomplished program development can progress using NoTouch ISP simply adding the desired code to the above.Application code in “C”, equivalent in assembler will work as well:

if (request_for_program_replacement_detected)

{

GoToBoot();

//above does not return, a reset will follow

}

Assembly code:

Note that the r0 value (20 shown here) must be set per AN-461 pg 9 “The oscillator frequency is an integer rounded down to the nearest megahertz”. The remaining code and values are constant for this application.

AUXR1 DATA 0A2h ;

WDTRST DATA 0A6h ;

PUBLIC GoToBoot

BOOTIT SEGMENT CODE

RSEG BOOTIT

GoToBoot:

mov AUXR1,#020h ;enable boot

mov r0,#20 ;oscillator freq = 20Mhz

mov r1,#6h ;program status byte

mov dptr,#0 ;specify status byte

mov a,#0ffh ;nonzero required

call 0fff0h

jmp $ ;wait for watchdog to reset

end

The process is:

1a) If the chosen method for entering “touchless” ISP/IAP is a command from a PC, connect a PC to the serial port and issue the command.

1b) Else use the chosen means to make the application code execute the above routine, then connect a PC to the serial port.

2) Use FlashMagic or some such program to program the microcontroller.

3) Power off the microcontroller.

4) Power on the microcontroller and the updated application will start.

Simple, isn’t it.

This method may, of course, be used even if the program is not updated through a PC running a program such as FlashMagic, the data stream may be issued by any means as long as it conforms to the record format specifications in the data sheet.

Just a note: With the latest version of FlashMagic and P89C51Rx2 rev G or later FlashMagic in combination with the boot ROM has the ability to use the watchdog to reset the microcontroller after the load is complete steps 3) and 4) can be omitted.

Friday, February 8, 2008

Intro

This document describes some prototype USB-to-JTAG interfaces I builtwith the FTDIChip FT2232C device. The primary purpose was to developa USB-connectable JTAG interface for the Open On-Chip DebuggerOpenOCD.

One very useful feature of the FTDIChip FT2232C devices is that it can drivea fast synchronous serial interface like SPI or JTAG. To do that, channel oneof the two-channel FT2232C has to be switched to "MPSSE" mode. The maximumclock frequency to achieve is about 6 MHz.

The other channel of the FT2232C is available for arbitrary other tasks. Atypical usage is to establish a UART connection to a microprocessor targetwhile channel one at the same time serves a JTAG connection.

Note that all the JTAG interfaces built with the FT2232C lack theadaptive clocking feature, i.e. the RTCK (return clock) JTAG signal offeredby some ARM controllers, e.g. the Oki 67Q4xxx, is not supported.

Prototype 1

Figure: Photography of the first prototype

This was the very first demonstrator to show that a JTAG port can bedriven with a FT2232C chip (I think it was in 2004). I mounted a readyto use FT2232M module by DLP Design on aprototyping PCB and did the wiring by hand. You can buy these modulese.g. at Elektronikladen orUnitronic.

Joern Kaipf's OOCD-Link

[2006-02-26] During Embedded World 2006 I came into contact with Joern Kaipf.He designed a JTAG interface with MAXIM level shifters which supports a targetvoltage range from 1.2 to 3.6 Volt. The following photography shows thisboard.

One year later I met Joern at Embedded World 2007. He now also has built aversion of the OOCD-Link adaptor which directly uses the FT2232 signals todrive the target. This works for targets running with 3.3V and 5V. A niceadditional feature is the 10-pin header which carries the UART signals ofchannel B. The adaptor is called "OOCD-Link-S". Please see the followingphotography:

Joern will give the PCB files to anyone who is interested in buildingsuch an adaptor. His E-mail address is joern (at) joernline.de. Seealso Joern's homepage http://www.joernonline.de.

The commercial adaptors

The following adaptors are all based on my original design using theFT2232. However the commercial adaptors have a differing pin usage andhave much better support for a wide target voltage range than myoriginal prototypes.

Amontec JTAGkey and JTAGkey-Tiny

Amontec sells a USB-to-JTAG interface also based on the FT2232C.It does not use the I-Coupler but much faster buffer devices specialized forlevel shifting (but not for electrical isolation). Target voltages down to1.8V are supported. Please see the following link to the "JTAGkey":http://www.amontec.com/jtagkey.shtmlNote that the JTAGkey uses a wiring of the FT2232 signals different frommy schematic.

Amontec JTAGkey (129 Euro)

Due to the rather high price for JTAGkey Amontec later designed a cheaperJTAG adaptor, the JTAGkey-Tiny. I recommend to buy this adaptorbecause it is really "tiny" and its price is reasonable. It directlyfits into a standard 20-pin JTAG header. On the side opposed to theJTAG header it has a Mini-USB connector with 5 pins.

Amontec JTAGkey-Tiny (29 Euro)

Olimex USB-JTAG

Olimex manufactures and sells many variants of reasonably priced ARM7and ARM9 board. If you consider to start with ARM controllers youshould go to http://www.olimex.com. They alsohave the following JTAG adaptors supported by OpenOCD: