#include #include #include #include #include #include #include #include #include #include #include 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; } } }