Search This Blog

Thursday, February 28, 2008

Idle and Power Save ADC Example ( Mega )

The second ADC control example is rather more ambitious and uses
both the Idle and Power Save sleep modes. The sample period is set via
an interrupt from Timer0.



/******************************************************************************

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.

Ron Kreymborg
May 2001

******************************************************************************/

#include <stdlib.h>
#include <interrupt.h>
#include <signal.h>

#define BYTE unsigned char
#define SLEEP asm("sleep"::)
#define CLK0_DIVIDER 0x05 // PCK0 / 128
#define CLK0_COUNT 256-128 // 500 mSec tick
#define ADC_CONTROL (1<<ADEN | 1<<ADIE | 1<<ADPS2 | 1<<ADPS0)

typedef enum
{
UNDEFINED_MODE,
POWER_SAVE_MODE,
IDLE_MODE
} MODE;

int main(void);
void AtoDconverter(void);
void SetPowerSaveMode(MODE type);
void InitAtoD(void);
void InitTicker(void);
void StartupDelay(void);

static volatile int Sample[8]; // a/d converter samples
static volatile BYTE Index; // current sample

int main(void)
{
// PORTB
outp(0xff, PORTB); // all low
outp(0xff, DDRB); // all output
sbi(ACSR, ACD); // disable comparator

InitTicker(); // configure Timer0
InitAtoD(); // init the A/D converter

StartupDelay(); // allow clocks to settle
sei(); // hello world

AtoDconverter(); // never comes back

return 0;
}

//---------------------------------------------------------------------
//
void AtoDconverter(void)
{
BYTE value;

while (1)
{
SLEEP; // power save sleep

// Ensure sleep mode during conversions is Idle mode.
//
SetPowerSaveMode(IDLE_MODE);

// Take the current sample readings
//
for (Index=0; Index < 8; Index++)
{
cbi(ADCSR, ADEN); // turn off ADC
outp(Index, ADMUX); // select the channel
outp(ADC_CONTROL | 1<<ADSC, ADCSR); // turn ADC on and start conversion
SLEEP; // idle sleep
}

// Restore sleep mode to Power Save for maximum power savings.
//
SetPowerSaveMode(POWER_SAVE_MODE);

value = ~(Sample[2]>>2); // display channel 3
outp(value, PORTB);
}
}

//-----------------------------------------------------------------------------
//
void InitAtoD(void)
{
// Enable ADC with a 125,000 KHz clock
//
outp(ADC_SAMPLE, ADCSR);

// Setup to start in Power Save sleep mode
//
SetPowerSaveMode(POWER_SAVE_MODE);
}

//---------------------------------------------------------------------
// Setup the MCUCR register as requested.
//
void SetPowerSaveMode(MODE type)
{
switch (type)
{
case POWER_SAVE_MODE:
sbi(MCUCR, SM0);
sbi(MCUCR, SM1);
sbi(MCUCR, SE);
break;

case IDLE_MODE:
cbi(MCUCR, SM0);
cbi(MCUCR, SM1);
sbi(MCUCR, SE);
break;
}
}

//---------------------------------------------------------------------
// Initialise the Timer0 to provide a sample period
//
void InitTicker(void)
{
sbi(ASSR, AS0); // clock from external crystal
outp(CLK0_DIVIDER, TCCR0);
outp(CLK0_COUNT, TCNT0);
sbi(TIMSK, TOIE0); // enable Timer0 interrupts
}

//---------------------------------------------------------------------
// Startup delay
//
void StartupDelay(void)
{
int i, j;

for (i=0; i<200; i++)
j = i;
}


//-----------------------------------------------------------------------------
// INTERRUPT HANDLERS
//-----------------------------------------------------------------------------
//
//---------------------------------------------------------------------
// The event that triggers an A/D sample.
//
SIGNAL(SIG_OVERFLOW0)
{
outp(CLK0_COUNT, TCNT0); // reset counter
}

//-----------------------------------------------------------------------------
// 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)<<8;
}

Simple Idle Mode ( Mega ) ADC Example

The first ADC control example uses the Idle sleep mode and a simple
delay loop between samples, and the use of a pointer to write to the
output array. The latter is hardly warranted in this case, but if the
output 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.



/******************************************************************************

Sample program to demonstrate using the Mega103 analog to digital
converter (ADC) in conjunction with the simple sleep instruction to
minimize power use.

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

Ron Kreymborg
May 2001

******************************************************************************/

#include <stdlib.h>
#include <interrupt.h>
#include <signal.h>

#define BYTE unsigned char
#define ADC_CONTROL (1<<ADEN | 1<<ADIE | 1<<ADPS2 | 1<<ADPS0)

int main(void);
void AtoDconverter(void);
void Delay(void);

static volatile int Sample[8]; // a/d converter samples
static volatile int *Pointer[8];
static volatile BYTE Index;

int main(void)
{
int i, value;

// PORTA
outp(0x00, PORTA); // all low
outp(0xff, DDRA); // all output
// PORTB
outp(0xff, PORTB); // all low
outp(0xff, DDRB); // all output
sbi(ACSR, ACD); // disable comparator
cbi(MCUCR, SM0);
cbi(MCUCR, SM1);
sbi(MCUCR, SE);

for (i=0; i<8; i++)
Pointer[i] = &Sample[i]; // initialise pointers

Delay(); // allow clocks to settle
sei(); // hello world

while (1)
{
AtoDconverter(); // take a sample
value = ~(Sample[2]>>2); // display channel 3 on the STK300
outp(value, PORTB); // set of leds
Delay();
}

return 0;
}

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

outp(ADC_CONTROL, ADCSR);
for (Index=0; Index<8; Index++)
{
sbi(PORTA, 3); // for scoping
cbi(ADCSR, ADEN); // turn off ADC
outp(Index, ADMUX); // select the channel
outp(ADC_CONTROL | 1<<ADSC, ADCSR); // turn ADC on and start conversion

// The read is done in the interrupt routine. Here we go to
// sleep in Idle mode until the conversion is done.
//
asm("sleep"::);
cbi(PORTA, 3); // for scoping
}

cbi(PORTA, 1); // for scoping
}

//---------------------------------------------------------------------
// Arbitrary inter-sample delay.
//
void Delay(void)
{
int i, j;

for (i=0; i<2000; i++)
j = i;
}

//---------------------------------------------------------------------
// ADC conversion complete interrupt
//
SIGNAL(SIG_ADC)
{
*Pointer[Index] = inp(ADCL) | inp(ADCH)<<8;
}

Using the Mega Analog to Digital Converter

This example will show how to configure and use the Analog to
Digital Converter (ADC) in the Atmel Mega103 micro. It will also show
how to use the sleep instruction in conjunction with the ADC to
minimise digital noise from the cpu. I will start with the simplest
non-interrupt code and progress to using interrupts and power saving
techniques. I assume you have the Mega103 Manual open at the section on
the ADC for reference.



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



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


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



#define ADC_CONTROL   (1<<ADEN | 1<<ADPS2 | 1<<ADPS0)


This enables the ADC and selects a divide by 32 clock which, with a
4 Mhz cpu clock, gives an ADC clock of 125 Khz. The specification
quotes 2 bits accuracy at 200 Khz, so there is little advantage in a
slower clock. Note that constants like ADEN are defined as a bit
position (ADEN=7), whereas I am going to use this define in an outp
instruction where the same bit is represented by the unsigned byte
0x80. If you shift 1 left 7 times you get 0x80. Hence the strange
looking 1<<ADEN.



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



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


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



    temp = inp(ADCL);
result = temp;
temp = inp(ADCH);
result |= temp<<8;


Or you could rely on avrgcc processing from left to right (check the assembly listing) and do this in one line:



    result = inp(ADCL) | inp(ADCH)<<8;


In most situations you will be reading a set of channels into an
integer array of results. You could enable the ADC and define the clock
speed first before entering the loop:



    outp(ADC_CONTROL, ADCSR);                   // enable the ADC and set clock speed
for (i=0; i<8; i++)
{
outp(i, ADMUX); // set the channel
sbi(ADCSR, ADSC); // start the conversion
while (!(inp(ADCSR) & 1<<ADIF)) // loop until finished
{;}
sbi(ADCSR, ADIF); // clear the ADIF bit
Sample[i] = inp(ADCL) | inp(ADCH)<<8; // read in the 10-bit result
}


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



Using interrupts actually makes for simpler code once you decide to
bite the bullet. The following code snippet assumes you have enabled
global interrupts elsewhere. The ADC uses the sleep instruction in Idle
mode (see Using the Sleep Instruction)
as the clocks must still run but the cpu can be turned off. Note that I
have re-defined the ADC_CONTROL variable to include the interrupt
enable.



#define ADC_CONTROL   (1<<ADEN | 1<<ADIE | 1<<ADPS2 | 1<<ADPS0)

cbi(MCUCR, SM0); // Idle mode for sleeps
cbi(MCUCR, SM1);
sbi(MCUCR, SE);
outp(ADC_CONTROL, ADCSR); // set clock speed and enable interrupt
for (Index=0; Index<8; Index++)
{
cbi(ADCSR, ADEN); // turn off ADC
outp(Index, ADMUX); // select the channel
outp(ADC_CONTROL | 1<<ADSC, ADCSR); // turn ADC on and start conversion
asm("sleep"::); // off to sleep until done
}


The interrupt function will read the conversion result for us. This function is simply:



SIGNAL(SIG_ADC)
{
Sample[Index] = inp(ADCL) | inp(ADCH)<<8;
}


The global variables Index and Sample are defined as:



static volatile int Sample[8];      // a/d converter samples
static volatile BYTE Index; // current sample


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



In most cases the results captured in the ADC handler must be stored
elsewhere for subsequent processing. Most likely a mathematical
conversion will be required to present the results in SI units. These
conversions and transfers are usually done after the sample set is
taken to ensure the measurements themselves are as close together in
time as possible. Where speed or storage are at a premium, you could
use global pointers to manage the storage task. It is also possible to
store the data by channel (rather than by sample data set) using an
array of pointers. For example the ADC control loop would remain the
same, but the interrupt routine would look something like:



SIGNAL(SIG_ADC)
{
*Pointer[Index]++ = inp(ADCL) | inp(ADCH)<<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 case
the data for each channel will go into contiguous arrays. Of course
there would need to be some test that the arrays had eventually filled
and the pointers reset to the start of the buffers.



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



- Ron Kreymborg

WinAVR GCC Programming \ Toggle port pins and controling port


Tuesday, February 19, 2008

Serial communication between PC and Atmel AVR attiny2313

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.



Attiny2313 datasheet page 27


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:


circuit diagram


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.


attiny2313 datasheet page 139


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)



The code may be downloaded here.

Code:

#include <avr/io.h>;

#include <avr/interrupt>;



/* Prototypes */

void InitUART (unsigned char baudrate);

unsigned char ReceiveByte (void);

void TransmitByte (unsigned char data);




/* --------------------------------------------------------------

Main - program that recieves a character then transmits back the next character.

An example would be if you send in an A, the chip will return a B

---------------------------------------------------------------- */

int main (void)

{

unsigned char i;

InitUART (95); /* Set the baudrate to

2400 bps using a 3.6846MHz crystal */

while (1)

{

TransmitByte (ReceiveByte () + 1);

/* Echo the received character + 1. Example send in A then send out B */

for (i = 0; i < 200; i++);

}

}



/* Initialize UART */

void

InitUART (unsigned char baudrate)

{

/* Set the baud rate */

UBRRL = baudrate;



/* Enable UART receiver and transmitter */

UCSRB = (1 << RXEN) | (1 << TXEN);



/* set to 8 data bits, 1 stop bit */

UCSRC = (1 << UCSZ1) | (1 << UCSZ0);



}


/* Read and write functions */

unsigned char

ReceiveByte (void)

{

/* Wait for incomming data */

while (!(UCSRA & (1 << RXC)));



/* Return the data */

return UDR;

}



void

TransmitByte (unsigned char data)

{

/* Wait for empty transmit buffer */

while (!(UCSRA & (1 << UDRE)));



/* Start transmittion */

UDR = data;

}



Resources used to make this howto:

http://www.booksbybibin.blogspot.com/ (has a great free ebook on AVR programming)

Avrfreaks design note #026 (also includes an alternate way to convert from ttl to rs232) http://avrfreaks.net/modules/FreaksFiles/files/405/DN_026.pdf


This artical is a copy of http://www.windmeadow.com/node/25 page.

Using external interrupts on an Atmel AVR microprocessor

The article is removed from here due to various comments and authenticity of the material.

A copy of this document can be found at 

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

Using Eclipse IDE for WinAVR compiler AVR

WinAVR comes with
Programmers Notepad UI by default. It is very powerful editor, but if
you want more robust UI with better project management abilities you
can try Java based Eclipse
IDE. It is universal open source IDE which supports almost any compiler
by using plugins. Eclipse has some nice features that makes it
attractive, like Subversion integration, code completion in editor.

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

Eclipse AVR device explorer



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

I
just tried to compile one of my project with this environment – it
worked without problems. Lets go through how to compile your first
AVR-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:

Image

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 files
created so I will need to add then to Eclipse project only. But first
of all... In Eclipse select New->Project and then select C Project.

New AVR-GCC project in Eclipse

Select AVR Cross Target Application In Toolchain section you can see WinAVR Toolchain
selected. Enter project name and click Next. In next window you will
have to select build configurations that include various settings that
have to be included in makefile. Settings can be saved separately for
debug and release configurations. Lets say wee select Release
configuration.

Image

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

AVR clock source

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

Eclipse AVR project

I
made IDE window smaller to show how all workspace look like. In the
left you can see project tree where source files are added. Next window
is for file contents. Then goes project outline. And the bottom are has
several tabs for displaying problems, properties, console and earlier
mentioned AVR device explorer. I really like the way Eclipse extracts
outline from source file. It is easy to find and navigate by selecting
variables, functions and defines. Source code outlining is also
pleasing. Even things like #ifdef ...#endif areas are greyed if not
defined.

Compiled
release is placed in different folder where all object, hex and other
compilation products are saved – this way it keeps source folder clean.

My
first impression with AVR Plugin for Eclipse is very good. I would say
this is must try tool. As it is quite new plugin, I would expect bugs
or problems appearing. I think main problems may appear with makefile
generation, so you can always use external makefile if needed. As far
as I tested this plugin with basic AVR programs it worked without
problems.

AVR Plugin for Eclipse home page: http://avr-eclipse.sourceforge.net;

AVR Plugin for Eclipse can be downloaded here;

Eclipse IDE can be downloaded here: http://www.eclipse.org/downloads/;

Latest WinAVR can be downloaded here.

Ref :http://winavr.scienceprog.com

Avrwiz-New C code generator for WinAVR

Some good news for those
who are tired of writing same program parts every time. Most time
consumption is during initial code writing. The guy named tcg in
avrfreaks have decided to write code generating tool which could robust
most common tasks.

Current
version of program is v0.009 (early beta stage of program) but it
already support baud calculator, timer calculator, multitasking
generator, interrupts, ports and more. But there are several thing to
be done like TWI, USI. As Author states there is lots of testing to be
done. Project is open for new ideas and suggestions.



Image

Nice
thing I like about it that program is capable to generate code
instantly. It can be saved as single file or whole Avr Studio project
with makefile which is ready to compile instantly.

Image

Hope this project will reach stabile and full non commercial release.

Download
http://www.avrfreaks.net/index.php?module=Freaks%20Files&func=viewFile&id=2457

Quick WinAvr C Tutorial

Because AVR
microcontrollers are Harvard architecture they have separate address
spaces for different memory types: SRAM, FLASH and EEPROM. Each of
these memories have their own purposes. If data will not change during
all time of program execution, then it should be stored as one type of
memory like EEPROM otherwise if data will be used frequently and will
change during program execution, then it should be stored in SRAM
memory. Where to store data decides program developer. One thing you
should note, that working with different types of memories require
different 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.

As
I mentioned no specific operations aren't needed to work with variables
sored 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 <avr/pgmspace.h>. Now wee can declare data to be stored in FLASH memory:


// custom LCD characters
const uint8_t backslash[] PROGMEM=  
{
0b00000000,	//back slash
0b00010000,
0b00001000,
0b00000100,
0b00000010,
0b00000001,
0b00000000,
0b00000000
};


Declaring variable with keyword PROGMEM shows compiler to store this constant in AVR 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 <avr\io.h>
#include <avr\iom8.h>
#include <avr\pgmspace.h>

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.

Choosing
proper variable type sometimes may be crucial in designing embedded
software as microcontroller resources are limited. Choice of proper
variable type may save lots of time and space of your program.

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



User types

C language allows defining user types. For this typedef keyword is used:

typedef unsigned char byte; //create byte type

typedef unsigned int word; //create word type

In other words defining custom types description structure is used:

typedef standard_type custom_type;

WinAVR compiler has predefined custom types:

typedef signed char int8_t; //located in header file inttypes.h

typedef unsigned char uint8_t; //located in header file inttypes.h

typedef int int16_t; //located in header file inttypes.h

typedef unsigned int uint16_t; //located in header file inttypes.h

typedef long int32_t; //located in header file inttypes.h

typedef unsigned long uint32_t; //located in header file inttypes.h

typedef long long int64_t; //located in header file inttypes.h

typedef unsigned long long uint64_t; //located in header file inttypes.h

typedef struct {int quot; int rem} div_t; //located in header file stdlib.h. It is used for standard function ldiv();

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

Each
port consists of three registers DDRx, PORTx and PINx (where x means
port letter). DDRx register selects direction of port pins. If logic
one is written to DDRx then port is configured to be as output. Zero
means that port is configured as input. If DDRx is written zero and
PORTx is written logic “1” then port is configured as input with
internal pull-up resistor. Otherwise if PORTx is written to zero, then
port is configured as input but pins are set to tri-state and you might
need 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.



Accessing AVR microcontroller ports with WinAVR GCC

Lets
move to C. How we can control AVR port pins? When using WinAVR GCC
first we need to set up proper library where PORT register names have
their addresses defined. Main library where general purpose registers
are defined is io.h located in avr directory of WINAVR installation
location.


#include <avr/io.h>


Now
we can use port names instead of their addresses. For instance if we
want 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<<1)|(1<<3)|(1<<5)|(1<<7); //using bit
shift “<<”operation and logical OR to set bits 1,3,5,7 to “1”


So we can output values to 1,3,5 and 7 pins


PORTD |=(1<<1)|(1<<3)|(1<<5)|(1<<7);


Or clear them


PORTD &=~((1<<1)|(1<<3)|(1<<5)|(1<<7));


Reading of port pins is easy. Set any pin(s) for input like this:


DDRD &=~((1<<1)|(1<<3)); //This clears bits 1 and 3 of port direction register

i=PIND; //reads all 8 pins of port D


You
can read 1 and 3 bits by using masks or simply shift i value by 1 ar 3
positions to compare LSB with 1. Of course there are some functions in
sfr_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 almost
worthless. Interrupt is called what interrupts normal program flow.
Interrupts are nothing more than subroutines that put on hold normal
program flow while they are executed. After interrupt subroutines are
finished they return to normal from last point. Those subroutines are
called interrupt handlers that are called by some event like toggle
external pin or some register value overfilled like timer overflow and
so on.
Why interrupts are so important? For instance without
interrupts you would have to do loops in order to check if one or
another event occurred. This operation is called polling. But pooling
has many disadvantages like program have do loops taking resources from
other task may be done. This is why microcontroller comes with multiple
interrupt sources. Instead of checking events microcontroller has
ability to interrupt normal program flow on event and jump to interrupt
service subroutine and then get back to normal program flow.



What
happens when interrupt occurs? After interrupt event microcontroller
stops the task at current point, saves current information to stack and
gives its resources to interrupt subroutine. When interrupt subroutine
is finished last program point is restored and program flow continues.

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

AVR microcontroller interrupts handling using WINAVR

This
table indicates where all interrupt subroutines are located. After
particular interrupt occurs, program pointer jumps to interrupt table
where it is directed to interrupt subroutine location.

For
instance every time you power up microcontroller program pointer jumps
to location $000 where it is directed to (RESET) location. With C
program this would be location of main() function.

C
Compiler creates this table while compiling the source code. But how to
describe interrupts handling routines in C language using WinAVR
toolset. All time when compilers are improving, there is no agreement
how to handle interrupt code. As compilers tries to stay away from
machine dependant details, each compiler is designed with their own
methods. AVR-GCC
isn’t exception. There each interrupt is pointed with predefined names
– you will find in microcontroller definition header file like in
iom8.h.

Defining the interrupt routines is ease…

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

#include <avr/interrupt.h>

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

ISR(ADC_vect)

{

//Your code here

}

This
subroutine is for ADC conversion complete handler. Macro command ISR()
is convenient for handling all unexpected interrupts. Just create
routine 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:

EMPTY_INTERRUPT(ADC_vect)

Example:

Simple program:

#include <avr\io.h>

#include <avr\iom8.h>

#include <avr\interrupt.h>

#define outp(a, b) b = a

#define inp(a) a

uint8_t led;

typedef unsigned char u08;

ISR(INT0_vect) { /* signal handler for external interrupt int0 */

led = 0x01;

}

ISR(INT1_vect) { /* signal handler for external interrupt int1 */

led = 0x00;

}

int main(void) {

outp(0x01, DDRB); /* use PortB for output (LED) */

outp(0x00, DDRD); /* use PortD for input (switches) */

outp((1<<INT0)|(1<<INT1), GIMSK); // enable external int0, int1

sei(); /* enable interrupts */

led = 0x01;

for (;;) {

outp(led, PORTB);

} /* loop forever */

}

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

Another
interesting interrupt handling macro is ISR_ALIAS(vector,
target_vector). This is used when you need to pint one vector o another
vector. This way you may handle multiple interrupts with single
implementation, for instance:

ISR(INT0_vect) { PORTB = 42; } ISR_ALIAS(INT1_vect, INT0_vect);



Ref : http://winavr.scienceprog.com


Tuesday, February 12, 2008

8051 Development Tools

Assembler

  • ASEM-51, by W.W. Heinz, is a free 8051 macro assembler for MS-DOS, Windows and Linux.
  • Download ASEM-51 v1.3 and unzip it into a sub-directory.
  • Issue "ASEMW DEMO.A51" within DOS box will process the source file "DEMO.A51" and generate a output file "DEMO.HEX" in Intel-HEX format and a list file "DEMO.LST" in plain text.
  • Refer to "ASEM_51.DOC" for detail usage. The example program "DEMO.A51" is very instructive.
  • "ASEMSYM.EXE" is a small utility by Chin-Shiuh Shieh which accept list file from ASEM-51 and produce symbol definition file for NoICE51.

Simulator


AT89C51 Programmer

AT89S51 Programmer


In-Circuit-Debugger

  • NoICE Remote Debugger - 8051 68HC08 68HC11 68HC12 Z80 Z180 6502 etc. is a shareware written by John Hartman.
  • With NoICE Remote Debugger, a monitor "MON8051.HEX" is programmed into ROM, which is controlled by "NoICE51.EXE" (running on PC) via RS232 to debug user program loaded into RAM.
  • NoICE for 8051 V5.0 is capable of single step execution, breakpoint execution, register inspection/modification, memory inspection/modification, assembler/disassembler, and more ...
  • Source code of "MON8051.HEX" is shipped with NoICE. It can be assembled by PseudoSam 8051 Assembler. Users may customize "MON8051.HEX" to fit their own design.
  • Winbond W78C438B is an 8051 variant with non-multiplex P0,P2,Address/Data Bus, and extra I/O port in 84-pin PLCC package. However, there is no on-chip ROM
  • Schematic diagram(pdf) of a W78C438B-based 8051 in-circuit-debugger, designed by Chin-Shiuh Shieh.
  • Above design, having 16KB ROM at 0000h-3FFFh and 32KB RAM at 4000h-BFFFh, is intended to work with NoICE for 8051 V5.0.
  • "MON8051-W78C438B.HEX" is revised by Chin-Shiuh Shieh according to:
    • Monitor Code Space: 0000h-3FFFh
    • User Code/Data Space: 4000h-BF7Fh
    • Monitor Data Space: BF80h-BFFFh
    • Baud Rate: 9600bps
    • RD, WR are used to access external ROM/RAM.
    • Hand-coded UART on P8.0 and P8.7.
  • Photograph of a finished board.
  • Download NoICE v5.0 for Windows or NoICE v3.1 for DOS and run it to unzip the package.
  • Run "NoICE51.exe" for Windows and set the baud rate to 9600bps.

    or run "NoICE51.exe" for DOS and set the baud rate to 9600bps.
  • NoICE for 8051 v5.0 has an inherent limitation that breakpoints must be at least 3 bytes apart from each other.
  • The EA/VPP,XTAL1, and XTAL2 of the target circuit must be left opened if a 40-pin cable is used while debugging.
  • Refer to the on-line help for detail usage of NoICE for 8051 v5.0.
  • A Brief Note on W78C438B-based 8051 In-Circuit-Debugger with NoICE for 8051.
  • A possible bug in W78C4538CP.
  • AT89C51-based 8051 in-circuit-debugger
  • DS5000-based 8051 in-circuit-debugger

C Compiler

Small Device C Compiler

  • SDCC - Small Device C Compiler is a free C compiler for 8051, although library is incomplete.
  • Download sdcc-2.3.0-i586-mingw32msvc.zip and unzip it to "c:\" with directory structure preserved.
  • Add "c:\sdcc\bin" to DOS search path.
  • Issue "sdcc --code-loc 0x4000 --xram-loc 0x8000 test.c" within DOS box will generate "test.ihx" in Intel-HEX format, where "--code-loc 0x4000" is an option used to specify starting code address, "--xram-loc 0x8000" is an option used to specify starting address of external data memory.
  • Refer to "c:\sdcc\share\doc\sdcc\sdccman.pdf" for SDCC Compiler User Guide.
  • uart.c is a UART library by Chin-Shiuh Shieh, including Character, String, and Integer I/O. Refer to sample.c for its usage.

Raisonance RIDE-51


BASIC Compiler

  • BASCOM-8051 is a 8051 BASIC Compiler with IDE and integrated simulator and terminal emulator by MCS Electronics.
  • Download and unzip dm8051_1.zip and dm8051_2.zip. Run SETUP.EXE to install the DEMO version (2KB Limited).
  • Refer to on-line help for further details.

Disassembler


Editor


Terminal Emulator


Schematic Drawing

Ref :

Monday, February 11, 2008

NoTouch method ( LPC932 )

this work as a NoTouch implementation for the LPC932

This is the NoTouch implementation for the LPC932

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.

Erik


Ref: http://www.8052.com/users/erikm/

Erik's Backdoor method ( P89C51RD2 )


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:



jb P3.1,xxxyyy ;TxD always high without cliplead



mov AUXR1,#020h
;enable boot



!!insert parametres for set boot
vector as in AN 461 pg 14



call 0fff0h



!! insert parametres for set
status 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.


My NoTouch document is available <a href="http://www.8052.com/users/erikm/notouch.doc">here</a>.





Powered by ScribeFire.

Erik's NoTouch method ( P89C51RD2 )

“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

USB to JTAG Interface

Intro



This document describes some prototype USB-to-JTAG interfaces I built
with the FTDIChip FT2232C device. The primary purpose was to develop
a USB-connectable JTAG interface for the Open On-Chip Debugger
OpenOCD.


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


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


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


Please see also my OpenOCD page:
http://www.fh-augsburg.de/~hhoegl/proj/openocd/index.html



Prototype 1






img/usbjtag-1-photo-small.jpg

Figure: Photography of the first prototype


This was the very first demonstrator to show that a JTAG port can be
driven with a FT2232C chip (I think it was in 2004). I mounted a ready
to use FT2232M module by DLP Design on a
prototyping PCB and did the wiring by hand. You can buy these modules
e.g. at Elektronikladen or
Unitronic.



Schematic (JPG)


http://www.fh-augsburg.de/~hhoegl/proj/usbjtag/img/usbjtag-1-sch.jpg



Schematic (XFIG)


http://www.fh-augsburg.de/~hhoegl/proj/usbjtag/img/usbjtag-1-sch.fig



Photography of the first prototype using a FT2232C DIL module (USBJTAG-1)


http://www.fh-augsburg.de/~hhoegl/proj/usbjtag/img/usbjtag-1-photo.jpg




Prototype 2






img/usbjtag-2-photo-small.jpg

Figure: Photography of the second prototype 2


My second prototype is a PCB with about 7 x 6 cm size with the following
components on board:




  • FT2232C with 93C56 EEPROM




  • Step up/down regulator to guarantee 5.0 Volt from 4.5 to 5.5 USB Voltage.




  • RS-232 Level Shifter (MAX3241)




  • ADuM1401BRW I-Coupler for JTAG port level shifting and electrical isolation.




  • RS-232 connector D-SUB9




  • JTAG Connector



Be aware, the design has some flaws:




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 target
voltage range from 1.2 to 3.6 Volt. The following photography shows this
board.



img/oocd-link-ew07.jpg


One year later I met Joern at Embedded World 2007. He now also has built a
version of the OOCD-Link adaptor which directly uses the FT2232 signals to
drive the target. This works for targets running with 3.3V and 5V. A nice
additional feature is the 10-pin header which carries the UART signals of
channel B. The adaptor is called "OOCD-Link-S". Please see the following
photography:



img/oocd-link-s-ew07.jpg


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



The commercial adaptors



The following adaptors are all based on my original design using the
FT2232. However the commercial adaptors have a differing pin usage and
have much better support for a wide target voltage range than my
original 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 for
level shifting (but not for electrical isolation). Target voltages down to
1.8V are supported. Please see the following link to the "JTAGkey":
http://www.amontec.com/jtagkey.shtml
Note that the JTAGkey uses a wiring of the FT2232 signals different from
my schematic.


Amontec JTAGkey (129 Euro)


img/jtagkey_small02.jpg



img/jtagkey-schema.jpg


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


Amontec JTAGkey-Tiny (29 Euro)


img/jtagkey-tiny-board-text.JPG


Olimex USB-JTAG


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


Olimex ARM-USB-TINY (49.95 USD)


img/msp430-jtag-tiny.jpg


Olimex ARM-USB-OCD (69.95 USD)


img/ARM-USB-OCD-3.jpg




Powered by ScribeFire.