111 lines
3.4 KiB
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);
|
|
}
|