AVR-Soundgenerator

Check-in [c13a8db10d]
Login

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:PWM-Timer jetzt hoffentlich richtig konfiguriert.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA3-256: c13a8db10d0f2dd9fdab110760d74bf8c4d343b133329c03a0a321cc3a6ef6a1
User & Date: tux12345@justmail.de 2016-04-14 10:30:27
Context
2016-12-24
17:54
Portbelegung für den AVR-Programmer als Bild mit allen Informationen. check-in: 173dad296b user: tux12345@justmail.de tags: trunk
2016-04-14
10:30
PWM-Timer jetzt hoffentlich richtig konfiguriert. check-in: c13a8db10d user: tux12345@justmail.de tags: trunk
10:29
AVR-CPU-Takt auf 8Mhz erhöht. check-in: c860fa0d40 user: tux12345@justmail.de tags: trunk
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to main/main.c.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

21
22
23
24
25
26
27
28
29
30
31
32
33
34
35









36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52


53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74








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



#include "timer.h"

/*
 * Konstanten
 */

// Melodiedefinitionen
const char melody1[] = "BY}6YB6%";
const char melody2[] = "Qj}6jQ6%";

/*
 * Globale Variablen
 */




// Der Tonindex zählt die Anzahl bereits gespielter Töne. Daraus ergibt sich der nächste Ton.
int32_t index = 0;



void write_PWM(uint8_t out);
uint8_t generator_step();
int32_t generator_tone(int32_t index, int32_t x, int32_t tone_choice, int32_t o);
void notify_timer_error();

int main() {











  while(1) {
    notify_timer_error();
    // Läuft, bis der Timer-Interrupt auftritt
    timer_hit = PROGRAM_IDLE;
    while (timer_hit == PROGRAM_IDLE);

    // Neue Werte berechnen
    uint8_t ret = generator_step();
    // Berechneter Ausgabewert per PWM schreiben
    write_PWM(ret);

  }
}


void write_PWM(uint8_t out) {




}

int32_t generator_tone(int32_t index, int32_t x, int32_t tone_choice, int32_t o){

  char tone = (3&index>>16?melody1:melody2)[tone_choice%8];
  tone += 51;
  return((3&x&( index*tone>>o))<<4);

}

uint8_t generator_step() {
  int32_t n=index>>14;
  int32_t s=index>>17;
  uint8_t ret = 0;
  ret += generator_tone(index, 1,   n,                   12);
  ret += generator_tone(index, s,   n^index>>13,         10);
  ret += generator_tone(index, s/3, n+((index>>11)%3),   10);
  ret += generator_tone(index, s/5, 8+n-((index>>10)%3), 9);
  ++index;
  return ret;
}










|















|
>



|






|


|
|
>
>
>
>
>
>
>
>
>

|

|
|
<

|

|
<




|
|
>
>



|


















>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50

51
52
53
54

55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91

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


#include "timer.h"

/*
 * Konstanten
 */

// Melodiedefinitionen
const char melody1[] = "BY}6YB6%";
const char melody2[] = "Qj}6jQ6%";

/*
 * Globale Variablen
 */
extern volatile uint8_t program_status;
extern volatile uint8_t timer_status;


// Der Tonindex zählt die Anzahl bereits gespielter Töne. Daraus ergibt sich der nächste Ton.
uint32_t index = 0;



void write_PWM(uint8_t out);
uint8_t generator_step();
int32_t generator_tone(int32_t index, int32_t x, int32_t tone_choice, int32_t o);
void check_timer_error();

int main() {
  //Energiesparen: Nicht benötigte Module ausschalten:
  //AD-Wandler, USART-Interface, SPI und Timer1 abschalten
  //PRR |= _BV(PRADC) | _BV(PRUSART0) | _BV(PRSPI) | _BV(PRTIM1);
  //Pin für Fehlerausgabe
  DDRC |= _BV(PORTC5);
  PORTC |= _BV(PORTC5);
  //Pin für PWM-Ausgabe
  DDRD |= _BV(PORTD6);
  PORTD &= (unsigned char) ~_BV(PORTD6);
  setup_Timer();
  sei();
  while(1) {
    check_timer_error();
    // Läuft, bis der Timer-Interrupt auftritt
    program_status = PROGRAM_IDLE;
    while (program_status == PROGRAM_IDLE);

    // Neue Werte berechnen
    uint8_t out = generator_step();
    // Berechneter Ausgabewert per PWM schreiben
    write_PWM(out);

  }
}


inline void write_PWM(uint8_t out) {
  // TODO: Funktioniert CTC auch mit 0 oder 0xFF als vergleichswert korrekt?
  //-> Ist der Port dauerhaft auf LOW, wenn 0 geschrieben wird und dauerhaft auf HIGH, wenn 0xFF geschrieben wird?
  OCR0A = out;

}

int32_t generator_tone(int32_t index, int32_t x, int32_t tone_choice, int32_t o) {

  char tone = (3&index>>16?melody1:melody2)[tone_choice%8];
  tone += 51;
  return((3&x&( index*tone>>o))<<4);

}

uint8_t generator_step() {
  int32_t n=index>>14;
  int32_t s=index>>17;
  uint8_t ret = 0;
  ret += generator_tone(index, 1,   n,                   12);
  ret += generator_tone(index, s,   n^index>>13,         10);
  ret += generator_tone(index, s/3, n+((index>>11)%3),   10);
  ret += generator_tone(index, s/5, 8+n-((index>>10)%3), 9);
  ++index;
  return ret;
}


inline void check_timer_error() {
  if(timer_status == TIMER_STATUS_ERROR)
    PORTC &= (unsigned char) ~_BV(PORTC5);
}

Changes to main/timer.c.

1
2
3
4
5
6


7




8
9
10
11
12


13
14
15
16


17
18
19
20
21



22

23






24
25
26
27
#include "timer.h"

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

ISR(TIMER1_OVF_vect) {


  register uint8_t number_timer_ticks_local = number_timer_ticks;




  ++number_timer_ticks_local;
  if(number_timer_ticks_local == TIMER_TICKS_PERIOD) {
    number_timer_ticks_local = 0;
    if(timer_hit == PROGRAM_IDLE)
      timer_hit = PROGRAM_BUSY;


    else
      timer_error = TIMER_STATUS_ERROR;
  }
  number_timer_ticks = number_timer_ticks_local;


}



void setup_Timer() {



  TCCR0 = _BV(CS00);











}





|
>
>
|
>
>
>
>
|
|
|
|
|
>
>

|

<
>
>





>
>
>
|
>
|
>
>
>
>
>
>




1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
#include "timer.h"

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


volatile uint8_t program_status = PROGRAM_IDLE;
volatile uint8_t timer_status = TIMER_STATUS_OK;
uint8_t number_timer_ticks = 0;


ISR(TIMER2_OVF_vect) {
  //TODO: 16-Bit Timer 1 verwenden. Vereinfacht den code…
  ++number_timer_ticks;
  if(number_timer_ticks == TIMER_TICKS_PERIOD) {
    number_timer_ticks = 0;
    if(program_status == PROGRAM_IDLE){
      program_status = PROGRAM_BUSY;
      PORTC &= (unsigned char) ~_BV(PORTC5);
    }
    else
      timer_status = TIMER_STATUS_ERROR;
  }

  else
    PORTC |= _BV(PORTC5);
}



void setup_Timer() {
  //Programmtimer (8kHz), stößt alle 125 Interrupts eine neue Berechnung an
  //
  //TCNT2 = 0x00; // Counter auf 0 setzen
  TIMSK2 |= _BV(TOIE2); // Timer 2 Overflow-interrupt einschalten
  TCCR2B |= _BV(CS21); // Taktgeber auf Prescaler mit F_CPU/8 setzen. Dadurch ergibt sich 8Mhz/8/125 = 8kHz Abtastrate
  
  // PWM-Timer hält die Lautsprechermembran auf einem Level. Wird bei jedem Programmtimerinterrupt neu programmiert.
  //
  OCR0A = 0x00; // // Vergleichswert für PWM mit 0 initialisieren. Wird von main berechnet und überschrieben
  //TCNT0 = 0x00; // Counter auf 0 setzen
  TCCR0A = _BV(WGM00) | _BV(WGM01) | _BV(COM0A1); // Timer 0 für Fast PWM konfigurieren
  TCCR0B |=_BV(CS00) | _BV(WGM02); // Taktgeber auf CPU-Takt setzen



}

Changes to main/timer.h.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#ifndef TIMER_H
#define TIMER_H

#include <stdint.h>

# define PROGRAM_BUSY 1
# define PROGRAM_IDLE 0
# define TIMER_TICKS_PERIOD 125

# define TIMER_STATUS_OK 0
# define TIMER_STATUS_ERROR 1

volatile uint8_t timer_hit = PROGRAM_IDLE;
volatile uint8_t timer_error = TIMER_STATUS_OK;
volatile uint8_t number_timer_ticks = 0;


void setup_Timer();

#endif












|
<
<





1
2
3
4
5
6
7
8
9
10
11
12
13


14
15
16
17
18
#ifndef TIMER_H
#define TIMER_H

#include <stdint.h>

# define PROGRAM_BUSY 1
# define PROGRAM_IDLE 0
# define TIMER_TICKS_PERIOD 125

# define TIMER_STATUS_OK 0
# define TIMER_STATUS_ERROR 1






void setup_Timer();

#endif