diff options
author | justanothercatgirl <sotov@twistea.su> | 2025-05-27 14:57:26 +0300 |
---|---|---|
committer | justanothercatgirl <sotov@twistea.su> | 2025-05-27 14:57:26 +0300 |
commit | ef2367f0625525707440092e56d76352c754cd7b (patch) | |
tree | cff49bd3ee569e14965e91c1a510938c010a84d5 | |
parent | 90a4d4a1353dd7b514fe4ef10c1ed2c6f24cadbe (diff) |
tried to add frequency generator
-rw-r--r-- | README.md | 1 | ||||
-rw-r--r-- | def.s | 33 | ||||
-rw-r--r-- | i2c.s | 71 | ||||
-rw-r--r-- | lcd.s | 43 | ||||
-rw-r--r-- | sleep.s | 216 | ||||
-rw-r--r-- | timer.s | 6 |
6 files changed, 355 insertions, 15 deletions
@@ -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 @@ -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 @@ -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 @@ -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: @@ -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 @@ -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 + +" |