funkstuff/pwm.c

203 lines
5.8 KiB
C

/***************************************************************************
* Copyright (C) 11/2014 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 <avr/io.h>
#include <avr/interrupt.h>
#include <avr/pgmspace.h>
#include "event.h"
#include "pwm.h"
#include "target.h"
/* *********************************************************************** */
const uint16_t pwmtable[128] PROGMEM =
{
0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 4, 4, 5, 5,
6, 6, 7, 8, 9, 9, 10, 11, 12, 14, 15, 16, 18, 20, 22, 24, 26,
28, 31, 34, 37, 40, 44, 48, 53, 58, 63, 69, 75, 82, 90, 98,
107, 116, 127, 139, 151, 165, 180, 196, 214, 234, 255, 278,
303, 331, 361, 394, 430, 469, 511, 557, 608, 663, 723, 789,
860, 938, 1023, 1116, 1217, 1327, 1447, 1578, 1721, 1877,
2047, 2232, 2434, 2655, 2895, 3157, 3443, 3755, 4095, 4466,
4870, 5311, 5792, 6316, 6888, 7511, 8191, 8932, 9741, 10623,
11584, 12633, 13776, 15023, 16383, 17866, 19483, 21246, 23169,
25267, 27553, 30047, 32767, 35733, 38967, 42494, 46340, 50534,
55108, 60096, 65535
};
#define PWMTABLE_SIZE (sizeof(pwmtable) / sizeof(uint16_t))
static uint8_t pwm_index[2];
static uint8_t pwm_setpoint[2];
static uint8_t pwm_setpoint_save[2];
/* *********************************************************************** */
void pwm_event_handler(struct event_entry *event)
{
uint8_t channel = event->num;
if (event->type == EVENT_TYPE_PWM_COMMAND)
{
switch (event->value)
{
case EVENT_VALUE_PWM_KEEP:
pwm_setpoint[channel] = pwm_index[channel];
break;
/* increment PWM */
case EVENT_VALUE_PWM_INC:
if (pwm_setpoint[channel] < (PWMTABLE_SIZE -1))
{
pwm_setpoint[channel]++;
}
break;
/* decrement PWM */
case EVENT_VALUE_PWM_DEC:
if (pwm_setpoint[channel] > 0)
{
pwm_setpoint[channel]--;
}
break;
/* fade to min */
case EVENT_VALUE_PWM_FADE_MIN:
pwm_setpoint[channel] = 0;
break;
/* fade to max */
case EVENT_VALUE_PWM_FADE_MAX:
pwm_setpoint[channel] = (PWMTABLE_SIZE -1);
break;
// FIXME: move to some other module?
case PWM_MODE_TOGGLE:
if (pwm_setpoint[channel] > 5)
{
pwm_setpoint_save[channel] = pwm_setpoint[channel];
pwm_setpoint[channel] = 0;
}
else
{
pwm_setpoint[channel] = pwm_setpoint_save[channel];
}
break;
default:
break;
}
PWM_TIM_ENABLE();
}
else if (event->type == EVENT_TYPE_PWM_VALUE)
{
pwm_setpoint[event->num] = event->value;
PWM_TIM_ENABLE();
}
} /* pwm_event_handler */
static void pwm_update(uint8_t channel)
{
if ((pwm_setpoint[channel] > pwm_index[channel]) &&
(pwm_index[channel] < (PWMTABLE_SIZE -1))
)
{
pwm_index[channel]++;
}
else if ((pwm_setpoint[channel] < pwm_index[channel]) &&
(pwm_index[channel] > 0)
)
{
pwm_index[channel]--;
}
/* if PWM is zero, disable output */
if (pwm_index[channel] == 0)
{
if (channel == 0)
{
PWM_CH0_OFF();
}
else
{
PWM_CH1_OFF();
}
}
/* if PWM is max, enable output */
else if (pwm_index[channel] == (PWMTABLE_SIZE -1))
{
if (channel == 0)
{
PWM_CH0_ON();
}
else
{
PWM_CH1_ON();
}
}
/* else load new PWM into timer */
else
{
if (channel == 0)
{
PWM_CH0_PWM(pgm_read_word(&pwmtable[pwm_index[0]]));
}
else
{
PWM_CH1_PWM(pgm_read_word(&pwmtable[pwm_index[1]]));
}
}
} /* pwm_set */
ISR(PWM_TIM_VECT)
{
static uint8_t delay;
delay++;
if (delay == 4)
{
delay = 0;
/* update PWM values */
pwm_update(0);
pwm_update(1);
/* disable timer if both channels are ON or OFF */
if (PWM_TIM_CHECK())
{
PWM_TIM_ENABLE();
}
else
{
PWM_TIM_DISABLE();
}
}
} /* TIM1_OVF_vect */
void pwm_init(void)
{
PWM_TIM_INIT();
} /* pwm_init */