aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorjustanothercatgirl <sotov@twistea.su>2025-05-27 14:57:26 +0300
committerjustanothercatgirl <sotov@twistea.su>2025-05-27 14:57:26 +0300
commitef2367f0625525707440092e56d76352c754cd7b (patch)
treecff49bd3ee569e14965e91c1a510938c010a84d5
parent90a4d4a1353dd7b514fe4ef10c1ed2c6f24cadbe (diff)
tried to add frequency generator
-rw-r--r--README.md1
-rw-r--r--def.s33
-rw-r--r--i2c.s71
-rw-r--r--lcd.s43
-rw-r--r--sleep.s216
-rw-r--r--timer.s6
6 files changed, 355 insertions, 15 deletions
diff --git a/README.md b/README.md
index 575493b..f8aa932 100644
--- a/README.md
+++ b/README.md
@@ -75,6 +75,7 @@ Not that you don't actually need `avr-libc` or `avr-gcc` to build assembly.
* [AVR instruction manual](https://ww1.microchip.com/downloads/en/DeviceDoc/AVR-Instruction-Set-Manual-DS40002198A.pdf)
* [AVR130: Setup and use of AVR Timers](https://ww1.microchip.com/downloads/en/Appnotes/Atmel-2505-Setup-and-Use-of-AVR-Timers_ApplicationNote_AVR130.pdf)
* [Arduino UNO R3 info](https://docs.arduino.cc/hardware/uno-rev3/), [PINOUT](https://docs.arduino.cc/resources/pinouts/A000066-full-pinout.pdf)
+* [AVR application notes at ProfessorDan.com](https://professordan.com/avr/techlib/techlib8/index.html)
## Read this if you are going into it blind
This section contains some of the pain that I've gone through while doing this
diff --git a/def.s b/def.s
index d4fdd44..1a81e09 100644
--- a/def.s
+++ b/def.s
@@ -5,15 +5,34 @@
.equ DDRD, 0x0A
.equ PORTD, 0x0B
.equ TIFR0, 0x15
-.equ ADDR, 0x256
+.equ TCCR0A, 0x24
+.equ TCCR0B, 0x25
+.equ TCNT0, 0x26
+.equ OCR0A, 0x27
.equ SPL, 0x3D
.equ SPH, 0x3E
.equ SREG, 0x3F
-.equ TCCR0A, 0x0024
-.equ TCCR0B, 0x0025
-.equ TCNT0, 0x0026
-.equ OCR0A, 0x0027
+
.equ TIMSK0, 0x006E
-.equ STOFL, 0xFF
-.equ STOFH, 0x08
+.equ TWBR, 0x00B8
+.equ TWSR, 0x00B9
+.equ TWAR, 0x00BA
+.equ TWDR, 0x00BB
+.equ TWCR, 0x00BC
+.equ TWAMR, 0x00BD
+
.equ TOIE0, 1
+
+.equ TWIE, 0
+
+.equ TWEN, 2
+.equ TWWC, 3
+.equ TWSTO, 4
+.equ TWSTA, 5
+.equ TWEA, 6
+.equ TWINT, 7
+
+.equ I2C_STATR, 0x08
+.equ I2C_WTR, 0x18
+.equ I2C_DATR, 0x28
+.equ I2C_PREMK, 0xF8
diff --git a/i2c.s b/i2c.s
index 83ef974..29b6a6c 100644
--- a/i2c.s
+++ b/i2c.s
@@ -1,15 +1,72 @@
+
i2cwait:
- in r17, TWCR
+ lds r17, TWCR
sbrs r17, TWINT
rjmp i2cwait
-; r16 : addr
-i2cstart:
+ ret
+
+; r16: addr -> r0: OK
+i2c_start_write:
ldi r17, (1 << TWSTA) | (1 << TWEN) | (1 << TWINT)
- out TWCR, r17
+ sts TWCR, r17
rcall i2cwait
- out TWDR, r16
+ lds r17, TWSR
+ andi r17, I2C_PREMK
+ cpi r17, I2C_STATR
+ brne .error
+
+ lsl r16
+ sbr r16, 0b00000001
+ sts TWDR, r16
andi r17, ~(1 << TWSTA)
- out TWCR, r17
+ sts TWCR, r17
rcall i2cwait
-; r16: data
+ lds r17, TWSR
+ andi r17, I2C_PREMK
+ cpi r17, I2C_WTR
+ brne .error
+
+ ldi r17, 1
+ rjmp ret
+.error:
+ ldi r17, 0
+.ret:
+ mov r0, r17
+ ret
+
+; r16: data -> r0: OK
writebyte:
+ ldi r17, (1 << TWEN) | (1 << TWINT)
+ sts TWDR, r16
+ sts TWCR, r17
+ rcall i2cwait
+ ldi r17, TWSR
+ andi r17, I2C_PREMK
+ cp r17, I2C_DATR
+ brne .error
+ ldi r17, 1
+ rjmp .ret
+.error:
+ ldi r17, 0
+.ret:
+ mov r0, r17
+ ret
+
+; r17: length, r27:r26: address -> r0: OK
+writebytes:
+ cpi r17, 0
+ breq .exit
+ ld r16, X+
+ rcall writebyte
+ cpi r0, 0
+ breq .exit
+ dec r17
+ rjmp writebytes
+.exit:
+ ret
+
+i2c_stop:
+ ldi r16, (1 << TWINT) | (1 << TWEN) | (1 << TWSTO)
+ sts TWCR, r16
+ ; call i2cwait ; ?
+ ret
diff --git a/lcd.s b/lcd.s
new file mode 100644
index 0000000..f3a8d4a
--- /dev/null
+++ b/lcd.s
@@ -0,0 +1,43 @@
+.include "def.s"
+
+.equ STRSTART, 0x100
+.equ STRSLEN, .endstrings-.startstrings
+
+.zerolabel:
+.org 0x0000
+ rjmp init
+
+init:
+ ldi r16, STRSLEN
+ ldi r31, (.startstrings-.zerolabel) >> 8
+ ldi r30, (.startstrings-.zerolabel) & 0xFF
+ ldi r27, STRSTART >> 8
+ ldi r26, STRSTART & 0xFF
+.init_loop:
+ cpi r16, 0
+ breq .init_endloop
+ lpm r0, Z+
+ st X+, r0
+ dec r16
+ rjmp .init_loop
+.init_endloop:
+ rjmp main
+
+main:
+ ldi r29, 0x100 >> 8
+ ldi r28, 0x100 & 0xFF
+ ldi r16, 0
+.main_loop:
+ ld r16, Y+
+ cpi r16, 0x69
+ breq .main_endloop
+ rjmp .main_loop
+.main_endloop: rjmp .
+
+; .include "i2c.s"
+
+.startstrings:
+hello: .asciz "hello, world!"
+bye: .asciz "he's got that DAWG in'im"
+.ascii "\x69"
+.endstrings:
diff --git a/sleep.s b/sleep.s
new file mode 100644
index 0000000..16817c2
--- /dev/null
+++ b/sleep.s
@@ -0,0 +1,216 @@
+.equ SREG, 0x3F
+
+.macro LDCPUF
+ ldi r19, hhi8(CPUF)
+ ldi r18, hlo8(CPUF)
+ ldi r17, hi8(CPUF)
+ ldi r16, lo8(CPUF)
+.endm
+
+.equ CPUF, 16000000
+
+.org 0x0000
+ cli
+main: rjmp hztest
+slc_test:
+ ldi r19, 0x00
+ ldi r18, 0x02
+ ldi r17, 0x00
+ ldi r16, 0x00
+ rcall sl16c32
+ nop
+div16_test:
+ ldi r17, 0xFF
+ ldi r16, 0xFF
+ ldi r19, 0x01
+ ldi r18, 0x00
+ rcall u16div
+ nop
+div32_test:
+ LDCPUF
+ ldi r23, 0x00
+ ldi r22, 0x00
+ ldi r21, hi8(440)
+ ldi r20, lo8(440)
+ rcall u32div
+ ; copypaste in GDB for testing
+ ; (((unsigned long)$r19 << 24) | ((unsigned long)$r18 << 16) | ((unsigned long)$r17 << 8) | (unsigned long)$r16 )
+ ; (((unsigned long)$r23 << 24) | ((unsigned long)$r22 << 16) | ((unsigned long)$r21 << 8) | (unsigned long)$r20 )
+ ; (((unsigned long)$r15 << 24) | ((unsigned long)$r14 << 16) | ((unsigned long)$r13 << 8) | (unsigned long)$r12 )
+ nop
+ls32_test:
+ LDCPUF
+ ldi r20, 4
+ rcall lsr32
+ nop
+ ldi r20, 5
+ rcall lsl32
+ nop
+ lsr r19
+ ror r18
+ ror r17
+ ror r16
+ nop
+hztest:
+ ldi r21, hi8(2)
+ ldi r20, lo8(2)
+ call genhz
+1: rjmp 1b
+
+; * r16 (divident) / r17(divisor) ->
+; -> r16 (quotient), r15 (remainder)
+; * Limits: r16 [0, 255]; r17 [1, 128]
+; * Note: at first, I implemented it myself in 18 instructions, and then I
+; learned that `dec` affects zero flag (and does not affect carry flag), so I
+; could make it a lot shorter
+u8div:
+ sub r15, r15 ; clears carry
+ ldi r18, 9 ; counter
+1: rol r16
+ dec r18
+ breq 3f
+ rol r15
+ sub r15, r17
+ brmi 2f
+ sec
+ rjmp 1b
+2: add r15, r17
+ clc
+ rjmp 1b
+3: ret
+
+; * {r17:r16} (divident) / {r19:r18} (divisor) ->
+; -> {r17:r16} (quotient), {r15:r14} (remainder)
+; * Limits: {r17:r16} [0, 65535], {r19:r18} [1, 32768]
+u16div:
+ eor r15, r15 ; clear {r15:r14}
+ sub r14, r14 ; clears carry
+ ldi r20, 17 ; counter
+1: rol r16
+ rol r17
+ dec r20
+ breq 3f
+ rol r14
+ rol r15
+ sub r14, r18
+ sbc r15, r19
+ brmi 2f
+ sec
+ rjmp 1b
+2: add r14, r18
+ adc r15, r19
+ clc
+ rjmp 1b
+3: ret
+
+; * {r19:r16} (divident) / {r23:r20} (divisor) ->
+; -> {r19:r16} (quotient), {r15:r12} (remainder)
+; * Limits: {r17:r16} [0, 1 << 32], {r19:r18} [1, 1 << 31]
+u32div:
+ eor r12, r12
+ eor r13, r13
+ eor r14, r14
+ sub r15, r15
+ ldi r24, 33
+1: rol r16
+ rol r17
+ rol r18
+ rol r19
+ dec r24
+ breq 3f
+ rol r12
+ rol r13
+ rol r14
+ rol r15
+ sub r12, r20
+ sbc r13, r21
+ sbc r14, r22
+ sbc r15, r23
+ brmi 2f
+ sec
+ rjmp 1b
+2: add r12, r20
+ adc r13, r21
+ adc r14, r22
+ adc r15, r23
+ clc
+ rjmp 1b
+3: ret
+
+; * {r19:r16} : CPU cycles / 16
+; * r16 - LSB, r19 - MSB
+; * This function will execute for EXACTLY
+; (2 + {r19:r16}*16 + 1 instructions)
+; * If you load a value in CPU cycles into {r19:r16},
+; then call lsr32 with r20=4 beforehand
+sl16c32:
+ ldi r20, 1
+ ldi r21, 0
+1: nop
+ nop
+ nop
+ nop
+ sub r16, r20
+ sbc r17, r21
+ sbc r18, r21
+ sbc r19, r21
+ cpi r16, 0
+ brne 2f
+ cpi r17, 0
+ brne 3f
+ cpi r18, 0
+ brne 4f
+ cpi r19, 0
+ brne 1b
+ ret
+2: nop
+ nop
+3: nop
+ nop
+4: nop
+ rjmp 1b
+
+; * r20: shift length
+; * {r19:r16}: shift value
+lsr32: cpi r20, 0
+ breq 1f
+ dec r20
+ lsr r19
+ ror r18
+ ror r17
+ ror r16
+ rjmp lsr32
+lsl32: cpi r20, 0
+ breq 1f
+ dec r20
+ lsl r16
+ rol r17
+ rol r18
+ rol r19
+ rjmp lsl32
+1: ret
+
+; * Plays sound at specified frequency
+; * {r21:r20} - frequency in Hertz
+genhz:
+ clr r22
+ clr r23
+ eor r10, r10
+ LDCPUF
+ rcall u32div
+ ldi r20, 4+1 ; 4 for sl16, 1 for frequency
+ rcall lsr32
+ mov r6, r16
+ mov r7, r17
+ mov r8, r18
+ mov r9, r19
+
+1: mov r16, r6
+ mov r17, r7
+ mov r18, r8
+ mov r19, r9
+ rcall sl16c32
+ inc r10
+ rjmp 1b
+
+; vim:ft=avra
diff --git a/timer.s b/timer.s
index c62b2b5..ccd51e0 100644
--- a/timer.s
+++ b/timer.s
@@ -1,14 +1,16 @@
.include "def.s"
+.equ ADDR, 0x256
.equ LOC, 0x128
.equ FREQ, 0x80
+.equ STOFL, 0xFF
+.equ STOFH, 0x08
.org 0x0000 ; reset interrupt
jmp init
.org 0x0040 ; timer 0 overflow interrupt
jmp tmrint
-
.org 0x0068
init:
; IO
@@ -87,3 +89,5 @@ main:
rjmp main
+
+"