This is my another “disco lights” project which is an upgraded version of ATtiny13 – dance lights with DFT. This time I used a full implementation of optimized DFT algorithm with reduced memory access to compute a power spectrum of audio signal. This version has also 3-channel lights but visual effects are much-much better!
Required Parts
- ATtiny13 – i.e. MBAVR-1 (Minimalist Development Board)
- C1 – capacitor 100nF
- R1,R2 – resistor 10kΩ
- R3,R4,R5 – resistor 220Ω, see LED Resistor Calculator
- R6 – trimm 100kΩ
- LED1, LED2, LED3 – red, green and blue LED
Circuit Diagram
Software
This code is written in C and can be compiled using the avr-gcc. All information about how to compile this project is here.
/** * Copyright (c) 2019, Łukasz Marcin Podkalicki <lpodkalicki@gmail.com> * ATtiny13/026 * Disco lights using DFT (Discrete Fourier Transformation) */ #include <avr/io.h> #include <avr/interrupt.h> #define LED_LOW PB0 #define LED_MID PB1 #define LED_HIGH PB2 #define LOW_THRESHOLD (48000UL) #define MID_THRESHOLD (128) #define HIGH_THRESHOLD (64) #define N (7) // N-points (DFT) #define B (3 * N / 4) // b-value (DFT) const int8_t W[N] = {10, 6, -2, -9, -9, -2, 6}; // twiddle factors (DFT) int8_t samples[N]; // raw samples (ADC) uint16_t power[N>>1]; // power spectrum (DFT) volatile uint8_t counter = 0; static void dft(void); int main(void) { /* setup */ DDRB |= _BV(LED_LOW)|_BV(LED_MID)|_BV(LED_HIGH); // set LED pins as OUTPUT ADCSRA |= _BV(ADPS2)|_BV(ADPS0); // set ADC division factor to 256 ADCSRA |= _BV(ADEN)|_BV(ADIE); // enable ADC interrupt ADMUX = _BV(MUX1); // set ADC4 (PB4) as audio input ADMUX |= _BV(ADLAR); // left adjust of ADC result sei(); // enable global interrupts ADCSRA |= _BV(ADSC); // start first signal acquisition /* loop */ while (1) { if (counter == N) { dft(); // do some DSP /* LOW freqency band */ if (power[0] > LOW_THRESHOLD) { PORTB |= _BV(LED_LOW); } else { PORTB &= ~_BV(LED_LOW); } /* MID freqency band */ if (power[1] > MID_THRESHOLD) { PORTB |= _BV(LED_MID); } else { PORTB &= ~_BV(LED_MID); } /* HIGH frequency band */ if (power[2] > HIGH_THRESHOLD) { PORTB |= _BV(LED_HIGH); } else { PORTB &= ~_BV(LED_HIGH); } counter = 0; // reset samples counter ADCSRA |= _BV(ADSC); // trigger next signal acqusistion } } } ISR(ADC_vect) { if (counter < N) { samples[counter++] = ADCH - 128; // read raw sample <-128; 127> ADCSRA |= _BV(ADSC); // trigger next signal acquisition } } /** * Twiddle-factor-based DFT algorithm with reduced memory access. */ void dft(void) { uint8_t a, b, i, j; int16_t re[N]; int16_t im[N]; for (i = 0; i < N; ++i) { re[i] = 0; im[i] = 0; } for (i = 0; i < (N>>1); ++i) { a = 0; b = B; for (j = 0; j < N; ++j) { re[i] += W[a%N] * samples[j]; im[i] -= W[b%N] * samples[j]; a += i; b += i; } power[i] = (re[i] * re[i] + im[i] * im[i]) >> 4; } }
Hi, great little project!
it’s working for me. I did the upload using Arduino IDE.
I am using an arduino nano to program attiny with Arduino IDE software.
Board: DiY ATtiny13 (in my case, does work only by choosing this board; otherwise, there is an DFP error)
Programmer: Arduino as ISP
If you have no 100k trim resistor, just use something below 100k. I am using 68k.
thanks a lot!
Hi,
please provide hex code and how should fuse settings be
Yes, should be fine. I’ve edited this page few days ago and I forgot to change function definition. Sorry for that. Now is up to date.
I use MkCLIPSE
logs:
main.c:45:13: warning: implicit declaration of function ‘dft’ [-Wimplicit-function-declaration]
dft(); // do some DSP
^
main.c: At top level:
main.c:87:1: warning: conflicting types for ‘dft’
dft(void)
^
main.c:45:13: note: previous implicit declaration of ‘dft’ was here
dft(); // do some DSP
^
main.c:26:13: warning: ‘fft’ declared ‘static’ but never defined [-Wunused-function]
static void fft(void);
I fixed the code, but I’m not sure it’s okay (now I can compile)
#include
#include
#define LED_LOW PB0
#define LED_MID PB1
#define LED_HIGH PB2
#define LOW_THRESHOLD (48000UL)
#define MID_THRESHOLD (128)
#define HIGH_THRESHOLD (64)
#define N (7) // N-points (FFT)
#define B (3 * N / 4) // b-value (FFT)
const int8_t W[N] = {10, 6, -2, -9, -9, -2, 6}; // twiddle factors (FFT)
int8_t samples[N]; // raw samples (ADC)
uint16_t power[N>>1]; // power spectrum (FFT)
volatile uint8_t counter = 0;
ISR(ADC_vect)
{
if (counter < N) {
samples[counter++] = ADCH – 128; // read raw sample
ADCSRA |= _BV(ADSC); // trigger next signal acquisition
}
}
static void
dft(void)
{
uint8_t a, b, i, j;
int16_t re[N];
int16_t im[N];
for (i = 0; i < N; ++i) {
re[i] = 0;
im[i] = 0;
}
for (i = 0; i >1); ++i) {
a = 0;
b = B;
for (j = 0; j > 4;
}
}
int
main(void)
{
/* setup */
DDRB |= _BV(LED_LOW)|_BV(LED_MID)|_BV(LED_HIGH); // set LED pins as OUTPUT
ADCSRA |= _BV(ADPS2)|_BV(ADPS0); // set ADC division factor to 256
ADCSRA |= _BV(ADEN)|_BV(ADIE); // enable ADC interrupt
ADMUX = _BV(MUX1); // set ADC4 (PB4) as audio input
ADMUX |= _BV(ADLAR); // left adjust of ADC result
sei(); // enable global interrupts
ADCSRA |= _BV(ADSC); // start first signal acquisition
/* loop */
while (1) {
if (counter == N) {
dft(); // do some DSP
/* LOW freqency band */
if (power[0] > LOW_THRESHOLD) {
PORTB |= _BV(LED_LOW);
} else {
PORTB &= ~_BV(LED_LOW);
}
/* MID freqency band */
if (power[1] > MID_THRESHOLD) {
PORTB |= _BV(LED_MID);
} else {
PORTB &= ~_BV(LED_MID);
}
/* HIGH frequency band */
if (power[2] > HIGH_THRESHOLD) {
PORTB |= _BV(LED_HIGH);
} else {
PORTB &= ~_BV(LED_HIGH);
}
counter = 0; // reset samples counter
ADCSRA |= _BV(ADSC); // trigger next signal acqusistion
}
}
}
Hi
I have a code problem, my compiler shows a bug in “dft(); // do some DSP ”
How can I solve this?
Hi Jacek,
could provide some logs describing this error?
Btw. in a december edition an EP (Elektronika Praktyczna) will publish my article about optimized DFT for microcontrollers. If it’s something you would like to dive deeper then I recommend to read it.
/L