summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--firmware/src/os/blinkcode.c38
-rw-r--r--firmware/src/os/main.c7
-rw-r--r--firmware/src/os/pit.c33
-rw-r--r--firmware/src/os/pit.h4
-rw-r--r--firmware/src/os/system_irq.c73
5 files changed, 98 insertions, 57 deletions
diff --git a/firmware/src/os/blinkcode.c b/firmware/src/os/blinkcode.c
index 8485392..22d4b25 100644
--- a/firmware/src/os/blinkcode.c
+++ b/firmware/src/os/blinkcode.c
@@ -19,14 +19,15 @@ enum blinkcode_state {
BLINKCODE_STATE_DONE,
};
-#define TIME_SILENT (1000)
-#define TIME_INIT (1000)
-#define TIME_BLINK (100)
+#define TIME_SILENT (1*HZ)
+#define TIME_INIT (1*HZ)
+#define TIME_BLINK (HZ/4)
struct blinker {
struct timer_list timer;
enum blinkcode_state state;
- int8_t num;
+ int num;
+ int cur;
u_int8_t led;
};
@@ -36,12 +37,15 @@ static void blinkcode_cb(void *data)
{
/* we got called back by the timer */
struct blinker *bl = data;
-
+
+ DEBUGPCRF("(jiffies=%lu, data=%p, state=%u)",
+ jiffies, data, bl->state);
switch (bl->state) {
case BLINKCODE_STATE_NONE:
led_switch(bl->led, 0);
bl->state = BLINKCODE_STATE_SILENT;
bl->timer.expires = jiffies + TIME_SILENT;
+ bl->cur = bl->num;
break;
case BLINKCODE_STATE_SILENT:
/* we've finished the period of silence, turn led on */
@@ -53,22 +57,27 @@ static void blinkcode_cb(void *data)
/* we've finished the period of init */
led_switch(bl->led, 0);
bl->state = BLINKCODE_STATE_BLINK_OFF;
- bl->timer.expires = jiffies + TIME_BLINK;
+ bl->timer.expires = jiffies + TIME_INIT;
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;
- }
+ bl->cur--;
+ bl->timer.expires = jiffies + TIME_BLINK;
+ if (bl->cur <= 0)
+ bl->state = BLINKCODE_STATE_DONE;
break;
case BLINKCODE_STATE_BLINK_ON:
/* we've been on, turn off */
led_switch(bl->led, 0);
bl->state = BLINKCODE_STATE_BLINK_OFF;
+ bl->timer.expires = jiffies + TIME_BLINK;
+ break;
+ case BLINKCODE_STATE_DONE:
+ /* we've been on, turn off */
+ led_switch(bl->led, 0);
+ return;
break;
}
/* default case: re-add the timer */
@@ -77,13 +86,16 @@ static void blinkcode_cb(void *data)
void blinkcode_set(int led, enum blinkcode_num num)
{
- if (led >= NUM_LEDS)
+ DEBUGPCRF("(jiffies=%lu, led=%u, num=%u)", jiffies, led, num);
+
+ if (--led > NUM_LEDS)
return;
timer_del(&blink_state[led].timer);
blink_state[led].num = num;
blink_state[led].state = BLINKCODE_STATE_NONE;
+ blink_state[led].timer.expires = jiffies;
if (num != BLINKCODE_NONE)
timer_add(&blink_state[led].timer);
@@ -97,5 +109,7 @@ void blinkcode_init(void)
blink_state[i].num = 0;
blink_state[i].state = BLINKCODE_STATE_NONE;
blink_state[i].led = i+1;
+ blink_state[i].timer.data = &blink_state[i];
+ blink_state[i].timer.function = &blinkcode_cb;
}
}
diff --git a/firmware/src/os/main.c b/firmware/src/os/main.c
index f39234b..0cc9d99 100644
--- a/firmware/src/os/main.c
+++ b/firmware/src/os/main.c
@@ -23,8 +23,12 @@
#include <include/lib_AT91SAM7.h>
#include <os/dbgu.h>
#include <os/led.h>
+#include <os/blinkcode.h>
#include <os/main.h>
#include <os/power.h>
+#include <os/system_irq.h>
+#include <os/pit.h>
+#include <os/wdt.h>
#include <os/usbcmd_generic.h>
#include <os/pcd_enumerate.h>
#include "../openpcd.h"
@@ -47,6 +51,7 @@ int main(void)
AT91F_PIOA_CfgPMC();
wdt_init();
pit_init();
+ blinkcode_init();
/* initialize USB */
req_ctx_init();
@@ -73,7 +78,7 @@ int main(void)
/* Call application specific main idle function */
_main_func();
dbgu_rb_flush();
- wdt_restart();
+ //wdt_restart();
#ifdef CONFIG_IDLE
//cpu_idle();
#endif
diff --git a/firmware/src/os/pit.c b/firmware/src/os/pit.c
index 8bf13ba..6b68e84 100644
--- a/firmware/src/os/pit.c
+++ b/firmware/src/os/pit.c
@@ -26,6 +26,7 @@
#include <lib_AT91SAM7.h>
#include <AT91SAM7.h>
#include <os/pit.h>
+#include <os/dbgu.h>
#include <os/system_irq.h>
#include "../openpcd.h"
@@ -35,7 +36,7 @@
static struct timer_list *timers;
-unsigned long jiffies;
+volatile unsigned long jiffies;
static void __timer_insert(struct timer_list *new)
{
@@ -63,7 +64,7 @@ static void __timer_insert(struct timer_list *new)
}
}
-static void __timer_remove(struct timer_list *old)
+static int __timer_remove(struct timer_list *old)
{
struct timer_list *tl, *tl_prev = NULL;
@@ -73,18 +74,24 @@ static void __timer_remove(struct timer_list *old)
timers = tl->next;
else
tl_prev->next = tl->next;
+ return 1;
}
tl_prev = tl;
}
+
+ return 0;
}
int timer_del(struct timer_list *tl)
{
unsigned long flags;
+ int ret;
local_irq_save(flags);
- __timer_remove(tl);
+ ret = __timer_remove(tl);
local_irq_restore(flags);
+
+ return ret;
}
void timer_add(struct timer_list *tl)
@@ -98,21 +105,23 @@ void timer_add(struct timer_list *tl)
static void pit_irq(u_int32_t sr)
{
- struct timer_list *tl;
+ struct timer_list *tl, *next;
unsigned long flags;
- jiffies += *AT91C_PITC_PIVR;
+ if (!(sr & 0x1))
+ return;
+
+ jiffies += *AT91C_PITC_PIVR >> 20;
/* 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);
+ for (tl = timers; tl != NULL; tl = next) {
+ next = tl->next;
+ if (tl->expires <= jiffies) {
/* delete timer from list */
- __timer_remove(tl);
- local_irq_restore(flags);
+ timer_del(tl);
+ tl->function(tl->data);
}
}
}
@@ -130,7 +139,7 @@ void pit_init(void)
{
AT91F_PITC_CfgPMC();
- AT91F_PITInit(AT91C_BASE_PITC, 1000 /* uS */, 48 /* MHz */);
+ AT91F_PITInit(AT91C_BASE_PITC, 1000000/HZ /* uS */, 48 /* MHz */);
sysirq_register(AT91SAM7_SYSIRQ_PIT, &pit_irq);
diff --git a/firmware/src/os/pit.h b/firmware/src/os/pit.h
index e941aeb..4a25cc1 100644
--- a/firmware/src/os/pit.h
+++ b/firmware/src/os/pit.h
@@ -3,6 +3,8 @@
#include <sys/types.h>
+#define HZ 100
+
/* This API (but not the code) is modelled after the Linux API */
struct timer_list {
@@ -12,7 +14,7 @@ struct timer_list {
void *data;
};
-extern unsigned long jiffies;
+extern volatile unsigned long jiffies;
extern void timer_add(struct timer_list *timer);
extern int timer_del(struct timer_list *timer);
diff --git a/firmware/src/os/system_irq.c b/firmware/src/os/system_irq.c
index 455791c..dc787eb 100644
--- a/firmware/src/os/system_irq.c
+++ b/firmware/src/os/system_irq.c
@@ -33,7 +33,7 @@ static sysirq_hdlr *sysirq_hdlrs[AT91SAM7_SYSIRQ_COUNT];
static void sys_irq(void)
{
u_int32_t sr;
- DEBUGP("sys_irq: ");
+ DEBUGP("sys_irq ");
/* Somehow Atmel decided to do really stupid interrupt sharing
* for commonly-used interrupts such as the timer irq */
@@ -41,9 +41,8 @@ static void sys_irq(void)
/* dbgu */
if (*AT91C_DBGU_IMR) {
sr = *AT91C_DBGU_CSR;
- DEBUGP("DBGU(");
if (sr & *AT91C_DBGU_IMR) {
- DEBUGP("found ");
+ DEBUGP("DBGU(");
if (sysirq_hdlrs[AT91SAM7_SYSIRQ_DBGU]) {
DEBUGP("handler ");
sysirq_hdlrs[AT91SAM7_SYSIRQ_DBGU](sr);
@@ -51,96 +50,108 @@ static void sys_irq(void)
*AT91C_DBGU_IDR = *AT91C_DBGU_IMR;
DEBUGP("no handler ");
}
+ DEBUGP(") ");
}
- DEBUGP(") ");
}
/* pit_irq */
if (*AT91C_PITC_PIMR & AT91C_PITC_PITIEN) {
sr = *AT91C_PITC_PISR;
- DEBUGP("PIT(");
if (sr & AT91C_PITC_PITS) {
- DEBUGP("found ");
if (sysirq_hdlrs[AT91SAM7_SYSIRQ_PIT]) {
- DEBUGP("handler ");
sysirq_hdlrs[AT91SAM7_SYSIRQ_PIT](sr);
} else {
+ DEBUGP("no handler DISABLE_PIT ");
*AT91C_PITC_PIMR &= ~AT91C_PITC_PITIEN;
- DEBUGP("no handler ");
}
}
- DEBUGP(") ");
}
/* rtt_irq */
if (*AT91C_RTTC_RTMR & (AT91C_RTTC_ALMIEN|AT91C_RTTC_RTTINCIEN)) {
sr = *AT91C_RTTC_RTSR;
- DEBUGP("RTT(");
if (sr) {
- if (sysirq_hdlrs[AT91SAM7_SYSIRQ_RTT])
+ DEBUGP("RTT(");
+ if (sysirq_hdlrs[AT91SAM7_SYSIRQ_RTT]) {
+ DEBUGP("handler ");
sysirq_hdlrs[AT91SAM7_SYSIRQ_RTT](sr);
- else
+ } else {
*AT91C_RTTC_RTMR &= ~(AT91C_RTTC_ALMIEN|
AT91C_RTTC_RTTINCIEN);
+ DEBUGP("no handler ");
+ }
+ DEBUGP(") ");
}
- DEBUGP(") ");
}
/* pmc_irq */
if (*AT91C_PMC_IMR) {
sr = *AT91C_PMC_SR;
- DEBUGP("PMC(");
if (sr & *AT91C_PMC_IMR) {
- if (sysirq_hdlrs[AT91SAM7_SYSIRQ_PMC])
+ DEBUGP("PMC(");
+ if (sysirq_hdlrs[AT91SAM7_SYSIRQ_PMC]) {
+ DEBUGP("handler ");
sysirq_hdlrs[AT91SAM7_SYSIRQ_PMC](sr);
- else
+ } else {
*AT91C_PMC_IDR = *AT91C_PMC_IMR;
+ DEBUGP("no handler ");
+ }
+ DEBUGP(") ");
}
- DEBUGP(") ");
}
/* rstc_irq */
if (*AT91C_RSTC_RMR & (AT91C_RSTC_URSTIEN|AT91C_RSTC_BODIEN)) {
sr = *AT91C_RSTC_RSR;
- DEBUGP("RSTC(");
if (sr & (AT91C_RSTC_URSTS|AT91C_RSTC_BODSTS)) {
- if (sysirq_hdlrs[AT91SAM7_SYSIRQ_RSTC])
+ DEBUGP("RSTC(");
+ if (sysirq_hdlrs[AT91SAM7_SYSIRQ_RSTC]) {
+ DEBUGP("handler ");
sysirq_hdlrs[AT91SAM7_SYSIRQ_RSTC](sr);
- else
+ } else {
*AT91C_RSTC_RMR &= ~(AT91C_RSTC_URSTIEN|
AT91C_RSTC_BODIEN);
+ DEBUGP("no handler ");
+ }
+ DEBUGP(") ");
}
- DEBUGP(") ");
}
/* mc_irq */
if (*AT91C_MC_FMR & (AT91C_MC_LOCKE | AT91C_MC_PROGE)) {
sr = *AT91C_MC_FSR;
- DEBUGP("EFC(");
if ((*AT91C_MC_FMR & AT91C_MC_LOCKE && (sr & AT91C_MC_LOCKE))||
(*AT91C_MC_FMR & AT91C_MC_PROGE && (sr & AT91C_MC_PROGE))){
- if (sysirq_hdlrs[AT91SAM7_SYSIRQ_EFC])
+ DEBUGP("EFC(");
+ if (sysirq_hdlrs[AT91SAM7_SYSIRQ_EFC]) {
+ DEBUGP("handler ");
sysirq_hdlrs[AT91SAM7_SYSIRQ_EFC](sr);
- else
+ } else {
*AT91C_MC_FMR &= ~(AT91C_MC_LOCKE |
AT91C_MC_PROGE);
+ DEBUGP("no handler ");
+ }
+ DEBUGP(") ");
}
- DEBUGP(") ");
}
/* wdt_irq */
if (*AT91C_WDTC_WDMR & AT91C_WDTC_WDFIEN) {
sr = *AT91C_WDTC_WDSR;
- DEBUGP("WDT(");
if (sr) {
- if (sysirq_hdlrs[AT91SAM7_SYSIRQ_WDT])
+ DEBUGP("WDT(");
+ if (sysirq_hdlrs[AT91SAM7_SYSIRQ_WDT]) {
+ DEBUGP("handler ");
sysirq_hdlrs[AT91SAM7_SYSIRQ_WDT](sr);
- /* we can't disable it... */
+ } else {
+ /* we can't disable it... */
+ DEBUGP("no handler ");
+ }
+ DEBUGP(") ");
}
- DEBUGP(") ");
}
AT91F_AIC_ClearIt(AT91C_BASE_AIC, AT91C_ID_SYS);
- DEBUGPCR("");
+ DEBUGPCR("END");
}
void sysirq_register(enum sysirqs irq, sysirq_hdlr *hdlr)
@@ -155,7 +166,7 @@ void sysirq_init(void)
{
AT91F_AIC_ConfigureIt(AT91C_BASE_AIC, AT91C_ID_SYS,
OPENPCD_IRQ_PRIO_SYS,
- AT91C_AIC_SRCTYPE_INT_POSITIVE_EDGE,
+ AT91C_AIC_SRCTYPE_INT_HIGH_LEVEL,
&sys_irq);
AT91F_AIC_EnableIt(AT91C_BASE_AIC, AT91C_ID_SYS);
}
personal git repositories of Harald Welte. Your mileage may vary