129 lines
3.8 KiB
C
129 lines
3.8 KiB
C
/* SimTrace TC (Timer / Clock) support code
|
|
* (C) 2006 by Harald Welte <hwelte@hmw-consulting.de>
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software
|
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
*
|
|
*/
|
|
|
|
#include <lib_AT91SAM7.h>
|
|
#include <AT91SAM7.h>
|
|
#include <os/dbgu.h>
|
|
|
|
#include "../openpcd.h"
|
|
|
|
static AT91PS_TCB tcb;
|
|
static AT91PS_TC tcetu = AT91C_BASE_TC0;
|
|
|
|
static uint16_t waiting_time = 9600;
|
|
static uint16_t clocks_per_etu = 372;
|
|
static uint16_t wait_events;
|
|
|
|
static __ramfunc void tc_etu_irq(void)
|
|
{
|
|
uint32_t sr = tcetu->TC_SR;
|
|
static uint16_t nr_events;
|
|
|
|
if (sr & AT91C_TC_ETRGS) {
|
|
/* external trigger, i.e. we have seen a bit on I/O */
|
|
//DEBUGPCR("tE");
|
|
nr_events = 0;
|
|
/* Make sure we don't accept any additional external trigger */
|
|
/* Enabling the line below will cause race conditions. We
|
|
* thus re-trigger at all zero-bits in the byte and thus wait
|
|
* up to 12 etu longer than required */
|
|
//tcetu->TC_CMR &= ~AT91C_TC_ENETRG;
|
|
}
|
|
|
|
if (sr & AT91C_TC_CPCS) {
|
|
/* Compare C event has occurred, i.e. 1 etu expired */
|
|
//DEBUGPCR("tC");
|
|
nr_events++;
|
|
if (nr_events >= wait_events) {
|
|
/* enable external triggers again to catch start bit */
|
|
tcetu->TC_CMR |= AT91C_TC_ENETRG;
|
|
|
|
/* disable and re-enable clock to make it stop */
|
|
tcetu->TC_CCR = AT91C_TC_CLKDIS;
|
|
tcetu->TC_CCR = AT91C_TC_CLKEN;
|
|
|
|
//DEBUGPCR("%u", nr_events);
|
|
|
|
/* Indicate that the waiting time has expired */
|
|
iso7816_wtime_expired();
|
|
}
|
|
}
|
|
}
|
|
|
|
static void recalc_nr_events(void)
|
|
{
|
|
wait_events = waiting_time/12;
|
|
/* clocks_per_etu * 12 equals 'sbit + 8 data bits + parity + 2 stop bits */
|
|
tcetu->TC_RC = clocks_per_etu * 12;
|
|
}
|
|
|
|
void tc_etu_set_wtime(uint16_t wtime)
|
|
{
|
|
waiting_time = wtime;
|
|
recalc_nr_events();
|
|
//DEBUGPCR("wtime=%u, actually waiting %u", wtime, wait_events * 12);
|
|
}
|
|
|
|
void tc_etu_set_etu(uint16_t etu)
|
|
{
|
|
clocks_per_etu = etu;
|
|
recalc_nr_events();
|
|
}
|
|
|
|
void tc_etu_init(void)
|
|
{
|
|
/* Cfg PA4(TCLK0), PA0(TIOA0), PA1(TIOB0) */
|
|
AT91F_PIO_CfgPeriph(AT91C_BASE_PIOA, 0,
|
|
AT91C_PA4_TCLK0 | AT91C_PA0_TIOA0 | AT91C_PA1_TIOB0);
|
|
|
|
AT91F_PMC_EnablePeriphClock(AT91C_BASE_PMC,
|
|
((unsigned int) 1 << AT91C_ID_TC0));
|
|
|
|
/* Connect TCLK0 to XC0 */
|
|
tcb->TCB_BMR &= ~(AT91C_TCB_TC0XC0S);
|
|
tcb->TCB_BMR |= AT91C_TCB_TC0XC0S_TCLK0;
|
|
|
|
/* Register Interrupt handler */
|
|
AT91F_AIC_ConfigureIt(AT91C_BASE_AIC, AT91C_ID_TC0,
|
|
OPENPCD_IRQ_PRIO_TC_FDT,
|
|
AT91C_AIC_SRCTYPE_INT_HIGH_LEVEL, &tc_etu_irq);
|
|
AT91F_AIC_EnableIt(AT91C_BASE_AIC, AT91C_ID_TC0);
|
|
|
|
/* enable interrupts for Compare-C and External Trigger */
|
|
tcetu->TC_IER = AT91C_TC_CPCS | AT91C_TC_ETRGS;
|
|
|
|
tcetu->TC_CMR = AT91C_TC_CLKS_XC0 | /* XC0 (TCLK0) clock */
|
|
AT91C_TC_WAVE | /* Wave Mode */
|
|
AT91C_TC_ETRGEDG_FALLING |/* Ext trig on falling edge */
|
|
AT91C_TC_EEVT_TIOB | /* Ext trigger is TIOB0 */
|
|
AT91C_TC_ENETRG | /* Enable ext. trigger */
|
|
AT91C_TC_WAVESEL_UP_AUTO |/* Wave mode UP */
|
|
AT91C_TC_ACPA_SET | /* Set TIOA0 on A compare */
|
|
AT91C_TC_ACPC_CLEAR | /* Clear TIOA0 on C compare */
|
|
AT91C_TC_ASWTRG_CLEAR; /* Clear TIOa0 on software trigger */
|
|
|
|
tc_etu_set_etu(372);
|
|
|
|
/* Enable master clock for TC0 */
|
|
tcetu->TC_CCR = AT91C_TC_CLKEN;
|
|
|
|
/* Reset to start timers */
|
|
tcb->TCB_BCR = 1;
|
|
}
|