-
Notifications
You must be signed in to change notification settings - Fork 0
/
Sound.c
407 lines (374 loc) · 11.1 KB
/
Sound.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
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
// Sound.c
// This is the starter file for CECS 447 Project 1 Part 2
// By Dr. Min He
// September 10, 2022
// Port B bits 5-0 outputs to the 6-bit DAC
// Port D bits 3-0 inputs from piano keys: CDEF:doe ray mi fa,negative logic connections.
// Port F is onboard LaunchPad switches and LED
// SysTick ISR: PF3 is used to implement heartbeat
#include "tm4c123gh6pm.h"
#include "sound.h"
#include <stdint.h>
// define bit addresses for Port B bits 0,1,2,3,4,5 => DAC inputs
#define DAC (*((volatile unsigned long *)0x400050FC))
// 6-bit: value range 0 to 2^6-1=63, 64 samples
const uint8_t SineWave[64] = {32, 35, 38, 41, 44, 47, 49, 52, 54, 56, 58, 59, 61, 62, 62, 63, 63, 63, 62, 62,
61, 59, 58, 56, 54, 52, 49, 47, 44, 41, 38, 35, 32, 29, 26, 23, 20, 17, 15, 12,
10, 8, 6, 5, 3, 2, 2, 1, 1, 1, 2, 2, 3, 5, 6, 8, 10, 12, 15, 17,
20, 23, 26, 29};
// initial values for piano major tones.
// Assume SysTick clock frequency is 16MHz.
const uint32_t tonetab[] =
// C, D, E, F, G, A, B
// 1, 2, 3, 4, 5, 6, 7
// lower C octave:130.813, 146.832,164.814,174.614,195.998, 220,246.942
// calculate reload value for the whole period:Reload value = Fclk/Ft = 16MHz/Ft
{ // C D E F G A B
30534 * 2, 27211 * 2, 24242 * 2, 22923 * 2, 20408 * 2, 18182 * 2, 16194 * 2, // C4 Major notes
15289 * 2, 13621 * 2, 12135 * 2, 11454 * 2, 10204 * 2, 9091 * 2, 8099 * 2, // C5 Major notes
7645 * 2, 6810 * 2, 6067 * 2, 5727 * 2, 5102 * 2, 4545 * 2, 4050 * 2}; // C6 Major notes
// Constants
// index definition for tones used in happy birthday.
enum note_names
{
C4,
D4,
E4,
F4,
G4,
A4,
B4,
C5,
D5,
E5,
F5,
G5,
A5,
B5,
C6,
D6,
E6,
F6,
G6,
A6,
B6
};
#define MAX_NOTES 255 // maximum number of notes for a song to be played in the program
// #define NUM_SONGS 3 // number of songs in the play list.
#define SILENCE MAX_NOTES // use the last valid index to indicate a silence note. The song can only have up to 254 notes.
#define NUM_OCT 3 // number of octave defined in tontab[]
#define NUM_NOTES_PER_OCT 7 // number of notes defined for each octave in tonetab
#define NVIC_EN0_PORTF 0x40000000 // enable PORTF edge interrupt
#define NVIC_EN0_PORTD 0x00000008 // enable PORTD edge interrupt
#define NUM_SAMPLES 64 // number of sample in one sin wave period
#define SW1 0x10 // bit position for onboard switch 1(left switch)
#define SW2 0x01 // bit position for onboard switch 2(right switch)
#define PIANO 0 // piano mode: press a key to play a tone
#define AUTO_PLAY 1 // auto play mode: automatic playing a song
#define PORTB5_B0 0x3F // PB5 - PB0 (0011 1111)
// note table for Happy Birthday
// doe ray mi fa so la ti
// C D E F G A B
NTyp playlist[][MAX_NOTES] =
{
// Mary Had A Little Lamb
{E4, 4, D4, 4, C4, 4, D4, 4, E4, 4, E4, 4, E4, 8,
D4, 4, D4, 4, D4, 8, E4, 4, G4, 4, G4, 8,
E4, 4, D4, 4, C4, 4, D4, 4, E4, 4, E4, 4, E4, 8,
D4, 4, D4, 4, E4, 4, D4, 4, C4, 8, 0, 0},
// Twinkle Twinkle Little Stars
{C4, 4, C4, 4, G4, 4, G4, 4, A4, 4, A4, 4, G4, 8, F4, 4, F4, 4, E4, 4, E4, 4, D4, 4, D4, 4, C4, 8,
G4, 4, G4, 4, F4, 4, F4, 4, E4, 4, E4, 4, D4, 8, G4, 4, G4, 4, F4, 4, F4, 4, E4, 4, E4, 4, D4, 8,
C4, 4, C4, 4, G4, 4, G4, 4, A4, 4, A4, 4, G4, 8, F4, 4, F4, 4, E4, 4, E4, 4, D4, 4, D4, 4, C4, 8, 0, 0},
// Happy Birthday
{// so so la so doe' ti
G4, 2, G4, 2, A4, 4, G4, 4, C5, 4, B4, 4,
// pause so so la so ray' doe'
SILENCE, 4, G4, 2, G4, 2, A4, 4, G4, 4, D5, 4, C5, 4,
// pause so so so' mi' doe' ti la
SILENCE, 4, G4, 2, G4, 2, G5, 4, E5, 4, C5, 4, B4, 4, A4, 8,
// pause fa' fa' mi' doe' ray' doe' stop
SILENCE, 4, F5, 2, F5, 2, E5, 4, C5, 4, D5, 4, C5, 8, SILENCE, 0},
};
// File scope golbal
volatile uint8_t curr_song = 0; // 0: Happy Birthday, 1: Mary Had A Little Lamb. 2: Twinkle Twinkle Little Stars
volatile uint8_t stop_play = 0; // 0: continue playing a song, 1: stop playing a song
volatile uint8_t skip_song = 0; // 0: continue playing a song, 1: skip song
volatile uint8_t octave = 0; // 0: lower C, 1: middle C, 2: upper C
uint8_t Index; // DAC SineWave array index
extern volatile uint8_t curr_mode;
// **************DAC_Init*********************
// Initialize 6-bit DAC
// Input: none
// Output: none
void DAC_Init(void)
{
SYSCTL_RCGC2_R |= SYSCTL_RCGC2_GPIOB; // activate Port B
while ((SYSCTL_RCGC2_R & SYSCTL_RCGC2_GPIOB) != SYSCTL_RCGC2_GPIOB)
;
GPIO_PORTB_AMSEL_R &= ~PORTB5_B0; // disable analog on PB5-0
GPIO_PORTB_PCTL_R &= ~0x00FFFFFF; // PCTL GPIO on PB5-0
GPIO_PORTB_DIR_R |= PORTB5_B0; // PB5-0 output (0011 1111)
GPIO_PORTB_AFSEL_R &= ~PORTB5_B0; // disable alt funct on PB5-0
GPIO_PORTB_DEN_R |= PORTB5_B0; // enable digital I/O on PB5-0
GPIO_PORTB_DR8R_R |= PORTB5_B0; // enable 8 mA drive on PB5-0
// Sound Initialization: Initialize SysTick periodic interrupts
Index = 0;
NVIC_ST_CTRL_R &= ~NVIC_ST_CTRL_ENABLE; // disable SysTick during setup
NVIC_SYS_PRI3_R = (NVIC_SYS_PRI3_R & 0x1FFFFFFF) | 0x20000000; // priority 1
NVIC_ST_CTRL_R |= NVIC_ST_CTRL_CLK_SRC | NVIC_ST_CTRL_INTEN; // enable SysTick with core clock and interrupts
}
// **************Sound_Start*********************
// Set reload value and enable systick timer
// Input: time duration to be generated in number of machine cycles
// Output: none
void Sound_Start(uint32_t period)
{
NVIC_ST_RELOAD_R = period - 1; // reload value (frequency)
NVIC_ST_CURRENT_R = 0; // any write to current clears it
NVIC_ST_CTRL_R |= NVIC_ST_CTRL_ENABLE;
}
void Sound_stop(void)
{
NVIC_ST_CTRL_R &= ~NVIC_ST_CTRL_ENABLE;
}
// Interrupt service routine
// Executed based on number of sampels in each period
void SysTick_Handler(void)
{
GPIO_PORTF_DATA_R ^= 0x08; // toggle PF3, debugging
Index = (Index + 1) % NUM_SAMPLES;
DAC = SineWave[Index]; // output to DAC: 6-bit data
}
/**
* @brief Handles the onboard push buttons that will change the system's mode or octive
*
* SW1: change system mode
* SW2: change octave or song
*/
void GPIOPortF_Handler(void)
{
// simple debouncing code: generate 20ms to 30ms delay
for (uint32_t time = 0; time < 72724; time++)
{
}
if (GPIO_PORTF_MIS_R & SW1) // change system mode
{
GPIO_PORTF_ICR_R = SW1; // acknowledge flag 0
if (curr_mode == PIANO)
{
stop_play = 0; // start playing a song
curr_mode = AUTO_PLAY;
}
else if (curr_mode == AUTO_PLAY)
{
stop_play = 1; // stop play a song
curr_mode = PIANO;
curr_song = 0; // reset playlist index
}
}
else if (GPIO_PORTF_MIS_R & SW2) // change song or octave
{
GPIO_PORTF_ICR_R = SW2; // acknowledge flag 4
if (curr_mode == AUTO_PLAY) // skip song
{
skip_song = 1;
}
else if (curr_mode == PIANO) // change octave
{
if (octave < 2)
octave++;
else
octave = 0;
}
}
}
//---------------------Delay10ms---------------------
// wait 10ms for switches to stop bouncing
// Input: none
// Output: none
void Delay10ms(void)
{
unsigned long volatile time;
time = 14545; // 10msec
while (time)
{
time--;
}
}
// Dependency: Requires PianoKeys_Init to be called first, assume at any time only one key is pressed
// Inputs: None
// Outputs: None
// Description: Rising/Falling edge interrupt on PD6-PD0. Whenever any
// button is pressed, or released the interrupt will trigger.
void GPIOPortD_Handler(void)
{
// simple debouncing code: generate 20ms to 30ms delay
for (uint32_t time = 0; time < 72724; time++)
{
}
if (curr_mode == AUTO_PLAY)
return;
if (GPIO_PORTD_MIS_R & 0x01) // PD0
{
GPIO_PORTD_ICR_R = 0x01;
if (!(GPIO_PORTD_DATA_R & 0x01))
{
Sound_Start(tonetab[(NUM_NOTES_PER_OCT * octave)] / NUM_SAMPLES); // C
}
else
{
Sound_stop();
}
}
else if (GPIO_PORTD_MIS_R & 0x02) // PD1
{
GPIO_PORTD_ICR_R = 0x02;
if (!(GPIO_PORTD_DATA_R & 0x02))
{
Sound_Start(tonetab[(NUM_NOTES_PER_OCT * octave) + 1] / NUM_SAMPLES); // D
}
else
{
Sound_stop();
}
}
else if (GPIO_PORTD_MIS_R & 0x04) // PD2
{
GPIO_PORTD_ICR_R = 0x04;
if (!(GPIO_PORTD_DATA_R & 0x04))
{
Sound_Start(tonetab[(NUM_NOTES_PER_OCT * octave) + 2] / NUM_SAMPLES); // E
}
else
{
Sound_stop();
}
}
else if (GPIO_PORTD_MIS_R & 0x08) // PD3
{
GPIO_PORTD_ICR_R = 0x08;
if (!(GPIO_PORTD_DATA_R & 0x08))
{
Sound_Start(tonetab[(NUM_NOTES_PER_OCT * octave) + 3] / NUM_SAMPLES); // F
}
else
{
Sound_stop();
}
}
else if (GPIO_PORTD_MIS_R & 0x40) // PD6
{
GPIO_PORTD_ICR_R = 0x40;
if (!(GPIO_PORTD_DATA_R & 0x40))
{
Sound_Start(tonetab[(NUM_NOTES_PER_OCT * octave) + 4] / NUM_SAMPLES); // G
}
else
{
Sound_stop();
}
}
else
{
Sound_stop();
}
// pause after each play
Delay10ms();
}
// ****** Piano extended buttons using Port A ********
// Dependancy: Requires PianoKeys_Init to be called first, assume at any time only one key is pressed
// Inputs: None
// Outputs: None
// Description: Rising/Falling edge interrupt on PA2-3. Whenever any
// button is pressed, or released the interrupt will trigger.
void GPIOPortA_Handler(void)
{
// simple debouncing code: generate 20ms to 30ms delay
for (uint32_t time = 0; time < 72724; time++)
{
}
if (curr_mode == AUTO_PLAY)
return;
if (GPIO_PORTA_MIS_R & 0x04) // PA2
{
GPIO_PORTA_ICR_R = 0x04;
if (!(GPIO_PORTA_DATA_R & 0x04))
{
Sound_Start(tonetab[(NUM_NOTES_PER_OCT * octave) + 5] / NUM_SAMPLES); // A
}
else
{
Sound_stop();
}
}
else if (GPIO_PORTA_MIS_R & 0x08) // PA3
{
GPIO_PORTA_ICR_R = 0x08;
if (!(GPIO_PORTA_DATA_R & 0x08))
{
Sound_Start(tonetab[(NUM_NOTES_PER_OCT * octave) + 6] / NUM_SAMPLES); // B
}
else
{
Sound_stop();
}
}
else
{
Sound_stop();
}
// pause after each play
Delay10ms();
}
// Subroutine to wait 0.1 sec
// Inputs: None
// Outputs: None
// Notes: ...
void Delay(void)
{
uint32_t volatile time;
time = 727240 * 20 / 91; // 0.1sec
while (time)
{
time--;
}
}
void play_a_song()
{
unsigned char i = 0, j;
while (playlist[curr_song][i].delay && curr_mode == AUTO_PLAY && skip_song == 0)
{
// Mode changed from AUTO_PLAY to PIANO in the middle of a note
if (stop_play)
{
Sound_stop();
return;
}
if (playlist[curr_song][i].tone_index == MAX_NOTES)
Sound_stop(); // silence tone, turn off SysTick timer
else
{
Sound_Start(tonetab[playlist[curr_song][i].tone_index + (octave * NUM_NOTES_PER_OCT)] / NUM_SAMPLES);
}
// tempo control: play current note for specified duration
for (j = 0; j < playlist[curr_song][i].delay; j++)
Delay();
Sound_stop();
i++; // move to the next note
}
if (curr_mode == AUTO_PLAY && skip_song == 0)
{
// pause after each play
for (j = 0; j < 15; j++)
Delay();
}
if (skip_song) // check if skip song flag has been set
{
if (curr_song < 2)
curr_song++;
else
curr_song = 0;
skip_song = 0;
}
}