This is a part of the Kinetiszer project.

Dependencies:   inc

Dependents:   kinetisizer

Revision:
0:cb80470434eb
--- /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;
+}
+
+/**
+ * @}
+ */