//-----------------------------------------------------------------------------
// Servo control with dsPIC 30F4012
// L. BAGHLI 30/10/2015
//-----------------------------------------------------------------------------
#include "p30F4012.h"

//Configuration bits
/// pas de Quartz !
// _FOSC(CSW_FSCM_OFF & FRC_PLL8);	// 7.37Mhz *8 = 58.96 /4 = 14.74 MIPS maxi pour ce pic
_FOSC(CSW_FSCM_OFF & FRC);	// 7.37Mhz /4 = 1.8425 MIPS pour ce pic
_FWDT(WDT_OFF);
_FBORPOR(PBOR_OFF & RST_PWMPIN & PWMxH_ACT_HI & PWMxL_ACT_LO &  PWRT_64 & MCLR_EN);
//_FGS(CODE_PROT_OFF);
//-----------------------------------------------------------------------------
//Program Specific Constants
//#define FCY 14740000					//Instruction cycle rate (Osc x PLL / 4) = 14.74 MIPS
#define FCY 1842500					//Instruction cycle rate (Osc / 4 ) = 1.8425 MIPS 
#define MILLISEC FCY/1842			// 1 mSec delay constant

// Pour FRC_PLL8    FCY 14740000
////#define FullDuty 18425				// 14.74 MHz*20 ms =294800 / 16 (prescaler 1:16) = 18425
//#define FullDuty 16583				// 18 ms 
//#define Duty100  3869               // 2.1 ms --> 1934.625 x2
//#define Duty50   2764               // 1.5 ms --> 1381.875 x2
//#define Duty0    1658                // 0.9 ms --> 829.125 x2
//#define coefadc 2.1591796875     // rapport (Duty100-Duty0) / 1024

// Pour FRC     FCY 1842500
#define FullDuty 9212				// 1842500 Hz*20 ms =294800 / 4 (prescaler 1:4) = 9212.5
//#define FullDuty 16583				// 18 ms 
#define Duty100  1935               // 2.1 ms --> 967.3125 x2 = 1934.625 resolution PWM double
#define Duty50   1382               // 1.5 ms --> x2
#define Duty0    829.125                // 0.9 ms --> x2 829.125
#define coefadc 1.07958984375     // rapport (Duty100-Duty0) / 1024
// AN0 entrée Potar
// PWM1H sortie servo

void setup_ports(void);
void InitADC10();
void InitMCPWM();
void DelayNmSec(unsigned int N);
void Delay(unsigned int N);

int ValPot;

//-----------------------------------------------------------------------------
//	Setup 
//-----------------------------------------------------------------------------
void setup_ports(void)
{
	ADPCFG=0xFFFE;	// AN0 entrée Potar, all others PORTB = Digital(1) 
	// Clear All Ports Prior to defining I/O
	PORTB=0;	//Initialize LED pin data to off state
	PORTC=0;
	PORTD=0;
	PORTE=0;	
	// Now set pin direction registers
	TRISB = 0xFFFF;		// entrées
	TRISC = 0xFFFF;		// entrées
	TRISD = 0xFFFF;		// entrées
	TRISE = 0xFFFD;		// PWM1H sortie : 1101
	TRISF = 0xFFFF;		// entrées
}
//-----------------------------------------------------------------------------
void InitADC10()
{
    ADCON1 = 0x006F;				// ADC Sampling auto , SOC by PWM
    ADCON2 = 0x0000;				// CH0 conversion only
    ADCHS  = 0x0000;				// Channel 0 positive input is AN0 et negative input is VREF-
    ADCON3 = 0x0080;				// Tad = internal RC (4uS)
    _ADIF = 0;      // Adc int flag Off
    _ADIE = 1;      // Adc int On
	_ADON = 1;		// turn ADC ON
}
//-----------------------------------------------------------------------------
//  InitMCPWM, intializes the PWM as follows:
//  FPWM = 16 khz voir en haut
//  Independant PWMs
//  Set ADC to be triggered by PWM special trigger
//-----------------------------------------------------------------------------
void InitMCPWM()
{
	PTPER = FullDuty;		// TPWM = 20 ms
	OVDCON = 0xFFFF;	// Cmde MLI, no effect of OVDCON
	PWMCON1= 0x0110;    // enable PWM outputs PWM1H only independant
	PDC1=Duty50;		// init sans rien, apres une regul ça change
	SEVTCMP = FullDuty;		// set ADC to trigeer at ...
	PWMCON2 = 0x0000;		// 1 PWM values
	//PTCON = 0x8008;			// start PWM asymetrique prescale 1:16
	PTCON = 0x8004;			// start PWM asymetrique prescale 1:4
}
//?????????????????????????????????????????????????????????????????????
// The ADC interrupt reads the demand pot value.
// tt est synchrone % à cette int de ADC int =2*PWMperiod=2*62.5 us=125 us
//?????????????????????????????????????????????????????????????????????
void __attribute__((interrupt, auto_psv)) _ADCInterrupt ()
{
    _ADIF = 0;
    ValPot = coefadc*ADCBUF0; // ADC read, potentiometer value
    PDC1 = Duty0+ValPot;
}
//-----------------------------------------------------------------------------
//Main routine
int main(void)
{
	setup_ports();
    InitADC10();
    InitMCPWM();
	while(1)
		{	
		}	// end of while (1)
}

//=============================================================================
//Error traps
//-----------------------------------------------------------------------------
//Oscillator Fail Error trap routine
void __attribute__((interrupt, auto_psv)) _OscillatorFail(void)
{	
	while(1); //Wait forever
}
//-----------------------------------------------------------------------------
//Address Error trap routine
void __attribute__((interrupt, auto_psv)) _AddressError(void)
{
	while(1); //Wait forever
}
//-----------------------------------------------------------------------------
//Stack Error trap routine
void __attribute__((interrupt, auto_psv)) _StackError(void)
{
	while(1); //Wait forever
}
//-----------------------------------------------------------------------------
//Math (Arithmetic) Error trap routine
void __attribute__((interrupt, auto_psv)) _MathError(void)
{
    while(1); //Wait forever
}
//---------------------------------------------------------------------
// This is a generic 1ms delay routine to give a 1mS to 65.5 Seconds delay
// For N = 1 the delay is 1 mS, for N = 65535 the delay is 65,535 mS. 
// Note that FCY is used in the computation.  Please make the necessary
// Changes(PLLx4 or PLLx8 etc) to compute the right FCY as in the define
// statement above.
//---------------------------------------------------------------------
void DelayNmSec(unsigned int N)
{
unsigned int j;
while(N--)
 	for(j=0;j < MILLISEC;j++);
}
//---------------------------------------------------------------------
void Delay(unsigned int N)
{
unsigned int j;
 	for(j=0;j < N; j++) __builtin_nop();
}
//---------------------------------------------------------------------
