W5500-8051
The goal of this project is to design a simple UDP/TCP responder using an STC89/STC12 microcontroller on a demo board.
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.