From 2d06c9700b635ac521778c25f5d47e80308b26b4 Mon Sep 17 00:00:00 2001 From: "Matthias@Dell" Date: Sat, 23 Dec 2023 14:17:49 +0100 Subject: [PATCH] use size, add write --- spicode.s65 | 99 ++++++++--------- system/spi.h65 | 24 +++-- system/spi.s65 | 280 ++++++++++++++++++++++++++++++++++++------------- 3 files changed, 273 insertions(+), 130 deletions(-) diff --git a/spicode.s65 b/spicode.s65 index 665f6fe..51163da 100644 --- a/spicode.s65 +++ b/spicode.s65 @@ -118,56 +118,57 @@ CODE_START: bra @loop -kbinit: - lda #'[' - jsr lcd::print_char - ; - use the shift register interrupts to read the first 8 bits - ; set shift register to shift in under external clock on CB1 - ; - configure timer for timing the read of the last 3 bits - ; timer 2 one shot mode is sufficient, leaves T1 available - lda #(IO::ACR::SR_SIN_PHIE | IO::ACR::T2_IRQ_LOAD) - tsb kb::KB_IO + IO::ACR - ; the 3 last bits take about 230us, at @1MHz => wait 230 cycles and then the shift register - lda #230 - sta kb::KB_IO + IO::T2CL - stz key_read - stz key_read+1 - - ; enable SR interrupts - lda #(IO::IRQ::IRQ | IO::IRQ::SR) - sta kb::KB_IO + IO::IER - ; load SR to reset - lda kb::KB_IO + IO::SR - lda #']' - jsr lcd::print_char - rts +; .proc kbinit +; lda #'[' +; jsr lcd::print_char +; ; - use the shift register interrupts to read the first 8 bits +; ; set shift register to shift in under external clock on CB1 +; ; - configure timer for timing the read of the last 3 bits +; ; timer 2 one shot mode is sufficient, leaves T1 available +; lda #(IO::ACR::SR_SIN_PHIE | IO::ACR::T2_IRQ_LOAD) +; tsb kb::KB_IO + IO::ACR +; ; the 3 last bits take about 230us, at @1MHz => wait 230 cycles and then the shift register +; lda #230 +; sta kb::KB_IO + IO::T2CL +; stz key_read +; stz key_read+1 +; ; enable SR interrupts +; lda #(IO::IRQ::IRQ | IO::IRQ::SR) +; sta kb::KB_IO + IO::IER +; ; load SR to reset +; lda kb::KB_IO + IO::SR +; lda #']' +; jsr lcd::print_char +; rts +; .endproc -;; @details -;; IO::SR has to be read before the next bit is shifted in, which happens ~75us after the irq -;; at 1MHz, handlings this interrupt takes about 50us (without any additional debug code), so it should work -irq_on_shift_reg: - ; lda #'{' - ; jsr lcd::print_char - lda kb::KB_IO + IO::SR - sta key_read - stz kb::KB_IO + IO::SR +; ;; @details +; ;; IO::SR has to be read before the next bit is shifted in, which happens ~75us after the irq +; ;; at 1MHz, handlings this interrupt takes about 50us (without any additional debug code), so it should work +; .proc irq_on_shift_reg +; ; lda #'{' +; ; jsr lcd::print_char +; lda kb::KB_IO + IO::SR +; sta key_read +; stz kb::KB_IO + IO::SR - ; disable SR interrupts - lda #IO::IRQ::SR - sta kb::KB_IO + IO::IER - ; enable timer interrupts - lda #(IO::IRQ::IRQ | IO::IRQ::T2) - sta kb::KB_IO + IO::IER - ; start timer - lda #1 - sta kb::KB_IO + IO::T2CH - ; lda #'}' - ; jsr lcd::print_char - rts +; ; disable SR interrupts +; lda #IO::IRQ::SR +; sta kb::KB_IO + IO::IER +; ; enable timer interrupts +; lda #(IO::IRQ::IRQ | IO::IRQ::T2) +; sta kb::KB_IO + IO::IER +; ; start timer +; lda #1 +; sta kb::KB_IO + IO::T2CH +; ; lda #'}' +; ; jsr lcd::print_char +; rts +; .endproc -irq_on_timer: +.proc irq_on_timer ; lda #'<' ; jsr lcd::print_char lda kb::KB_IO + IO::SR @@ -201,13 +202,14 @@ irq_on_timer: stz key_read+1 rts +.endproc -key_read: .res 2 -keycode: .res 1 +; key_read: .res 2 +; keycode: .res 1 kb_irq1: ; lda #'!' ; jsr lcd::print_char - jsr irq_on_shift_reg + jsr kb::on_shift_reg_irq ; lda #':' ; jsr lcd::print_char rts @@ -215,6 +217,7 @@ kb_irq1: kb_irq2: ; lda #'?' ; jsr lcd::print_char + ; jsr kb::on_timer_irq jsr irq_on_timer ; lda #';' ; jsr lcd::print_char diff --git a/system/spi.h65 b/system/spi.h65 index 62f8544..b93c4b0 100644 --- a/system/spi.h65 +++ b/system/spi.h65 @@ -1,9 +1,10 @@ -;******************************************************************************** -; @module SPI -; @type driver -; @details -; @depends IO-W65C22N -;******************************************************************************** +;;******************************************************************************** +;; @module SPI-P +;; @type driver +;; @details +;; Support being a peripheral SPI device. +;; @depends IO-W65C22N +;;******************************************************************************** .ifndef INCLUDE_SPI INCLUDE_SPI = 1 @@ -11,8 +12,15 @@ INCLUDE_SPI = 1 .scope spi_p SPI_IO = IO2 -.import CODE_START:absolute -Import spi_p, begin, end, read, pages_written, bytes_written +Import spi_p, begin_read, irq_read_byte, begin_write, irq_write_byte, end, recv_bytes, sent_bytes, status + +.enum STATUS + XFER_SIZEL = %10000000 + XFER_SIZEH = %01000000 + XFER = %00000001 + DONE = %00000000 + ERROR = %11111111 +.endenum .endscope .endif ; guard diff --git a/system/spi.s65 b/system/spi.s65 index 8938b51..7e60d83 100644 --- a/system/spi.s65 +++ b/system/spi.s65 @@ -1,69 +1,90 @@ .include "spi.h65" -Export spi_p, begin, end, read, pages_written, bytes_written +Export spi_p, begin_read, irq_read_byte, begin_write, irq_write_byte, end, recv_bytes, sent_bytes, status, spi_irq .zeropage -code_page: .res 2 ; CODE_START + pages_written * 256 +buffer_start: .res 2 .bss -bytes_written: .res 1 -pages_written: .res 1 +recv_bytes: +sent_bytes: .res 2 +status: .res 1 +buffer_size: .res 2 +irq_handler: .res 2 + SPI_IO := spi_p::SPI_IO -CODE_START := spi_p::CODE_START ; spi-transferred code will be placed here ; SPI_P = as peripheral .code -.struct SPI_P_Pins - ; VIA addresses - DDR_a .word ; address of the data direction register - R_a .word ; address of the register - ; pin mask - SCLK_p .byte ; Serial Clock - POCI_p .byte ; Peripheral Out / Controller In - PICO_p .byte ; Peripheral In / Controller Out - CSB_p .byte ; Chip Select - ; settings - CPOL .byte ; Clock Polarity - CPHA .byte ; Clock Phase -.endstruct +; .struct SPI_P_Pins +; ; VIA addresses +; DDR_a .word ; address of the data direction register +; R_a .word ; address of the register +; ; pin mask +; SCLK_p .byte ; Serial Clock +; POCI_p .byte ; Peripheral Out / Controller In +; PICO_p .byte ; Peripheral In / Controller Out +; CSB_p .byte ; Chip Select +; ; settings +; CPOL .byte ; Clock Polarity +; CPHA .byte ; Clock Phase +; .endstruct + + +;;******************************************************************************** +;; @function Begin listening for SPI transfers +;; @details +;; The transfer must be: SIZE, data (SIZE bytes) +;; +;; - initialize variables +;; - configure shift register to shift in under external clock +;; - enable shift register interrupts +;; @param ARG0-1: Start address of the buffer +;; @param ARG2-3: Size of the buffer +;; @todo: Use irq register handler +;; @note: The buffer must be large enough for the received data. +;;******************************************************************************** +.proc begin_read + stz recv_bytes + stz recv_bytes+1 + lda #%spi_p::STATUS::XFER_SIZEL + sta status -;******************************************************************************** -; @function Begin listening for SPI transfers -; @details -; - initialize variables -; - configure shift register to shift in under external clock -; - enable shift register interrupts -;******************************************************************************** -.proc begin - stz pages_written - stz bytes_written ; store address in zp - lda #CODE_START - sta code_page + 1 - ; todo USE MASKS - ; set Shift register to shift in under external clock on CB1 - lda #IO::ACR::SR_SIN_PHIE - sta SPI_IO + IO::ACR + lda #ARG1 + sta buffer_start+1 + ; load irq handler + lda #irq_read_byte + sta irq_handler+1 + + ; temporarily store the low byte in buffer, will be checked later + lda #ARG3 + sta buffer_size+1 + ; set Shift register to shift in under external clock on CB1 + MaskedWrite SPI_IO+IO::ACR, #IO::ACR::SR_SIN_PHIE, #IO::ACR_MASK::SR ; enable SR interrupts lda #(IO::IRQ::IRQ | IO::IRQ::SR) sta SPI_IO + IO::IER - ; load SR to reset lda SPI_IO + IO::SR rts .endproc -;******************************************************************************** -; @function Stop listening for SPI transfers -; @details -; Disables shift register interrupts -; @modifies A -;******************************************************************************** +;;******************************************************************************** +;; @function Stop reading/writing from/to SPI +;; @details +;; Disables shift register interrupts +;; @modifies A +;;******************************************************************************** .proc end ; disable SR interrupts lda #IO::IRQ::SR @@ -72,43 +93,154 @@ CODE_START := spi_p::CODE_START .endproc -;******************************************************************************** -; @function Read a byte from SPI -; @details -; Reads a byte from the shift register and stores it in the SPI code buffer -; @modifies A,Y -;******************************************************************************** -.proc read - ldy bytes_written +;;******************************************************************************** +;; @function Read a byte from SPI +;; @details +;; Reads a byte from the shift register and stores it in the SPI code buffer +;; The first two bytes must be the size of the incumong data (LE). +;; The spi_p:status is updated according to the current stage of the transfer. +;; If the buffer size given in begin_read is too small too fit the incoming data, +;; the status is set to ERROR and spi (shift register) interrupts are disabled before +;; the first real byte is read. +;; @modifies A,Y +;;******************************************************************************** +.proc irq_read_byte lda SPI_IO + IO::SR - sta (code_page),y - inc bytes_written + bit status + bmi @read_size1 + bvs @read_size2 + ldy recv_bytes + sta (buffer_start),y + inc recv_bytes beq @new_page rts @new_page: - inc pages_written - inc code_page + 1 + inc recv_bytes+1 + inc buffer_start+1 + rts +@read_size1: + sta buffer_size + lda #spi_p::STATUS::XFER_SIZEH + sta status + rts +@read_size2: + ; todo: check if the buffer is large enough: + ; low byte of buffer size in (buffer_start), high byte in buffer_size+1 + ; low byte of recv buffer size in buffer_size, high byte in A + cmp buffer_size+1 + beq @hieq + sta buffer_size+1 + bcs @enough ; buffer larger + bra @not_enough +@hieq: ; high bytes are equal, check lo + lda (buffer_start) + cmp buffer_size + bcs @enough +@not_enough: + lda #spi_p::STATUS::ERROR + sta status + ; disable SR interrupts + lda #IO::IRQ::SR + sta SPI_IO + IO::IER + rts +@enough: + lda #spi_p::STATUS::XFER + sta status rts .endproc - -;******************************************************************************** -; @function Initialize the IO Adapter for SPI -; @param ARG0-1 Address of the SPI_Pins struct -;******************************************************************************** -;******************************************************************************** -; @function Read bytes -; @param X Number of bytes to send -; @param ARG0-1 Address of the SPI_Pins struct -; @param ARG2-3 Address of the first byte -;******************************************************************************** -.proc recv_data + +;;******************************************************************************** +;; @function Begin writing to spi +;; @details +;; - initialize variables +;; - configure shift register to shift in under external clock +;; - enable shift register interrupts +;; @param ARG0-1: Start address of the buffer +;; @param ARG2-3: Size of the buffer +;; @todo: Use irq register handler +;;******************************************************************************** +.proc begin_write + stz recv_bytes + stz recv_bytes+1 + ; store address in zp + lda #ARG1 + sta buffer_start+1 + ; store size + lda #ARG3 + sta buffer_size+1 + ; load irq handler + lda #irq_read_byte + sta irq_handler+1 + ; set Shift register to shift out under external clock on CB1 + MaskedWrite SPI_IO+IO::ACR, #IO::ACR::SR_SOUT_PHIE, #IO::ACR_MASK::SR + ; enable SR interrupts + lda #(IO::IRQ::IRQ | IO::IRQ::SR) + sta SPI_IO + IO::IER + ; write the first byte +@write_size1: + lda buffer_size + sta SPI_IO+IO_SR + lda #spi_p::STATUS::XFER_SIZEH + sta status + rts + rts .endproc -;******************************************************************************** -; @function Send bytes -; @param X Number of bytes to send -; @param ARG0-1 Address of the SPI_Pins struct -; @param ARG2-3 Address of the first byte -;******************************************************************************** -.proc send_data + +;;;******************************************************************************** +;;; @function Write a byte +;;; @details +;;; Write a byte to the spi shift reister +;;; @modifies A,Y +;;;******************************************************************************** +;.proc irq_write_byte +; ldy sent_bytes +; lda (buffer_start),y +; sta SPI_IO + IO::SR +; inc sent_bytes +; beq @new_page +; rts +;@new_page: +; inc sent_bytes+1 +; inc buffer_start+1 +; rts +;.endproc + + +;;******************************************************************************** +;; @function Write a byte to SPI +;; @details +;; Write a byte from the buffer to the (spi) shift register. +;; The first two bytes are the size of the data (LE). +;; The spi_p:status is updated according to the current stage of the transfer. +;; @modifies A,Y +;;******************************************************************************** +.proc irq_write_byte + bit status + bvs @write_size2 ; bit 6 set -> XFER_SIZEH + ldy sent_bytes + lda (buffer_start),y + sta SPI_IO + IO::SR + inc sent_bytes + beq @new_page + rts +@new_page: + inc sent_bytes+1 + inc buffer_start+1 + rts +@write_size2: + lda buffer_size+1 + sta SPI_IO+IO_SR + lda #spi_p::STATUS::XFER + sta status + rts +.endproc + + .endproc