; ***************************************************************************
; copyright   : (C) 2025 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_ILI9341_MAIN_ASM
#define AQH_AVR_ILI9341_MAIN_ASM



; generally we use the following parameters here:
; @param r1:r0   background color
; @param r3:r2   foreground color
; @param r5:r4   X0
; @param r7:r6   Y0
; @param r9:r8   X1/W
; @param r11:r10 Y1/H
; @param r13:r12 source data width in bytes (for bit blit, i.e. byte offset from
;                one source data line to the next)


; ***************************************************************************
; data

.dseg

;ILI9341_buffer:          .byte 128


; ***************************************************************************
; code

.cseg



; ---------------------------------------------------------------------------
; @routine ILI9341_Init @global

ILI9341_Init:
  rcall ILI9341IoInit
  rcall ILI9341_Reset
  rcall ILI9341_LeaveSleepMode
  
  ldi r16, 0x20
  rcall Display_SetBacklight

  sec
  ret
; @end



; ---------------------------------------------------------------------------
; @routine ILI9341_Fini @global

ILI9341_Fini:
  ret
; @end



; ---------------------------------------------------------------------------
; @routine ili9341_SendCommands
;
; @clobbers r16

; Z=byte pointer to command list (as for LPM)

ili9341SendCommands:
  rcall ili9341BeginSpi                     ; (R16, R17)
ili9341SendCommands_loop1:
    lpm r16, Z+                             ; read command
    lpm r18, Z+                             ; read number of args
    cpi r18, 0xff                           ; end?
    breq ili9341SendCommands_end
    rcall ili9341SendCommand
    mov r19, r18
    andi r19, 1                             ; if 1: need to skip filler byte
    tst r18
    breq ili9341SendCommands_loop1          ; no args, next command
ili9341SendCommands_loop2:
      lpm r16, Z+
      rcall ili9341SendData                 ; (R16)
      dec r18
    brne ili9341SendCommands_loop2
    add zl, r19                             ; possibly skip filler byte
    adc zh, r19
    sub zh, r19
  rjmp ili9341SendCommands_loop1
ili9341SendCommands_end:
  rcall ili9341EndSpi                       ; (R16)
  ret
; @end



; ---------------------------------------------------------------------------
; @routine ILI9341_Reset @global

; @clobbers (R22)

ILI9341_Reset:
  cbi ILI9341_RESET_OUTPUT, ILI9341_RESET_PIN
  ldi r16, 100
  rcall Utils_WaitForMilliSecs
  sbi ILI9341_RESET_OUTPUT, ILI9341_RESET_PIN
  ldi r16, 50
  rcall Utils_WaitForMilliSecs
  
  ldi zl, LOW(ili9341InitCommands*2)
  ldi zh, HIGH(ili9341InitCommands*2)
  rcall ili9341SendCommands

  ldi r16, 120
  rcall Utils_WaitForMilliSecs
  
  rcall ili9341BeginSpi
  ldi r16, 0x29                 ; display on
  rcall ili9341SendCommand
  rcall ili9341EndSpi

  ldi r16, 120
  rcall Utils_WaitForMilliSecs
  
  ret
; @end



; ---------------------------------------------------------------------------
; @routine Display_SetBacklight @global
;
; @param r16 0=off, on otherwise
; @clobbers r16, r17

Display_SetBacklight:
  tst r16
  brne Display_SetBacklight_on
  cbi ILI9341_LED_OUTPUT, ILI9341_LED_PIN
  ret
Display_SetBacklight_on:
  sbi ILI9341_LED_OUTPUT, ILI9341_LED_PIN
ret ; DEBUG

  push r16
    rcall ili9341BeginSpi
    
    ldi r16, ILI9341_CMD_WRITECTLDISPLAY
    rcall ili9341SendCommand
    ; BCTRL=1, DD=1, BL=1   (or: 0x24 reported to work)
    ldi r16, (1<<5) | (1<<3) | (1<<2)
    rcall ili9341SendData

    ldi r16, ILI9341_CMD_SETDSPBRIGHTNESS
    rcall ili9341SendCommand
  pop r16
  rcall ili9341SendData

;  ldi r16, 0xbe
;  rcall ili9341SendCommand
;  ldi r16, 0x0f
;  rcall ili9341SendData

  rcall ili9341EndSpi
  
  ret
; @end




ILI9341_LeaveSleepMode:
  rcall ili9341BeginSpi
  ldi r16, 0x11 ; sleep out
  rcall ili9341SendCommand
  rcall ili9341EndSpi
  ldi r16, 120
  rcall Utils_WaitForMilliSecs

  rcall ili9341BeginSpi
  ldi r16, 0x38 ; idle mode off
  rcall ili9341SendCommand
  rcall ili9341EndSpi

  rcall ili9341BeginSpi
  ldi r16, 0x13 ; normal mode on
  rcall ili9341SendCommand
  rcall ili9341EndSpi
  
  ret
; @end



ili9341InitCommands:
#if 1
; display off
  .db 0x28, 0
; PowerCtlA
  .db 0xcb, 5, 0x39, 0x2C, 0x00, 0x34, 0x02, 0x00
; PowerCtlB
  .db 0xcf, 3, 0x00, 0xC1, 0x30, 0x00
; DriverTimingCtlA
  .db 0xe8, 3, 0x85, 0x00, 0x78, 0x00
; DriverTimingCtlB
  .db 0xea, 2, 0x00, 0x00
; _PowerSeqCtl
  .db 0xed, 4, 0x64, 0x03, 0x12, 0x81
; PumpRatioCtl
  .db 0xf7, 1, 0x20, 0x00
; PowerCtl1
  .db 0xc0, 1, 0x23, 0x00                    ; lookup!
; PowerCtl2
  .db 0xc1, 1, 0x10, 0x00                    ; lookup!
; VomCtl1
  .db 0xc5, 2, 0x3e, 0x28                    ; lookup!
; VomCtl2
  .db 0xc7, 1, 0x86, 0x00                    ; lookup!
; ColMod
  .db 0x3A, 1, 0x55, 0x00                    ; DPI=16bits/pixel, DBI=16bits/pixel
; FrameRateCtl
  .db 0xb1, 2, 0x00, ILI9341_FRAMERATE_79_HZ
; DspFnCtl
  .db 0xb6, 3, 0x08, 0x82, 0x27, 0x00
; GammaCurve
  .db 0x26, 1, 0x01, 0x00
; PosGamma
  .db 0xe0, 15
  .db 0x0F, 0x31, 0x2B, 0x0C, 0x0E, 0x08, 0x4E, 0xF1
  .db 0x37, 0x07, 0x10, 0x03, 0x0E, 0x09, 0x00, 0x00
; NegGamma
  .db 0xe1, 15
  .db 0x00, 0x0E, 0x14, 0x03, 0x11, 0x07, 0x31, 0xC1
  .db 0x48, 0x08, 0x0F, 0x0C, 0x31, 0x36, 0x0F, 0x00
; memory access control    (use ILI9341_MADCTL_MV to flip X/Y)
;                MMMMBM
;                YXVLGH00
  .db 0x36, 1, 0b11101000, 0x00
; normal mode on
;  .db 0x13, 0

; end
  .db 0xff, 0xff

#else
  .db 0xef, 3,  0x03, 0x80, 0x02, 0x00
  .db 0xcf, 3,  0x00, 0xc1, 0x30, 0x00
  .db 0xed, 4,  0x64, 0x03, 0x12, 0x81
  .db 0xe8, 3,  0x85, 0x00, 0x78, 0x00
  .db 0xcb, 5,  0x39, 0x2c, 0x00, 0x34, 0x02, 0x00
  .db 0xf7, 1,  0x20, 0x00
  .db 0xea, 2,  0x00, 0x00
  .db 0xc0, 1,  0x23, 0x00
  .db 0xc1, 1,  0x10, 0x00
  .db 0xc5, 2,  0x3e, 0x28
;  .db 0xc7, 1,  0x86, 0x00
  .db 0xc7, 1,  0xb7, 0x00
  .db 0x36, 1,  0b11101000, 0x00
  .db 0x3a, 1,  0x55, 0x00
  .db 0xb1, 2,  0x00, ILI9341_FRAMERATE_100_HZ
  .db 0xb6, 3,  0x08, 0x82, 0x27, 0x00
  .db 0xf2, 1,  0x00, 0x00
  .db 0x26, 1,  0x01, 0x00
  .db 0xe0, 15, 0x0f, 0x31, 0x2b, 0x0c, 0x0e, 0x08, 0x4e, 0xf1
  .db           0x37, 0x07, 0x10, 0x03, 0x0e, 0x09, 0x00, 0x00
  .db 0xe1, 15, 0x00, 0x0e, 0x14, 0x03, 0x11, 0x07, 0x31, 0xc1
  .db           0x48, 0x08, 0x0f, 0x0c, 0x31, 0x36, 0x0f, 0x00
; end
  .db 0xff, 0xff


#endif ; AQH_AVR_ILI9341_MAIN_ASM


