aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/twi.spec.ts176
1 files changed, 175 insertions, 1 deletions
diff --git a/src/twi.spec.ts b/src/twi.spec.ts
index 4f57dc7..de7ceb8 100644
--- a/src/twi.spec.ts
+++ b/src/twi.spec.ts
@@ -191,7 +191,6 @@ describe('TWI', () => {
// Step 4: wait for stop condition
runInstructions(cpu, twi, 16);
- console.log(cpu.data[16]);
expect(twi.eventHandler.stop).toHaveBeenCalled();
runInstructions(cpu, twi, 16);
@@ -201,5 +200,180 @@ describe('TWI', () => {
runInstructions(cpu, twi, 16);
expect(cpu.data[17]).toEqual(0x42);
});
+
+ it('should successfully receive a byte from a slave', () => {
+ const { program } = asmProgram(`
+ ; register addresses
+ _REPLACE TWSR, 0xb9
+ _REPLACE TWDR, 0xbb
+ _REPLACE TWCR, 0xbc
+
+ ; TWCR bits
+ _REPLACE TWEN, 0x04
+ _REPLACE TWSTO, 0x10
+ _REPLACE TWSTA, 0x20
+ _REPLACE TWEA, 0x40
+ _REPLACE TWINT, 0x80
+
+ ; TWSR states
+ _REPLACE START, 0x8 ; TWI start
+ _REPLACE MT_SLAR_ACK, 0x40 ; Slave Adresss ACK has been received
+ _REPLACE MT_DATA_RECV, 0x50 ; Data has been received
+ _REPLACE MT_DATA_RECV_NACK, 0x58 ; Data has been received, NACK has been returned
+
+ ; Send start condition
+ ldi r16, TWEN
+ sbr r16, TWSTA
+ sbr r16, TWINT
+ sts TWCR, r16
+
+ ; Wait for TWINT Flag set. This indicates that the START condition has been transmitted
+ call wait_for_twint
+
+ ; Check value of TWI Status Register. Mask prescaler bits. If status different from START go to ERROR
+ lds r16, TWSR
+ andi r16, 0xf8
+ ldi r18, START
+ cpse r16, r18
+ jmp error ; only jump if r16 != r18 (START)
+
+ ; Load SLA_R into TWDR Register. Clear TWINT bit in TWCR to start transmission of address
+ ; 0xa1 = Address 0x50, read mode (R/W bit set)
+ _REPLACE SLA_R, 0xa1
+ ldi r16, SLA_R
+ sts TWDR, r16
+ ldi r16, TWINT
+ sbr r16, TWEN
+ sts TWCR, r16
+
+ ; Wait for TWINT Flag set. This indicates that the SLA+W has been transmitted, and ACK/NACK has been received.
+ call wait_for_twint
+
+ ; Check value of TWI Status Register. Mask prescaler bits. If status different from MT_SLA_ACK go to ERROR
+ lds r16, TWSR
+ andi r16, 0xf8
+ cpi r16, MT_SLAR_ACK
+ brne error
+
+ ; Clear TWINT bit in TWCR to receive the next byte, set TWEA to send ACK
+ ldi r16, TWINT
+ sbr r16, TWEA
+ sbr r16, TWEN
+ sts TWCR, r16
+
+ ; Wait for TWINT Flag set. This indicates that the DATA has been received, and ACK has been transmitted
+ call wait_for_twint
+
+ ; Check value of TWI Status Register. Mask prescaler bits. If status different from MT_DATA_RECV go to ERROR
+ lds r16, TWSR
+ andi r16, 0xf8
+ cpi r16, MT_DATA_RECV
+ brne error
+
+ ; Validate that we recieved the desired data - first byte should be 0x66
+ lds r16, TWDR
+ cpi r16, 0x66
+ brne error
+
+ ; Clear TWINT bit in TWCR to receive the next byte, this time we don't ACK
+ ldi r16, TWINT
+ sbr r16, TWEN
+ sts TWCR, r16
+
+ ; Wait for TWINT Flag set. This indicates that the DATA has been received, and NACK has been transmitted
+ call wait_for_twint
+
+ ; Check value of TWI Status Register. Mask prescaler bits. If status different from MT_DATA_RECV_NACK go to ERROR
+ lds r16, TWSR
+ andi r16, 0xf8
+ cpi r16, MT_DATA_RECV_NACK
+ brne error
+
+ ; Validate that we recieved the desired data - second byte should be 0x77
+ lds r16, TWDR
+ cpi r16, 0x77
+ brne error
+
+ ; Transmit STOP condition
+ ldi r16, TWINT
+ sbr r16, TWEN
+ sbr r16, TWSTO
+ sts TWCR, r16
+
+ ; Wait for TWINT Flag set. This indicates that the STOP condition has been sent
+ call wait_for_twint
+
+ ; Check value of TWI Status Register. The masked value should be 0xf8 once done
+ lds r16, TWSR
+ andi r16, 0xf8
+ cpi r16, 0xf8
+ brne error
+
+ ; Indicate success by loading 0x42 into r17
+ ldi r17, 0x42
+
+ loop:
+ jmp loop
+
+ ; Busy-waits for the TWINT flag to be set
+ wait_for_twint:
+ lds r16, TWCR
+ andi r16, TWINT
+ breq wait_for_twint
+ ret
+
+ ; In case of an error, toggle a breakpoint
+ error:
+ break
+ `);
+ const cpu = new CPU(program);
+ const twi = new AVRTWI(cpu, twiConfig, FREQ_16MHZ);
+ twi.eventHandler = {
+ start: jest.fn(),
+ stop: jest.fn(),
+ connectToSlave: jest.fn(),
+ writeByte: jest.fn(),
+ readByte: jest.fn()
+ };
+
+ // Step 1: wait for start condition
+ runInstructions(cpu, twi, 4);
+ expect(twi.eventHandler.start).toHaveBeenCalledWith(false);
+
+ runInstructions(cpu, twi, 16);
+ twi.completeStart();
+
+ // Step 2: wait for slave connect in read mode
+ runInstructions(cpu, twi, 16);
+ expect(twi.eventHandler.connectToSlave).toHaveBeenCalledWith(0x50, false);
+
+ runInstructions(cpu, twi, 16);
+ twi.completeConnect(true);
+
+ // Step 3: send the first byte to the master, expect ack
+ runInstructions(cpu, twi, 16);
+ expect(twi.eventHandler.readByte).toHaveBeenCalledWith(true);
+
+ runInstructions(cpu, twi, 16);
+ twi.completeRead(0x66);
+
+ // Step 4: send the first byte to the master, expect nack
+ runInstructions(cpu, twi, 16);
+ expect(twi.eventHandler.readByte).toHaveBeenCalledWith(false);
+
+ runInstructions(cpu, twi, 16);
+ twi.completeRead(0x77);
+
+ // Step 5: wait for stop condition
+ runInstructions(cpu, twi, 24);
+ expect(twi.eventHandler.stop).toHaveBeenCalled();
+
+ runInstructions(cpu, twi, 16);
+ twi.completeStop();
+
+ // Step 6: wait for the assembly code to indicate success by settings r17 to 0x42
+ runInstructions(cpu, twi, 16);
+ expect(cpu.data[17]).toEqual(0x42);
+ });
});
});
If you find this content useful please consider a small donation via bitcoin: bitcoin:1mxKyQsHHugqRxPKgwaA7wUwJEGCNthn2?amount=0.001&message=Donation Scraping git contents via cgit is very resource intensive. The continued hosting of these git repositories is entirely financed by your bitcoin contributions. For donations of a least 1 mBTC you include your IP address in the message of your bitcoin donation. This will remove this message in the future for requests from your IP, which will significantly reduce token usage. In any case, any contributions to bitcoin address 1mxKyQsHHugqRxPKgwaA7wUwJEGCNthn2 are very welcome. Thanks in advance for you contribution to a self-sustaining ecosystem.