- 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:
laforge 2006-10-01 19:23:15 +00:00
parent 778802a3a4
commit 6c0b462a2c
4 changed files with 217 additions and 1 deletions

101
firmware/src/os/blinkcode.c Normal file
View File

@ -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;
}
}

View File

@ -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

View File

@ -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)

View File

@ -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);