Blinking led with Atmel studio

The Arduino IDE is great, but with Atmel studio you can do more including easier debugging. Besides that, it’s the original IDE from AVR, the maker of the Atmega328p microcontroller (used by Arduino). With Atmel studio it is possible to program a wide range of AVR microcontrollers which will be usefull in the future. I tried to use the latest version 7 from Atmel, but i run into a lot of blue screens. I had to turn off my virusscanner to avoid blue screens so i decided to keep using the older version 6.2 (AS6) You can download it from http://www.atmel.com/tools/studioarchive.aspx

The AVR Dragon board

 

The cheapest board with some debugging options I could find is the AVR Dragon board (http://www.atmel.com/tools/avrdragon.aspx ). It is possible to use an Arduino board together with Atmel studio, but with this board you can also program different microcontrollers.

Connect the Atmega328p to the AVR Dragon board

Before you use the original Atmega328p microcontroller from your Arduino keep in mind that you will loose the bootloader inside the microcontroller. That means you can’t use the Atmega328p on your Arduino anymore ! So just buy a seperate microcontroller and keep your original Arduino working. You can directly put the Atmega328p on the Dragon board, but if you use an external bread board you can easily put more components on that board and do much more testing.

Build on a bread board

 

Connect the Dragon to the Atmega328p following this wiring. HV_PROG is the Dragon and DEVICE the Atmega328p.

 

After connecting everything you should end up with something like this.

 

 

For a quick reference see the Atmega328p pinout here. I used digital pin9 for the blinking led and that is the physical pin number 15.

 

Test the connectivity

After installling the software and AVR dragon USB drivers , start the AS6 software. First check if AS6 had found the AVR Dragon and the Atmega328p. Go in the top menu and click Tools -> Device programming. Select in tools your AVR Dragon. Select ISP for the interface and and press apply. When the connections are done correctly you should be able read out the Dragon. Click on read at “device signature” when you get some info the Atmega328p is also connected correctly.

If you receive something like these parameters everything should be connected correctly and ready for compiling.

The multi thread source code in a frame work

Why a framework? Thats to make your life easier in the future. By using a framework you will have always the basic setup for a design. For every new project you load the same framework and add your new project source code. This will safe time and bring some standardization into your projects. The main reason I used a framework is to be able to use multi threats in a clear way. There are often many things your microcontroller have to do at the same time and to keep track of your code this framework might help.

The framework

 

This framework is downloadable here. It contains of a few files linked together. main.c is the file that will start at first when you startup the Atmega328p. With Arduino you will have a setup part which is only executed 1 time during start up. For the setup procedures I use a seperate file called initialize.c and it does the same as setup() for Arduino. The first thing main.c does is starting the initialize() only once.

Try not to put your new project code in main.c like you do with Arduino. We use the file application1.c to put in the code that should run in a loop. By using an application file for each routine you can keep track of your source code and it will be easy in the future to troubleshoot. The only thing main.c does is starting the initialize.c (setup in Arduino) once during boot and then it will start the operational() function which is located in the file operational.c. This function runs all the application files you want to use after each other in a loop. The file also returns an alarm/error code if something goes wrong in any of the applications. If there is an alarm/error the framework will stop running all the applications and you can use the errorHandle() function in main.c to blink a led or show an error code on a display. Everything will become more clear when you start using it.

main.c

/*
* main.c
*
* Created: 20-5-2017
* Author: HdH
* Description: main, initializing en starting the app
* Global functions:
* 
*
*/

#define WATCHDOG_ALARM 2
#define NO_ALARM 0

#include <avr/io.h>

void errorHandle(int receivedAlarm);
int operational(void);
void initialize(void);

int errorCode = NO_ALARM; //

int main(void)
{
	initialize(); //start only once (setup with Arduino)
	
    errorCode = operational(); //the main loop
	if (errorCode == WATCHDOG_ALARM){ // you only end up here if there is an alarm.
		errorHandle(errorCode);
	}
	else{ 
		errorHandle(errorCode); //one of the apps is returning the error
	}	
}

void errorHandle(int receivedAlarm){
	
	while(1){ //blink some leds or show an error message on a display..
	}
}

 

initialize.c

/*
 * projectInit.c
 *
 * Created: 20-5-2017 15:07:22
 * Author: HdH
 * Description: initialization off the project
 */ 

#define PINNUMBER 9

#include "gpiolib.h"


void initialize(){


	pinMode(PINNUMBER,PINMODEOUTPUT); //set pin to output	
}

 

operational.c

/*
* inBedrijf.c
*
* Created: 20-5-2017 15:07:22
* Author: HdH
* Description: Main loop going trough all the apps
*/

#define NO_ALARM 0

#include <avr/io.h>

void Application1(void);
void Application2(void);
void Application3(void);
void Application4(void);

extern int errorCode;

int operational(void){
	
	int applicationCounter = 0;
	
	do
	{
		applicationCounter = (applicationCounter +1) % 5;
		
		if (applicationCounter == 1)
		{
			Application1();
		}
		if (applicationCounter == 2)
		{
			Application2();
		}
		if (applicationCounter == 3)
		{
			Application3();
		}
		if (applicationCounter == 4)
		{
			Application4();
		}
		
	} while (errorCode == NO_ALARM);
	
	return errorCode;
}



 

Application1.c

/*
 * operational.c
 *
 * Created: 20-5-2017 15:07:22
 * Author: HdH
 * Description: Application for multi threat
 */ 

#define F_CPU 16000000UL // 16 MHz clock speed needed for delay.h
#define PINNUMBER 9
#define DELAYMILIS 2000

#include <avr/io.h>
#include <util/delay.h>
#include "gpiolib.h"

extern int alarmCode;

void Application1(void){
	
	WritePin(PINNUMBER,HIGH);
	_delay_ms(DELAYMILIS);
	WritePin(PINNUMBER,LOW);
	_delay_ms(DELAYMILIS);
}

The only new code in the framework (the rest is the default framework) is setting up the pin as output. This line of code is added in initialize.c

 pinMode(PINNUMBER,PINMODEOUTPUT); //set pin to output 

And in apllication1.c the following lines to get the led blinking.

WritePin(PINNUMBER,HIGH);
_delay_ms(DELAYMILIS);
WritePin(PINNUMBER,LOW);
_delay_ms(DELAYMILIS);

 

The GPIO library

What id didn’t mentioned yet are the library files gpiolib.c and gpiolib.h. This library supports the functions pinMode() and WritePin(). Arduino already comes with simular libraries, but for AS6 we have to writer them ourselves. It is possible to import the Arduino libraries, but for learning purposes you will get a better understanding what the libraries actually are doing. For your AS6 to locate these files you have to add the directory where you put the files at the following places. For the compiler to find these files I added the directory at properties -> toolchain -> Directorys and General.

See here the source code for the 2 library files or download all the files at once.

gpiolib.h

/*
* gpgiolib.h
*
* Created: 20-5-2017
* Author: HdH
* Description: functions to control the GPIO
* Global functions:
* pinmode() used to set the pin as output or input
* WritePin(int pin, int value), write only 1 pin with a specific value
* int ReadPin(int pin), read a specified pin and returns the value
*
*/


#ifndef GPIOLIB_H
#define GPIOLIB_H

/****************************************************************************
	Bit and byte definitions
****************************************************************************/
#define PINMODEOUTPUT 1
#define PINMODEINPUT 0
#define HIGH 1
#define LOW 0
#define HIGH 1
#define LOW 0
#define WRONGPIN 2
#define WRONGMODE 3
#define SUCCCESFULL 0
#define WRONGPARAMETER 1

/****************************************************************************
	Function definitions
****************************************************************************/
int pinMode(int pin, int mode);
int WritePin(int pin, int value);
int ReadPin(int pin);


#endif

gpiolib.c

/*
* gpiolib.c
*
* Created: 20-5-2017
* Author: HdH
* Description: functions to control the GPIO
* Global functions:
* WritePin(int pin, int value), write only 1 pin with a specific value
* int ReadPin(int pin), read a specified pin and returns the value
*
*/

#include <avr/io.h> // needed to recognize the macros DDRD and DDRB etc.
#include "gpiolib.h"

int pinMode(int pin, int mode){
	
	if(pin < 0 || pin > 13){
		return WRONGPIN; //pin number is out of range
	}
	if ((mode != PINMODEOUTPUT) && (mode != PINMODEINPUT)){
		return WRONGMODE; //mode is out of range
	}
	
	if(mode == PINMODEOUTPUT){
		if ((pin >= 0) && (pin <= 7)){
			DDRD |= (1<<pin); //set pin as output
			return SUCCCESFULL; //successfully set pin as output
		}
		
		if ((pin >= 8) && (pin <= 13)){
			DDRB |= (1<<(pin-8)); //set pin as output
			return SUCCCESFULL; //successfully set pin as output
		}
	}
	if(mode == PINMODEINPUT){
		if ((pin >= 0) && (pin <= 7)){
			DDRD &= ~(1<<pin); // set pin as input
			return SUCCCESFULL; //successfully set pin as input
		}
		if ((pin >= 8) && (pin <= 13)){
			DDRB &= ~(1<<(pin-8)); // set pin as input
			return SUCCCESFULL; //successfully set pin as input
		}
	}
	return WRONGPARAMETER;
}


int WritePin(int pin, int value){ // function also meant for future apps on different MCU Instead of using the Digital.write().
	
	if ((pin >= 0) && (pin <= 7)){
		if (value == 1){
			PORTD |= (1<<pin); //set pin
		}
		else{
			PORTD &= ~(1<<pin); // reset pin
		}
		return SUCCCESFULL; //return ok
	}
	if ((pin >= 8) && (pin <= 13)){
		if (value == 1){
			PORTB |= (1<<(pin-8)); // set pin
		}
		else {
			PORTB &= ~(1<<(pin-8)); // reset pin
		}
		return SUCCCESFULL; // return ok
	}
	return WRONGPIN; // error
}

int ReadPin(int pin){ // function also meant for future apps on different MCU Instead of using the Digital.read().
	
	if ((pin >= 0) && (pin <= 7)){
		if (PIND & (1<<pin)){
			
			return HIGH;
		}
		else
		return LOW;
	}
	if ((pin >= 8) && (pin <= 13)){
		if (PINB & (1<<(pin-8))){
			return HIGH;
		}
		else{
			return LOW;
		}
		
	}
	return WRONGPIN;//wrong pin number given. Not handled yet
}


Start the blinking LED

All files are in place now and ready to compile, but first select the correct board and make sure you
don’t use the simulator.

Select the AVR Dragon board and NOT simulation.

 

Now it’s time to compile and load the program into the Atmega328p bij clicking the “Start without debugging” button and the led will start blinking in a multi thread !

The good thing is the framework works nice, but the bad thing is we don’t use the framework correct with the blinking led. The reason for this is I used the funtion _delay_ms(2000). What this function is doing is basically keep the microcontroller doing nothing for 2 seconds. That means that application2 till application4 will start running after the 2 times 2000 milliseconds delay and not at the same time as the blinking led application. To get this issue solved I will introduce some new functions to avoid the use of delays. I will do this in the next blog. So if you don’t see the advantages of this framework yet then it will come clear in the next blog where i will show you how to use 3 application files.