


; Utils_WaitNanoSecs  waittime_in_ns , cyles_already_used , waitcount_register 
;
;     cycles already used will be subtracted from the delay
;     the waittime resolution is 1 cycle (delay from exact to +1 cycle)
;     the maximum delay at 20MHz (50ns/clock) is 38350ns
;     waitcount register must specify an immediate register
; taken from https://www.mikrocontroller.net/articles/AVR_Assembler_Makros#Verz%C3%B6gerung_um_X_Nanosekunden
;
.set     Osc_Hz         = clock                    ; 1 MHz
.set     cycle_time_ns  = (1000000000 / Osc_Hz)      ; clock duration
.macro   Utils_WaitNanoSecs
  .set cycles = ((@0 + cycle_time_ns - 1) / cycle_time_ns - @1)
  .if (cycles > (255 * 3 + 2))
    .error "MACRO Utils_WaitNanoSecs - too many cycles to burn"
  .else
    .if (cycles > 6)
      .set  loop_cycles = (cycles / 3)      
      ldi   @2,loop_cycles
      dec   @2
      brne  pc-1
      .set  cycles = (cycles - (loop_cycles * 3))
    .endif
    .if (cycles > 0)
      .if   (cycles & 4)
        rjmp  pc+1
        rjmp  pc+1
      .endif
      .if   (cycles & 2)
        rjmp  pc+1
      .endif
      .if   (cycles & 1)
        nop
      .endif
    .endif
  .endif
.endmacro





; ***************************************************************************
; Utils_FillSram
;
; IN:
; - x: pointer to SRAM to fill
; - r16: value to fill the SRAM with
; - r17: size of area to fill
; OUT:
; - nothing
; MODIFIED REGISTERS: r17, x

Utils_FillSram:
  tst r17
  breq Utils_FillSram_end

Utils_FillSram_loop:
    st x+, r16
    dec r17
  brne Utils_FillSram_loop
Utils_FillSram_end:
  ret



; ***************************************************************************
; Increment a 32 bit counter at the address given by X.
; IN:
; - X: Address of the 4 byte counter (1. byte is LSB)
; OUT:
; - nothing
; MODIFIED REGISTERS: r18, r19, r20, r21, 22

Utils_IncrementCounter32:
  ld r18, x+
  ld r19, x+
  ld r20, x+
  ld r21, x
  clr r22
  inc r18
  adc r19, r22
  adc r20, r22
  adc r21, r22
  st x, r21
  st -x, r20
  st -x, r19
  st -x, r18
  ret




; ***************************************************************************
; Utils_ReadEeprom
;
; Read a byte from EEPROM (see example in ATtiny24/44/84 manual p.19).
;
; IN:
; - X: EEPROM Address to read from
; OUT:
; - R16: byte read
; MODIFIED REGISTERS: R16

Utils_ReadEeprom:
  sbic EECR, EEPE          ; wait for previous write to complete (if any)
    rjmp Utils_ReadEeprom
  out EEARH, xh            ; set EEPROM address
  out EEARL, xl
  sbi EECR, EERE           ; start EEPROM read by writing EERE
  in r16, EEDR             ; read data from data register
  ret



; ***************************************************************************
; Utils_WriteEeprom
;
; Write a byte to EEPROM (see example in ATtiny24/44/84 manual p.18).
;
; IN:
; - R16: byte to write
; - X: EEPROM Address to read from
; OUT:
; - nothing
; MODIFIED REGISTERS: R17

Utils_WriteEeprom:
  sbic EECR, EEPE          ; wait for previous write to complete (if any)
    rjmp Utils_WriteEeprom
  ldi r17, (0<<EEPM1) | (0<<EEPM0) ; set programming mode
  out EECR, r17
  out EEARH, xh                    ; set EEPROM address
  out EEARL, xl
  out EEDR,  r16                   ; write data to data register
  sbi EECR, EEMPE                  ; write logical one to EEMPE
  sbi EECR, EEPE                   ; start EEPROM write by setting EEPE
  ret






