Get PWM working
This commit is contained in:
parent
77aba4d21d
commit
3514b2576c
8
.gitignore
vendored
Normal file
8
.gitignore
vendored
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
obj
|
||||||
|
*.bin
|
||||||
|
*.eep
|
||||||
|
*.elf
|
||||||
|
*.hex
|
||||||
|
*.lss
|
||||||
|
*.map
|
||||||
|
*.sym
|
115
Descriptors.h
115
Descriptors.h
@ -36,75 +36,74 @@
|
|||||||
#ifndef _DESCRIPTORS_H_
|
#ifndef _DESCRIPTORS_H_
|
||||||
#define _DESCRIPTORS_H_
|
#define _DESCRIPTORS_H_
|
||||||
|
|
||||||
/* Includes: */
|
/* Includes: */
|
||||||
#include <LUFA/Drivers/USB/USB.h>
|
#include <LUFA/Drivers/USB/USB.h>
|
||||||
|
|
||||||
#include <avr/pgmspace.h>
|
#include <avr/pgmspace.h>
|
||||||
|
|
||||||
/* Macros: */
|
/* Macros: */
|
||||||
/** Endpoint address of the CDC device-to-host notification IN endpoint. */
|
/** Endpoint address of the CDC device-to-host notification IN endpoint. */
|
||||||
#define CDC_NOTIFICATION_EPADDR (ENDPOINT_DIR_IN | 2)
|
#define CDC_NOTIFICATION_EPADDR (ENDPOINT_DIR_IN | 2)
|
||||||
|
|
||||||
/** Endpoint address of the CDC device-to-host data IN endpoint. */
|
/** Endpoint address of the CDC device-to-host data IN endpoint. */
|
||||||
#define CDC_TX_EPADDR (ENDPOINT_DIR_IN | 3)
|
#define CDC_TX_EPADDR (ENDPOINT_DIR_IN | 3)
|
||||||
|
|
||||||
/** Endpoint address of the CDC host-to-device data OUT endpoint. */
|
/** Endpoint address of the CDC host-to-device data OUT endpoint. */
|
||||||
#define CDC_RX_EPADDR (ENDPOINT_DIR_OUT | 4)
|
#define CDC_RX_EPADDR (ENDPOINT_DIR_OUT | 4)
|
||||||
|
|
||||||
/** Size in bytes of the CDC device-to-host notification IN endpoint. */
|
/** Size in bytes of the CDC device-to-host notification IN endpoint. */
|
||||||
#define CDC_NOTIFICATION_EPSIZE 8
|
#define CDC_NOTIFICATION_EPSIZE 8
|
||||||
|
|
||||||
/** Size in bytes of the CDC data IN and OUT endpoints. */
|
/** Size in bytes of the CDC data IN and OUT endpoints. */
|
||||||
#define CDC_TXRX_EPSIZE 16
|
#define CDC_TXRX_EPSIZE 16
|
||||||
|
|
||||||
/* Type Defines: */
|
/* Type Defines: */
|
||||||
/** Type define for the device configuration descriptor structure. This must be defined in the
|
/** Type define for the device configuration descriptor structure. This must be defined in the
|
||||||
* application code, as the configuration descriptor contains several sub-descriptors which
|
* application code, as the configuration descriptor contains several sub-descriptors which
|
||||||
* vary between devices, and which describe the device's usage to the host.
|
* vary between devices, and which describe the device's usage to the host.
|
||||||
*/
|
*/
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
USB_Descriptor_Configuration_Header_t Config;
|
USB_Descriptor_Configuration_Header_t Config;
|
||||||
|
|
||||||
// CDC Control Interface
|
// CDC Control Interface
|
||||||
USB_Descriptor_Interface_t CDC_CCI_Interface;
|
USB_Descriptor_Interface_t CDC_CCI_Interface;
|
||||||
USB_CDC_Descriptor_FunctionalHeader_t CDC_Functional_Header;
|
USB_CDC_Descriptor_FunctionalHeader_t CDC_Functional_Header;
|
||||||
USB_CDC_Descriptor_FunctionalACM_t CDC_Functional_ACM;
|
USB_CDC_Descriptor_FunctionalACM_t CDC_Functional_ACM;
|
||||||
USB_CDC_Descriptor_FunctionalUnion_t CDC_Functional_Union;
|
USB_CDC_Descriptor_FunctionalUnion_t CDC_Functional_Union;
|
||||||
USB_Descriptor_Endpoint_t CDC_NotificationEndpoint;
|
USB_Descriptor_Endpoint_t CDC_NotificationEndpoint;
|
||||||
|
|
||||||
// CDC Data Interface
|
// CDC Data Interface
|
||||||
USB_Descriptor_Interface_t CDC_DCI_Interface;
|
USB_Descriptor_Interface_t CDC_DCI_Interface;
|
||||||
USB_Descriptor_Endpoint_t CDC_DataOutEndpoint;
|
USB_Descriptor_Endpoint_t CDC_DataOutEndpoint;
|
||||||
USB_Descriptor_Endpoint_t CDC_DataInEndpoint;
|
USB_Descriptor_Endpoint_t CDC_DataInEndpoint;
|
||||||
} USB_Descriptor_Configuration_t;
|
} USB_Descriptor_Configuration_t;
|
||||||
|
|
||||||
/** Enum for the device interface descriptor IDs within the device. Each interface descriptor
|
/** Enum for the device interface descriptor IDs within the device. Each interface descriptor
|
||||||
* should have a unique ID index associated with it, which can be used to refer to the
|
* should have a unique ID index associated with it, which can be used to refer to the
|
||||||
* interface from other descriptors.
|
* interface from other descriptors.
|
||||||
*/
|
*/
|
||||||
enum InterfaceDescriptors_t
|
enum InterfaceDescriptors_t
|
||||||
{
|
{
|
||||||
INTERFACE_ID_CDC_CCI = 0, /**< CDC CCI interface descriptor ID */
|
INTERFACE_ID_CDC_CCI = 0, /**< CDC CCI interface descriptor ID */
|
||||||
INTERFACE_ID_CDC_DCI = 1, /**< CDC DCI interface descriptor ID */
|
INTERFACE_ID_CDC_DCI = 1, /**< CDC DCI interface descriptor ID */
|
||||||
};
|
};
|
||||||
|
|
||||||
/** Enum for the device string descriptor IDs within the device. Each string descriptor should
|
/** Enum for the device string descriptor IDs within the device. Each string descriptor should
|
||||||
* have a unique ID index associated with it, which can be used to refer to the string from
|
* have a unique ID index associated with it, which can be used to refer to the string from
|
||||||
* other descriptors.
|
* other descriptors.
|
||||||
*/
|
*/
|
||||||
enum StringDescriptors_t
|
enum StringDescriptors_t
|
||||||
{
|
{
|
||||||
STRING_ID_Language = 0, /**< Supported Languages string descriptor ID (must be zero) */
|
STRING_ID_Language = 0, /**< Supported Languages string descriptor ID (must be zero) */
|
||||||
STRING_ID_Manufacturer = 1, /**< Manufacturer string ID */
|
STRING_ID_Manufacturer = 1, /**< Manufacturer string ID */
|
||||||
STRING_ID_Product = 2, /**< Product string ID */
|
STRING_ID_Product = 2, /**< Product string ID */
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Function Prototypes: */
|
/* Function Prototypes: */
|
||||||
uint16_t CALLBACK_USB_GetDescriptor(const uint16_t wValue,
|
uint16_t CALLBACK_USB_GetDescriptor(const uint16_t wValue,
|
||||||
const uint16_t wIndex,
|
const uint16_t wIndex,
|
||||||
const void** const DescriptorAddress)
|
const void** const DescriptorAddress)
|
||||||
ATTR_WARN_UNUSED_RESULT ATTR_NON_NULL_PTR_ARG(3);
|
ATTR_WARN_UNUSED_RESULT ATTR_NON_NULL_PTR_ARG(3);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
2
Makefile
2
Makefile
@ -18,7 +18,7 @@ F_CPU = 16000000
|
|||||||
F_USB = $(F_CPU)
|
F_USB = $(F_CPU)
|
||||||
OPTIMIZATION = s
|
OPTIMIZATION = s
|
||||||
TARGET = usbfanctrl
|
TARGET = usbfanctrl
|
||||||
SRC = main.c Descriptors.c $(LUFA_SRC_USB) $(LUFA_SRC_USBCLASS) $(LUFA_SRC_PLATFORM)
|
SRC = $(wildcard *.c) $(LUFA_SRC_USB) $(LUFA_SRC_USBCLASS) $(LUFA_SRC_PLATFORM)
|
||||||
LUFA_PATH = LUFA/LUFA
|
LUFA_PATH = LUFA/LUFA
|
||||||
CC_FLAGS = -DUSE_LUFA_CONFIG_HEADER -IConfig
|
CC_FLAGS = -DUSE_LUFA_CONFIG_HEADER -IConfig
|
||||||
LD_FLAGS =
|
LD_FLAGS =
|
||||||
|
66
event.c
Normal file
66
event.c
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
/***************************************************************************
|
||||||
|
* Copyright (C) 01/2019 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/interrupt.h>
|
||||||
|
#include <avr/io.h>
|
||||||
|
|
||||||
|
#include "event.h"
|
||||||
|
|
||||||
|
/* *********************************************************************** */
|
||||||
|
|
||||||
|
static event_entry_t events[EVENT_COUNT];
|
||||||
|
static volatile uint8_t event_in_idx;
|
||||||
|
static volatile uint8_t event_out_idx;
|
||||||
|
|
||||||
|
/* *********************************************************************** */
|
||||||
|
|
||||||
|
void event_queue(uint8_t type, uint8_t num, uint16_t value)
|
||||||
|
{
|
||||||
|
event_entry_t * p_event;
|
||||||
|
uint8_t sreg_save;
|
||||||
|
uint8_t idx;
|
||||||
|
|
||||||
|
sreg_save = SREG;
|
||||||
|
cli();
|
||||||
|
|
||||||
|
idx = event_in_idx;
|
||||||
|
p_event = &events[idx++];
|
||||||
|
if (p_event->type == EVENT_TYPE_EMPTY)
|
||||||
|
{
|
||||||
|
p_event->type = type;
|
||||||
|
p_event->num = num;
|
||||||
|
p_event->value = value;
|
||||||
|
event_in_idx = idx % EVENT_COUNT;
|
||||||
|
}
|
||||||
|
|
||||||
|
SREG = sreg_save;
|
||||||
|
} /* event_queue */
|
||||||
|
|
||||||
|
|
||||||
|
event_entry_t * event_get(void)
|
||||||
|
{
|
||||||
|
return &events[event_out_idx];
|
||||||
|
} /* event_get */
|
||||||
|
|
||||||
|
|
||||||
|
void event_clear(void)
|
||||||
|
{
|
||||||
|
uint8_t idx = event_out_idx;
|
||||||
|
events[idx++].type = EVENT_TYPE_EMPTY;
|
||||||
|
event_out_idx = idx % EVENT_COUNT;
|
||||||
|
} /* event_clear */
|
27
event.h
Normal file
27
event.h
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
#ifndef __EVENT_H__
|
||||||
|
#define __EVENT_H__
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
/* *********************************************************************** */
|
||||||
|
|
||||||
|
#define EVENT_COUNT 16
|
||||||
|
|
||||||
|
#define EVENT_TYPE_EMPTY 0x00
|
||||||
|
|
||||||
|
typedef struct event_entry_s
|
||||||
|
{
|
||||||
|
uint8_t type;
|
||||||
|
uint8_t num;
|
||||||
|
uint16_t value;
|
||||||
|
} event_entry_t;
|
||||||
|
|
||||||
|
/* *********************************************************************** */
|
||||||
|
|
||||||
|
void event_queue (uint8_t type, uint8_t num, uint16_t value);
|
||||||
|
event_entry_t * event_get (void);
|
||||||
|
void event_clear (void);
|
||||||
|
|
||||||
|
/* *********************************************************************** */
|
||||||
|
|
||||||
|
#endif /* __EVENT_H__ */
|
49
main.c
49
main.c
@ -5,6 +5,9 @@
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
#include "Descriptors.h"
|
#include "Descriptors.h"
|
||||||
|
#include "event.h"
|
||||||
|
#include "pwm.h"
|
||||||
|
#include "timer.h"
|
||||||
|
|
||||||
#include <LUFA/Drivers/USB/USB.h>
|
#include <LUFA/Drivers/USB/USB.h>
|
||||||
#include <LUFA/Platform/Platform.h>
|
#include <LUFA/Platform/Platform.h>
|
||||||
@ -39,12 +42,52 @@ int main(void)
|
|||||||
{
|
{
|
||||||
SetupHardware();
|
SetupHardware();
|
||||||
|
|
||||||
|
timer_init();
|
||||||
|
pwm_init();
|
||||||
|
|
||||||
GlobalInterruptEnable();
|
GlobalInterruptEnable();
|
||||||
|
|
||||||
|
event_queue(EVENT_TYPE_PWM_COMMAND, 0, EVENT_VALUE_PWM_FADE_MAX);
|
||||||
|
event_queue(EVENT_TYPE_PWM_COMMAND, 1, EVENT_VALUE_PWM_FADE_MAX);
|
||||||
|
event_queue(EVENT_TYPE_PWM_COMMAND, 2, EVENT_VALUE_PWM_FADE_MAX);
|
||||||
|
|
||||||
for (;;)
|
for (;;)
|
||||||
{
|
{
|
||||||
CDC_Task();
|
// CDC_Task();
|
||||||
USB_USBTask();
|
// USB_USBTask();
|
||||||
|
|
||||||
|
timer_check(0);
|
||||||
|
|
||||||
|
event_entry_t* p_event = event_get();
|
||||||
|
if (p_event->type != EVENT_TYPE_EMPTY)
|
||||||
|
{
|
||||||
|
switch (p_event->type)
|
||||||
|
{
|
||||||
|
case EVENT_TYPE_PWM_COMMAND:
|
||||||
|
case EVENT_TYPE_PWM_VALUE:
|
||||||
|
pwm_event_handler(p_event);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case EVENT_TYPE_PWM_STATUS:
|
||||||
|
break;
|
||||||
|
|
||||||
|
case EVENT_TYPE_TIMER_SET:
|
||||||
|
timer_event_handler(p_event);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case EVENT_TYPE_TIMER_ELAPSED:
|
||||||
|
if (p_event->num == EVENT_NUM_TIMER_PWM)
|
||||||
|
{
|
||||||
|
pwm_event_handler(p_event);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
event_clear();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -58,7 +101,7 @@ void SetupHardware(void)
|
|||||||
/* Disable clock division */
|
/* Disable clock division */
|
||||||
clock_prescale_set(clock_div_1);
|
clock_prescale_set(clock_div_1);
|
||||||
|
|
||||||
USB_Init();
|
// USB_Init();
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Event handler for the USB_Connect event. This indicates that the device is enumerating via the status LEDs and
|
/** Event handler for the USB_Connect event. This indicates that the device is enumerating via the status LEDs and
|
||||||
|
354
pwm.c
Normal file
354
pwm.c
Normal file
@ -0,0 +1,354 @@
|
|||||||
|
/***************************************************************************
|
||||||
|
* Copyright (C) 01/2019 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/interrupt.h>
|
||||||
|
#include <avr/pgmspace.h>
|
||||||
|
|
||||||
|
#include "pwm.h"
|
||||||
|
#include "timer.h"
|
||||||
|
|
||||||
|
|
||||||
|
/* *********************************************************************** */
|
||||||
|
|
||||||
|
#define PWM_TIM_16BIT 1
|
||||||
|
|
||||||
|
#define PWM_TIM_INIT() { \
|
||||||
|
/* enable output for OC1A, OC1B, OC3A */ \
|
||||||
|
DDRB |= (1<<PORTB5) | (1<<PORTB6); \
|
||||||
|
DDRC |= (1<<PORTC6); \
|
||||||
|
/* reset and hold prescaler */ \
|
||||||
|
GTCCR = (1<<TSM) | (1<<PSRSYNC); \
|
||||||
|
/* FastModePWM, ICRn is TOP */ \
|
||||||
|
TCCR1A = (1<<WGM11); \
|
||||||
|
TCCR1B = (1<<WGM13) | (1<<WGM12); \
|
||||||
|
ICR1 = 0xFFFF; \
|
||||||
|
TCNT1 = 0x0000; \
|
||||||
|
TCCR3A = (1<<WGM31); \
|
||||||
|
TCCR3B = (1<<WGM33) | (1<<WGM32); \
|
||||||
|
ICR3 = 0xFFFF; \
|
||||||
|
TCNT3 = 0x8000; \
|
||||||
|
/* release prescaler */ \
|
||||||
|
GTCCR = (1<<PSRSYNC); \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define PWM_TIM1_ENABLE() { TCCR1B |= (1<<CS10); }
|
||||||
|
#define PWM_TIM1_DISABLE() { TCCR1B &= ~(1<<CS10); }
|
||||||
|
#define PWM_TIM1_RUNNING() (TCCR1B & ((1<<CS10) | (1<<CS11) | (1<<CS12)))
|
||||||
|
#define PWM_TIM1_CHECK() (TCCR1A & ((1<<COM1A1) | (1<<COM1B1)))
|
||||||
|
|
||||||
|
#define PWM_TIM3_ENABLE() { TCCR3B |= (1<<CS30); }
|
||||||
|
#define PWM_TIM3_DISABLE() { TCCR3B &= ~(1<<CS30); }
|
||||||
|
#define PWM_TIM3_RUNNING() (TCCR3B & ((1<<CS30) | (1<<CS31) | (1<<CS32)))
|
||||||
|
#define PWM_TIM3_CHECK() (TCCR3A & ((1<<COM3A1) | (1<<COM3B1)))
|
||||||
|
|
||||||
|
#define PWM_TIMER_FADE_STEP_MS 10
|
||||||
|
|
||||||
|
#define PWM_CH0_PORT PORTB
|
||||||
|
#define PWM_CH0_NUM 5
|
||||||
|
#define PWM_CH0_OFF() { PWM_CH0_PORT &= ~(1<<PWM_CH0_NUM); TCCR1A &= ~(1<<COM1A1); }
|
||||||
|
#define PWM_CH0_ON() { PWM_CH0_PORT |= (1<<PWM_CH0_NUM); TCCR1A &= ~(1<<COM1A1); }
|
||||||
|
#define PWM_CH0_PWM(x) { PWM_CH0_PORT &= ~(1<<PWM_CH0_NUM); TCCR1A |= (1<<COM1A1); OCR1A = x; }
|
||||||
|
|
||||||
|
#define PWM_CH1_PORT PORTB
|
||||||
|
#define PWM_CH1_NUM 6
|
||||||
|
#define PWM_CH1_OFF() { PWM_CH1_PORT &= ~(1<<PWM_CH1_NUM); TCCR1A &= ~(1<<COM1B1); }
|
||||||
|
#define PWM_CH1_ON() { PWM_CH1_PORT |= (1<<PWM_CH1_NUM); TCCR1A &= ~(1<<COM1B1); }
|
||||||
|
#define PWM_CH1_PWM(x) { PWM_CH1_PORT &= ~(1<<PWM_CH1_NUM); TCCR1A |= (1<<COM1B1); OCR1B = x; }
|
||||||
|
|
||||||
|
#define PWM_CH2_PORT PORTC
|
||||||
|
#define PWM_CH2_NUM 6
|
||||||
|
#define PWM_CH2_OFF() { PWM_CH2_PORT &= ~(1<<PWM_CH2_NUM); TCCR3A &= ~(1<<COM3A1); }
|
||||||
|
#define PWM_CH2_ON() { PWM_CH2_PORT |= (1<<PWM_CH2_NUM); TCCR3A &= ~(1<<COM3A1); }
|
||||||
|
#define PWM_CH2_PWM(x) { PWM_CH2_PORT &= ~(1<<PWM_CH2_NUM); TCCR3A |= (1<<COM3A1); OCR3A = x; }
|
||||||
|
|
||||||
|
#if (PWM_TIM_16BIT)
|
||||||
|
#define PWM_TABLE_SIZE 128
|
||||||
|
#define PWM_TABLE_GET(x) pgm_read_word(&pwmtable16[x])
|
||||||
|
const uint16_t pwmtable16[PWM_TABLE_SIZE] 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
|
||||||
|
};
|
||||||
|
#else
|
||||||
|
#define PWM_TABLE_SIZE 32
|
||||||
|
#define PWM_TABLE_GET(x) pgm_read_byte(&pwmtable8[x])
|
||||||
|
const uint8_t pwmtable8[PWM_TABLE_SIZE] PROGMEM =
|
||||||
|
{
|
||||||
|
0, 0, 1, 1, 1, 2, 2, 3,
|
||||||
|
4, 5, 6, 7, 9, 10, 12, 15,
|
||||||
|
18, 22, 26, 31, 37, 44, 53, 63,
|
||||||
|
75, 90, 107, 127, 151, 180, 214, 255
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static uint8_t pwm_index[3];
|
||||||
|
static uint8_t pwm_setpoint[3];
|
||||||
|
static uint8_t pwm_setpoint_save[3];
|
||||||
|
static uint8_t pwm_fade_timer_running;
|
||||||
|
|
||||||
|
/* *********************************************************************** */
|
||||||
|
|
||||||
|
static void pwm_update(uint8_t channel)
|
||||||
|
{
|
||||||
|
uint8_t check_setpoint = 0;
|
||||||
|
|
||||||
|
if (pwm_setpoint[channel] >= PWM_TABLE_SIZE)
|
||||||
|
{
|
||||||
|
pwm_setpoint[channel] = (PWM_TABLE_SIZE - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((pwm_setpoint[channel] > pwm_index[channel]) &&
|
||||||
|
(pwm_index[channel] < (PWM_TABLE_SIZE - 1))
|
||||||
|
)
|
||||||
|
{
|
||||||
|
pwm_index[channel]++;
|
||||||
|
check_setpoint = 1;
|
||||||
|
}
|
||||||
|
else if ((pwm_setpoint[channel] < pwm_index[channel]) &&
|
||||||
|
(pwm_index[channel] > 0)
|
||||||
|
)
|
||||||
|
{
|
||||||
|
pwm_index[channel]--;
|
||||||
|
check_setpoint = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* setpoint reached, notify others */
|
||||||
|
if (check_setpoint)
|
||||||
|
{
|
||||||
|
if (pwm_index[channel] == pwm_setpoint[channel])
|
||||||
|
{
|
||||||
|
event_queue(EVENT_TYPE_PWM_STATUS,
|
||||||
|
channel,
|
||||||
|
pwm_setpoint[channel]);
|
||||||
|
}
|
||||||
|
else if (!pwm_fade_timer_running)
|
||||||
|
{
|
||||||
|
event_queue(EVENT_TYPE_TIMER_SET,
|
||||||
|
EVENT_NUM_TIMER_PWM,
|
||||||
|
PWM_TIMER_FADE_STEP_MS);
|
||||||
|
|
||||||
|
pwm_fade_timer_running = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* if PWM is zero, disable output */
|
||||||
|
if (pwm_index[channel] == 0)
|
||||||
|
{
|
||||||
|
switch (channel)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
PWM_CH0_OFF();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 1:
|
||||||
|
PWM_CH1_OFF();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 2:
|
||||||
|
PWM_CH2_OFF();
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* if PWM is max, enable output */
|
||||||
|
else if (pwm_index[channel] == (PWM_TABLE_SIZE - 1))
|
||||||
|
{
|
||||||
|
switch (channel)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
PWM_CH0_ON();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 1:
|
||||||
|
PWM_CH1_ON();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 2:
|
||||||
|
PWM_CH2_ON();
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* else load new PWM into timer */
|
||||||
|
else
|
||||||
|
{
|
||||||
|
switch (channel)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
PWM_CH0_PWM(PWM_TABLE_GET(pwm_index[0]));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 1:
|
||||||
|
PWM_CH1_PWM(PWM_TABLE_GET(pwm_index[1]));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 2:
|
||||||
|
PWM_CH2_PWM(PWM_TABLE_GET(pwm_index[2]));
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (channel)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
case 1:
|
||||||
|
/* disable timer if all channels are ON or OFF */
|
||||||
|
if (PWM_TIM1_CHECK())
|
||||||
|
{
|
||||||
|
PWM_TIM1_ENABLE();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
PWM_TIM1_DISABLE();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 2:
|
||||||
|
/* disable timer if all channels are ON or OFF */
|
||||||
|
if (PWM_TIM3_CHECK())
|
||||||
|
{
|
||||||
|
PWM_TIM3_ENABLE();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
PWM_TIM3_DISABLE();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} /* pwm_update */
|
||||||
|
|
||||||
|
|
||||||
|
void pwm_event_handler(event_entry_t * p_event)
|
||||||
|
{
|
||||||
|
if (p_event->type == EVENT_TYPE_PWM_COMMAND)
|
||||||
|
{
|
||||||
|
uint8_t channel = p_event->num;
|
||||||
|
|
||||||
|
switch (p_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] < (PWM_TABLE_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] = (PWM_TABLE_SIZE - 1);
|
||||||
|
break;
|
||||||
|
|
||||||
|
/* toggle between 0 and stored value */
|
||||||
|
case EVENT_VALUE_PWM_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_update(channel);
|
||||||
|
}
|
||||||
|
else if (p_event->type == EVENT_TYPE_PWM_VALUE)
|
||||||
|
{
|
||||||
|
uint8_t channel = p_event->num;
|
||||||
|
|
||||||
|
if (p_event->value < PWM_TABLE_SIZE)
|
||||||
|
{
|
||||||
|
pwm_setpoint[channel] = p_event->value;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
pwm_setpoint[channel] = (PWM_TABLE_SIZE - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
pwm_update(channel);
|
||||||
|
}
|
||||||
|
else if ((p_event->type == EVENT_TYPE_TIMER_ELAPSED) &&
|
||||||
|
(p_event->num == EVENT_NUM_TIMER_PWM)
|
||||||
|
)
|
||||||
|
{
|
||||||
|
pwm_fade_timer_running = 0;
|
||||||
|
|
||||||
|
pwm_update(0);
|
||||||
|
pwm_update(1);
|
||||||
|
pwm_update(2);
|
||||||
|
}
|
||||||
|
} /* pwm_event_handler */
|
||||||
|
|
||||||
|
|
||||||
|
uint8_t pwm_get_sleep_mode(void)
|
||||||
|
{
|
||||||
|
if (PWM_TIM1_RUNNING() || PWM_TIM3_RUNNING())
|
||||||
|
{
|
||||||
|
return SLEEP_MODE_IDLE;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return SLEEP_MODE_PWR_DOWN;
|
||||||
|
}
|
||||||
|
} /* pwm_get_sleep_mode */
|
||||||
|
|
||||||
|
|
||||||
|
void pwm_init(void)
|
||||||
|
{
|
||||||
|
PWM_TIM_INIT();
|
||||||
|
} /* pwm_init */
|
32
pwm.h
Normal file
32
pwm.h
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
#ifndef __PWM_H__
|
||||||
|
#define __PWM_H__
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include "event.h"
|
||||||
|
|
||||||
|
/* *********************************************************************** */
|
||||||
|
|
||||||
|
#define EVENT_TYPE_PWM_COMMAND 0x04
|
||||||
|
#define EVENT_TYPE_PWM_VALUE 0x05
|
||||||
|
#define EVENT_TYPE_PWM_STATUS 0x06
|
||||||
|
|
||||||
|
#define EVENT_NUM_PWM_CH0 0x00
|
||||||
|
#define EVENT_NUM_PWM_CH1 0x01
|
||||||
|
#define EVENT_NUM_PWM_CH2 0x02
|
||||||
|
|
||||||
|
#define EVENT_VALUE_PWM_KEEP 0x00
|
||||||
|
#define EVENT_VALUE_PWM_INC 0x01
|
||||||
|
#define EVENT_VALUE_PWM_DEC 0x02
|
||||||
|
#define EVENT_VALUE_PWM_FADE_MIN 0x03
|
||||||
|
#define EVENT_VALUE_PWM_FADE_MAX 0x04
|
||||||
|
#define EVENT_VALUE_PWM_TOGGLE 0x05
|
||||||
|
|
||||||
|
/* *********************************************************************** */
|
||||||
|
|
||||||
|
void pwm_init (void);
|
||||||
|
void pwm_event_handler (event_entry_t * p_event);
|
||||||
|
uint8_t pwm_get_sleep_mode (void);
|
||||||
|
|
||||||
|
/* *********************************************************************** */
|
||||||
|
|
||||||
|
#endif /* __PWM_H__ */
|
133
timer.c
Normal file
133
timer.c
Normal file
@ -0,0 +1,133 @@
|
|||||||
|
/***************************************************************************
|
||||||
|
* Copyright (C) 01/2019 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/interrupt.h>
|
||||||
|
#include <avr/io.h>
|
||||||
|
#include <avr/sleep.h>
|
||||||
|
|
||||||
|
#include "event.h"
|
||||||
|
#include "timer.h"
|
||||||
|
|
||||||
|
/* *********************************************************************** */
|
||||||
|
|
||||||
|
#define TIMER_TIM_INIT() { \
|
||||||
|
TCCR0A = 0x00; \
|
||||||
|
TCCR0B = 0x00; \
|
||||||
|
TIMSK0 = (1<<TOIE0); \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define TIMER_TIM_ENABLE() { TCCR0B |= ((1<<CS00) | (1<<CS01)); }
|
||||||
|
#define TIMER_TIM_DISABLE() { TCCR0B &= ~((1<<CS00) | (1<<CS01)); }
|
||||||
|
#define TIMER_TIM_RUNNING() (TCCR0B & ((1<<CS00) | (1<<CS01) | (1<<CS02)))
|
||||||
|
#define TIMER_TIM_RELOAD(x) { TCNT0 = (0xFF - (x)); }
|
||||||
|
#define TIMER_TIM_VECT TIMER0_OVF_vect
|
||||||
|
|
||||||
|
#define TIMER_DIVISOR 64
|
||||||
|
#define TIMER_IRQFREQ_MS 1
|
||||||
|
|
||||||
|
#define TIMER_MSEC2TICKS(x) ((x * F_CPU) / (TIMER_DIVISOR * 1000ULL))
|
||||||
|
#define TIMER_MSEC2IRQCNT(x) (x / TIMER_IRQFREQ_MS)
|
||||||
|
|
||||||
|
static uint16_t timers[TIMER_COUNT];
|
||||||
|
volatile static uint8_t timer_ticked;
|
||||||
|
|
||||||
|
/* *********************************************************************** */
|
||||||
|
|
||||||
|
ISR(TIMER_TIM_VECT)
|
||||||
|
{
|
||||||
|
/* 1ms interrupt */
|
||||||
|
TIMER_TIM_RELOAD(TIMER_MSEC2TICKS(TIMER_IRQFREQ_MS));
|
||||||
|
|
||||||
|
timer_ticked = 1;
|
||||||
|
} /* TIM1_OVF_vect */
|
||||||
|
|
||||||
|
|
||||||
|
uint8_t timer_check(uint8_t timer_needed)
|
||||||
|
{
|
||||||
|
if (timer_ticked)
|
||||||
|
{
|
||||||
|
uint8_t i;
|
||||||
|
|
||||||
|
timer_ticked = 0;
|
||||||
|
|
||||||
|
for (i = 0; i < TIMER_COUNT; i++)
|
||||||
|
{
|
||||||
|
if (timers[i] > 0)
|
||||||
|
{
|
||||||
|
timers[i]--;
|
||||||
|
if (timers[i] == 0)
|
||||||
|
{
|
||||||
|
event_queue(EVENT_TYPE_TIMER_ELAPSED, i, 0);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
timer_needed = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* stop timer */
|
||||||
|
if (timer_needed == 0)
|
||||||
|
{
|
||||||
|
TIMER_TIM_DISABLE();
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
} /* timer_check */
|
||||||
|
|
||||||
|
|
||||||
|
void timer_event_handler(event_entry_t * p_event)
|
||||||
|
{
|
||||||
|
if ((p_event->type == EVENT_TYPE_TIMER_SET) &&
|
||||||
|
(p_event->num < TIMER_COUNT)
|
||||||
|
)
|
||||||
|
{
|
||||||
|
timers[p_event->num] = p_event->value;
|
||||||
|
|
||||||
|
/* start timer if needed */
|
||||||
|
if (!TIMER_TIM_RUNNING())
|
||||||
|
{
|
||||||
|
TIMER_TIM_RELOAD(TIMER_MSEC2TICKS(TIMER_IRQFREQ_MS));
|
||||||
|
TIMER_TIM_ENABLE();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} /* timer_event_handler */
|
||||||
|
|
||||||
|
|
||||||
|
uint8_t timer_get_sleep_mode(void)
|
||||||
|
{
|
||||||
|
if (TIMER_TIM_RUNNING())
|
||||||
|
{
|
||||||
|
return SLEEP_MODE_IDLE;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return SLEEP_MODE_PWR_DOWN;
|
||||||
|
}
|
||||||
|
} /* timer_get_sleep_mode */
|
||||||
|
|
||||||
|
|
||||||
|
void timer_init(void)
|
||||||
|
{
|
||||||
|
TIMER_TIM_INIT();
|
||||||
|
TIMER_TIM_RELOAD(TIMER_MSEC2TICKS(TIMER_IRQFREQ_MS));
|
||||||
|
TIMER_TIM_ENABLE();
|
||||||
|
} /* timer_init */
|
25
timer.h
Normal file
25
timer.h
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
#ifndef __TIMER_H__
|
||||||
|
#define __TIMER_H__
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include "event.h"
|
||||||
|
|
||||||
|
/* *********************************************************************** */
|
||||||
|
|
||||||
|
#define TIMER_COUNT 1
|
||||||
|
|
||||||
|
#define EVENT_TYPE_TIMER_SET 0x01
|
||||||
|
#define EVENT_TYPE_TIMER_ELAPSED 0x02
|
||||||
|
|
||||||
|
#define EVENT_NUM_TIMER_PWM 0
|
||||||
|
|
||||||
|
/* *********************************************************************** */
|
||||||
|
|
||||||
|
void timer_init (void);
|
||||||
|
uint8_t timer_check (uint8_t timer_needed);
|
||||||
|
void timer_event_handler (event_entry_t * p_event);
|
||||||
|
uint8_t timer_get_sleep_mode (void);
|
||||||
|
|
||||||
|
/* *********************************************************************** */
|
||||||
|
|
||||||
|
#endif /* __TIMER_H__ */
|
Loading…
Reference in New Issue
Block a user