390 lines
9.1 KiB
NASM
390 lines
9.1 KiB
NASM
; ***************************************************************************
|
|
; copyright : (C) 2026 by Martin Preuss
|
|
; email : martin@libchipcard.de
|
|
;
|
|
; ***************************************************************************
|
|
; * This file is part of the project "AqHome". *
|
|
; * Please see toplevel file COPYING of that project for license details. *
|
|
; ***************************************************************************
|
|
|
|
#ifndef AQH_AVR_MODULES_MULTIFAN_MAIN_ASM
|
|
#define AQH_AVR_MODULES_MULTIFAN_MAIN_ASM
|
|
|
|
|
|
|
|
; ***************************************************************************
|
|
; defs
|
|
|
|
|
|
.equ MULTIFAN_FAN_OFFS_COUNTER_LO = 0
|
|
.equ MULTIFAN_FAN_OFFS_COUNTER_HI = 1
|
|
.equ MULTIFAN_FAN_OFFS_CURR_FREQUENCY_LO = 2
|
|
.equ MULTIFAN_FAN_OFFS_CURR_FREQUENCY_HI = 3
|
|
.equ MULTIFAN_FAN_OFFS_DUTYCYCLE = 4 ; 0-99 (*40/100=PWM value)
|
|
.equ MULTIFAN_FAN_SIZE = 5
|
|
|
|
|
|
|
|
; ***************************************************************************
|
|
; data
|
|
|
|
.dseg
|
|
|
|
multiFanDataBegin:
|
|
multiFanPrevPortVal: .byte 1
|
|
multiFanObjects: .byte (MULTIFAN_FANS*MULTIFAN_FAN_SIZE)
|
|
multiFanDataEnd:
|
|
|
|
|
|
|
|
; ***************************************************************************
|
|
; code
|
|
|
|
.cseg
|
|
|
|
|
|
MultiFan_Init:
|
|
ldi xl, LOW(multiFanDataBegin)
|
|
ldi xh, HIGH(multiFanDataBegin)
|
|
ldi r17, (multiFanDataEnd-multiFanDataBegin)
|
|
clr r16
|
|
bigcall Utils_FillSram
|
|
|
|
ldi r16, 0xff
|
|
sts multiFanPrevPortVal, r16
|
|
|
|
rcall multiFanSetupTimer
|
|
rcall multiFanSetupPins
|
|
|
|
.ifdef MULTIFAN_SETUPIRQ_FN
|
|
bigcall MULTIFAN_SETUPIRQ_FN
|
|
.endif
|
|
|
|
sec
|
|
ret
|
|
; @end
|
|
|
|
|
|
|
|
; ---------------------------------------------------------------------------
|
|
; @routine MultiFan_OnEverySecond @global
|
|
;
|
|
; @clobbers r16, r17, r18, r19, r24, Y
|
|
|
|
MultiFan_OnEverySecond:
|
|
ldi yl, LOW(multiFanObjects)
|
|
ldi yh, HIGH(multiFanObjects)
|
|
ldi r24, MULTIFAN_FANS
|
|
push r15
|
|
inr r15, SREG
|
|
MultiFan_OnEverySecond_loop:
|
|
cli
|
|
ldd r16, Y+MULTIFAN_FAN_OFFS_COUNTER_LO
|
|
ldd r17, Y+MULTIFAN_FAN_OFFS_COUNTER_HI
|
|
; clear counter for next round
|
|
clr r18
|
|
std Y+MULTIFAN_FAN_OFFS_COUNTER_LO, r18
|
|
std Y+MULTIFAN_FAN_OFFS_COUNTER_HI, r18
|
|
outr SREG, r15 ; restore IRQ flag
|
|
|
|
; counter*30=RPM
|
|
mov r18, r16
|
|
mov r19, r17
|
|
lsl r16 ; x2
|
|
rol r17
|
|
add r16, r18 ; x3
|
|
adc r17, r19
|
|
lsl r16 ; x6
|
|
rol r17
|
|
add r16, r18 ; x7
|
|
adc r17, r19
|
|
lsl r16 ; x14
|
|
rol r17
|
|
add r16, r18 ; x15
|
|
adc r17, r19
|
|
lsl r16 ; x30
|
|
rol r17
|
|
|
|
std Y+MULTIFAN_FAN_OFFS_CURR_FREQUENCY_LO, r16
|
|
std Y+MULTIFAN_FAN_OFFS_CURR_FREQUENCY_HI, r17
|
|
|
|
adiw yh:yl, MULTIFAN_FAN_SIZE
|
|
dec r24
|
|
brne MultiFan_OnEverySecond_loop
|
|
|
|
pop r15
|
|
ret
|
|
; @end
|
|
|
|
|
|
|
|
; ---------------------------------------------------------------------------
|
|
; @routine MultiFan_CheckPort @global
|
|
;
|
|
; @param r16 new port value (e.g. PINB)
|
|
; @param r18 port change value (0 in a bit pos means: bit flipped to 0)
|
|
; @clobbers r24, r25, Y
|
|
|
|
MultiFan_CheckPort:
|
|
ldi yl, LOW(multiFanObjects)
|
|
ldi yh, HIGH(multiFanObjects)
|
|
|
|
sbrs r18, MULTIFAN_TACHO1_PIN
|
|
rcall multiFanIncCounter ; (r24, r25)
|
|
|
|
.if MULTIFAN_FANS >1
|
|
adiw yh:yl, MULTIFAN_FAN_SIZE
|
|
sbrs r18, MULTIFAN_TACHO2_PIN
|
|
rcall multiFanIncCounter ; (r24, r25)
|
|
.endif
|
|
|
|
.if MULTIFAN_FANS >2
|
|
adiw yh:yl, MULTIFAN_FAN_SIZE
|
|
sbrs r18, MULTIFAN_TACHO3_PIN
|
|
rcall multiFanIncCounter
|
|
.endif
|
|
|
|
ret
|
|
; @end
|
|
|
|
|
|
|
|
MultiFan_SetFan1Duty:
|
|
ldi yl, LOW(multiFanObjects)
|
|
ldi yh, HIGH(multiFanObjects)
|
|
std Y+MULTIFAN_FAN_OFFS_DUTYCYCLE, r16
|
|
|
|
rcall multiFanCalcTimerValue ; r17:r16=timer value
|
|
; set OC register
|
|
outr TC1H, r17
|
|
outr OCR1A, r16
|
|
ret
|
|
; @end
|
|
|
|
|
|
|
|
.if MULTIFAN_FANS > 1
|
|
MultiFan_SetFan2Duty:
|
|
ldi yl, LOW(multiFanObjects+MULTIFAN_FAN_SIZE)
|
|
ldi yh, HIGH(multiFanObjects+MULTIFAN_FAN_SIZE)
|
|
std Y+MULTIFAN_FAN_OFFS_DUTYCYCLE, r16
|
|
|
|
rcall multiFanCalcTimerValue ; r17:r16=timer value
|
|
; set OC register
|
|
outr TC1H, r17
|
|
outr OCR1B, r16
|
|
ret
|
|
; @end
|
|
.endif
|
|
|
|
|
|
|
|
.if MULTIFAN_FANS > 2
|
|
MultiFan_SetFan3Duty:
|
|
ldi yl, LOW(multiFanObjects+(MULTIFAN_FAN_SIZE*2))
|
|
ldi yh, HIGH(multiFanObjects+(MULTIFAN_FAN_SIZE*2))
|
|
std Y+MULTIFAN_FAN_OFFS_DUTYCYCLE, r16
|
|
|
|
rcall multiFanCalcTimerValue ; r17:r16=timer value
|
|
; set OC register
|
|
outr TC1H, r17
|
|
outr OCR1D, r16
|
|
ret
|
|
; @end
|
|
.endif
|
|
|
|
|
|
; ---------------------------------------------------------------------------
|
|
; @routine multiFanCalcTimerValue
|
|
;
|
|
; @param r16 duty value (0-99)
|
|
; @return r17:r16 timer value
|
|
; @clobbers r16, r17, r18, r19, r20, r21, r25
|
|
|
|
multiFanCalcTimerValue:
|
|
; x40
|
|
clr r17
|
|
mov r18, r16
|
|
mov r19, r17
|
|
lsl r16 ; x2
|
|
rol r17
|
|
lsl r16 ; x4
|
|
rol r17
|
|
add r16, r18 ; x5
|
|
adc r17, r19
|
|
lsl r16 ; x10
|
|
rol r17
|
|
lsl r16 ; x20
|
|
rol r17
|
|
lsl r16 ; x40
|
|
rol r17
|
|
; /100
|
|
mov r20, r16
|
|
mov r21, r17
|
|
ldi r22, 100
|
|
clr r23
|
|
bigjmp Utils_Divu16_16_16 ; r17:r16=result
|
|
; @end
|
|
|
|
|
|
|
|
|
|
; ---------------------------------------------------------------------------
|
|
; @routine multiFanIncCounter
|
|
;
|
|
; @param Y pointer to FAN object
|
|
; @clobbers r24, r25
|
|
|
|
multiFanIncCounter:
|
|
ldd r24, Y+MULTIFAN_FAN_OFFS_COUNTER_LO
|
|
ldd r25, Y+MULTIFAN_FAN_OFFS_COUNTER_HI
|
|
adiw r25:r24, 1
|
|
std Y+MULTIFAN_FAN_OFFS_COUNTER_LO, r24
|
|
std Y+MULTIFAN_FAN_OFFS_COUNTER_HI, r25
|
|
ret
|
|
; @end
|
|
|
|
|
|
|
|
; ---------------------------------------------------------------------------
|
|
; @routine multiFanSetupPins
|
|
;
|
|
; @clobbers r16
|
|
|
|
multiFanSetupPins:
|
|
; set pins for PWM to output
|
|
inr r16, MULTIFAN_PWM_DDR
|
|
.if MULTIFAN_FANS == 1
|
|
ori r16, (1<<MULTIFAN_PWM1_PIN) | (0<<MULTIFAN_PWM2_PIN) | (0<<MULTIFAN_PWM3_PIN)
|
|
.elif MULTIFAN_FANS == 2
|
|
ori r16, (1<<MULTIFAN_PWM1_PIN) | (1<<MULTIFAN_PWM2_PIN) | (0<<MULTIFAN_PWM3_PIN)
|
|
.elif MULTIFAN_FANS == 3
|
|
ori r16, (1<<MULTIFAN_PWM1_PIN) | (1<<MULTIFAN_PWM2_PIN) | (1<<MULTIFAN_PWM3_PIN)
|
|
.else
|
|
.error "Invalid number of fans (only 1-3 allowed)
|
|
.endif
|
|
outr MULTIFAN_PWM_DDR, r16
|
|
|
|
; set pins for Tacho to input
|
|
inr r16, MULTIFAN_TACHO_DDR
|
|
.if MULTIFAN_FANS == 1
|
|
cbr r16, (1<<MULTIFAN_TACHO1_PIN) | (0<<MULTIFAN_TACHO2_PIN) | (0<<MULTIFAN_TACHO3_PIN)
|
|
.elif MULTIFAN_FANS == 2
|
|
cbr r16, (1<<MULTIFAN_TACHO1_PIN) | (1<<MULTIFAN_TACHO2_PIN) | (0<<MULTIFAN_TACHO3_PIN)
|
|
.elif MULTIFAN_FANS == 3
|
|
cbr r16, (1<<MULTIFAN_TACHO1_PIN) | (1<<MULTIFAN_TACHO2_PIN) | (1<<MULTIFAN_TACHO3_PIN)
|
|
.else
|
|
.error "Invalid number of fans (only 1-3 allowed)
|
|
.endif
|
|
outr MULTIFAN_PWM_DDR, r16
|
|
|
|
ret
|
|
; @end
|
|
|
|
|
|
|
|
; ---------------------------------------------------------------------------
|
|
; @routine multiFanSetupTimer
|
|
;
|
|
; @clobbers r16, r17
|
|
|
|
multiFanSetupTimer:
|
|
.if clock == 1000000
|
|
; prescaler 1
|
|
ldi r16, (0<<PSR1)|(0<<DTPS11)|(0<<DTPS10) | (0<<CS13)|(0<<CS12)|(0<<CS11)|(1<<CS10)
|
|
.elif clock == 8000000
|
|
; prescaler 8
|
|
ldi r16, (0<<PSR1)|(0<<DTPS11)|(0<<DTPS10) | (0<<CS13)|(1<<CS12)|(0<<CS11)|(0<<CS10)
|
|
.else
|
|
.error "Unhandled clock"
|
|
.endif
|
|
outr TCCR1B, r16
|
|
; select fast PWM, enable PIN output (don't activate negated pin outputs)
|
|
.if MULTIFAN_FANS == 1
|
|
ldi r16, (1<<COM1A1)|(0<<COM1A0) | (0<<COM1B1)|(0<<COM1B0) | (1<<PWM1A) | (0<<PWM1B)
|
|
outr TCCR1A, r16
|
|
ldi r16, (1<<COM1A1S)|(0<<COM1A0S) | (1<<COM1B1S)|(0<<COM1B0S) | (0<<PWM1D)
|
|
outr TCCR1C, r16
|
|
ldi r16, (0<<FPIE1)|(0<<FPEN1)|(0<<FPNC1)|(0<<FPES1)(0<<FPAC1)|(0<<FPF1) | (0<<WGM11)|(0<<WGM10)
|
|
outr TCCR1D, r16
|
|
.elif MULTIFAN_FANS == 2
|
|
ldi r16, (1<<COM1A1)|(0<<COM1A0) | (1<<COM1B1)|(0<<COM1B0) | (1<<PWM1A) | (1<<PWM1B)
|
|
outr TCCR1A, r16
|
|
ldi r16, (1<<COM1A1S)|(0<<COM1A0S) | (1<<COM1B1S)|(0<<COM1B0S) | (0<<COM1D1)|(0<<COM1D0) | (0<<PWM1D)
|
|
outr TCCR1C, r16
|
|
ldi r16, (0<<FPIE1)|(0<<FPEN1)|(0<<FPNC1)|(0<<FPES1)(0<<FPAC1)|(0<<FPF1) | (0<<WGM11)|(0<<WGM10)
|
|
outr TCCR1D, r16
|
|
.elif MULTIFAN_FANS == 3
|
|
ldi r16, (1<<COM1A1) |(0<<COM1A0) | (1<<COM1B1) |(0<<COM1B0) | (1<<PWM1A) | (1<<PWM1B)
|
|
outr TCCR1A, r16
|
|
ldi r16, (1<<COM1A1S)|(0<<COM1A0S) | (1<<COM1B1S)|(0<<COM1B0S) | (1<<COM1D1)|(0<<COM1D0) | (1<<PWM1D)
|
|
outr TCCR1C, r16
|
|
ldi r16, (0<<FPIE1)|(0<<FPEN1)|(0<<FPNC1)|(0<<FPES1)|(0<<FPAC1)|(0<<FPF1) | (0<<WGM11)|(0<<WGM10)
|
|
outr TCCR1D, r16
|
|
.else
|
|
.error "Invalid number of fans (only 1-3 allowed)
|
|
.endif
|
|
; 1MHz/40: 25kHz
|
|
clr r17
|
|
ldi r16, 40-1
|
|
outr TC1H, r17
|
|
outr OCR1C, r16
|
|
; preset fans to 50 %
|
|
ldi r16, 20
|
|
outr TC1H, r17
|
|
outr OCR1A, r16
|
|
.if MULTIFAN_FANS > 1
|
|
outr TC1H, r17
|
|
outr OCR1B, r16
|
|
.endif
|
|
.if MULTIFAN_FANS > 2
|
|
outr TC1H, r17
|
|
outr OCR1D, r16
|
|
.endif
|
|
|
|
ret
|
|
; @end
|
|
|
|
|
|
|
|
; ---------------------------------------------------------------------------
|
|
; @routine multiFanPinChangeIsr @global @isr
|
|
;
|
|
|
|
multiFanPinChangeIsr:
|
|
push r15
|
|
in r15, SREG
|
|
push r16
|
|
in r16, MULTIFAN_TACHO_INPUT
|
|
push r18
|
|
lds r18, multiFanPrevPortVal
|
|
sts multiFanPrevPortVal, r16
|
|
eor r18, r16 ; r18: changes in bits=1
|
|
com r18 ; r18: changes in bits=0
|
|
or r18, r16 ; r18: 0=bit flipped to 0
|
|
|
|
push r24
|
|
push r25
|
|
push yl
|
|
push yh
|
|
rcall MultiFan_CheckPort ; (r24, r25, Y)
|
|
pop yh
|
|
pop yl
|
|
pop r25
|
|
pop r24
|
|
pop r18
|
|
pop r16
|
|
out SREG, r15
|
|
pop r15
|
|
reti
|
|
; @end
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#endif
|