Akash Kollipara
Published © GPL3+

DFT Audio Analyser

Implementing DFT on ATMega328p microcontroller.

IntermediateFull instructions provided5,724
DFT Audio Analyser

Things used in this project

Story

Read more

Code

DFT Audio Analyzer

C/C++
/*
 * DFT_on_AVR.c
 *
 * Created: 19-08-2016 11:02:32 PM
 * Author : Akash Kollipara
 */ 
#define F_CPU 16000000UL
#define RS 2
#define EN 3

#include <avr/io.h>
#include <util/delay.h>
#include <math.h>
#include <avr/pgmspace.h>

//INITIALZATIONS

#define N 32		//#samples
uint16_t f[N], angle;
float cs, ss;
uint8_t x, k;
char pin;
char arr[8][8]=
{
	{0, 0, 0, 0, 0, 0, 0, 31}, 		//L1
	{0, 0, 0, 0, 0, 0, 31, 31}, 		//L2
	{0, 0, 0, 0, 0, 31, 31, 31}, 		//L3
	{0, 0, 0, 0, 31, 31, 31, 31}, 		//L4
	{0, 0, 0, 31, 31, 31, 31, 31}, 		//L5
	{0, 0, 31, 31, 31, 31, 31, 31}, 	//L6
	{0, 31, 31, 31, 31, 31, 31, 31}, 	//L7
	{31, 31, 31, 31, 31, 31, 31, 31}	//L8
};	

//PRTOTYPING

//LCD FUNCTIONS
void lcd_init();
void cmd(char);
void Data(char);
void lcd_clear();
void lcd_printc(char);
void lcd_prints(char *);
void lcd_cust_char(char, char *);
void lcd_setCursor(char, char);

//ADC FUNCTIONS
void adc_init();
uint16_t analogRead();

//BOOTUP
void bootup();

const int16_t cosine_lookup[] PROGMEM =
{
	1000, 980, 923, 831, 707, 555, 382, 195, 0, -195, -382, -555, -707, -831, -923, -980, -1000, -980, -923, -831, -707, -555, -382, -195, 0, 195, 382, 555, 707, 831, 923, 980, 1000, 923, 707, 382, 0, -382, -707, -923, -1000, -923, -707, -382, 0, 382, 707, 923, 1000, 923, 707, 382, 0, -382, -707, -923, -1000, -923, -707, -382, 0, 382, 707, 923, 1000, 831, 382, -195, -707, -980, -923, -555, 0, 555, 923, 980, 707, 195, -382, -831, -1000, -831, -382, 195, 707, 980, 923, 555, 0, -555, -923, -980, -707, -195, 382, 831, 1000, 707, 0, -707, -1000, -707, 0, 707, 1000, 707, 0, -707, -1000, -707, 0, 707, 999, 707, 0, -707, -1000, -707, 0, 707, 1000, 707, 0, -707, -1000, -707, 0, 707, 1000, 555, -382, -980, -707, 195, 923, 831, 0, -831, -923, -195, 707, 980, 382, -555, -1000, -555, 382, 980, 707, -195, -923, -831, 0, 831, 923, 195, -707, -980, -382, 555, 1000, 382, -707, -923, 0, 923, 707, -382, -1000, -382, 707, 923, 0, -923, -707, 382, 1000, 382, -707, -923, 0, 923, 707, -382, -1000, -382, 707, 923, 0, -923, -707, 382, 1000, 195, -923, -555, 707, 831, -382, -980, 0, 980, 382, -831, -707, 555, 923, -195, -1000, -195, 923, 555, -707, -831, 382, 980, 0, -980, -382, 831, 707, -555, -923, 195, 1000, 0, -1000, 0, 1000, 0, -1000, 0, 999, 0, -1000, 0, 1000, 0, -1000, 0, 1000, 0, -1000, 0, 1000, 0, -1000, 0, 1000, 0, -1000, 0, 1000, 0, -1000, 0, 1000, -195, -923, 555, 707, -831, -382, 980, 0, -980, 382, 831, -707, -555, 923, 195, -1000, 195, 923, -555, -707, 831, 382, -980, 0, 980, -382, -831, 707, 555, -923, -195, 1000, -382, -707, 923, 0, -923, 707, 382, -1000, 382, 707, -923, 0, 923, -707, -382, 1000, -382, -707, 923, 0, -923, 707, 382, -1000, 382, 707, -923, 0, 923, -707, -382, 1000, -555, -382, 980, -707, -195, 923, -831, 0, 831, -923, 195, 707, -980, 382, 555, -1000, 555, 382, -980, 707, 195, -923, 831, 0, -831, 923, -195, -707, 980, -382, -555, 1000, -707, 0, 707, -1000, 707, 0, -707, 1000, -707, 0, 707, -1000, 707, 0, -707, 1000, -707, 0, 707, -1000, 707, 0, -707, 1000, -707, 0, 707, -1000, 707, 0, -707, 1000, -831, 382, 195, -707, 980, -923, 555, 0, -555, 923, -980, 707, -195, -382, 831, -1000, 831, -382, -195, 707, -980, 923, -555, 0, 555, -923, 980, -707, 195, 382, -831, 1000, -923, 707, -382, 0, 382, -707, 923, -1000, 923, -707, 382, 0, -382, 707, -923, 1000, -923, 707, -382, 0, 382, -707, 923, -1000, 923, -707, 382, 0, -382, 707, -923, 1000, -980, 923, -831, 707, -555, 382, -195, 0, 195, -382, 555, -707, 831, -923, 980, -1000, 980, -923, 831, -707, 555, -382, 195, 0, -195, 382, -555, 707, -831, 923, -980, 1000, -1000, 1000, -1000, 999, -1000, 1000, -1000, 1000, -1000, 1000, -1000, 1000, -1000, 1000, -1000, 1000, -1000, 1000, -1000, 1000, -1000, 1000, -999, 1000, -1000, 1000, -1000, 1000, -999, 1000, -1000
};

const int16_t sine_lookup[] PROGMEM =
{	
	0, 195, 382, 555, 707, 831, 923, 980, 1000, 980, 923, 831, 707, 555, 382, 195, 0, -195, -382, -555, -707, -831, -923, -980, -1000, -980, -923, -831, -707, -555, -382, -195, 0, 382, 707, 923, 1000, 923, 707, 382, 0, -382, -707, -923, -1000, -923, -707, -382, 0, 382, 707, 923, 999, 923, 707, 382, 0, -382, -707, -923, -1000, -923, -707, -382, 0, 555, 923, 980, 707, 195, -382, -831, -1000, -831, -382, 195, 707, 980, 923, 555, 0, -555, -923, -980, -707, -195, 382, 831, 1000, 831, 382, -195, -707, -980, -923, -555, 0, 707, 1000, 707, 0, -707, -1000, -707, 0, 707, 999, 707, 0, -707, -1000, -707, 0, 707, 1000, 707, 0, -707, -1000, -707, 0, 707, 1000, 707, 0, -707, -1000, -707, 0, 831, 923, 195, -707, -980, -382, 555, 999, 555, -382, -980, -707, 195, 923, 831, 0, -831, -923, -195, 707, 980, 382, -555, -1000, -555, 382, 980, 707, -195, -923, -831, 0, 923, 707, -382, -1000, -382, 707, 923, 0, -923, -707, 382, 1000, 382, -707, -923, 0, 923, 707, -382, -1000, -382, 707, 923, 0, -923, -707, 382, 1000, 382, -707, -923, 0, 980, 382, -831, -707, 555, 923, -195, -1000, -195, 923, 555, -707, -831, 382, 980, 0, -980, -382, 831, 707, -555, -923, 195, 1000, 195, -923, -555, 707, 831, -382, -980, 0, 1000, 0, -1000, 0, 999, 0, -1000, 0, 1000, 0, -1000, 0, 1000, 0, -1000, 0, 1000, 0, -1000, 0, 1000, 0, -1000, 0, 1000, 0, -1000, 0, 1000, 0, -1000, 0, 980, -382, -831, 707, 555, -923, -195, 1000, -195, -923, 555, 707, -831, -382, 980, 0, -980, 382, 831, -707, -555, 923, 195, -1000, 195, 923, -555, -707, 831, 382, -980, 0, 923, -707, -382, 999, -382, -707, 923, 0, -923, 707, 382, -1000, 382, 707, -923, 0, 923, -707, -382, 1000, -382, -707, 923, 0, -923, 707, 382, -1000, 382, 707, -923, 0, 831, -923, 195, 707, -980, 382, 555, -1000, 555, 382, -980, 707, 195, -923, 831, 0, -831, 923, -195, -707, 980, -382, -555, 1000, -555, -382, 980, -707, -195, 923, -831, 0, 707, -1000, 707, 0, -707, 1000, -707, 0, 707, -1000, 707, 0, -707, 1000, -707, 0, 707, -1000, 707, 0, -707, 1000, -707, 0, 707, -999, 707, 0, -707, 999, -707, 0, 555, -923, 980, -707, 195, 382, -831, 1000, -831, 382, 195, -707, 980, -923, 555, 0, -555, 923, -980, 707, -195, -382, 831, -1000, 831, -382, -195, 707, -980, 923, -555, 0, 382, -707, 923, -1000, 923, -707, 382, 0, -382, 707, -923, 1000, -923, 707, -382, 0, 382, -707, 923, -1000, 923, -707, 382, 0, -382, 707, -923, 999, -923, 707, -382, 0, 195, -382, 555, -707, 831, -923, 980, -1000, 980, -923, 831, -707, 555, -382, 195, 0, -195, 382, -555, 707, -831, 923, -980, 999, -980, 923, -831, 707, -555, 382, -195, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
};


//MAIN
int main(void)
{
    bootup();
    while(1)
    {
	    for(k = 0; k < N; k++)
			f[k] = analogRead();			//fetch samples
	    for(k = 0; k < N/2; k++)
	    {
		    cs = ss = 0;
			for(x = 0; x < N; x++)
			{
				angle = x + (32*k);
				cs += (float)f[x]*(int16_t)pgm_read_word(&cosine_lookup[angle]);		//real part of dft
				ss += (float)f[x]*(int16_t)pgm_read_word(&sine_lookup[angle]);			//imaginary part of dft
			}
			cs /= N*1000;
			ss /= N*1000;
			x = (uint8_t)sqrt((cs*cs)+(ss*ss));		//absolute value of dft
			x /= 2;		//scaling
			x++;
			if(x > 16) x = 16;
			if(x < 9)
			{
				lcd_setCursor(k, 0);
				lcd_printc(' ');
				lcd_setCursor(k, 1);
				lcd_printc(x);

			}
			else
			{
				lcd_setCursor(k, 1);
				lcd_printc(8);
				lcd_setCursor(k, 0);
				lcd_printc(x-8);
			}
		}
		if(!(PINB & 0x01) && ((pin & 0x80) == 0x00))
		{
			pin |= 0x80;
			pin++;
			if((pin & 0x0f)>1) pin &= 0xf0;
			switch((pin & 0x0f))
			{
				case 0:
				{
					ADCSRA = 0x86;
					lcd_clear();
					lcd_setCursor(2, 0);
					lcd_prints("560 - 8960 Hz");
					_delay_ms(1000);
					break;
				}
				case 1:
				{
					ADCSRA = 0x87;
					lcd_clear();
					lcd_setCursor(2, 0);
					lcd_prints("280 - 4480 Hz");
					_delay_ms(1000);
					break;
				}
			}
		}
		else if((pin & 0x80) && ((PINB & 0x01)))
		{
			pin &= 0x7f;
		}
    }
	return 0;
}

//bootup functions
void bootup()
{
	PORTB = 0x01;		//internal pull-up
	DDRD = 0xfc;		//set o/p port for LCD
	adc_init();
	_delay_ms(1);
	lcd_init();
	for(k = 0; k < 8; k++)
		lcd_cust_char((k+1), arr[k]);	//load custom characters
	lcd_clear();
}

//SYSTEM FUNCTIONS
void adc_init()
{
	ADCSRA = 0x86;
	ADMUX = 0x40;
}

uint16_t analogRead()
{
	uint16_t adcl, adch;
	ADCSRA |= (1<<ADSC);
	while((ADCSRA & (1<<ADSC)));
	adcl = ADCL;
	adch = ADCH;
	return((adch<<8)|adcl);
}

void lcd_init()
{	
	cmd(0x28);		//2->4-bit mode, 8->2-line disp mode
	_delay_ms(1);
	cmd(0x28);		//2->4-bit mode, 8->2-line disp mode
	_delay_ms(1);
	cmd(0x0c);
	_delay_ms(1);
	cmd(0x06);
	_delay_ms(1);
	cmd(0x80);
	_delay_ms(1);
	lcd_clear();
}

void cmd(char comm)
{
	PORTD = (comm & 0xf0) | (1<<EN);
	PORTD = (comm & 0xf0) & (~(1<<EN));
	PORTD = ((comm << 4) & 0xf0) | (1<<EN);
	PORTD = ((comm << 4) & 0xf0) & (~(1<<EN));
	_delay_us(1150);
}

void lcd_clear()
{
	cmd(0x01);
}

void lcd_printc(char c)
{
        Data(c);
}

void lcd_prints(char *arr)
{
	for(uint8_t i = 0; arr[i] != '\0'; i++)
		Data(arr[i]);
}

void Data(char comm)
{
	PORTD = (comm & 0xf0) | (1<<EN) | (1<<RS);
	PORTD = ((comm & 0xf0) & (~(1<<EN))) | (1<<RS);
	PORTD = ((comm<<4) & 0xf0) | (1<<EN) | (1<<RS);
	PORTD = (((comm<<4) & 0xf0) & (~(0<<EN))) | (1<<RS);
	_delay_us(100);
}

void lcd_cust_char(char i, char *arr)
{
	cmd(0x40 | (8*i));
	for(int j = 0; j <8; j++)
	Data(arr[j]);
	cmd(0x80);
}

void lcd_setCursor(char x, char y)
{
	if(y)
		cmd(0x80 + 0x40 + x);
	else if(!y)
		cmd(0x80 + x);
}

Credits

Akash Kollipara

Akash Kollipara

10 projects • 20 followers
Seeker • Engineer • Thinker I am Electronics and Embedded Systems enthusiast driven towards making things simple and best!

Comments