Path:AVR-EN => Applications => ATtiny24 stepper motor control => Source code
stepper_tn24 small Applications of
AVR Single chip controllers AT90S, ATtiny, ATmega and ATxmega
Stepper motor controller with an ATtiny24
Logo

Software for the stepper motor 28BYJ-48 control with an ATtiny24

Assembler source code (as asm source code here)

;
; ***************************************
; * Stepper motor control with ATtiny24 *
; * 16 bit position, Full/Half step     *
; * Version 1, March 2018, V1           *
; * (C)2018 by avr-asm-tutorial.net     *
; ***************************************
;
.nolist
.include "tn24adef.inc" ; Define device ATtiny24A
.list
;
; **********************************
;    M O D E - S E L E C T I O N
; **********************************
;
.equ Halfstep = 0 ; 1=Halb step, 0=Full step
;
; **********************************
;    D E B U G - S W I T C H E S
; **********************************
;
; Debug off: all switches to 0
;
; Test ADC value calculation
.equ TestAdc = 0 ; Test ADC channel number
  .equ TestChannel=2 ; Channel to simulate (0..2)
  .equ TestValue = 255*256
;
; Test motor driver output
.equ TestMotor = 0 ; Test motor driver
  .equ TestCurr = 32768 ; current position
  .equ TestNext = 32767 ; next position
;
;        H A R D W A R E
; **********************************
;
; Device: ATtiny24, Package: 14-pin-PDIP_SOIC
;               _________
;            1 /         |14
;      +Ub o--|VCC    GND|--o -Ub
;            2|          |13
; Duo AnRd o--|PB0   ADC0|--o Potentiometer CLOSE
;            3|          |12
; LED AnYe o--|PB1   ADC1|--o Potentiometer OPEN
;            4|          |11
;    RESET o--|RES   ADC2|--o Potentiometer Speed
;            5|          |10
;   Switch o--|PB2    PA3|--o LED Cathode Gn
;            6|          |9
;  ULN IN7 o--|PA7    PA4|--o ULN IN4
;            7|          |8
;  ULN IN6 o--|PA6    PA5|--o ULN IN5
;             |__________|
;
; **********************************
;  P O R T S   A N D   P I N S
; **********************************
; Duo-LED control
.equ pDuoO = PORTB ; Duo-LED output port
.equ pDuoD = DDRB ; Duo-LED direction port
.equ bDuoAR = PORTB0 ; Red anode portpin
.equ bDuoAY = PORTB1 ; Yellow anode portpin
; Switch control
.equ pSwO = PORTB ; Switch output port
.equ pSwD = DDRB ; Switch direction port
.equ pSwI = PINB ; Switch input port
.equ bSwO = PORTB2 ; Switch output portpin
.equ bSwD = DDB2 ; Switch direction portpin
.equ bSwI = PINB2 ; Switch input portpin
; OK-LED control
.equ pOkO = PORTA ; OK-LED output port
.equ pOkD = DDRA ; OK-LED direction port
.equ pOkI = PINA ; OK-LED input port
.equ bOkO = PORTA3 ; OK-LED output portpin
.equ bOkD = DDA3 ; OK-LED direction portpin
.equ bOkI = PINA3 ; OK-LED input portpin
; Stepper motor control
.equ pStpO = PORTA ; Stepper output port
.equ pStpD = DDRA ; Stepper direction port
.equ mStpD = 0xF0 ; Mask stepper direction
;
; **********************************
;   A D J U S T A B L E   C O N S T
; **********************************
;
; Clock frequency default (CLKDIV8 set)
.equ clock=1000000 ; Define clock frequency
;
; Degrees maximum angle (maximum gear):
.equ cAngleMax = 180 ; Degrees maximum angle
;
; Start speed, default until first measurement
;   is completed
.equ cSecOpenClose = 10 ; 10 seconds
;
; Time after last motor move until magnets off
;   Minimum: 1 (1 ms), Maximum: 6,710 (6,71 s)
.equ cMotOffms = 1000 ; Milli seconds until motor off
;
; **********************************
;  F I X  &  D E R I V.  C O N S T
; **********************************
;
; Motor with gear 1:64
; Stepps per round:
.equ cStepsRound = 64 * 64
; Medium position:
.equ cMiddle = 32768
; Steps per maximum angle:
.equ cStepsAngle = (cStepsRound*cAngleMax+180)/ 360
; Stepps per half maximum angle
; (from middle to max. up or down):
.equ cStepsUpDown = (cStepsAngle+1) / 2
;
; Calculation of CTC value for start speed
.equ cTC0Presc = 64 ; Prescaler TC0
; TC0Ticks in micro seconds:
.equ cTC0Tick = (1000000*cTC0Presc)/clock
; Duration in micro seconds for full opening/closing
;   over maximum angle
.equ cUsSwing = (1000000*cSecOpenClose)/cStepsAngle
; CTC value for 8 bit TC0
.equ cCTCDef = (cUsSwing+cTC0Tick/2)/cTC0Tick
;
; CTC value for 16 bit TC1 motor off
.equ cMotOff = (1000*cMotOffms+512)/1024-1
;
; **********************************
;          T I M I N G
; **********************************
;
; TC0 is stepper motor position control
;   runs in CTC mode with Compare A
;   clock               = 1,000,000 Hz
;   Vorteiler           =        64
;   Timer tick          =        64 us
; Full step mode:
;   Steps for 180 deg   =   1,024
;   Slow motion         =        16.78 s
;     Time per step     =    16,384 us
;     CTC ticks         =       256
;     Compare A value   =       255
;   Rapid motion        =         2.03 s
;     Time per step     =     1,984 us
;     CTC ticks         =        31
;     Compare A value   =        30
;     (Remark: limited to fastest motor movement)
;   Calculation of CTC from MSB ADC sum on ADC2:
;     Compare A = (ADC-MSB * 225)/256+30
; Half step mode:
;   Steps 180 degrees   =     2,048
;   Slow motion         =        17.7 s
;     Time per step     =    16,384 us
;     CTC ticks         =       135
;     Compare A value   =       134
;   Rapid motion        =         1.97 s
;     Time per step     =       960 us
;     CTC ticks         =        15
;     Compare A value   =        14
;   Calculation of CTC from MSB ADC sum on ADC2:
;     Compare A = (ADC-MSB * 241)/256+14
;
; TC1 is timing the motor off (magnets off)
;   runs in normal mode with Compare A
;   Clock               = 1,000,000 Hz
;   Prescaler           =     1,024
;   Timer tick          =     1,024 us
;   Maximum until OVF   =    65,536
;   Respective time     =         6.7 s
;   Adjusted to         =         1 s
;
; ADC measures potentionmeter 1, 2 and 3
;   Clock               = 1,000,000 Hz
;   ADC prescaler       =       128
;   ADC tick            =       128 us
;   Conversion clocks   =        14
;   Time per meassurem. =     1,792 us
;   64 measurements     =   114,688 us
;   Three channels      =   344,064 us
;   Cycles per second   =         2.9
;
; **********************************
;       R E G I S T E R S
; **********************************
;
; R0, R1, R2, used for multiplications etc.
; free: R4
; ADC value summing
.def rAdcL = R5 ; Sum ADC value, LSB
.def rAdcH = R6 ; dto., MSB
; Register values for stepper positioning
  .equ cStepSetS = 7 ; for Reading/Writing EEPROM
.def rMark1 = R7
.def rCloseL = R8
.def rCloseH = R9
.def rOpenL = R10
.def rOpenH = R11
.def rCurrValL = R12
.def rCurrValH = R13
.def rMark2 = R14
  .equ cStepSetE = 15 ; End of the data set
.def rSreg = R15 ; Save/Restore status port
.def rmp = R16 ; Define multipurpose register
.def rimp = R17 ; Multipurpose inside interrupts
.def rFlag = R18 ; Flags
  .equ bWrite = 0 ; Write data set to EEPROM
  .equ bAdc = 1 ; 64 AD conversions completed
.def rAdc = R19 ; ADC counter
.def rSetValL = R20 ; Current position stepper, LSB
.def rSetValH = R21 ; dto., MSB
; free: R22 to R25
; used: R27:R26 = X Pointer outside interrupts
; used: R29:R28 = Y Pointer for EEPROM write
; used: R31:R30 = Z Pointer multipurpose, for LPM
;
; **********************************
;           S R A M
; **********************************
;
.dseg
.org SRAM_START
; (Not used, only for stack)
;
; **********************************
;         C O D E
; **********************************
;
.cseg
.org 000000
;
; ***********************************
; R E S E T  &  I N T - V E C T O R S
; ***********************************
	rjmp Main ; Reset vector
	rjmp Int0Isr ; EXT_INT0, switch
	reti ; PCI0
	reti ; PCI1
	reti ; WATCHDOG
	reti ; ICP1
	rjmp OC1AIsr ; OC1A, motor time out
	reti ; OC1B
	reti ; OVF1
	rjmp OC0AIsr ; OC0A, motor movement
	reti ; OC0B
	reti ; OVF0
	reti ; ACI
	rjmp AdcIsr ; ADCC, Potentiometers
	rjmp EepIsr ; ERDY, EEPROM write
	reti ; USI_STR
	reti ; USI_OVF
;
; **********************************
;  I N T - S E R V I C E   R O U T .
; **********************************
;
; INT0 Interrupt Service Routine
;   Switch actions trigger INT0
;   on rising and falling edges
Int0Isr:
  set ; Update set value for motor
  reti
;
; OC0A Interrupt Service Routine
;   moves stepper if necessary
OC0AIsr:  in rSreg,SREG ; Save SREG
  cp rCurrValL,rSetValL ; LSB rCurr = rSet?
  brne OC0AIsr1 ; LSB differs
  cp rCurrValH,rSetValH
  breq OC0AIsr8 ; MSB equals, too, do nothing
  cp rCurrValL,rSetValL ; LSB compare again
OC0AIsr1:
  ; rCurr and rSet differ, Move motor
  cpc rCurrValH,rSetValH ; Test MSB
  brcs OC0AIsr4 ; rCurr smaller than rSet
  ; rCurr larger than rSet, move backwards
  tst rCurrValL ; Check LSB=0
  brne OC0AIsr2 ; LSB not zero
  dec rCurrValH ; Decrease MSB
OC0AIsr2:
  dec rCurrValL ; One step back
  sbi pDuoO,bDuoAY ; Yellow LED on
  cp rCurrValL,rSetValL ; Last step 
  breq OC0AIsr3 ; Yes, do not blink
  sbrc rCurrValL,3 ; Bit 3 for blink
  cbi pDuoO,bDuoAY ; Yellow LED off
OC0AIsr3:
  cbi pDuoO,bDuoAR ; Cathode yellow LED low
  rjmp OC0AIsr7 ; Adjust stepper position
  ; rCurr smaller than rSet
OC0AIsr4:
  inc rCurrValL ; One step forward
  brne OC0AIsr5 ; LSB not zero
  inc rCurrValH ; Increase MSB
OC0AIsr5:
  sbi pDuoO,bDuoAR ; Anode red LED on
  cp rCurrValL,rSetValL ; Last step?
  breq OC0AIsr6 ; Yes, do not blink
  sbrc rCurrValL,3 ; Bit 3 for blink
  cbi pDuoO,bDuoAR ; Red LED off
OC0AIsr6:
  cbi pDuoO,bDuoAY ; Cathode red LED low
OC0AIsr7:
  push ZH ; Save Z
  push ZL
  mov rimp,rCurrValL ; Copy current position
.if Halfstep == 1
  ldi ZH,High(2*StepTab8) ; Z to 8 step table
  ldi ZL,Low(2*StepTab8)
  andi rimp,0x07 ; Isolate the lowest three bit
  .else
  ldi ZH,High(2*StepTab4) ; Z to 4 step table
  ldi ZL,Low(2*StepTab4)
  andi rimp,0x03 ; Isolate the lowest two bit
  .endif
  add ZL,rimp ; Add to table address
  ldi rimp,0 ; Add carry
  adc ZH,rimp
  lpm rimp,Z ; Read table byte
  in ZL,pStpO ; Read current port outputs
  andi ZL,0x0F ; Save the lowest four bits
  or ZL,rimp ; Set motor and Ok output bits
  out pStpO,ZL ; To motor output, clear OK LED
  pop ZL ; Restore Z
  pop ZH
  clr rimp ; Restart motor off timer
  out TCNT1H,rimp
  out TCNT1L,rimp
OC0AIsr8:
  out SREG,rSreg ; Restore SREG
  reti
;
.if Halfstep == 1
  ; Step table half step mode
  StepTab8:
  .db 0x18,0x38,0x28,0x68,0x48,0xC8,0x88,0x98
  .else
  ; Step table full step mode
  StepTab4:
  .db 0x18,0x28,0x48,0x88
  .endif
;
; OC1A-ISR switches motor magnets off
;
OC1AIsr:
  in rSreg,SREG ; Save SREG
  sbic pOkO,bOkO ; Green LED already on? If not ...
  sbr rFlag,1<<bWrite ; Write data set to EEPROM
  in rimp,pStpO ; Read motor output port
  andi rimp,0x07 ; Save lower three bits
  out pStpO,rimp ; Motor off, green LED on
  cbi pDuoO,bDuoAR ; Red/Yellow LED off
  cbi pDuoO,bDuoAY
  out SREG,rSreg ; Restore SREG
  reti
;
; AD Conversion complete interrupt
AdcIsr:
  in rSreg,SREG ; SaVE status
  in rimp,ADCL ; Read LSB ADC result
  add rAdcL,rimp ; Add to sum
  in rimp,ADCH ; Read MSB ADC result
  adc rAdcH,rimp ; Add to sum with carry
  dec rAdc ; Count downwards
  brne AdcIsr1 ; Not yet 64 measurements
  sbr rFlag,1<<bAdc ; Set flag
  rjmp AdcIsr2 ; Do not start next
AdcIsr1:
  ; Start next measurement
  ldi rimp,(1<<ADEN)|(1<<ADSC)|(1<<ADIE)|(1<<ADPS2)|(1<<ADPS1)|(1<<ADPS0)
  out ADCSRA,rimp
AdcIsr2:
  out SREG,rSreg ; Restore status
  reti
;
; EEPROM Ready interrupt
EepIsr:
  in rSreg,SREG ; Save SREG
  in rimp,EEARL ; Read LSB address
  inc rimp ; Next address
  out EEARL,rimp ; To address port
  ld rimp,Y+ ; Read next byte from register
  out EEDR,rimp ; To data port
  sbi EECR, EEMPE ; Enable EEPROM write
  sbi EECR, EEPE ; Start EEPROM write
  cpi YL,cStepSetE ; Last byte?
  brcs EepIsr1 ; No, continue write
  cbi EECR,EERIE ; No more EEP-RDY interrupts
  cbr rFlag,1<<bWrite ; Clear write flag
EepIsr1:
  out SREG,rSreg ; Restore SREG
  reti
;
; **********************************
;  M A I N   P R O G R A M   I N I T
; **********************************
;
Main:
  ldi rmp,Low(RAMEND)
  out SPL,rmp ; Init LSB stack pointer
;
; Check debug switches
.if TestAdc == 1
  ; Test calculation from ADC values
  ldi rmp,High(TestValue)
  mov rAdcH,rmp
  ldi rmp,Low(TestValue)
  mov rAdcL,rmp
  ldi rmp,TestChannel
  out ADMUX,rmp
  rcall AdcFlag
  TestAdcLoop:
  rjmp TestAdcLoop
  .endif
.if TestMotor == 1 ; Test motor positioning
  ldi rmp,High(TestCurr) ; Current position
  mov rCurrValH,rmp
  ldi rmp,Low(TestCurr)
  mov rCurrValL,rmp
  ldi rmp,High(TestNext)
  mov rSetValH,rmp
  ldi rmp,Low(TestNext)
  mov rSetValL,rmp
  TestMotorLoop:
    rcall OC0AIsr
    rjmp TestMotorLoop
  .endif
  ;
  ; Re-adjust?
  cbi pOkD,bOkD ; Direction of green LED input
  sbi pOkO,bOkO ; Switch on pull-up resistor
  sbic pOkI,bOkI ; Pin low?
  rjmp LeseEeprom ; No, no re-adjust
  ; Re-adjust to middle position
  ldi rmp,High(32768)
  mov rSetValH,rmp
  mov rCurrValH,rmp
  mov rOpenH,rmp
  mov rCloseH,rmp
  ldi rmp,Low(32768)
  mov rSetValL,rmp
  mov rCurrValL,rmp
  mov rOpenL,rmp
  mov rCloseL,rmp
  sbr rFlag,1<<bWrite ; Set write flag EEPROM
WaitRestart:
  ldi ZH,High(14287) ; Wait for 100 ms
  ldi ZL,Low(14287)
WaitInactive:
  sbis pOkI,bOkI ; Skip next if pin  is high
  rjmp WaitRestart ; Pin is low, restart loop
  sbiw ZL,1 ; Count down
  brne WaitInactive ; Not yet 100 ms delay
  rjmp NoEpromRead ; Ready, do not read EEPROM
  ; Read EEPROM data set
LeseEeprom:
  rcall ReadEep ; Read the data set from EEPROM
NoEpromRead:
  ; Init Duo-LED
  sbi pDuoD,bDuoAR ; Direction red anode output
  sbi pDuoD,bDuoAY ; Direction yellow anode output
  cbi pDuoO,bDuoAR ; Red anode low
  cbi pDuoO,bDuoAY ; Yellow anode low
  ; Init green Ok LED
  sbi pOkD,bOkD ; Ok LED direction output
  sbi pOkO,bOkO ; Ok LED off
  ; Init switch
  cbi pSwD,bSwD ; Direction of switch to input
  sbi pSwO,bSwO ; Switch input pull-Up resistor on
  ; Init AD converter
  clr rmp ; Start with channel 0 beginnen, URef=5V
  out ADMUX,rmp
  ldi rAdc,64 ; 64 measurements
  ldi rmp,(1<<ADEN)|(1<<ADSC)|(1<<ADIE)|(1<<ADPS2)|(1<<ADPS1)|(1<<ADPS0)
  out ADCSRA,rmp ; Start first conversion and interrupts
  ; Init stepper motor
  in rmp,pStpO ; Read output on port
  andi rmp,0x0F ; Save lower four bits, upper nibble=0
  out pStpO,rmp ; To output port motor
  in rmp,pStpD ; Read direction port
  ori rmp,mStpD ; OR with motor direction mask
  out pStpD,rmp ; To direction port as output
  ; Init TC1 as motor magnet off timer
  ldi rmp,High(cMotOff) ; Time until motor off
  out OCR1AH,rmp ; to OCR1A
  ldi rmp,Low(cMotOff)
  out OCR1AL,rmp
  clr rmp ; TC1 normal mode
  out TCCR1A,rmp
  ldi rmp,(1<<CS12)|(1<<CS10) ; Prescaler=1024
  out TCCR1B,rmp
  ldi rmp,1<<OCIE1A ; Compare Match A Interrupt
  out TIMSK1,rmp
  ; Init TC0 as stepper motor control
  ldi rmp,cCtcDef ; Lowest start speed
  out OCR0A,rmp ; Set CTC value
  ldi rmp,1<<WGM01 ; No OC output, WGM01 for CTC
  out TCCR0A,rmp
  ldi rmp,(1<<CS01)|(1<<CS00) ; CTC, Presc=64
  out TCCR0B,rmp
  ldi rmp,1<<OCIE0A ; Compare Match A Interrupt
  out TIMSK0,rmp
  ; Sleep, external ints and int enable
  ldi rmp,(1<<ISC00)|(1<<SE) ; External INT0, sleep mode idle
  out MCUCR,rmp
  ldi rmp,1<<INT0 ; External INT0 enable
  out GIMSK,rmp
  sei ; Enable interrupts
;
; **********************************
;    P R O G R A M   L O O P
; **********************************
;
Loop:
  sleep
  nop
  sbrc rFlag,bAdc
  rcall AdcFlag ; Convert ADC value
  sbrc rFlag,bWrite
  rcall WriteEep ; Start EEPROM write
  brtc Loop ; No update of set value
  clt ; Clear set value update flag
  sbis pSwI,bSwI ; Skip next if switch open
  rjmp SetOpen ; Switch is open
  cli ; Disable interrupts
  mov rSetValL,rCloseL ; Set value = rClose
  mov rSetValH,rCloseH
  sei ; Enable interrupts
  rjmp Loop
SetOpen:
  cli ; Disable interrupts
  mov rSetValL,rOpenL ; Set value = rOpen
  mov rSetValH,rOpenH
  sei ; Enable interrupt
  rjmp loop
;
; ADC flag set, 64 measurements complete
AdcFlag:
  cbr rFlag,1<<bAdc ; Clear flag
  in rmp,ADMUX ; Read current channel from MUX
  cpi rmp,1 ; Channel = ADC1?
  breq AdcFlag1 ; Yes
  brcs AdcFlag0 ; Channel = ADC0
  rjmp AdcFlag2 ; Channel = ADC2
AdcFlag0:
  ; ADC0 was measured
  ; Invert ADC value and multiply by 2
  mov R0,rAdcH ; Copy MSB ADC result to LSB
  com R0 ; Invert result
  clr R1 ; Clear MSB
  rol rAdcL ; Shift upper bit of LSB result to carry
  rol R0 ; Rotate into LSB
  rol R1 ; And into MSB
.if HalfStep == 1
  ; Half step mode, multiply by 2 again
  lsl R0 ; Rotate LSB left
  rol R1 ; Rotate into MSB
  .endif
  ; Subtract result from 32.768
  ldi ZH,High(32768)
  ldi ZL,Low(32768)
  sub ZL,R0
  sbc ZH,R1
  mov rOpenH,ZH ; Copy value to rOpen
  mov rOpenL,ZL
  ldi rmp,1 ; Continue measurements on channel 1
  out ADMUX,rmp
  set ; Set T flag for updating set value
  rjmp AdcFlag9
AdcFlag1:
  ; Channel 1 was measured
  mov R0,rAdcH ; MSB ADC result to LSB
  com R0 ; Invert result
  clr R1 ; Clear upper bits
  rol rAdcL ; Shift upper bit of LSB result to carry
  rol R0 ; Rotate into LSB
  rol R1 ; And into MSB
.if Halfstep == 1
  ; Half step mode, multiply by 2 again
  lsl R0 ; Left shift LSB
  rol R1 ; Rotate into MSB
  .endif
  ; Add value to 32.768
  ldi ZH,High(32768)
  ldi ZL,Low(32768)
  add ZL,R0
  adc ZH,R1
  mov rCloseH,ZH ; Copy result to rClose
  mov rCloseL,ZL
  ldi rmp,2 ; Continue with channel 2
  out ADMUX,rmp
  set ; Set T flag for updating set value
  rjmp AdcFlag9
AdcFlag2:
  ; Channel 2 was measured
.if Halfstep == 1
  ldi rmp,120 ; Multiplicator for half step
  ldi ZH,14 ; Minimum CTC value
  .else
  ldi rmp,225 ; Multiplicator for full step
  ldi ZH,30 ; Minimum CTC value
  .endif
  clr ZL ; Clear LSB result
  mov R0,rAdcH ; Copy MSB ADC result to LSB
  clr R1 ; Clear R1 as MSB
AdcFlag21:
  lsr rmp ; Multiplicator right shift into carry
  brcc AdcFlag22 ; Zero, do not add
  add ZL,R0 ; One, add multiplicator
  adc ZH,R1
AdcFlag22:
  ; Multiply multiplicator by two
  lsl R0
  rol R1
  tst rmp ; All ones multiplied?
  brne AdcFlag21 ; No, continue
  out OCR0A,ZH ; Write MSB result to Compare A
  ldi rmp,0 ; Continue with channel 0
  out ADMUX,rmp
AdcFlag9:
  clr rAdcH ; Clear sum
  clr rAdcL
  ldi rAdc,64 ; Restart 64 measurements
  ldi rmp,(1<<ADEN)|(1<<ADSC)|(1<<ADIE)|(1<<ADPS2)|(1<<ADPS1)|(1<<ADPS0)
  out ADCSRA,rmp ; Start first measurement
  ret
;
; *************************************
;    E E P R O M - C O N T R O L
; *************************************
;
; Write current data set in registers to EEPROM
;
WriteEep:
  sbic EECR, EEPE ; Wait until EEPROM is ready
  rjmp WriteEep ; Not yet ready
  cbr rFlag,1<<bWrite ; Clear write flag
  ldi ZH,High(EepAdrs) ; Z to EEPROM start address
  ldi ZL,Low(EepAdrs)
  ldi YH,High(cStepSetS) ; Point Y to first register
  ldi YL,Low(cStepSetS)
  out EEARH,ZH ; Z to EEPROM address port
  out EEARL,ZL
  ld rmp,Y+ ; Read first byte
  out EEDR,rmp ; Write to EEPROM data port
  cli ; Disable interrupts
  sbi EECR, EEMPE ; Enable EEPROM write
  sbi EECR, EEPE ; Start EEPROM write
  sei ; Re-enable interrupts
  sbi EECR,EERIE ; Enable EEP RDY interrupts
  ret
;
; Read EEPROM values to registers
ReadEep:
  ldi ZH,High(EepAdrs) ; Z to EEPROM address
  ldi ZL,Low(EepAdrs)
  ldi XH,High(cStepSetS) ; X to register address
  ldi XL,Low(cStepSetS)
  ldi rmp,cStepSetE-cStepSetS ; Number of bytes
  mov R0,rmp ; to R0
ReadEep1:
  sbic EECR, EEPE ; Wait until EEPROM ready
  rjmp ReadEep1 ; Not yet ready
ReadEep2:
  out EEARH,ZH ; Set Read address EEPROM
  out EEARL,ZL
  sbi EECR, EERE ; Read enable EEPROM
  in rmp, EEDR ; Read byte from EEPROM
  st X+,rmp ; And store in register
  adiw ZL,1 ; Next address
  dec R0 ; All bytes read?
  brne ReadEep2 ; No, continue
  mov rmp,rMark1 ; Check mark bytes
  eor rmp,rMark2 ; Exclusive-OR
  cpi rmp,0xFF ; Correct?
  breq ReadEep3 ; Yes, correct marks
  ; Incorrect marks, ignore EEPROM data
  ldi rmp,High(32768) ; Set default
  mov rOpenH,rmp ; To middle position
  mov rCloseH,rmp
  mov rCurrValH,rmp
  clr rOpenL
  clr rCloseL
  clr rCurrValL
ReadEep3:
  ret
;
; EEPROM content default
;
.eseg
.org 0x0010 ; EEPROM segment from 0x10
EepAdrs:
; Default values: Mark1 (0xAA), Close value, Open value, SET value,
;   Mark2 (0x55)
.db 0xAA ; Mark 1
.dw 32768 ; Close
.dw 32768 ; Open
.dw 32768 ; Set value
.db 0x55 ; Mark 2
;
; End of source code
;



Praise, error reports, scolding and spam please via the comment page to me. Spammers: please note that behind this is not a dump standard script but I personally select the entries to be published.

©2018 by http://www.avr-asm-tutorial.net