/*************************************************************************** * sam7fc - Periodic Timer Handling * * * * 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 "AT91SAM7S256.h" #include "at91_pitc.h" #include "at91_sysc.h" #include "board.h" #define PITC_HZ 1000 /* PIV is 20bit -> min. 3Hz @48MHz MCK */ #define HZ_TO_PIV(HZ) (MCK / (16 * HZ)) static LIST_HEAD(timer_list); volatile static uint32_t pitc_ticks; static void _pitc_schedule_timer(struct pitc_timer *timer) { timer->nextrun = timer->interval + pitc_ticks; struct pitc_timer *search; list_for_each_entry(search, &timer_list, list) if (search->nextrun > timer->nextrun) break; list_add_tail(&timer->list, &search->list); } void pitc_schedule_timer(struct pitc_timer *timer) { /* disable PITC interrupt */ *AT91C_PITC_PIMR &= ~AT91C_PITC_PITIEN; /* check it timer is already running */ if (timer->nextrun == 0 && timer->interval > 0) _pitc_schedule_timer(timer); // TODO: if timer is running, interval changes are delayed /* enable PITC interrupt */ *AT91C_PITC_PIMR |= AT91C_PITC_PITIEN; } void pitc_remove_timer(struct pitc_timer *timer) { timer->interval = 0; } static void pitc_isr(uint32_t status) { /* get Ticks and clear interrupt */ pitc_ticks += (*AT91C_PITC_PIVR & AT91C_PITC_PICNT) >> 20; struct pitc_timer *search, *tmp; list_for_each_entry_safe(search, tmp, &timer_list, list) { /* if this entry not scheduled yet, abort search */ if (pitc_ticks < search->nextrun) break; /* remove from list */ list_del(&search->list); /* exec handler */ if ((search->interval == 0) || search->func(search) == PITC_REMOVE_TIMER) { /* one-shot timer, mark as completed */ search->nextrun = 0; continue; } /* interval timer, reschedule it */ _pitc_schedule_timer(search); } } uint32_t pitc_get_ticks(void) { return pitc_ticks; } void at91_pitc_init(void) { sysc_register_isr(AT91_SYSIRQ_PIT, &pitc_isr); *AT91C_PITC_PIMR = (AT91C_PITC_PIV & HZ_TO_PIV(PITC_HZ)) | AT91C_PITC_PITEN | AT91C_PITC_PITIEN; }