174 lines
2.9 KiB
C++
174 lines
2.9 KiB
C++
#include <stdint.h>
|
|
#include <avr/io.h>
|
|
#include <util/delay.h>
|
|
#include <avr/interrupt.h>
|
|
#include <avr/sleep.h>
|
|
#include <stdbool.h>
|
|
#include <avr/cpufunc.h>
|
|
#include <avr/eeprom.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <stdlib.h>
|
|
|
|
extern "C" {
|
|
#include "usbdrv.h"
|
|
}
|
|
|
|
enum {
|
|
COMMAND_HEARTBEAT = 1,
|
|
COMMAND_SET_FAN = 2,
|
|
};
|
|
|
|
volatile uint32_t second;
|
|
volatile uint32_t lastSeenSec;
|
|
|
|
ISR(RTC_PIT_vect)
|
|
{
|
|
RTC_PITINTFLAGS = RTC_PI_bm;
|
|
PORTC_OUTTGL = PIN3_bm;
|
|
++second;
|
|
}
|
|
|
|
constexpr uint8_t FAN_A_PIN = PIN6_bm;
|
|
constexpr uint8_t FAN_B_PIN = PIN4_bm;
|
|
constexpr uint8_t FAN_C_PIN = PIN7_bm;
|
|
constexpr uint8_t FAN_D_PIN = PIN5_bm;
|
|
|
|
constexpr uint8_t fanNumToPin(uint8_t num)
|
|
{
|
|
switch(num)
|
|
{
|
|
case 0:
|
|
return FAN_A_PIN;
|
|
case 1:
|
|
return FAN_B_PIN;
|
|
case 2:
|
|
return FAN_C_PIN;
|
|
case 3:
|
|
return FAN_D_PIN;
|
|
}
|
|
return FAN_A_PIN;
|
|
};
|
|
|
|
volatile bool irq = true;
|
|
static uint8_t fanSpeeds[4] = {0x07, 0x07, 0x07, 0x07};
|
|
|
|
usbMsgLen_t usbFunctionSetup(uchar data[8])
|
|
{
|
|
usbRequest_t *rq = (usbRequest_t *)data;
|
|
static uint8_t dataBuffer[8];
|
|
usbMsgLen_t ret = 0;
|
|
|
|
if(rq->bRequest == COMMAND_HEARTBEAT)
|
|
{
|
|
lastSeenSec = second;
|
|
ret = 0;
|
|
}
|
|
else if(rq->bRequest == COMMAND_SET_FAN)
|
|
{
|
|
lastSeenSec = second;
|
|
if(rq->wIndex.word > 3 || rq->wValue.word > 255)
|
|
{
|
|
dataBuffer[0] = 0xFF;
|
|
}
|
|
else
|
|
{
|
|
PORTC_OUTSET = PIN3_bm;
|
|
fanSpeeds[rq->wIndex.word] = rq->wValue.word>>4;
|
|
dataBuffer[0] = 0;
|
|
}
|
|
ret = 1;
|
|
}
|
|
|
|
usbMsgPtr = (short unsigned int)dataBuffer;
|
|
return ret;
|
|
}
|
|
|
|
static void setup_tca(void)
|
|
{
|
|
PORTB_DIR |= PIN0_bm | PIN1_bm;
|
|
|
|
TCA0_SINGLE_CMP0 = 1000;
|
|
TCA0_SINGLE_CTRLA = TCA_SINGLE_ENABLE_bm; //enable TCA with /1 clock scaler
|
|
TCA0_SINGLE_CTRLB = 1 | TCA_SINGLE_CMP0EN_bm; //output on WO0
|
|
}
|
|
|
|
static void setup_tcb(void)
|
|
{
|
|
TCB0_CTRLA = TCB_ENABLE_bm;
|
|
}
|
|
|
|
static void setup_pit(void)
|
|
{
|
|
while(RTC_PITSTATUS & RTC_CTRLBUSY_bm);
|
|
RTC_PITINTCTRL = RTC_PI_bm; // enable pit isr
|
|
while(RTC_PITSTATUS & RTC_CTRLBUSY_bm);
|
|
RTC_PITCTRLA = RTC_PERIOD_CYC32768_gc | RTC_PITEN_bm; // 256hz
|
|
RTC_CNT = 0;
|
|
}
|
|
|
|
void setup_clock(void)
|
|
{
|
|
CPU_CCP = CCP_IOREG_gc; //unlock MCLKCTRLB
|
|
CLKCTRL_MCLKCTRLB = 0; //disable main clock divider
|
|
|
|
_PROTECTED_WRITE(CLKCTRL_OSC20MCALIBA, 42);
|
|
}
|
|
|
|
int main(void)
|
|
{
|
|
PORTA_DIR |= fanNumToPin(0) | fanNumToPin(1) | fanNumToPin(2) | fanNumToPin(3);
|
|
PORTC_DIR |= PIN2_bm | PIN3_bm;
|
|
|
|
_delay_ms(100);
|
|
|
|
setup_clock();
|
|
setup_tca();
|
|
setup_pit();
|
|
setup_tcb();
|
|
|
|
usbInit();
|
|
usbDeviceDisconnect();
|
|
|
|
PORTC_OUTSET = PIN2_bm;
|
|
|
|
usbDeviceConnect();
|
|
|
|
sei();
|
|
uint8_t pwmTimer = 0;
|
|
while(true)
|
|
{
|
|
usbPoll();
|
|
|
|
if(second-lastSeenSec > 60)
|
|
{
|
|
for(uint8_t i = 0; i < 4; ++i)
|
|
fanSpeeds[i] = 0x07;
|
|
}
|
|
|
|
if(TCB0_CNT > 100)
|
|
{
|
|
|
|
if(++pwmTimer > 0x0F)
|
|
{
|
|
for(uint8_t i = 0; i < 4; ++i)
|
|
{
|
|
if(fanSpeeds[i] > 0)
|
|
PORTA_OUTSET = fanNumToPin(i);
|
|
}
|
|
pwmTimer = 0;
|
|
}
|
|
|
|
for(uint8_t i = 0; i < 4; ++i)
|
|
{
|
|
if(fanSpeeds[i] < pwmTimer)
|
|
PORTA_OUTCLR = fanNumToPin(i);
|
|
}
|
|
|
|
TCB0_CNT = 0;
|
|
}
|
|
|
|
}
|
|
}
|
|
|