/* timing: crystal: 14.7456 MHz control port: 115200 baud mux ports: 9600 baud timer: 38400 interrupts / sec (4 * 9600) cycles per IRQ: 384 (max 64 per port) register use: reg fnc descr r0 MAIN port 0 data r1 MAIN port 1 data r2 MAIN port 2 data r3 MAIN port 3 data r4 MAIN port 4 data r5 MAIN port 5 data r6 r7 r8 IRQ temp r9 IRQ temp r10 r11 r12 r13 r14 r15 OVF TXD baud counter r16 IRQ temp r17 IRQ temp r18 IRQ temp r19 IRQ temp r20 r21 r22 MAIN temp, start bits, data bits, stop bits r23 MAIN temp r24 MAIN temp r25 MAIN output_bits_cntr value to wait for r26 MAIN pointer r27 MAIN pointer r28 OVF pointer to uart_send_buf r29 OVF pointer to uart_send_buf r30 IRQ pointer r31 IRQ pointer port_struct: char counter char data char bufferflag char bufferin char bufferout char fill[3] char buffer[8] counter values: 0x1B waiting for start bit bit = 0: start bit 8 + 6 = 14 bit = 1: no start bit 23 + 3 = 26 0x20 sample bit 0 12 + 12 = 24 0x24 sample bit 1 0x28 sample bit 2 0x2C sample bit 3 0x30 sample bit 4 0x34 sample bit 5 0x38 sample bit 6 0x3C sample bit 7 0x40 sample stop bit bit = 1: stop bit 26 + 5 = 31 bit = 0: no stop bit 13 + 5 = 18 0x41 error, waiting for 'stop bit' bit = 1: stop bit 15 + 5 = 20 bit = 0: no stop bit 13 + 5 = 18 0x1C-0x1F delay slot 12 + 6 = 18 0x21-0x3F delay slot 14 + 6 = 20 average cycles: 0x1B wait 2 26 52 0x1B start bit 1 14 14 0x1X delay 4 18 72 0x2X data 8 24 192 0x2X delay 24 20 480 0x40 stop bit 1 31 31 sum 40 841 average 21.025 average 6 ports 126.15 */ /*----------------------------------------------------------------------------*/ .file "sermuxa.a" .arch atmega88 .ident "sermuxa.a V0.1" __SREG__ = 0x3f __SP_H__ = 0x3e __SP_L__ = 0x3d /* port registers */ PINB = 0x03 DDRB = 0x04 PORTB = 0x05 PINC = 0x06 DDRC = 0x07 PORTC = 0x08 /* timer 0 registers */ TCCR0A = 0x24 TCCR0B = 0x25 OCR0A = 0x27 mTIMSK0 = 0x6E WGM00 = 0 WGM01 = 1 WGM02 = 3 CS00 = 0 CS01 = 1 CS02 = 2 TOIE0 = 1 /* uart 0 registers */ mUCSR0A = 0xC0 mUCSR0B = 0xC1 mUCSR0C = 0xC2 mUBRR0L = 0xC4 mUBRR0H = 0xC5 mUDR0 = 0xC6 RXC0 = 7 UDRE0 = 5 U2X0 = 1 RXEN0 = 4 TXEN0 = 3 UCSZ00 = 1 /* port_struct offsets */ PS_COUNTER = 0 PS_DATA = 1 PS_BUFIN = 2 PS_BUFOUT = 3 PS_BUFFLAG = 4 /* PS_BUFSYNC = 5 */ PS_BUFFER = 8 PS_SIZE = 16 /* buffer flag value */ BUF_FLAG = 0x40 SYNC_FLAG = 0x80 /* port_struct counter special values */ RXD_OFF = 0x1B RXD_DATA = 0x20 RXD_STOP = 0x40 RXD_ERROR = 0x41 RXD_BITS = 0x03 foo = r17 .global __do_copy_data .global __do_clear_bss .text /*----------------------------------------------------------------------------*/ /* TIMER0_OVF_vect */ /* registers used r8 temp r9 temp r16 loop counter, temp r17 ser bit counter r18 temp r19 temp r28 pointer to uart_send_buf r29 pointer to uart_send_buf r30 pointer r31 pointer cycles used: worst case average save registers 3 write TXDs 18 * optimize * process RXDs 194 122? init 8 loop 6 * 31 UART send 18 UART receive 34 restore registers 7 TOTAL 249 191? */ .global __vector_16 .type __vector_16, @function __vector_16: /* save registers */ in r8,__SREG__ /* cycles: 1 */ push r8 /* cycles: 2 */ /* total cycles: 3 */ /* --------------------------------- */ /* write TXDs */ /* baud counter */ dec r15 /* cycles: 1 */ brpl OVF_OBC_END /* cycles: 1 */ ldi r16, 3 /* cycles: 1 */ mov r15, r16 /* cycles: 1 */ /* +++ could be optimized if TX buffer is 256 bytes and 256 aligned */ lds r16, output_bits_cntr /* cycles: 2 */ mov r30, r16 /* cycles: 1 */ clr r31 /* cycles: 1 */ subi r30, lo8(-(output_bits_data)) /* cycles: 1 */ sbci r31, hi8(-(output_bits_data)) /* cycles: 1 */ subi r16, lo8(1) /* cycles: 1 */ brpl OVF_OBC_PL /* cycles: 1/2 */ ldi r16, 19 /* cycles: 1 */ OVF_OBC_PL: sts output_bits_cntr, r16 /* cycles: 2 */ ld r9, Z /* cycles: 2 */ out PORTB, r9 /* cycles: 1 */ OVF_OBC_END: /* max cycles: 18 */ /* --------------------------------- */ /* process RXDs */ /* register use: r8 RXDs r9 temp r16 loop counter r17 ser bit counter r18 temp r19 temp r28 pointer to uart_send_buf r29 pointer to uart_send_buf r30 pointer r31 pointer */ /* read RXDs into r8 */ in r8, PINC /* cycles: 1 */ lsl r8 /* cycles: 1 */ lsl r8 /* cycles: 1 */ ldi r16, 6 /* cycles: 1 */ ldi r30, lo8(port_struct+(6-1)*PS_SIZE) /* cycles: 1 */ ldi r31, hi8(port_struct+(6-1)*PS_SIZE) /* cycles: 1 */ /* jump into loop */ rjmp OVF_IB_LOOP /* cycles: 2 */ /* total cycles: 8 */ /* shift bit into data byte */ OVF_IB_ADDBIT: /* 12 till OVF_IB_LOOP */ ldd r9, Z+PS_DATA /* cycles: 2 */ lsl r8 /* cycles: 1 */ ror r9 /* cycles: 1 */ std Z+PS_DATA, r9 /* cycles: 2 */ /* increase counter, store it */ OVF_IB_CNTINC: /* 6 till OVF_IB_LOOP */ inc r17 /* cycles: 1 */ /* store counter */ OVF_IB_CNTSTORE: /* 5 till OVF_IB_LOOP */ st Z, r17 /* cycles: 2 */ /* decrease loop counter */ OVF_IB_CONT: /* 3 till OVF_IB_LOOP */ dec r16 /* cycles: 1 */ brmi OVF_IB_END /* cycles: 1/2 */ /* decrease Z by sizeof(port_struct) */ subi r30, PS_SIZE /* cycles: 1 */ /*** loop over all 6 ports ***/ OVF_IB_LOOP: ld r17, Z /* cycles: 2 */ /* if counter == RXD_OFF branch to check for start bit */ cpi r17, RXD_OFF /* cycles: 1 */ /* 3 from OVF_IB_LOOP */ breq OVF_IB_START /* cycles: 1/2 */ /* if counter >= RXD_STOP branch to check for stop bit */ cpi r17, RXD_STOP /* cycles: 1 */ /* 5 from OVF_IB_LOOP */ brge OVF_IB_STOP /* cycles: 1/2 */ /* if counter < RXD_DATA branch to discard bit and increase counter */ cpi r17, RXD_DATA /* cycles: 1 */ /* 7 from OVF_IB_LOOP */ brmi OVF_IB_DISCARD /* cycles: 1/2 */ /* if at read position branch to add bit */ mov r18, r17 /* cycles: 1 */ andi r18, RXD_BITS /* cycles: 1 */ /* 10 from OVF_IB_LOOP */ breq OVF_IB_ADDBIT /* cycles: 1/2 */ /* discard bit */ /* 11 from OVF_IB_LOOP */ OVF_IB_DISCARD: lsl r8 /* cycles: 1 */ rjmp OVF_IB_CNTINC /* cycles: 2 */ /* max 14 from OVF_IB_LOOP */ /* check for start bit */ OVF_IB_START: lsl r8 /* cycles: 1 */ /* 6 from OVF_IB_LOOP */ /* if bit == 0 branch to increase counter */ brcc OVF_IB_CNTINC /* cycles: 1/2 */ /* not a start bit, check if sync is needed */ ldd r18, Z+PS_BUFFLAG /* cycles: 2 */ cpi r18, (BUF_FLAG|SYNC_FLAG) /* cycles: 1 */ brne OVF_IB_CONT /* cycles: 1/2 */ /* do sync, send flag plus port number */ st Y, r18 /* cycles: 2 */ std Y+1, r16 /* cycles: 2 */ /* increase count */ subi r28, (-2) /* cycles: 1 */ sts uart_send_in, r28 /* cycles: 2 */ /* clear flags */ clr r18 /* cycles: 1 */ std Z+PS_BUFFLAG, r18 /* cycles: 2 */ /* continue loop */ rjmp OVF_IB_CONT /* cycles: 2 */ /* 23 from OVF_IB_LOOP */ /* check stop bit */ OVF_IB_STOP: /* 7 from OVF_IB_LOOP */ lsl r8 /* cycles: 1 */ /* if bit == 0 it's an error, branch to increase counter */ brcs OVF_IB_ERROR /* cycles: 1/2 */ /* check that counter == RXD_STOP, if not we can clear the error */ cpi r18, RXD_STOP /* cycles: 1 */ brne OVF_IB_RESET /* cycles: 1/2 */ /* 11 from OVF_IB_LOOP */ /* got a full data byte including valid stop bit */ /* clear sync flag, store port number plus buffer flag */ ldd r18, Z+PS_BUFFLAG /* cycles: 2 */ andi r18, BUF_FLAG /* cycles: 1 */ std Z+PS_BUFFLAG, r18 /* cycles: 2 */ or r18, r16 /* cycles: 1 */ st Y, r18 /* cycles: 2 */ /* store data byte */ ldd r18, Z+PS_DATA /* cycles: 2 */ std Y+1, r18 /* cycles: 2 */ /* increase count */ subi r28, (-2) /* cycles: 1 */ sts uart_send_in, r28 /* cycles: 2 */ /* 26 from OVF_IB_LOOP */ /* reset counter */ OVF_IB_RESET: ldi r17, RXD_OFF /* cycles: 1 */ rjmp OVF_IB_CNTSTORE /* cycles: 2 */ /* max 29 from OVF_IB_LOOP */ /* error, no stop bit found */ OVF_IB_ERROR: /* 10 from OVF_IB_LOOP */ ldi r17, (RXD_OFF+1) /* cycles: 1 */ rjmp OVF_IB_CNTSTORE /* cycles: 2 */ /* 13 from OVF_IB_LOOP */ /* end of processing input bits */ OVF_IB_END: /* --------------------------------- */ /* UART send */ /* is UART ready to send? */ lds r31, mUCSR0A /* cycles: 2 */ andi r31, (1< fosc/9600/4 = 384 = 64 * 6 fast pwm: WGM = 7 fosc/64: CS = 3 top = 5: OCRA = 5 ovf irq: TIMSK.TOIE = 1 */ ldi r16, (1<