This is a part of the Kinetiszer project.
Diff: main.c
- Revision:
- 0:cb80470434eb
diff -r 000000000000 -r cb80470434eb main.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/main.c Tue Oct 28 12:19:42 2014 +0000 @@ -0,0 +1,325 @@ +/* + * @brief J2B Synthesizer + * + * @note + * Copyright (C) Elektor, 2014 + * All rights reserved. + * + * @par + * This software is supplied "AS IS" without any warranties of any kind, + * and Elektor and its licensor disclaim any and all warranties, express + * or implied, including all implied warranties of merchantability, + * fitness for a particular purpose and non-infringement of intellectual + * property rights. Elektor assumes no responsibility or liability for + * the use of the software, conveys no license or rights under any patent, + * copyright, mask work right, or any other intellectual property rights in + * or to any products. Elektor reserves the right to make changes in the + * software without notification. Elektor also makes no representation or + * warranty that such application will be suitable for the specified use + * without further testing or modification. + * + * @par + * Permission to use, copy, modify, and distribute this software and its + * documentation is hereby granted, under Elektor's and its licensor's + * relevant copyrights in the software, without fee. This copyright, + * permission, and disclaimer notice must appear in all copies of this code. + */ + +//#include "chip.h" +#include "board.h" +#include "systick.h" +#include "pwm_timer.h" +#include "atmegatron.h" +#include "lcd.h" + + +pwm_timer_t sample_rate_clock; +pwm_timer_t audio_out_clock; +#define AUDIO_OUT_CHANNEL_1 (0) +#define AUDIO_OUT_CHANNEL_2 (2) +#define AUDIO_OUT_FREQUENCY_REGISTER (PWM_TIMER_FREQUENCY_REGISTER) +#define SAMPLE_RATE_OUT_CHANNEL (3) +#define SAMPLE_RATE_FREQUENCY_REGISTER (0) + +volatile uint32_t pwm_update = 256; +volatile uint32_t pwm_update_ch2 = 256; +boolean mono = false; + +// Audio out ISR +void TIMER32_1_IRQHandler(void) +{ + /*if (Chip_TIMER_MatchPending(LPC_TIMER32_1,AUDIO_OUT_FREQUENCY_REGISTER)) + { + Chip_TIMER_ClearMatch(LPC_TIMER32_1,AUDIO_OUT_FREQUENCY_REGISTER); + Chip_TIMER_SetMatch(LPC_TIMER32_1,AUDIO_OUT_CHANNEL_1,pwm_update); + Chip_TIMER_SetMatch(LPC_TIMER32_1,AUDIO_OUT_CHANNEL_2,pwm_update_ch2); + }*/ +} + + +// Pitch ISR +void TIMER32_0_IRQHandler(void) +{ + //if (Chip_TIMER_MatchPending(LPC_TIMER32_0,SAMPLE_RATE_FREQUENCY_REGISTER)) + { + // Clear interrupt flag. + //Chip_TIMER_ClearMatch(LPC_TIMER32_0,SAMPLE_RATE_FREQUENCY_REGISTER); + // If at end of wavetable, go back to start. + if (master_index>WAVE_LEN-1) + { + master_index = 0; + } + + // Set sample value. + // We have 4 bits more resolution than on AVR so multiply by 4. + // pwm_update is consumed in the Audio Out ISR. + pwm_update = master_output[master_index] + 128; + if (mono==true) pwm_update_ch2 = master_output[master_index] + 128; + else pwm_update_ch2 = master_output_ch2[master_index] + 128; + //Chip_TIMER_SetMatch(audio_out_clock.timer,AUDIO_OUT_CHANNEL,master_output[master_index]+128); + // Increment position in wavetable. + master_index++; + // Set pitch. + //Chip_TIMER_SetMatch(LPC_TIMER32_0,SAMPLE_RATE_FREQUENCY_REGISTER,master_ocr1); + // Keep duty-cycle of 50%. + //Chip_TIMER_SetMatch(LPC_TIMER32_0,SAMPLE_RATE_OUT_CHANNEL,master_ocr1>>1); + } +} + + +void setup(void) +{ + // The hardware setup has been removed from setup and is done before. + // Here we now only initialize synthesizer stuff. + + Init_Waves(); // Initialize wavetables. + Init_Hardware(); // Initialize input controls. + LFO_CalcVal(); // Initialize LFO. + AEnv_CalcVal(); // Initialize amplitude envelope. + FEnv_CalcVal(); // Initialize filter/pitch envelope. + Filt_CalcVals(); // Initialize filter. + + if (POLL_MIDI==1) + { + // Open MIDI port (standard serial port) + MIDI_Init(); + } + else + { + // Open the port for debugging. + Serial.begin(9600); + } + + Memory_Vanilla(); //load the Vanilla patch + Hardware_LED_StartFlash(0,5); //flash to say "I'm ready!" +} + + +void loop_priority_low(void) +{ + static uint32_t t_prev = 0; + uint32_t t; + + if (POLL_MIDI==1) + { + // Poll the MIDI input. + MIDI_Poll(); + } + if (POLL_HARD==1) + { + t = systick_counter; + if (t>=t_prev+10) + { + // Limit hardware polling to 100 Hz. + t_prev = t; + // Poll the hardware (potentiometers, rotary encoders and buttons). + Hardware_Poll(); + } + } + + if (POLL_TEST==1) + { + if (master_tick>=Testmode_Get_NextTick()) + { + // If test mode is being used, trigger next test note if it's time to. + Testmode_ProcessNext(); + } + } + +#ifdef __HAS_ARPEGGIATOR__ + Arp_Poll(); //poll the arpeggiator and see if it's time for a note (if it's on) +#endif // __HAS_ARPEGGIATOR__ + + display_draw(false); + keyboard_scan_matrix(); +} + + +void loop_priority_high(void) +{ + // Update master_tick. + master_tick = systick_counter; + + LFO_CalcVal(); //calculate the current output of the LFO + AEnv_CalcVal(); //calculate the current output of the amplitude envelope + FEnv_CalcVal(); //calculate the current output of the filter/pitch envelope + Filt_CalcVals(); //calculate the variables used by the filter + Pitch_Process(); //calculate the current pitch + Master_Let_SampleFreq(); //set interrupt freq based on above calculation + // If a key is down (actually is amplitude envelope idle): + if (Aenv_Get_State()>0) + { + // Process the wavetable (filter/envelope/fx etc...). + Wave_Process(); + Flange_Process_Channel2(); + } + // Otherwise clear the wavetable. This is to stop. + else + { + Wave_Clear(); + Flange_ClearBuffer(); + } +} + + +/*void loop(void) +{ + if (POLL_MIDI==1) + { + // Poll the MIDI input. + Chip_GPIO_WritePortBit(LPC_GPIO_PORT,0,10,true); + MIDI_Poll(); + Chip_GPIO_WritePortBit(LPC_GPIO_PORT,0,10,false); + } + if (POLL_HARD==1) + { + // Poll the hardware (potentiometers, rotary encoders and buttons). + Hardware_Poll(); + } + + // Update master_tick. + master_tick = systick_counter; + + if (POLL_TEST==1) + { + if (master_tick>=Testmode_Get_NextTick()) + { + // If test mode is being used, trigger next test note if it's time to. + Testmode_ProcessNext(); + } + } +#ifdef __HAS_ARPEGGIATOR__ + Arp_Poll(); //poll the arpeggiator and see if it's time for a note (if it's on) +#endif // __HAS_ARPEGGIATOR__ + LFO_CalcVal(); //calculate the current output of the LFO + AEnv_CalcVal(); //calculate the current output of the amplitude envelope + FEnv_CalcVal(); //calculate the current output of the filter/pitch envelope + Filt_CalcVals(); //calculate the variables used by the filter + Pitch_Process(); //calculate the current pitch + Master_Let_SampleFreq(); //set interrupt freq based on above calculation + // If a key is down (actually is amplitude envelope idle): + if (Aenv_Get_State()>0) + { + // Process the wavetable (filter/envelope/fx etc...). + Wave_Process(); + } + // Otherwise clear the wavetable. This is to stop. + else + { + Wave_Clear(); + Flange_ClearBuffer(); + } +}*/ + + +int main_org(void) +{ + // Generic initialization. + // Before we get here the startup routine has already called SystemInit, + // which resides in the file sysinit.c + //SystemCoreClockUpdate(); + Board_Init(); + //SysTick_Config(SystemCoreClock/SYSTICK_RATE_HZ); + + // Setup LCD, pushbuttons and rotary encoders. + keyboard_init(); + display_init(); + + // Setup PWM timer for audio output. + // Use default frequency register (MR3). + // Audio timer is LPC_TIMER32_1, i.e. CT32B1 + // MAT10 (PIO0_13) is PWM1. + // MAT11 (PIO0_14) is shared with S5B. + // MAT12 (PIO0_15) is shared with green LED1. + // MAT13 (PIO0_16) is shared with S6B. + audio_out_clock = pwm_timers[AUDIO_OUT_TIMER]; + audio_out_clock.frequency_register = AUDIO_OUT_FREQUENCY_REGISTER; + PwmTimer_Init(&audio_out_clock,281250/2); + // Setup channel 0 for PWM output on pin 34 (PIO0_13). + PwmTimer_InitChannel(&audio_out_clock,AUDIO_OUT_CHANNEL_1,500); // Duty-cycle x10 for more precision. + PwmTimer_InitChannel(&audio_out_clock,AUDIO_OUT_CHANNEL_2,500); // Duty-cycle x10 for more precision. + PwmTimer_Start(&audio_out_clock); + PwmTimer_EnableInterrupt(&audio_out_clock,AUDIO_OUT_FREQUENCY_REGISTER); + //NVIC_SetPriority(TIMER_32_1_IRQn,0); + + // Setup PWM timer for pitch/sample rate. + // Sample rate timer is LPC_TIMER32_0, i.e. CT32B0 + // MAT00 (PIO0_18) is PWM2. + // MAT01 (PIO0_19) is shared with S6A. + // MAT02 (PIO0_1) is shared with the ISP enable pin / S9. + // MAT03 (PIO1_27) is FX32. + sample_rate_clock = pwm_timers[SAMPLE_RATE_TIMER]; + sample_rate_clock.frequency_register = SAMPLE_RATE_FREQUENCY_REGISTER; + // This frequency setting has no effect because master_ocr1 controls the frequency. + PwmTimer_Init(&sample_rate_clock,440*32); + // Setup channel 0 for PWM output on pin 12 (PIO1_27). + PwmTimer_InitChannel(&sample_rate_clock,SAMPLE_RATE_OUT_CHANNEL,500); // Duty-cycle x10 for more precision. + PwmTimer_Start(&sample_rate_clock); + PwmTimer_EnableInterrupt(&sample_rate_clock,SAMPLE_RATE_FREQUENCY_REGISTER); + //NVIC_SetPriority(TIMER_32_0_IRQn,1); + + // Initialize random number generator (seems to be missing in original code). + randomSeed(0); // TODO: find a better seed. + + // Call the Arduino setup function. + setup(); + + // LEDs toggle in interrupt handlers. + //uint32_t seconds_counter_prev = seconds_counter; + + while (1) + { + // Use pushbutton S11 ("Spare") to quickly enter ISP mode. + /*if (keyboard_get_pushbutton(BOARD_KEYBOARD_S22)==key_pressed) + { + __disable_irq(); + // How can we invoke USB ISP mode from software? + // This call invokes serial ISP. + Chip_FLASH_ReInvokeISP(); + }*/ + + if (keyboard_get_pushbutton_changed(BOARD_KEYBOARD_S22)==true) + { + if (keyboard_get_pushbutton(BOARD_KEYBOARD_S22,true)==key_pressed) + { + mono = !mono; + } + } + + loop_priority_low(); + // The idea was to call loop_priority_high from the systick ISR to + // fix the sample calculation rate to a stable known value. This + // was OK on the LPC1343, but execution is too long on the LPC1347? + // The assembly code is identical for both cases. + loop_priority_high(); + + // Do we need this? + //__WFI(); + } + + //return 0; +} + +/** + * @} + */