The weekly assignment were:
The software that i've used this week are:
I was already very familiar with the Arduino IDE so i've started to programm the boards from here.
To use Arduino IDE to program the attiny, is necessary to download and unzip in the folder xxxxxx
the libraries for the microcontrollers.
In this way is possible to select the Attiny44 from the list of programmable devices.
This is the sketch that i've used to blink the led while the button is pressed (DOWNLOAD)
void setup() {
// initialize digital pin 13 as an output.
pinMode(8, OUTPUT);
}
void loop() {
digitalWrite(8, HIGH); // turn the LED on (HIGH is the voltage level)
delay(100); // wait for a second
digitalWrite(8, LOW); // turn the LED off by making the voltage LOW
delay(100); // wait for a second
}
After i've succesfully programmed the hello board, I moved to the Satshakit and to C language.
I had a previous knowledge in C but i've never programmed an AVR microcontroller.
At this point it was crucial to open the datasheet of the atmega328p...
...and reading the datasheet from the beginning was really soporific -.-.
So i've decided to connect to the board an analog photocell (which i want to include in my final project) and i've started to
look inside the datasheet to find the part related to the ADC converter.
First i've wired the Satshakit to the FabISP in this way:
And then i've added:
#include
int main (void)
{
DDRB |= (1 << PB2); // Set LED pin as output ("Configuring the pin", pg 76)
ADCSRA |= (1 << ADPS2) | (1 << ADPS1) | (1 << ADPS0); // Set ADC prescalar to 128 - 125KHz sample rate @ 16MHz (Ch. 24, "Prescaling and Conversion Timing", pg.240 - pg.249)
ADMUX |= (1 << REFS0); // Set ADC reference to AVCC (Ch. 24, pg. 248)
ADMUX |= (1 << ADLAR); // Left adjust ADC result to allow easy 8 bit reading (Ch. 24, pg. 247, pg. 249, pg. 250)
// No MUX values needed to be changed to use ADC0 (pg. 249, table 24-4)
ADCSRA |= (1 << ADFR); // Set ADC to Free-Running Mode (WRONG! there is no ADFR bit inside the ADCSRA for the atmega328p, pg. 239)
ADCSRA |= (1 << ADEN); // Enable ADC (pg. 238)
ADCSRA |= (1 << ADSC); // Start A2D Conversions (pg. 239)
for(;;) // Loop Forever
{
if(ADC < 128) //Reading the results (p. "ADC conversion result, "pg. 247)
{
PORTB |= (1 << PB2); // Turn on LED (pg. 76)
}
else
{
PORTB &= ~(1 << PB2); // Turn off LED (pg. 76)
}
}
}
#include "avr/io.h"
#include "util/delay.h"
#include "avr/pgmspace.h"
#define output(directions,pin) (directions |= pin) // set port direction for output
#define input(directions, pin) (directions &= (~pin)) //set port direction for input
#define set(port,pin) (port |= pin) // set port pin
#define clear(port,pin) (port &= (~pin)) // clear port pin
#define delay() _delay_ms(10)
#define led_pin (1 << PB2)
#define adc_pin 0
int main(void){
output(DDRB,led_pin); //write 1 in DDRB.PB2 (set the pin as output)
clear(PORTB,led_pin); //be sure that the led is turned off (0 in PB2)
ADCSRA |= (1 << ADEN); //Power up the ADC
ADMUX &= 0xf0; //Ensure the zeroes inside MUX3..0
ADMUX |= adc_pin; //Set MUX3...0 accordingly to adc_pin we defined (0 in this case)
for(;;){ //Loop
ADCSRA |= (1 << ADSC); //Start the conversion
delay(); //Wait the end of the conversion
if(ADC > 512){ //Read the result of the conversion from the ADC register
PORTB |= (1 << PB2); //If ADC value is above 512 turn led on
}
else {
PORTB &= ~(1 << PB2); //Else turn led off
}
}
return 0;
}
PROJECT=adc
SOURCES=$(PROJECT).c
MMCU=atmega328p
F_CPU = 16000000
CFLAGS=-mmcu=$(MMCU) -Wall -Os -DF_CPU=$(F_CPU)
$(PROJECT).hex: $(PROJECT).out
avr-objcopy -O ihex $(PROJECT).out $(PROJECT).c.hex;\
avr-size --mcu=$(MMCU) --format=avr $(PROJECT).out
$(PROJECT).out: $(SOURCES)
avr-gcc $(CFLAGS) -I./ -o $(PROJECT).out $(SOURCES)
program-bsd: $(PROJECT).hex
avrdude -p m328p -c bsd -U flash:w:$(PROJECT).c.hex
program-dasa: $(PROJECT).hex
avrdude -p m328p -P /dev/ttyUSB0 -c dasa -U flash:w:$(PROJECT).c.hex
program-avrisp2: $(PROJECT).hex
avrdude -p m328p -P usb -c avrisp2 -U flash:w:$(PROJECT).c.hex
program-avrisp2-fuses: $(PROJECT).hex
avrdude -p m328p -P usb -c avrisp2 -U lfuse:w:0x5E:m
program-usbtiny: $(PROJECT).hex
avrdude -p m328p -P usb -c usbtiny -U flash:w:$(PROJECT).c.hex
program-usbtiny-fuses: $(PROJECT).hex
avrdude -p m328p -P usb -c usbtiny -U lfuse:w:0x5E:m
program-dragon: $(PROJECT).hex
avrdude -p m328p -P usb -c dragon_isp -U flash:w:$(PROJECT).c.hex
make -f xxx.make
sudo make -f xxx.make program-usbtiny-fuses
sudo make -f xxx.make program-usbtiny
#include "avr/io.h"
#include "util/delay.h"
#include "avr/pgmspace.h"
#define output(directions,pin) (directions |= pin) // set port direction for output
#define input(directions, pin) (directions &= (~pin)) //set port direction for input
#define set(port,pin) (port |= pin) // set port pin
#define clear(port,pin) (port &= (~pin)) // clear port pin
#define led_pin (1 << PB2)
#define ADC_PIN 0
#define ADC_THRESHOLD 512
uint16_t adc_read(uint8_t adcpin);
int main(void){
output(DDRB,led_pin); //write 1 in DDRB.PB2 (set the pin as output)
clear(PORTB,led_pin); //be sure that the led is turned off (0 in PB2)
ADCSRA |= (1 << ADEN); //Power up the ADC
ADMUX &= 0xf0; //Ensure the zeroes inside MUX3..0
ADMUX |= ADC_PIN; //Set MUX3...0 accordingly to adc_pin we defined
for(;;){ //Loop
if (adc_read(ADC_PIN) > ADC_THRESHOLD)
PORTB |= (1 << PB2); //Turn led on
else
PORTB &= ~(1 << PB2); //Else turn led off
}
}
return 0;
}
uint16_t adc_read(uint8_t adcpin) {
ADMUX &= 0xf0; //Ensure the zeroes inside MUX3..0
ADMUX |= adcpin; //Set MUX3...0 accordingly to adc_pin we defined
ADCSRA |= (1 << ADSC); //Start the conversion
while ( (ADCSRA & (1 << ADSC)) ); //Do nothing until the conversion is finished
return ADC; //Return the value of the conversion
}
To test more environment, i've used Eclipse + AVR plugin.
To setup the environment i've folowed this tutorial
and the followings are some screenshots about the settings that i've modified:
I've used this sketch and the hello board + FabISP programmer:
#include "avr/io.h"
#include "util/delay.h"
#include "avr/pgmspace.h"
#define led_delay() _delay_ms(5)
int main(void){
PORTB &= ~(1 << PB2);
DDRB |= (1 << PB2); //output led pin PA7
PORTA |= (1 << PA7);
DDRA &= ~(1 << PA7); //input button pin PB2
while(1){
if((PINA & (1 << PA7))==0){
PORTB |= (1 << PB2);
}
else{
PORTB &= ~( 1<< PB2);
}
}
}
#include "avr/io.h"
#include "util/delay.h"
#include "avr/pgmspace.h"
#include "avr/interrupt.h"
#define output(directions,pin) (directions |= pin) // set port direction for output
#define clear(port,pin) (port &= (~pin)) // clear port pin
#define led_pin (1 << PB2)
#define ADC_PIN 0
#define ADC_THRESHOLD 512
ISR(ADC_vect){
ADCSRA |= (1 << ADSC);
while ( (ADCSRA & (1 << ADSC)) );
if (ADC > ADC_THRESHOLD)
PORTB |= (1 << PB2); //Turn led on
else
PORTB &= ~(1 << PB2); //Else turn led off
}
int main(void){
output(DDRB,led_pin); //write 1 in DDRB.PB2 (set the pin as output)
clear(PORTB,led_pin); //be sure that the led is turned off (0 in PB2)
ADCSRA |= (1 << ADEN); //Power up the ADC
ADMUX &= 0xf0; //Ensure the zeroes inside MUX3..0
ADMUX |= ADC_PIN; //Set MUX3...0 accordingly to adc_pin we defined
ADCSRA |= (1 << ADIE);
sei();
ADCSRA |= (1 << ADSC);
//Start the conversion
while(1);
}
After i've tried Eclipse, i've moved to Atmel studio. At the beginning i was not
happy to move to this environment because is windows-only but i must admit that
once i've tried it, i've found it really confortable and handy.
The IDE is full of functionality but i had to make some adjustments in order to use it with
the FabISP as a programmer.
First of all, i had installed the Win-AVR package
which contains the avr-gcc toolchain.
Then, i've started the IDE and i've created a new "GCC C Executable Project":
For a first try, i've used the same code that i've used in eclipse for the photocell
and the led.
Then i've configured the programmer. I've followed this tutorial
but i could not found the "External Tool" option under the "Tools" tab of the menu. After some tries,
the solution was to enable the "Advanced Profile" under the "Tools"-->"Set Profile" as shown in the picture below:
After i've selected "Advanced", the "External Tools" option became visible.
Then i've added a new external tool as shown in the picture:
In the "Command" option, i've added the path to my avrdude.exe file (which is installed through the Win-AVR package);
In the arguments, i've used the following string:
-c usbtiny -p m328p -v -v -v -U flash:w:$(TargetDir)$(TargetName).hex:i
#define F_CPU 16000000UL
#include "avr/io.h"
#include "util/delay.h"
#include "avr/pgmspace.h"
#include "avr/interrupt.h"
#define BAUDRATE 9600
#define BAUD_PRESCALLER (((F_CPU / (BAUDRATE * 16UL))) - 1) //pg. 173 datasheet
#define output(directions,pin) (directions |= pin) // set port direction for output
#define clear(port,pin) (port &= (~pin)) // clear port pin
#define led_pin (1 << PB2)
#define ADC_PIN 0
#define ADC_PIN_TEMP 8
#define ADC_THRESHOLD 512
//Declaration of our functions
void USART_init(void);
unsigned char USART_receive(void);
void USART_send( unsigned char data);
void USART_putstring(char* StringPtr);
void ADC_start(int pin);
char temp=0;
char String[]="Hello World!!";
int main(void){
USART_init(); //Call the USART initialization code
output(DDRB,led_pin); //write 1 in DDRB.PB2 (set the pin as output)
clear(PORTB,led_pin); //be sure that the led is turned off (0 in PB2)
ADC_start(ADC_PIN_TEMP);
temp=ADC;
while(1){ //Infinite loop
USART_send(temp); //Pass the temp to the USART_send function and sends it over the serial
_delay_ms(5000); //Delay for 5 seconds so it will re-send the value every 5 seconds
}
return 0;
}
void USART_init(void){
UBRR0H = (uint8_t)(BAUD_PRESCALLER>>8); // Load upper 8-bits of the baud rate value into the high byte of the UBRR register
UBRR0L = (uint8_t)(BAUD_PRESCALLER); // Load lower 8-bits of the baud rate value into the low byte of the UBRR register
UCSR0B = (1 << RXEN0)|(1 << TXEN0); // Turn on the transmission and reception circuitry
UCSR0C = (3 << UCSZ00); //pg 194, set 011 bit to define 8-bit char-size
}
unsigned char USART_receive(void){
while(!(UCSR0A & (1 << RXC0)));
return UDR0;
}
void USART_send( unsigned char data){
while(!(UCSR0A & (1 << UDRE0)));
UDR0 = data;
}
void USART_putstring(char* StringPtr){
while(*StringPtr != 0x00){
USART_send(*StringPtr);
StringPtr++;}
}
void ADC_start(int pin){
ADCSRA |= (1 << ADEN); //Power up the ADC
ADMUX &= 0xf0; //Ensure the zeroes inside MUX3..0
ADMUX |= pin; //Set MUX3...0 accordingly to adc_pin we defined
ADCSRA |= (1 << ADIE);
sei();
ADCSRA |= (1 << ADSC); // start conversion
}
ISR(ADC_vect){
ADCSRA |= (1 << ADSC);
while ( (ADCSRA & (1 << ADSC)) );
if (ADC > ADC_THRESHOLD)
PORTB |= (1 << PB2); //Turn led on
else
PORTB &= ~(1 << PB2); //Else turn led off
}
I've tried to connect this adapter to the satshakit
to check the program i wrote in a serial terminal.I've connected the satsha and the FTDI adapter in this way:
But when i've tried to open the serial terminal, i was not able to see any data. By looking at the specific of
the Sparkfun adapter i've found the following:
So i've decided to write a simpler code to test only the USART communication. Moreover,
i've decided to burn the Arduino bootloader on the satshakit and to use the Arduino IDE to upload the code
to the board (the procedure is described here).
The code that i've used is the following:
#define F_CPU 16000000
#include "avr/io.h"
#include "util/delay.h"
#define BAUD 9600
#define BRC ((F_CPU/16/BAUD) - 1)
int main (void)
{
UBRR0H = (BRC >> 8);
UBRR0L = BRC;
UCSR0B = (1 << TXEN0);
UCSR0C = (1 << UCSZ01) | (1 << UCSZ00);
while(1)
{
UDR0 = '8';
_delay_ms(1000);
}
}
I've really liked this week. Reading the datasheet was really hard at the beginning because i've found that
document really full of information. Once i've familiarized with the basic organization of the datasheet,
it started to become a foundamental instrument to understand what to do to properly program the MCU. To be honest,
the majority of the information for each chapter that i've explored, is still not clear (especially the theorical stuff)
but at least, i've started to be familiar with registers and operations among them.
For this week i've used only two languages (which can be considered the same because arduino language is a simplified C) and
i whis have tried more but honestly speaking, i've preferred to put the accent on the datasheet reading and on the understanding
of the different register that i've used.On the other hand, i've tried 4 different environment and i found very confortable with both
Eclipse and Atmel Studio.
There are a huge amount of material on the web on the AVR programming so, combining
tutorials and guides with the datasheet reading was really useful.
I've also explored some of MCU functionalities that i will use in my final project (eg. ADC conversion and interrupts).