From b37bb42f035fd5a5cdfacded92ef2e016e47e888 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lukas=20F=C3=BCrderer?= Date: Sun, 15 Nov 2020 20:14:26 +0100 Subject: [PATCH] Use the speaker to play music Closes #1 --- Main.c | 12 +++ RTE/_MCB1760_mit_LPC1768/RTE_Components.h | 59 ++++++------ Welcome.uvoptx | 105 ++++++++++++++++++++- Welcome.uvprojx | 25 ++++- audio.c | 106 ++++++++++++++++++++++ audio.h | 8 ++ melody.c | 90 ++++++++++++++++++ melody.h | 9 ++ 8 files changed, 381 insertions(+), 33 deletions(-) create mode 100644 audio.c create mode 100644 audio.h create mode 100644 melody.c create mode 100644 melody.h diff --git a/Main.c b/Main.c index 508ac95..efebb3e 100644 --- a/Main.c +++ b/Main.c @@ -8,6 +8,8 @@ This file contains the main app function and init. */ +#include "audio.h" +#include "Board_DAC.h" #include "Welcome.h" //25x25 Dot Qr Code, 25bits per line (x) @@ -71,6 +73,9 @@ int main (void) */ static void vMainInitApp(void) { + // Init audio pin + DAC_Initialize(); + // Init GLCD GLCD_Initialize (); GLCD_SetForegroundColor (GLCD_COLOR_BLACK); @@ -81,6 +86,13 @@ static void vMainInitApp(void) // Init LED LED_Initialize(); + + vStartAudio(); + vPrintQr(); + + while (1) + { + } } /** diff --git a/RTE/_MCB1760_mit_LPC1768/RTE_Components.h b/RTE/_MCB1760_mit_LPC1768/RTE_Components.h index cc7f6a8..77d94e1 100644 --- a/RTE/_MCB1760_mit_LPC1768/RTE_Components.h +++ b/RTE/_MCB1760_mit_LPC1768/RTE_Components.h @@ -1,27 +1,32 @@ - -/* - * Auto generated Run-Time-Environment Component Configuration File - * *** Do not modify ! *** - * - * Project: 'Welcome' - * Target: 'MCB1760 mit LPC1768' - */ - -#ifndef RTE_COMPONENTS_H -#define RTE_COMPONENTS_H - - -/* - * Define the Device Header File: - */ -#define CMSIS_device_header "LPC17xx.h" - -#define RTE_DEVICE_STARTUP_LPC17XX /* Device Startup for NXP17XX */ -#define RTE_Drivers_I2C0 /* Driver I2C0 */ - #define RTE_Drivers_I2C1 /* Driver I2C1 */ - #define RTE_Drivers_I2C2 /* Driver I2C2 */ -#define RTE_Drivers_SPI0 /* Driver SPI0 */ - #define RTE_Drivers_SPI1 /* Driver SPI1 */ -#define RTE_Drivers_SPI2 /* Driver SPI2 */ - -#endif /* RTE_COMPONENTS_H */ + +/* + * Auto generated Run-Time-Environment Configuration File + * *** Do not modify ! *** + * + * Project: 'Welcome' + * Target: 'MCB1760 mit LPC1768' + */ + +#ifndef RTE_COMPONENTS_H +#define RTE_COMPONENTS_H + + +/* + * Define the Device Header File: + */ +#define CMSIS_device_header "LPC17xx.h" + +/* Keil::CMSIS Driver:I2C:2.4.0 */ +#define RTE_Drivers_I2C0 /* Driver I2C0 */ + #define RTE_Drivers_I2C1 /* Driver I2C1 */ + #define RTE_Drivers_I2C2 /* Driver I2C2 */ +/* Keil::CMSIS Driver:SPI:SPI:2.1.0 */ +#define RTE_Drivers_SPI2 /* Driver SPI2 */ +/* Keil::CMSIS Driver:SPI:SSP:2.7.0 */ +#define RTE_Drivers_SPI0 /* Driver SPI0 */ + #define RTE_Drivers_SPI1 /* Driver SPI1 */ +/* Keil::Device:Startup:1.0.0 */ +#define RTE_DEVICE_STARTUP_LPC17XX /* Device Startup for NXP17XX */ + + +#endif /* RTE_COMPONENTS_H */ diff --git a/Welcome.uvoptx b/Welcome.uvoptx index 513fe7f..b8173f7 100644 --- a/Welcome.uvoptx +++ b/Welcome.uvoptx @@ -10,7 +10,7 @@ *.s*; *.src; *.a* *.obj; *.o *.lib - *.txt; *.h; *.inc + *.txt; *.h; *.inc; *.md *.plm *.cpp 0 @@ -77,7 +77,7 @@ 0 1 - 0 + 8 0 1 @@ -140,10 +140,59 @@ 0 UL2CM3 - -UAny -O206 -S8 -C0 -P00 -N00("ARM CoreSight SW-DP") -D00(2BA01477) -L00(0) -TO18 -TC10000000 -TP21 -TDS8007 -TDT0 -TDC1F -TIEFFFFFFFF -TIP8 -FO7 -FD10000000 -FCFE0 -FN1 -FF0LPC_IAP_512.FLM -FS00 -FL080000 -FP0($$Device:LPC1768$Flash\LPC_IAP_512.FLM) + -UAny -O206 -S8 -C0 -P00 -N00("ARM CoreSight SW-DP") -D00(2BA01477) -L00(0) -TO65554 -TC10000000 -TT10000000 -TP21 -TDS8007 -TDT0 -TDC1F -TIEFFFFFFFF -TIP8 -FO7 -FD10000000 -FCFE0 -FN1 -FF0LPC_IAP_512.FLM -FS00 -FL080000 -FP0($$Device:LPC1768$Flash\LPC_IAP_512.FLM) - + + + 0 + 0 + 48 + 1 +
0
+ 0 + 0 + 0 + 0 + 0 + 0 + .\audio.c + + +
+ + 1 + 0 + 47 + 1 +
0
+ 0 + 0 + 0 + 0 + 0 + 0 + .\audio.c + + +
+ + 2 + 0 + 81 + 1 +
8200
+ 0 + 0 + 0 + 0 + 0 + 1 + .\audio.c + + \\Welcome\audio.c\81 +
+
0 @@ -226,6 +275,54 @@ 0 0 + + 1 + 3 + 1 + 1 + 0 + 0 + .\audio.c + audio.c + 0 + 0 + + + 1 + 4 + 5 + 0 + 0 + 0 + .\audio.h + audio.h + 0 + 0 + + + 1 + 5 + 1 + 0 + 0 + 0 + .\melody.c + melody.c + 0 + 0 + + + 1 + 6 + 5 + 0 + 0 + 0 + .\melody.h + melody.h + 0 + 0 + diff --git a/Welcome.uvprojx b/Welcome.uvprojx index f351e56..e542e43 100644 --- a/Welcome.uvprojx +++ b/Welcome.uvprojx @@ -10,7 +10,7 @@ MCB1760 mit LPC1768 0x4 ARM-ADS - 5060750::V5.06 update 6 (build 750)::ARMCC + 5060960::V5.06 update 7 (build 960)::.\ARMCC 0 @@ -185,6 +185,7 @@ 0 0 0 + 0 1 0 8 @@ -351,7 +352,7 @@ 0 0 0 - 0 + 4 @@ -392,6 +393,26 @@ 5 .\Welcome.h + + audio.c + 1 + .\audio.c + + + audio.h + 5 + .\audio.h + + + melody.c + 1 + .\melody.c + + + melody.h + 5 + .\melody.h + diff --git a/audio.c b/audio.c new file mode 100644 index 0000000..3af528d --- /dev/null +++ b/audio.c @@ -0,0 +1,106 @@ +#include "audio.h" +#include "Board_DAC.h" +#include "LPC17xx.h" +#include "melody.h" + +#define FREQ(x) ((x & 0xffff0000) >> 16) +#define WAVES(x) (x & 0xffff) + +struct AudioState +{ + bool highState; + uint16_t u16RemainingWaves; + uint32_t u32EndBreak; + const uint32_t *cpu32NextAction; + uint32_t u32StackPointer; + const uint32_t *cpu32Stack[10]; +}; + +static struct AudioState sAudioState; + +bool bPerformAudioStep() +{ + bool bSuccess = true; + struct AudioState *psState = &sAudioState; + psState = psState; + + sAudioState.highState = !sAudioState.highState; + if (sAudioState.highState) + { + DAC_SetValue(512); + if (sAudioState.u16RemainingWaves == 0) + { + LPC_TIM0->MR0 = sAudioState.u32EndBreak; + } + } + else + { + DAC_SetValue(0); + if (sAudioState.u16RemainingWaves > 0) + { + sAudioState.u16RemainingWaves--; + } + else + { + if (FREQ(*sAudioState.cpu32NextAction) == 0) + { + sAudioState.highState = true; + sAudioState.cpu32NextAction = cppu32JumpLabels[*sAudioState.cpu32NextAction]; + bSuccess = false; + } + else if (FREQ(*sAudioState.cpu32NextAction) == 1) + { + sAudioState.highState = true; + sAudioState.cpu32Stack[sAudioState.u32StackPointer] = sAudioState.cpu32NextAction + 1; + sAudioState.cpu32NextAction = cppu32JumpLabels[WAVES(*sAudioState.cpu32NextAction)]; + sAudioState.u32StackPointer++; + bSuccess = false; + } + else if (FREQ(*sAudioState.cpu32NextAction) == 2) + { + sAudioState.highState = true; + sAudioState.u32StackPointer--; + sAudioState.cpu32NextAction = sAudioState.cpu32Stack[sAudioState.u32StackPointer]; + bSuccess = false; + } + else + { + uint32_t u32Frequency = FREQ(*sAudioState.cpu32NextAction); + LPC_TIM0->MR0 = u32Frequency * 2; + uint32_t u32Waves = WAVES(*sAudioState.cpu32NextAction); + sAudioState.u16RemainingWaves = u32Waves * 9 / 10 - 1; + sAudioState.u32EndBreak = u32Waves * u32Frequency * 2 / 5; + sAudioState.cpu32NextAction++; + } + } + } + + return bSuccess; +} + +void TIMER0_IRQHandler() +{ + LPC_TIM0->IR = 0x1; // acknowledge interrupt + + while (!bPerformAudioStep()) + { + } +} + +// Initializes the interrupt-driven audio output +void vStartAudio() +{ + sAudioState.highState = true; + sAudioState.u16RemainingWaves = 0; + sAudioState.cpu32NextAction = cpu32EntryPoint; + sAudioState.u32StackPointer = 0; + + // Init timerinterrupt 0 (20 ms) + LPC_SC->PCONP |= (1 << 2); // turn on + LPC_SC->PCLKSEL0 |= (1 << 2); // select clock + LPC_TIM0->MR0 = 100000 * 2 - 1; + LPC_TIM0->MCR = 0x3; + NVIC_SetPriority(TIMER0_IRQn, 1U); // priority + NVIC_EnableIRQ(TIMER0_IRQn); + LPC_TIM0->TCR = 1; // start +} diff --git a/audio.h b/audio.h new file mode 100644 index 0000000..4d7694e --- /dev/null +++ b/audio.h @@ -0,0 +1,8 @@ +#ifndef AUDIO_H +#define AUDIO_H + +#include + +void vStartAudio(void); + +#endif diff --git a/melody.c b/melody.c new file mode 100644 index 0000000..c09dc68 --- /dev/null +++ b/melody.c @@ -0,0 +1,90 @@ +#include "melody.h" + +// freq: wave duration as multiple of 40ns +// duration: total duration as multiple of 40ns +#define TONE(freq, duration) ((((uint32_t)freq & 0xffff) << 16) | (((uint32_t)duration / (uint32_t)freq) & 0xffff)) + +const uint32_t TACT = 2120 * 1000 * 25; // 2.12 seconds for one tact + +const uint32_t GIS2 = 30098; +const uint32_t F = 35793; +const uint32_t DIS = 40177; +const uint32_t CIS = 45097; +const uint32_t C = 47778; +const uint32_t B = 53629; +const uint32_t GIS = 60197; + +const uint32_t CALL = 0x10000; +const uint32_t RETURN = 0x20000; + +const uint32_t refrain[]; +const uint32_t quadrupel[]; +const uint32_t *cpu32EntryPoint = refrain; + +const uint32_t GOTO_REFRAIN = 0; +const uint32_t CALL_QUADRUPEL = CALL + 1; + +const uint32_t *jumplabels[] = { + refrain, + quadrupel, +}; +const uint32_t **cppu32JumpLabels = jumplabels; + +const uint32_t quadrupel[] = { + TONE(GIS, TACT / 16), + TONE(B, TACT / 16), + TONE(CIS, TACT / 16), + TONE(B, TACT / 16), + RETURN, +}; + +const uint32_t refrain[] = { + CALL_QUADRUPEL, + + TONE(F, TACT * 3 / 16), + TONE(F, TACT * 3 / 16), + TONE(DIS, TACT * 3 / 8), + CALL_QUADRUPEL, + + TONE(DIS, TACT * 3 / 16), + TONE(DIS, TACT * 3 / 16), + TONE(CIS, TACT * 3 / 16), + TONE(C, TACT / 16), + TONE(B, TACT / 8), + CALL_QUADRUPEL, + + TONE(CIS, TACT / 4), + TONE(DIS, TACT / 8), + TONE(C, TACT * 3 / 16), + TONE(B, TACT / 16), + TONE(GIS, TACT / 4), + TONE(GIS, TACT / 8), + + TONE(DIS, TACT / 4), + TONE(CIS, TACT / 2), + CALL_QUADRUPEL, + + TONE(F, TACT * 3 / 16), + TONE(F, TACT * 3 / 16), + TONE(DIS, TACT * 3 / 8), + CALL_QUADRUPEL, + + TONE(GIS2,TACT / 4), + TONE(C, TACT / 8), + TONE(CIS, TACT * 3 / 16), + TONE(C, TACT / 16), + TONE(B, TACT / 8), + CALL_QUADRUPEL, + + TONE(CIS, TACT / 4), + TONE(DIS, TACT / 8), + TONE(C, TACT * 3 / 16), + TONE(B, TACT / 16), + TONE(GIS, TACT / 4), + TONE(GIS, TACT / 8), + + TONE(DIS, TACT / 4), + TONE(CIS, TACT / 2), + + GOTO_REFRAIN, +}; diff --git a/melody.h b/melody.h new file mode 100644 index 0000000..c8bbdd3 --- /dev/null +++ b/melody.h @@ -0,0 +1,9 @@ +#ifndef MELODY_H +#define MELODY_H + +#include "stdint.h" + +extern const uint32_t *cpu32EntryPoint; +extern const uint32_t **cppu32JumpLabels; + +#endif