ATTINY817 UART with PuTTY

In this article I will show you how to use the ATTINY817 XPLAINED to communicate via UART using PuTTY software. This is very useful when you want to debug your hardware using your PC. This comes in handy if your hardware have no display and other means for human interface.

Setting up

When you connect your xplained kit, a new hardware is being added into your system. You will find it under “Device Manager -> Ports(COM & LPT) -> COMxx” where xx is the number of the device. It is different on every system so take  note of it. On my machine it is COM10, this might be different on your machine.

Open PuTTY and click on “serial” and then Type the COMxx number on the text box. In this example it is COM10. Leave other settings as is and click ok.

About the Program

The program is written in C and fairly simple. It make use of the ISR or Interrupt Service Routine for executing program when a UART activity is detected. When you type any character on the PuTTY terminal, your PC will send UART data to your device and the device will  receive the data and send it back to the PC for display. The microcontroller now search and evaluates the commands it received, if found valid, it will execute the command request.

 

Full Code:

/*
 * UART_simple.c
 * Author : tataylino.com
 */ 
#define F_CPU 20000000UL  // 20 MHz
#define NEWLINE_ON 1
#define NEWLINE_OFF 0
#define ENABLE 1
#define DISABLE 0
#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>
#include 
#include 
#include 
#include 
	
char msg_tx[] = "tataylino.com UART Utility v1.0 \n\rCommands: \
				\n\r h - help \
				\n\r a - read ADC \
				\n\r d xx - set DAC \
				\n\r c xx - set PortC \
				\n\r Notes\n xx- 8bit hex value";
	int x = 0;
	char msg_rx[];
	char msg_tx[];
	char param1[5];
	uint16_t hex_value;

void dac_init()
{
	DAC0_CTRLA = 0xC1; // enable DAC
}

void adc_init (void)
{
	ADC0_CTRLA = (0<<ADC_RUNSTBY_bp)|(0<<ADC_RESSEL_10BIT_gc)|(1<<ADC_ENABLE_bp);    //Disabled run in standby, enabled ADC & full 10-bit resolution
	VREF_CTRLA = (1<<VREF_ADC0REFSEL0_bp)|(VREF_DAC0REFSEL_1V1_gc);		             //ADC voltage reference = 1.1V (0x1), DAC to 1.1V
	ADC0_CTRLC = (1<<ADC_SAMPCAP_bp)|(0<<ADC_REFSEL_gp);							//Set Internal reference, set reduced size of sampling capacitance, set prescaler to CLK_PER/4
	ADC0_CTRLD = (1<<ADC_INITDLY1_bp)|(0<<ADC_ASDV_bp)|(0<<ADC_SAMPDLY0_bp);         //These bits define the delay when initializing the ADC or changing the source of the reference voltage.
	ADC0_SAMPCTRL = (1<<ADC_SAMPLEN4_bp);                                            //0x10, These bits control the ADC sampling time in number of CLK_ADC cycles,
	ADC0_MUXPOS = ADC_MUXPOS_TEMPSENSE_gc;                                           //0x1E Temperature sensor - Single ended analog input connected to ADC
	ADC0_CTRLB = 0x06;																// 32 samples
}

void set_dac(uint16_t val)
{
	DAC0_DATA = val;
}

void read_adc(char ch)
{	// Read ADC
	char buffer[6];									//Array with three elements, 8-bits in each element
	uint16_t adc_val = 0;
	double adc_ave = 0;
	double adc_v = 0;
	char run = 0;
	run = 0;
	ADC0_MUXPOS = ch;								// channel select
	_delay_ms(1); 
start_conversion:
	ADC0_COMMAND = (1<<ADC_STCONV_bp);               // Start conversion//Writing a '1' to this bit in single-shot mode starts one conversion.
    while (ADC0_COMMAND & (1<<ADC_STCONV_bp));      // while conversion is on-going
     _delay_ms(10);
	 if (run < 5)									// discard 5 adc readings
	 {
		 run++; 
		 adc_val = ((ADC0_RESH << 8) | ADC0_RESL);	//ADC conversion result to make sure adc reading is good
		 goto start_conversion;
	 }  else {
		adc_val = ((ADC0_RESH << 8) | ADC0_RESL); //ADC conversion result with 1.1 V internal reference adc_ave = adc_val/64; // Average from 64 samples adc_v = (adc_ave/1024)*1.1; // 1.1 is VREF, 1024 is the adc resolution(10bit) dtostrf(adc_v, 6, 3, buffer); //double to string conversion send_msg(buffer, NEWLINE_OFF); } } ISR(USART0_RXC_vect) { // When any key is pressed char value = 0; value = USART0_RXDATAL; if(value != "") { msg_rx[x] = value; USART_SendByte(msg_rx[x]); //send back the character typed to display if(value != 8 && value != 127) // if backspace/delete is pressed, { x++; } else { x--; } if(value == '\r') //if enter is pressed, process command { USART_SendByte('\n'); // new line check_cmd(msg_rx); // check for command request x = 0; } } } void check_param(char msg[]) { // read param param1[0] = msg[2]; param1[1] = msg[3]; param1[2] = '\0'; // add null character } void convert_to_int() { // ASCII to integer conversion hex_value = (uint8_t)(strtol(param1, NULL, 16)); } void check_cmd(char msg[]) { char cmd; char chk_space; cmd = msg[0]; // get first character chk_space = msg[1]; // get second character -should be space if(chk_space == ' ' || cmd == 'h' || cmd == 't') { switch(cmd) { case 'h': // Help send_msg(msg_tx, NEWLINE_ON); break; case 'a': // ADC read send_msg("ADC reading: ", NEWLINE_OFF); check_param(msg); convert_to_int(); read_adc(hex_value); send_msg("V", NEWLINE_ON); //Display Unit break; case 'd': // DAC set send_msg("DAC SET: ", NEWLINE_OFF); check_param(msg); convert_to_int(); if(hex_value > 0xFF)
				{
					send_msg("Out of range ", NEWLINE_ON);
				}
				set_dac(hex_value);
				read_adc(0x1C);				// Read actual DAC voltage
				send_msg("V ", NEWLINE_ON);	// Display unit V
			break;
			case 'c':					// GPIO Set port C
				send_msg("PORT C set: ", NEWLINE_OFF);
				check_param(msg);
				convert_to_int();
				gpio_on(hex_value);
				send_msg(param1, NEWLINE_ON);
			break;
			default:
				send_msg("Unknown Command! Type h to get list of commands!");
			}
	} else{
		send_msg("Invalid Command!");
	}
}

void USART_Init(void)
{
	USART0_CTRLB = USART_RXEN_bm | USART_TXEN_bm | USART_RXCIE_bm;
	USART0_CTRLC = USART_CMODE_ASYNCHRONOUS_gc | USART_PMODE_DISABLED_gc | USART_CHSIZE_8BIT_gc;
	USART0_CTRLA = (1<<USART_RXCIE_bp)|(0<<USART_TXCIE_bp);
	PORTB_DIRSET = (0<<PIN3_bp) | (1<<PIN2_bp);
	USART0_BAUD = 1388;					//Calculate baud rate setting,	Industrial,		BAUD = 64*CLK_PER/S*fBAUD = 64*3.33MHz/16*9600 = 1388
	USART0_STATUS = USART_RXCIF_bm | USART_TXCIF_bm;
}

void USART_SendByte(uint8_t u8Data)
{ // Send Character
	USART0_TXDATAL = u8Data;
	while((USART0_STATUS &(1<<USART_TXCIF_bp)) == 0);
	USART0_STATUS = (1<<USART_TXCIF_bp);			// clear flag
}

void send_msg(char msg[], char new_line)
{ // send message to UART
	int i = 0;
	for(i = 0; i < strlen(msg); i++)
	{
		USART_SendByte(msg[i]);			// send value
	}
	if(new_line == ENABLE)
	{
		USART_SendByte('\n');			// new line
		USART_SendByte('\r');			// return	
	}
}

void gpio_on(char val)
{
	PORTC_OUT = val;			// PORT C output
}

int main(void)
{
PORTA_DIR = 0x40; // SET PA6 as output
PORTC_DIR = 0xff; // Set PORT C as output
PORTC_OUT = 0x00; // initial value
USART_Init(); // Initialize USART
adc_init(); //Calling ADC init
dac_init(); // initialize DAC
sei(); // enable all interrupts
send_msg(msg_tx, NEWLINE_ON);
while (1)
{ 

}
}

This should be the output of our program.

Download

You can download the original code on my download page here