Wednesday, March 18, 2015

Creative T20 speakers standby mode Attiny45 C source code


This code is from project: Creative T20 speakers standby mode

delay.h

#ifndef _H_DELAY_
#define _H_DELAY_

#define nop()  __asm__ __volatile__("nop")

void delay_ms(unsigned short ms);
void delay_us(unsigned short us);

#endif

delay.c

#include "main.h"
#include <util/delay.h>

#include "delay.h"

/****************************************************************************/
/* It is better to put a delay in the loop than provide high value to       */
/* standard function, because the code will be smaller,                     */
/****************************************************************************/
void delay_ms(unsigned short ms) {
    while ( ms ) {
      ms--;
      _delay_ms(1);
   }
}

void delay_us(unsigned short us) {
    while ( us ) {
      us--;
      _delay_us(1);
   }
}

main.h

#ifndef _H_MAIN_H
#define _H_MAIN_H

// This is wrong, should be 1MHz, and it could affect _delay_ms().
// You can change this in your device. I don't bother to
// disassembly T20 again and upload fix on MCU,
// because it works ok for me.
#define F_CPU 8000000L

// some usefeuul macros
#define H(a,b) a |=(1<<(b))
#define L(a,b) a &=~(1<<(b))
#define IS(a,b) bit_is_set(a,b)
#define BS(a,b) (a & (1<<(b)))

#endif

main.c

#include "main.h"

#include <avr/io.h>
#include <avr/interrupt.h>

#include "delay.h"

#define DIMMER_LEVEL  0x0F

#define ADC_LEVEL  5

// globals
uint8_t dimmer = 0; 
uint8_t up = 1;
uint8_t disable_sleep = 0;

void turn_on();
void turn_off();

/****************************************************************************/
/* Interrupt handler. When button is pressed, this will happen.             */
/****************************************************************************/
SIGNAL(SIG_INTERRUPT0) {

   // if sleep mode is off, switch
   // it on and blink led once
   if(disable_sleep) {
      disable_sleep = 0;

      OCR0A = 0xFF;
      OCR0A = 0x00;
      delay_ms(100);
      OCR0A = 0xFF;

   }
   else {
      // disable sleep mode and blink led twice
      disable_sleep = 1;
      OCR0A = 0xFF;
      OCR0A = 0x00;
      delay_ms(100);
      OCR0A = 0xFF;
      delay_ms(100);
      OCR0A = 0x00;
      delay_ms(100);
      OCR0A = 0xFF;
      turn_on();
   }

   // be sure not to fire INT0 couple of times
   delay_ms(500);
}   


/****************************************************************************/
/* Function changes led brightness to the max, sets PB1 to high state       */
/* (shutdown pin from TPA3123 will be in high state). Turns dimmer off.     */
/****************************************************************************/
void turn_on() {
   OCR0A = 0xFF;
   dimmer = 0; 
   H(PORTB, PB1);
}


/****************************************************************************/
/* Opposite of function above: shuts down TPA3123 by forcing low state on   */
/* shutdown pin and turns on led dimmer.                                    */
/****************************************************************************/
void turn_off() {
   while(OCR0A-- > DIMMER_LEVEL) {
      delay_ms(1);
   }
   up = 0;
   dimmer = 1; 
   L(PORTB, PB1);
}


/****************************************************************************/
/* Main, everything is in while(1) loop.                                    */
/****************************************************************************/
int main()
{
   // pin state init
   H(DDRB, PB0);
   H(PORTB, PB0);

   H(DDRB, PB1);
   H(PORTB, PB1);

   L(DDRB, PB2);

   // PWM init
   H(TCCR0A, COM0A0);
   H(TCCR0A, COM0A1);

   H(TCCR0A, WGM00);
   H(TCCR0A, WGM01);

   H(TCCR0B, CS00);
   TCNT0 = 0x00;
   OCR0A = 0x00;

   // ADC init
   L(ADMUX, REFS0);
   H(ADMUX, REFS1); 
   H(ADMUX, REFS2); 

   H(ADMUX, ADLAR);

   L(ADCSRA, ADPS0);
   H(ADCSRA, ADPS1);
   H(ADCSRA, ADPS2);
   H(ADCSRA, ADEN);

   // INT0 init
   L(MCUCR, ISC00);
   L(MCUCR, ISC01);
   H(GIMSK, INT0);

   // enable interrupts (INT0)
   sei();

   turn_off();

   // main locals
   uint8_t adc = 0;
   uint8_t cnt = 0;

   while(1) {

      if(disable_sleep) 
         continue;

      // get value from ADC differential mode 20x gain
      H(ADMUX, MUX0); 
      H(ADMUX, MUX1); 
      H(ADMUX, MUX2); 
      H(ADCSRA, ADSC);
      while (ADCSRA & (1 << ADSC));
      adc = ADCH;

      if (adc > ADC_LEVEL) {
         // turn on immediately when
         // there is someting on ADC input
         cnt = 0;
         turn_on();
      } else {
         // count down to shut down mode
         cnt++;
         delay_ms(25);
      }

      if(cnt > 200) {
         // shut down after no sound
         cnt = 0;
         turn_off();
      }

      // led pwm dimmer
      if(dimmer)  {
         if(up)
            OCR0A++;
         else
            OCR0A--;

         if(OCR0A >= DIMMER_LEVEL) {
            up = 0;
         }

         if(OCR0A < 1) {
            up = 1;
         }
         delay_ms(10);
      }
  } 
}

Makefile

CPU=attiny45

GCC=avr-gcc
CFLAGS= -Os -mmcu=$(CPU) -Wall -fpack-struct -fshort-enums -funsigned-bitfields -Wl,--relax -fno-move-loop-invariants -funsigned-char -fno-inline-small-functions -fdata-sections -fno-tree-loop-optimize -lprintf_min 

INCLUDES=
LIBS=

OBJCPY=avr-objcopy
OBJECTS=main.o delay.o

PROJECT_NAME=auto_speakers
HEX_FILE=$(PROJECT_NAME).hex
HEX_FILE_DUMP=$(PROJECT_NAME)_dump.hex

# this line shoud be replaced by your programmator
PROG=avrdude
PROG_FLAGS=-V -c usbasp -p $(CPU)

all: cls $(PROJECT_NAME) obj size #upload

$(PROJECT_NAME): $(OBJECTS)
  $(GCC) -o $(PROJECT_NAME) $(OBJECTS) $(CFLAGS) $(LIBS) $(INCLUDES)

main.o: main.c main.h 
  $(GCC) $(CFLAGS) $(INCLUDES) -c main.c

delay.o: delay.c delay.h
  $(GCC) $(CFLAGS) $(INCLUDES) -c delay.c

obj: $(OBJECTS)
  $(OBJCPY) -O ihex $(PROJECT_NAME) $(HEX_FILE)

clean:
  rm -f $(PROJECT_NAME) $(OBJECTS) $(HEX_FILE)

cls:
  clear

size:
  du -b $(HEX_FILE) 

# this line shoud be replaced by your programmator
upload: all $(HEX_FILE)
  $(PROG) $(PROG_FLAGS) -e -U flash:w:$(HEX_FILE)


# this line shoud be replaced by your programmator
download:
  $(PROG) $(PROG_FLAGS) -U flash:r:$(HEX_FILE_DUMP)

# this line shoud be replaced by your programmator
reset:
  $(PROG) $(PROG_FLAGS)

No comments:

Post a Comment