This is a part of the Kinetiszer project.

Dependencies:   inc

Dependents:   kinetisizer

main.c

Committer:
Clemo
Date:
2014-10-28
Revision:
1:8ae4ab73ca6a
Parent:
0:cb80470434eb

File content as of revision 1:8ae4ab73ca6a:

/*
 * @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;
}

/**
 * @}
 */