sam7fc/src/at91_tc1.c

111 lines
3.4 KiB
C

/***************************************************************************
* Copyright (C) 01/2008 by Olaf Rempel *
* razzor@kopf-tisch.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; version 2 of the License *
* *
* 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 <stdint.h>
#include <stdio.h>
#include "AT91SAM7S256.h"
#include "board.h"
#include "at91_tc1.h"
#define ROUND_DIV256(x) ((x >> 8) + ((x & 0x80) ? 1 : 0))
static uint32_t ppm_arr[MAX_CHANNELS];
static uint32_t ch, cnt, valid;
static void ppm_isr(void)
{
/* RC Compare -> no TIOA1 edge for 2.5ms */
uint32_t status = *AT91C_TC1_SR;
if (status & AT91C_TC_CPCS) {
/* average channel count */
cnt = ((cnt * 7) + (ch << 8)) / 8;
/* at least 4 channels and a stable channel count */
valid = (ROUND_DIV256(cnt) == ch) && (ch >= 4);
/* reset index */
ch = 0;
}
/* edge on TIOA1 */
if (status & AT91C_TC_LDRAS) {
/* get impulse width */
uint16_t ra = *AT91C_TC1_RA;
/* valid range: 1 - 2ms */
if (ra > 0x0500 && ra < 0x0D00) {
if (ch < ARRAY_SIZE(ppm_arr))
ppm_arr[ch] = ((ppm_arr[ch] * 3) + ra) / 4;
ch++;
}
}
}
/*
struct cal_data {
uint16_t min;
uint16_t mid;
uint16_t max;
};
int16_t getval(struct cal_data *cal, uint16_t input)
{
int32_t x = (input - cal->mid) * 1024;
uint32_t y = (x > 0) ? (cal->max - cal->mid) : (cal->mid - cal->min);
return x / y;
}
*/
uint32_t rc_ppm_getvalues(struct rc_values *rc)
{
uint32_t i;
rc->count = MIN(ROUND_DIV256(cnt), ARRAY_SIZE(ppm_arr));
for (i = 0; i < rc->count; i++)
rc->ch[i] = (ppm_arr[i] - 0x8C0);
return valid;
}
void at91_tc1_init(void)
{
/* enable TC1 clock */
*AT91C_PMC_PCER = (1 << AT91C_ID_TC1);
/* MCK /32, trigger & capture on falling TIOA1 edge */
*AT91C_TC1_CMR = AT91C_TC_CLKS_TIMER_DIV3_CLOCK | AT91C_TC_LDRA_FALLING |
AT91C_TC_ETRGEDG_FALLING | AT91C_TC_ABETRG;
/* enable RA load and RC compare interrupt */
*AT91C_TC1_IER = AT91C_TC_LDRAS | AT91C_TC_CPCS;
/* RC Compare Interrupt if no rising Edge on TIOA1 for 2.56ms */
*AT91C_TC1_RC = 0x0F00;
/* enable & trigger the clock */
*AT91C_TC1_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG;
/* level triggered, own vector */
AT91S_AIC *aic = AT91C_BASE_AIC;
aic->AIC_SMR[AT91C_ID_TC1] = IRQPRIO_TC1 | AT91C_AIC_SRCTYPE_INT_HIGH_LEVEL;
aic->AIC_SVR[AT91C_ID_TC1] = (uint32_t)ppm_isr;
aic->AIC_IECR = (1 << AT91C_ID_TC1);
}