Wiznet makers

ssekim

Published October 31, 2023 © Apache License 2.0 (Apache-2.0)

54 UCC

27 VAR

0 Contests

0 Followers

0 Following

Original Link

W5500-8051

The goal of this project is to design a simple UDP/TCP responder using an STC89/STC12 microcontroller on a demo board.

COMPONENTS Hardware components

WIZnet - W5500

x 1


PROJECT DESCRIPTION

This example demonstrates a simple TCP/IP communication example without using the ioLibrary. The following is part of loop() function.

 if (status == SOCK_ESTABLISHED) {
        while (_w5500_bytesinbuffer(SOCKET1)) {
                P1_0 = 0;
                P1_1 = 1;
            rec_char_byte_tcp = _w5500_readchar(SOCKET1);
            if (islower(rec_char_byte_tcp)) {
                rec_char_byte_tcp = toupper(rec_char_byte_tcp);
            }
            arrbuf[count] = rec_char_byte_tcp;
            recieved_tcp = 1;
            count = count + 1;
        }
        if(recieved_tcp){
            P1_0 = 1;
            P1_1 = 0;
            if (arrbuf[0] == ':' && arrbuf[1] == '<' && arrbuf[count-1] == '>') {
                arrbuf[1] = '[';
                arrbuf[count - 1] = ']';
                if(arrbuf[2] == RTU_Address){
                    _w5500_writeto(SOCKET1, arrbuf, count);  
                } else {
                    _w5500_writeto(SOCKET1, arrbuf, count);  
                }
            _w5500_send(SOCKET1);
            recieved_tcp = 0;
        } 
    }

This source code has a unique aspect in that, while other sources and functions are written in the C language, the SPI-related functions are implemented separately in both C and ASM. It seems like this is likely to verify the performance difference in the W5500 handler part between C and ASM.

The following is a part of the source code of "SPIGeneric.C".

unsigned char _spigeneric_spit_byte(unsigned char byte) {
    unsigned char i, result = 0;
    for (i = 0; i < 8; i++) {
        result <<= 1;
        result |= _spigeneric_spit_bit((byte >> (7 - i)) & 0x01);
    }
    return result;
}

Below is a file compiled into ASM from this function.

__spigeneric_spit_byte:
	mov	r7,dpl
;	SPIGeneric.c:34: unsigned char i, result = 0;
	mov	r6,#0x00
;	SPIGeneric.c:35: for (i = 0; i < 8; i++) {
	mov	r5,#0x00
00102$:
;	SPIGeneric.c:36: result <<= 1;
	mov	ar4,r6
	mov	a,r4
	add	a,r4
	mov	r4,a
;	SPIGeneric.c:37: result |= _spigeneric_spit_bit((byte >> (7 - i)) & 0x01);
	mov	a,#0x07
	clr	c
	subb	a,r5
	mov	r3,a
	mov	b,r3
	inc	b
	mov	a,r7
	sjmp	00118$
00117$:
	clr	c
	rrc	a
00118$:
	djnz	b,00117$
	anl	a,#0x01
	mov	dpl,a
	push	ar7
	push	ar5
	push	ar4
	lcall	__spigeneric_spit_bit
	mov	r3,dpl
	pop	ar4
	pop	ar5
	pop	ar7
	mov	a,r3
	orl	a,r4
	mov	r6,a
;	SPIGeneric.c:35: for (i = 0; i < 8; i++) {
	inc	r5
	cjne	r5,#0x08,00119$
00119$:
	jc	00102$
;	SPIGeneric.c:39: return result;
	mov	dpl,r6
;	SPIGeneric.c:40: }
	ret

This author optimized these aspects as ASM code.

__spigeneric_spit_byte:
    MOV R7,DPL ;R7 stores the byte we are clocking out
	MOV R6,#0x00 ;R6 stores the byte we are returning
	MOV R5,#0x08 ;R5 is our loop counter since we gotta go through the loop eight times regardless of the contents of the byte

    TEST:
        CJNE	R5,#0x00,LOOPTY
        SJMP    ALLDONE
    LOOPTY:
        DEC R5
        MOV	A,#0x80
        ANL	A,R7
        MOV	DPL,A
        ACALL	__spigeneric_spit_bit
        MOV A,R6
        RL  A
        ORL	A,DPL
        MOV	R6,A
        MOV A,R7
        RL  A
        MOV	R7,A
        SJMP	TEST
    ALLDONE:
        MOV DPL,R6
        RET

 

Assembly (ASM) is faster than C for specific tasks in this code due to the following reasons:

Direct Hardware Control: ASM allows direct control of hardware registers, resulting in precise and optimized code for a specific microcontroller or platform.

Minimal Overhead: ASM code typically has less overhead compared to C. C compilers generate more general-purpose code that includes function calls and parameter handling. ASM can be tailored for a specific task, reducing unnecessary overhead.

Fine-Grained Optimization: ASM code permits optimization at the instruction level, making efficient use of resources such as CPU cycles and memory.

 

The reasons for writing code in assembly language (ASM) in an Interrupt Service Routine (ISR) are as follows:

Speed and Efficiency: Assembly language is closely related to machine code and allows for a more direct interaction with hardware compared to compilers. As a result, assembly code can help in writing faster and more efficient code. ISRs often need to execute very quickly, making assembly code a suitable choice.

Low-Level Control: ISRs are responsible for responding to hardware interrupts and saving/restoring the system's state. Using assembly language allows precise control and execution of these tasks by directly accessing registers and memory locations.

Code Size and Performance Optimization: Code written in assembly language is typically more optimized in terms of code size and performance compared to code generated by a compiler. This optimization is crucial, especially in embedded systems with limited memory and processing capabilities.

Meeting Specific Hardware Requirements: Assembly language allows for the precise fulfillment of specific hardware architecture requirements. Assembly code can directly leverage the instruction set of a particular processor or microcontroller.

Of course, assembly language is harder to read and write and is more prone to errors compared to high-level programming languages. Therefore, the decision to use assembly language for an ISR depends on project requirements, performance goals, and the developer's expertise.

 

Inline assembly is the technique of inserting assembly language code within high-level programming languages (e.g., C or C++). The main reasons for using inline assembly are as follows:

Hardware Control: When you need to directly access specific hardware registers or perform certain hardware operations, inline assembly allows you to control the hardware directly alongside high-level language code.

Optimization: While high-level language compilers typically optimize code, it can be challenging to control the level of optimization for specific tasks. Inline assembly allows you to optimize specific parts of your code directly.

Using a Specific Instruction Set: When you want to utilize a particular instruction set or write code optimized for a specific hardware architecture, inline assembly can be invaluable.

Low-Level Operations: When you need to manipulate memory addresses directly or perform other low-level operations, inline assembly becomes essential.

Specific Optimization: If you need to optimize a particular algorithm or task, writing inline assembly code directly can maximize efficiency.

Platform Dependence: When you must write platform-dependent code for a specific platform, using inline assembly can help handle platform-specific differences.

However, inline assembly has the disadvantages of being challenging to understand, difficult to debug, and maintain. It can also reduce portability and may be error-prone. Therefore, when using inline assembly, careful consideration of its major advantages and drawbacks is essential.

 

Documents
Comments Write