- finish implementation of timers based on PIT
- add [untested] code for timer-based LED blink codes git-svn-id: https://svn.openpcd.org:2342/trunk@242 6dc7ffe9-61d6-0310-9af1-9938baff3ed1
This commit is contained in:
parent
778802a3a4
commit
6c0b462a2c
|
@ -0,0 +1,101 @@
|
|||
/* SAM7DFU blink code support
|
||||
* (C) 2006 by Harald Welte <laforge@gnumonks.org>
|
||||
*
|
||||
*/
|
||||
|
||||
#include <os/pit.h>
|
||||
#include <os/dbgu.h>
|
||||
#include <os/led.h>
|
||||
#include <os/blinkcode.h>
|
||||
|
||||
#define NUM_LEDS 2
|
||||
|
||||
enum blinkcode_state {
|
||||
BLINKCODE_STATE_NONE,
|
||||
BLINKCODE_STATE_SILENT, /* period of silence at start */
|
||||
BLINKCODE_STATE_INIT, /* initial long light */
|
||||
BLINKCODE_STATE_BLINK_OFF, /* blinking out, currently off */
|
||||
BLINKCODE_STATE_BLINK_ON, /* blinking out, currently on */
|
||||
BLINKCODE_STATE_DONE,
|
||||
};
|
||||
|
||||
#define TIME_SILENT (1000)
|
||||
#define TIME_INIT (1000)
|
||||
#define TIME_BLINK (100)
|
||||
|
||||
struct blinker {
|
||||
struct timer_list timer;
|
||||
enum blinkcode_state state;
|
||||
int8_t num;
|
||||
u_int8_t led;
|
||||
};
|
||||
|
||||
static struct blinker blink_state[NUM_LEDS];
|
||||
|
||||
static void blinkcode_cb(void *data)
|
||||
{
|
||||
/* we got called back by the timer */
|
||||
struct blinker *bl = data;
|
||||
|
||||
switch (bl->state) {
|
||||
case BLINKCODE_STATE_NONE:
|
||||
led_switch(bl->led, 0);
|
||||
bl->state = BLINKCODE_STATE_SILENT;
|
||||
bl->timer.expires = jiffies + TIME_SILENT;
|
||||
break;
|
||||
case BLINKCODE_STATE_SILENT:
|
||||
/* we've finished the period of silence, turn led on */
|
||||
led_switch(bl->led, 1);
|
||||
bl->state = BLINKCODE_STATE_INIT;
|
||||
bl->timer.expires = jiffies + TIME_INIT;
|
||||
break;
|
||||
case BLINKCODE_STATE_INIT:
|
||||
/* we've finished the period of init */
|
||||
led_switch(bl->led, 0);
|
||||
bl->state = BLINKCODE_STATE_BLINK_OFF;
|
||||
bl->timer.expires = jiffies + TIME_BLINK;
|
||||
break;
|
||||
case BLINKCODE_STATE_BLINK_OFF:
|
||||
/* we've been off, turn on */
|
||||
led_switch(bl->led, 1);
|
||||
bl->state = BLINKCODE_STATE_BLINK_ON;
|
||||
bl->num--;
|
||||
if (bl->num <= 0) {
|
||||
bl->state = BLINKCODE_STATE_NONE;
|
||||
return;
|
||||
}
|
||||
break;
|
||||
case BLINKCODE_STATE_BLINK_ON:
|
||||
/* we've been on, turn off */
|
||||
led_switch(bl->led, 0);
|
||||
bl->state = BLINKCODE_STATE_BLINK_OFF;
|
||||
break;
|
||||
}
|
||||
/* default case: re-add the timer */
|
||||
timer_add(&bl->timer);
|
||||
}
|
||||
|
||||
void blinkcode_set(int led, enum blinkcode_num num)
|
||||
{
|
||||
if (led >= NUM_LEDS)
|
||||
return;
|
||||
|
||||
timer_del(&blink_state[led].timer);
|
||||
|
||||
blink_state[led].num = num;
|
||||
blink_state[led].state = BLINKCODE_STATE_NONE;
|
||||
|
||||
if (num != BLINKCODE_NONE)
|
||||
timer_add(&blink_state[led].timer);
|
||||
}
|
||||
|
||||
void blinkcode_init(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < NUM_LEDS; i++) {
|
||||
blink_state[i].num = 0;
|
||||
blink_state[i].state = BLINKCODE_STATE_NONE;
|
||||
blink_state[i].led = i+1;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
#ifndef _BLINKCODE_H
|
||||
#define _BLINKCODE_H
|
||||
|
||||
enum blinkcode_num {
|
||||
BLINKCODE_NONE,
|
||||
BLINKCODE_IDLE,
|
||||
BLINKCODE_DFU_MODE,
|
||||
BLINKCODE_DFU_PROBLEM,
|
||||
BLINKCODE_
|
||||
};
|
||||
|
||||
extern void blinkcode_set(int led, enum blinkcode_num);
|
||||
extern void blinkcode_init(void);
|
||||
#endif
|
|
@ -15,20 +15,105 @@
|
|||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*
|
||||
* TODO: handle jiffies wrap correctly!
|
||||
*/
|
||||
|
||||
#include <errno.h>
|
||||
#include <sys/types.h>
|
||||
#include <asm/system.h>
|
||||
|
||||
#include <lib_AT91SAM7.h>
|
||||
#include <AT91SAM7.h>
|
||||
#include <os/pit.h>
|
||||
|
||||
#include "../openpcd.h"
|
||||
|
||||
/* PIT runs at MCK/16 (= 3MHz) */
|
||||
#define PIV_MS(x) (x * 3000)
|
||||
|
||||
static struct timer_list *timers;
|
||||
|
||||
unsigned long jiffies;
|
||||
|
||||
static void __timer_insert(struct timer_list *new)
|
||||
{
|
||||
struct timer_list *tl, *tl_prev = NULL;
|
||||
|
||||
if (!timers) {
|
||||
/* optimize for the common, fast case */
|
||||
new->next = NULL;
|
||||
timers = new;
|
||||
return;
|
||||
}
|
||||
|
||||
for (tl = timers; tl != NULL; tl = tl->next) {
|
||||
if (tl->expires < new->expires) {
|
||||
/* we need ot add just before this one */
|
||||
if (!tl_prev) {
|
||||
new->next = timers;
|
||||
timers = new;
|
||||
} else {
|
||||
new->next = tl;
|
||||
tl_prev->next = new;
|
||||
}
|
||||
}
|
||||
tl_prev = tl;
|
||||
}
|
||||
}
|
||||
|
||||
static void __timer_remove(struct timer_list *old)
|
||||
{
|
||||
struct timer_list *tl, *tl_prev = NULL;
|
||||
|
||||
for (tl = timers; tl != NULL; tl = tl->next) {
|
||||
if (tl == old) {
|
||||
if (tl == timers)
|
||||
timers = tl->next;
|
||||
else
|
||||
tl_prev->next = tl->next;
|
||||
}
|
||||
tl_prev = tl;
|
||||
}
|
||||
}
|
||||
|
||||
int timer_del(struct timer_list *tl)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
local_irq_save(flags);
|
||||
__timer_remove(tl);
|
||||
local_irq_restore(flags);
|
||||
}
|
||||
|
||||
void timer_add(struct timer_list *tl)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
local_irq_save(flags);
|
||||
__timer_insert(tl);
|
||||
local_irq_restore(flags);
|
||||
}
|
||||
|
||||
static void pit_irq(void)
|
||||
{
|
||||
/* FIXME: do something */
|
||||
struct timer_list *tl;
|
||||
unsigned long flags;
|
||||
|
||||
jiffies++;
|
||||
|
||||
/* this is the most simple/stupid algorithm one can come up with, but
|
||||
* hey, we're on a small embedded platform with only a hand ful
|
||||
* of timers, at all */
|
||||
for (tl = timers; tl != 0; tl = tl->next) {
|
||||
if (tl->expires >= jiffies) {
|
||||
tl->function(tl->data);
|
||||
local_irq_save(flags);
|
||||
/* delete timer from list */
|
||||
__timer_remove(tl);
|
||||
local_irq_restore(flags);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void pit_mdelay(u_int32_t ms)
|
||||
|
|
|
@ -1,6 +1,22 @@
|
|||
#ifndef _PIT_H
|
||||
#define _PIT_H
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
/* This API (but not the code) is modelled after the Linux API */
|
||||
|
||||
struct timer_list {
|
||||
struct timer_list *next;
|
||||
unsigned long expires;
|
||||
void (*function)(void *data);
|
||||
void *data;
|
||||
};
|
||||
|
||||
extern unsigned long jiffies;
|
||||
|
||||
extern void timer_add(struct timer_list *timer);
|
||||
extern int timer_del(struct timer_list *timer);
|
||||
|
||||
extern void pit_init(void);
|
||||
extern void pit_mdelay(u_int32_t ms);
|
||||
|
||||
|
|
Loading…
Reference in New Issue