SAM4E16C: missing TC1 instance

Discussion around product based on ARM Cortex M4 core.

Moderators: nferre, ncollot

Daredevil2
Posts: 6
Joined: Fri Jun 27, 2014 10:45 pm

SAM4E16C: missing TC1 instance

Tue Oct 14, 2014 9:47 pm

Hi all,

datasheet to SAM4E16C says that device has 9 timers (three instances x three channels). Unfortunately, Atmel CMSIS include file sam4e16c.h does not have any definitions of TC1 instance (e.g. undefined ID_TC3 channel...) nor TC2 instance. 

Should I trust datasheet and define rest of timer instances by hand or device has only three timers and datasheet is wrong? Maybe Atmel should update its CMSIS files.

ARM toolchain version: 4.8.3.227
CMSIS version: 3.20

Btw: Naming conventions of timers instances / channels are one big mess (TC3 channel is channel 0 in TC1 instance, so we need to turn on TC3 clock and handle TC3 event - WHAT THE ...??? :?  ). Maybe this is the reason of mentioned confusing / missing definitions of TC1 instance by Atmel. 
cwunder
Posts: 34
Joined: Fri Jul 01, 2011 9:39 pm

Re: SAM4E16C: missing TC1 instance

Wed Oct 15, 2014 12:41 am

In the datasheet the configuration summary listed in Table 1-1. Configuration Summary only one Timer with three Channels is available on the SAM4E16C.
configuration summary.png
configuration summary.png (67.91 KiB) Viewed 2307 times
Daredevil2
Posts: 6
Joined: Fri Jun 27, 2014 10:45 pm

Re: SAM4E16C: missing TC1 instance

Wed Oct 15, 2014 6:58 pm

Apparently I have an out-dated datasheet (version from 12-June-2014) downloaded from Atmel website today:
http://www.atmel.com/Images/Atmel_11157 ... asheet.pdf
still states 9 TC channels.  Thanks for correct info.

Just out of curiosity: Where did you downloaded proper datasheet?
cwunder
Posts: 34
Joined: Fri Jul 01, 2011 9:39 pm

Re: SAM4E16C: missing TC1 instance

Wed Oct 15, 2014 10:06 pm

You are correct. The datasheet version I referenced was revision C 11157C–ATARM–25-Jul-13.

As you point out the latest datasheet revision D states that there are 9 timer channels but only 3 map to pins. I have not used the TC on the SAM4E16C and if the documentation in AS6 is not correct (missing). Then Atmel needs to update the ASF and CMSIS. I would suggest you place a help ticket to Atmel directly asking for this. In the meantime you would have to create the missing defines/struct by taking what was defined for the SAM4E16E assuming it is correct to port to the SAM4E16C.

Sorry for the confusion I caused.
Daredevil2
Posts: 6
Joined: Fri Jun 27, 2014 10:45 pm

Re: SAM4E16C: missing TC1 instance

Thu Oct 16, 2014 7:35 pm

Actually, I think that datasheet version C was correct and the new revision D is wrong. Reasons:
  1. 1. part parameters to SAM4E16C on web says 3 channels: 
    http://www.atmel.com/devices/sam4e16c.a ... parameters
  • 2. I tried to define instaces for CMSIS TC1 channel 0 but program does not work. When I used TC0 channel 2 everything worked perfectly.
I have posted it to Atmel support. 
TekLord
Posts: 2
Joined: Tue Nov 11, 2014 7:49 pm

Re: SAM4E16C: missing TC1 instance

Tue Nov 11, 2014 10:21 pm

The Atmel documentation is cryptic. Here is the code that I finally wrote for an ATSAM4E16E that allows you to control all 9 timers...

// In PMC, TCs are named as ID_TC0 == TC0.channel0, ID_TC1 == TC0.channel1, ID_TC2 == TC0.channel2, ID_TC3 == TC1.channel0, ... etc.

void configure_timer(uint32_t timer_id, uint16_t timer_freq, bool timer_start)
{
// timer_id = ID_TC0, ID_TC1, ... ID_TC8
// timer_freq = desired frequency in Hz
// timer_start true=start, false=stop

uint32_t ul_div = 0;
uint32_t ul_tcclks = 0;
uint32_t ul_sysclk = sysclk_get_cpu_hz();

uint8_t tchannel = 0;
Tc *p_tc;

// timer 0
if (timer_id == ID_TC0) {
p_tc = TC0;
tchannel = 0;
}
else if (timer_id == ID_TC1) {
p_tc = TC0;
tchannel = 1;
}
else if (timer_id == ID_TC2) {
p_tc = TC0;
tchannel = 2;
}
// timer 1
else if (timer_id == ID_TC3) {
p_tc = TC1;
tchannel = 0;
}
else if (timer_id == ID_TC4) {
p_tc = TC1;
tchannel = 1;
}
else if (timer_id == ID_TC5) {
p_tc = TC1;
tchannel = 2;
}
// timer 2
else if (timer_id == ID_TC6) {
p_tc = TC2;
tchannel = 0;
}
else if (timer_id == ID_TC7) {
p_tc = TC2;
tchannel = 1;
}
else if (timer_id == ID_TC8) {
p_tc = TC2;
tchannel = 2;
}

if (timer_start == true) {
pmc_enable_periph_clk(timer_id); // enable the peripheral clock for timer 0

/* find the best PBA/MCK divisor with div being the lowest possible value to maximize timing adjustment resolution
(MCK / DIV * 65536)) <= freq <= (MCK / DIV)
tc_find_mck_divisor(ul_freq, ul_mck, p_uldiv, ul_tcclks, ul_boardmck)
* ul_freq (IN) = desired timer frequency
* ul_mck (IN) = PBA clock frequency
* p_uldiv (OUT) = divisor value
* p_ultcclks (OUT) = TCCLKS field value for divisor
* ul_boardmck (IN) = board clock frequency

Clocks - ul_tcclks is returned by tc_find_mck_divisor
TIMER_CLOCK1 = MCK/2 TC_CMR_TCCLKS_TIMER_CLOCK1
TIMER_CLOCK2 = MCK/8 TC_CMR_TCCLKS_TIMER_CLOCK2
TIMER_CLOCK3 = MCK/32 TC_CMR_TCCLKS_TIMER_CLOCK3
TIMER_CLOCK4 = MCK/128 TC_CMR_TCCLKS_TIMER_CLOCK4
TIMER_CLOCK5 = SLCK TC_CMR_TCCLKS_TIMER_CLOCK5
*/
tc_find_mck_divisor(timer_freq, ul_sysclk, &ul_div, &ul_tcclks, BOARD_MCK); // find the best div for the specified frequency

/* Configure TC for timer, waveform generation, or capture
p_tc = module hardware register base address pointer
ul_channel = channel to configure
ul_mode = control mode register bitmask value to set
*/
tc_init(p_tc, tchannel, ul_tcclks | TC_CMR_CPCTRG | TC_CMR_WAVE |TC_CMR_ACPA_CLEAR | TC_CMR_ACPC_SET);
//tc_init(p_tc, tchannel, TC_CMR_TCCLKS_TIMER_CLOCK1 | TC_CMR_CPCTRG | TC_CMR_WAVE |TC_CMR_ACPA_CLEAR | TC_CMR_ACPC_SET);

// TC0->TC_CHANNEL[0].TC_RA = (ul_sysclk / ul_div) / 2; // RA and RB are used for waveform generation - see AVR32110
p_tc->TC_CHANNEL[tchannel].TC_RC = (ul_sysclk / ul_div) / timer_freq; // compare value
// tc_write_rc(TC0, 0, (ul_sysclk / ul_div) / 1000); // alt compare value method

/* interrupts - see AVR32110
* COVFS = Counter Overflow
* LOVRS = Load Overrun
* CPAS = RA Compare
* CPBS = RB Compare
* CPCS = RC Compare
* LDRAS = RA Loading
* LDRBS = RB Loading
* ETRGS = External Trigger
*/
tc_enable_interrupt(p_tc, tchannel, TC_IER_CPCS); // Configure and enable interrupt on RC compare

tc_start(p_tc, tchannel); // start the timer

NVIC_DisableIRQ((IRQn_Type) timer_id); // disable interrupts for this timer before making changes
NVIC_ClearPendingIRQ((IRQn_Type) timer_id); // clear any pending interrupts (there should not be any)
NVIC_SetPriority((IRQn_Type) timer_id, 0); // interrupt priority
NVIC_EnableIRQ((IRQn_Type) timer_id); // enable interrupts for this timer
}
else if (timer_start == false) {
pmc_disable_periph_clk(timer_id); // disable the peripheral clock for this timer
tc_disable_interrupt(p_tc, tchannel, TC_IER_CPCS); // disable interrupt on RC compare for this timer
tc_stop(p_tc, tchannel); // stop the timer

NVIC_DisableIRQ((IRQn_Type) timer_id); // disable interrupts for this timer
NVIC_ClearPendingIRQ((IRQn_Type) timer_id); // clear any pending interrupts
}
}



// Timer 0, Channel 0
void TC0_Handler()
{
// you must read the status to acknowledge or the system will eventually reset
volatile uint32_t timer_status;
timer_status = tc_get_status(TC0, 0);
}

Return to “SAM4 Cortex-M4 MCU”

Who is online

Users browsing this forum: No registered users and 2 guests