summaryrefslogtreecommitdiff
path: root/openpicc/application/led.c
diff options
context:
space:
mode:
Diffstat (limited to 'openpicc/application/led.c')
-rw-r--r--openpicc/application/led.c127
1 files changed, 108 insertions, 19 deletions
diff --git a/openpicc/application/led.c b/openpicc/application/led.c
index cab12b1..df13d21 100644
--- a/openpicc/application/led.c
+++ b/openpicc/application/led.c
@@ -3,6 +3,7 @@
* OpenBeacon.org - LED support
*
* Copyright 2007 Milosch Meriac <meriac@openbeacon.de>
+ * Copyright 2008 Henryk Plötz <henryk@ploetzli.ch>
*
***************************************************************
@@ -27,43 +28,102 @@
#include <board.h>
#include <task.h>
#include "led.h"
+
+#include "gammatable.inc"
+
/**********************************************************************/
#define BLINK_TIME 5
+#define PWM_PERIOD GAMMA_MAX
+const struct channel_definition {
+ int channel_no;
+ enum { PERIPH_NONE=0, PERIPH_A, PERIPH_B} periph;
+ AT91PS_PWMC_CH channel;
+}
+pwm_channels[] = {
+ [0] = {0, PERIPH_A, AT91C_BASE_PWMC_CH0},
+ [1] = {1, PERIPH_A, AT91C_BASE_PWMC_CH1},
+ [2] = {2, PERIPH_A, AT91C_BASE_PWMC_CH2},
+ [7] = {3, PERIPH_B, AT91C_BASE_PWMC_CH3},
+ [11] = {0, PERIPH_B, AT91C_BASE_PWMC_CH0},
+ [12] = {1, PERIPH_B, AT91C_BASE_PWMC_CH1},
+ [13] = {2, PERIPH_B, AT91C_BASE_PWMC_CH2},
+ [14] = {3, PERIPH_B, AT91C_BASE_PWMC_CH3},
+ [23] = {0, PERIPH_B, AT91C_BASE_PWMC_CH0},
+ [24] = {1, PERIPH_B, AT91C_BASE_PWMC_CH1},
+ [25] = {2, PERIPH_B, AT91C_BASE_PWMC_CH2},
+};
-void vLedSetRed(bool_t on)
+static const struct channel_definition* find_channel(unsigned int led)
+{
+ unsigned int pos = ffs(led);
+ if(pos==0) return 0;
+
+ if(pos-1 >= sizeof(pwm_channels) / sizeof(pwm_channels[0]) ) return 0;
+ if(pwm_channels[pos-1].periph == PERIPH_NONE) return 0;
+ return &pwm_channels[pos-1];
+}
+
+// Brightness is in per thousand
+void vLedSetBrightness(unsigned int led, int brightness)
+{
+ const struct channel_definition *c = find_channel(led);
+ if(c==0) return;
+
+ if(brightness < 0) brightness = 0;
+ if(brightness > GAMMA_LEN-1) brightness = GAMMA_LEN-1;
+
+ int duty = gammatable[brightness];
+ if(duty > 1) {
+ c->channel->PWMC_CUPDR = duty;
+ if(c->periph == PERIPH_A) {
+ AT91F_PIO_CfgPeriph(AT91C_BASE_PIOA, led, 0);
+ } else if(c->periph == PERIPH_B) {
+ AT91F_PIO_CfgPeriph(AT91C_BASE_PIOA, 0, led);
+ }
+ } else {
+ vLedSet(led, 0);
+ }
+}
+
+void vLedSet(int led, bool_t on)
{
if(on)
- AT91F_PIO_ClearOutput( AT91C_BASE_PIOA, LED_RED );
+ AT91F_PIO_ClearOutput( AT91C_BASE_PIOA, led );
else
- AT91F_PIO_SetOutput( AT91C_BASE_PIOA, LED_RED );
+ AT91F_PIO_SetOutput( AT91C_BASE_PIOA, led );
+ AT91F_PIO_CfgOutput( AT91C_BASE_PIOA, led );
+}
+
+void vLedBlink(int led)
+{
+ volatile int i=0;
+ vLedSet(led, 1);
+ for(i=0; i<BLINK_TIME; i++) {vLedSet(led,0);vLedSet(led,1);}
+ vLedSet(led, 0);
}
+
/**********************************************************************/
+void vLedSetRed(bool_t on)
+{
+ vLedSet(LED_RED, on);
+}
void vLedBlinkRed(void)
{
- volatile int i=0;
- vLedSetRed(1);
- for(i=0; i<BLINK_TIME; i++) {vLedSetRed(0);vLedSetRed(1);}
- vLedSetRed(0);
+ vLedBlink(LED_RED);
}
/**********************************************************************/
void vLedSetGreen(bool_t on)
{
- if(on)
- AT91F_PIO_ClearOutput( AT91C_BASE_PIOA, LED_GREEN );
- else
- AT91F_PIO_SetOutput( AT91C_BASE_PIOA, LED_GREEN );
+ vLedSet(LED_GREEN, on);
}
/**********************************************************************/
void vLedBlinkGreen(void)
{
- volatile int i=0;
- vLedSetGreen(1);
- for(i=0; i<BLINK_TIME; i++) {vLedSetGreen(0);vLedSetGreen(1);}
- vLedSetGreen(0);
+ vLedBlink(LED_GREEN);
}
/**********************************************************************/
@@ -72,7 +132,7 @@ void vLedHaltBlinking(int reason)
volatile u_int32_t i=0;
while(1)
{
- AT91F_PIO_ClearOutput( AT91C_BASE_PIOA, LED_MASK );
+ AT91F_PIO_ClearOutput( AT91C_BASE_PIOA, LED_RED | LED_GREEN );
for(i=0; i<MCK/40; i++) ;
switch(reason) {
@@ -96,15 +156,44 @@ void vLedHaltBlinking(int reason)
}
for(i=0; i<MCK/20; i++) ;
- AT91F_PIO_SetOutput( AT91C_BASE_PIOA, LED_MASK );
+ AT91F_PIO_SetOutput( AT91C_BASE_PIOA, LED_RED | LED_GREEN );
for(i=0; i<MCK/40; i++) ;
}
}
/**********************************************************************/
+static void init_led_pwm(unsigned int led)
+{
+ const struct channel_definition *c = find_channel(led);
+
+ if(c==0) return;
+
+ // Set PIO mapping
+ if(c->periph == PERIPH_A) {
+ AT91F_PIO_CfgPeriph(AT91C_BASE_PIOA, led, 0);
+ } else if(c->periph == PERIPH_B) {
+ AT91F_PIO_CfgPeriph(AT91C_BASE_PIOA, 0, led);
+ } else
+ return;
+
+ // Configure channel: clock = MCK, period = PWM_PERIOD, CPOL=1, duty cycle variable
+ c->channel->PWMC_CMR = 0x0 | AT91C_PWMC_CPOL;
+ c->channel->PWMC_CDTYR = 1;
+ c->channel->PWMC_CPRDR = PWM_PERIOD;
+
+ AT91C_BASE_PWMC->PWMC_ENA = (1<<(c->channel_no));
+ vLedSetBrightness(led, 0);
+}
+
void vLedInit(void)
{
// turn off LED's
- AT91F_PIO_CfgOutput( AT91C_BASE_PIOA, LED_MASK );
- AT91F_PIO_SetOutput( AT91C_BASE_PIOA, LED_MASK );
+ AT91F_PIO_CfgOutput( AT91C_BASE_PIOA, LED_RED | LED_GREEN );
+ AT91F_PIO_SetOutput( AT91C_BASE_PIOA, LED_RED | LED_GREEN );
+
+ AT91F_PMC_EnablePeriphClock(AT91C_BASE_PMC,
+ ((unsigned int) 1 << AT91C_ID_PWMC));
+
+ init_led_pwm(LED_GREEN);
+ init_led_pwm(LED_RED);
}
personal git repositories of Harald Welte. Your mileage may vary