Hiya all,
I have been working on something along the same lines. I was hoping to build a function to set 1 or more of the three timers to produce a clock pulse of 100Hz to 2MHz. Built a library and a function using the AT91 and sam3x8w datasheets provided by Atmel.
Register_Deff.h
//Software
//Define control registers locations.
///////////////////////////////////////////////////////////////////
// Timers
///////////////////////////////////////////////////////////////////
//For Timer 1
#define TC1_CCR ((volatile unsigned int *) 0x40080000)
#define TC1_CMR ((volatile unsigned int *) 0x40080004)
#define TC1_RA ((volatile unsigned int *) 0x40080014)
#define TC1_RB ((volatile unsigned int *) 0x40080018)
#define TC1_RC ((volatile unsigned int *) 0xFFFE005C)
//For Timer 2
#define TC2_CCR ((volatile unsigned int *) 0x40080040)
#define TC2_CMR ((volatile unsigned int *) 0x40080044)
#define TC2_RA ((volatile unsigned int *) 0x40080054)
#define TC2_RB ((volatile unsigned int *) 0x40080058)
#define TC2_RC ((volatile unsigned int *) 0x4008005C)
//For Timer 3
#define TC3_CCR ((volatile unsigned int *) 0x40080080)
#define TC3_CMR ((volatile unsigned int *) 0x40080084)
#define TC3_RA ((volatile unsigned int *) 0x40080094)
#define TC3_RB ((volatile unsigned int *) 0x40080098)
#define TC3_RC ((volatile unsigned int *) 0x4008009C)
////////////////////////////////////////////////////////////////////
// General Ports
////////////////////////////////////////////////////////////////////
#define PortA_DIR ((volatile unsigned int *) 0x400E0E04)
#define PORTB_DIR ((volatile unsigned int *) 0x400E1004)
#define PORTC_DIR ((volatile unsigned int *) 0x400E1204)
#define PORTD_DIR ((volatile unsigned int *) 0x400E1404)
#define PORTE_DIR ((volatile unsigned int *) 0x400E1604)
#define PORTF_DIR ((volatile unsigned int *) 0x400E1804)
Function
int Pulse(Timer_ID, Frequency, Pulse_Width)
{
/*
This function will put out two PWM signals out of TIOAx (Desired pulse width),TIOBx (Always set to 50%). This is a hardware function, meaning once set it will have no effect on the external program.
Unless the external program trys to use the timer that has been initialised here
*/
//* TC_CMR: Timer Counter Channel Mode Register Bits Definition
unsigned int
TC_CLKS_MCK2 = 0x0,
TC_EEVT_XC0 = 0x400,
TC_CPCTRG = 0x4000,
TC_WAVE = 0x8000,
TC_ACPA_TOGGLE_OUTPUT = 0x30000,
TC_ACPC_TOGGLE_OUTPUT = 0xC0000,
TC_ASWTRG_SET_OUTPUT = 0x400000,
TC_BCPB_TOGGLE_OUTPUT = 0x3000000,
TC_BCPC_TOGGLE_OUTPUT = 0xC000000,
TC_BSWTRG_SET_OUTPUT = 0x40000000;
//* TC_CCR: Timer Counter Control Register Bits Definition
unsigned int
TC_CLKEN = 0x1,
TC_CLKDIS = 0x2,
TC_SWTRG = 0x4;
// Porting
int
PIOTIOA1 = 4, // Timer 1 Signal A
PIOTIOB1 = 5; // Timer 1 Signal B
*TC1_CCR = TC_CLKDIS ; // Disable the Clock Counter
*PortA_DIR = (1<<PIOTIOA1) | (1<<PIOTIOB1) ; // Define TIOA1 and TIOB1 as peripheral
//* Compare registers initialization
RC_Value = (42000000)/Frequency ; /* MCK/2/Frequency =>PWM generation Frequency */
RB_Value= RC_Value/2; /* 50% duty cycle on TIOB1 */
RA_Value = RC_Value*Pulse_Width; /* Desired Duty Cycle on TIOA1 */
//Timer Select
switch (Timer_ID)
{
case 1:
*TC1_CMR =
TC_BSWTRG_SET_OUTPUT | /* BSWTRG : software trigger set TIOB */
TC_BCPC_TOGGLE_OUTPUT | /* BCPC : Register C compare toggle TIOB */
TC_BCPB_TOGGLE_OUTPUT | /* BCPB : Register B compare toggle TIOB */
TC_ASWTRG_SET_OUTPUT | /* ASWTRG : software trigger set TIOA */
TC_ACPC_TOGGLE_OUTPUT | /* ACPC : Register C compare toggle TIOA */
TC_ACPA_TOGGLE_OUTPUT | /* ACPA : Register A compare toggle TIOA */
TC_WAVE | /* WAVE : Waveform mode */
TC_CPCTRG | /* CPCTRG : Register C compare trigger enable */
TC_EEVT_XC0 | /* EEVT : XC0 as external event (TIOB=output) */
TC_CLKS_MCK2 ; /* TCCLKS : MCK / 2 */
*TC1_RC = RC_Value ; /* PWM generation */
*TC1_RB = RB_Value ; /* duty cycle on TIOB1 */
*TC1_RA = RA_Value ; /* duty cycle on TIOA1 */
break;
case 2:
*TC2_CMR=
TC_BSWTRG_SET_OUTPUT | /* BSWTRG : software trigger set TIOB */
TC_BCPC_TOGGLE_OUTPUT | /* BCPC : Register C compare toggle TIOB */
TC_BCPB_TOGGLE_OUTPUT | /* BCPB : Register B compare toggle TIOB */
TC_ASWTRG_SET_OUTPUT | /* ASWTRG : software trigger set TIOA */
TC_ACPC_TOGGLE_OUTPUT | /* ACPC : Register C compare toggle TIOA */
TC_ACPA_TOGGLE_OUTPUT | /* ACPA : Register A compare toggle TIOA */
TC_WAVE | /* WAVE : Waveform mode */
TC_CPCTRG | /* CPCTRG : Register C compare trigger enable */
TC_EEVT_XC0 | /* EEVT : XC0 as external event (TIOB=output) */
TC_CLKS_MCK2 ; /* TCCLKS : MCK / 2 */
*TC2_RC = RC_Value ;
*TC2_RB = RB_Value ;
*TC2_RA = RA_Value ;
break;
case 3:
*TC3_CMR=
TC_BSWTRG_SET_OUTPUT | /* BSWTRG : software trigger set TIOB */
TC_BCPC_TOGGLE_OUTPUT | /* BCPC : Register C compare toggle TIOB */
TC_BCPB_TOGGLE_OUTPUT | /* BCPB : Register B compare toggle TIOB */
TC_ASWTRG_SET_OUTPUT | /* ASWTRG : software trigger set TIOA */
TC_ACPC_TOGGLE_OUTPUT | /* ACPC : Register C compare toggle TIOA */
TC_ACPA_TOGGLE_OUTPUT | /* ACPA : Register A compare toggle TIOA */
TC_WAVE | /* WAVE : Waveform mode */
TC_CPCTRG | /* CPCTRG : Register C compare trigger enable */
TC_EEVT_XC0 | /* EEVT : XC0 as external event (TIOB=output) */
TC_CLKS_MCK2 ; /* TCCLKS : MCK / 2 */
*TC3_RC = RC_Value ;
*TC3_RB = RB_Value ;
*TC3_RA = RA_Value ;
break;
default:
break;
}
//Turn it all on
*TC1_CCR = TC_CLKEN ; /* Enable the Clock counter */
*TC1_CCR = TC_SWTRG ; /* Trig the timer */
}
Though I ran into a couple of problems:
-Everyone's code I have seen so far has been using 16 bit timers for the AT91 (including Atmel's), though by the looks of the sam3x8e data sheet it has 32 bit registers (timer and compare registers). This would explain the constant high output I am getting.
The Due should be able to produce hardware driven PWM frequencies into the MHZ (havn't seen any posts on it yet), even if they are not perfectly clean. Can someone please point me in the right direction, is the coding or my text book reading wrong.