USB
  FIFO read/write performance

Post New Topic  Post A Reply
profile | register | preferences | faq | search

UBBFriend: Email This Page to Someone! next newest topic | next oldest topic
Author Topic:   FIFO read/write performance
Tsuneo
Member
posted October 13, 2005 04:12 AM     Click Here to See the Profile for Tsuneo   Click Here to Email Tsuneo     Edit/Delete Message
FIFO read/write performance

FIFO_Read() and FIFO_Write() are essential routines for every type of transfer. SiLabs examples implement "universal" FIFO read/write routines and use them both of the enumeration process and the bulk/interrupt transfer. They are suitable for the enumeration process, but aren't good for the bulk/interrupt transfer because of its low speed performance.

The reason of its low performance is twofold.
a) Generic pointers are used to accept any type of pointer as the buffer.
b) Loop is not fully optimized by compiler
Then, implementing these routines as inline C expansions and asm subroutines using memory-specific pointer, their performance were compared.

The result was,
a) Asm subroutines was three times faster than the original
b) Inline C expansions was almost as fast as asm sburoutines except the case of xdata buffer.

Bulk transfer is time-critical, and interrupt transfer sometimes requires better performance when the other tasks are busy. Use faster routine for the interrupt/bulk endpoint FIFO.

Tsuneo

My USB topics
How to increase HID_Example In/Out packet size?
FIFO read/write performance
256000 bytes/sec Isochronous transfer
Isochronous test patch
Multi-thread and Overlapped example for USB_INT Host Application
Vendor Requests test code
USB_INT and USB_BULK on Cypress device driver

Performance of 64 bytes FIFO IN/OUT
(SYSCLK = 24MHz, USBCLK = 48MHz)

a) Original generic pointer routine (usec)
buffer idata pdata xdata
IN USB_ISR 172.5 185.8 183.1
Handle_In1 167.9 181.2 178.5
Fifo_Write 165.1 178.5 175.8

OUT USB_ISR 154.5 167.8 167.8
Handle_Out2 149.8 163.2 163.2
Fifo_Read 146.1 159.5 159.5

b) Inline C code (usec)
buffer idata pdata xdata
IN USB_ISR 69.3 72.0 80.1
Handle_In1 64.7 67.4 75.5
Fifo_Write 61.5 64.2 72.2

OUT USB_ISR 49.0 57.0 80.9
Handle_Out2 44.3 52.3 76.3
Fifo_Read 40.0 48.0 71.9

c) Asm subroutine (usec)
buffer idata pdata xdata
IN USB_ISR 59.3 62.0 62.1
Handle_In1 54.7 57.4 57.5
Fifo_Write 52.0 54.7 54.8

OUT USB_ISR 44.5 47.1 47.3
Handle_Out2 39.8 42.5 42.6
Fifo_Read 36.2 38.8 39.0


[test code]
"HID_Example" "Last updated: 25 MAY 2005"
Compiler: Keil (optimization: default)

//------------ inline C code --------------
//-------------- USB_ISR.c ----------------
void Handle_In1()
{
...
// Fifo_Write(FIFO_EP1, EP1_PACKET_SIZE, (BYTE *)In_Packet);
// inline C code
{
unsigned char i;
buf_t* ptr = In_Packet;

while(USB0ADR & 0x80); // Wait for BUSY->'0'
// (register available)
USB0ADR = FIFO_EP1; // Set address (mask out bits7-6)
// Write to the selected FIFO
for ( i = EP1_PACKET_SIZE; i > 0; i-- ) {
// USB0DAT = *ptr++; // Push to FIFO
USB0DAT = *ptr; // Separating dereference and increment results better Asm code
ptr++;
while(USB0ADR & 0x80); // Wait for BUSY->'0' (data ready)
}
}
...

void Handle_Out2()
{
...
// Fifo_Read(FIFO_EP2, EP2_PACKET_SIZE, (BYTE*)Out_Packet);
// inline C code
{
unsigned char i; buf_t * ptr = Out_Packet;

USB0ADR = FIFO_EP2; // Set address
USB0ADR |= 0xC0; // Set auto-read and initiate first read

// Unload from the selected FIFO
for ( i = EP2_PACKET_SIZE; i > 0; i-- )
{
while(USB0ADR & 0x80); // Wait for BUSY->'0' (data ready)
// *ptr++ = USB0DAT; // Copy data byte
*ptr = USB0DAT; // Separating dereference and increment results better Asm code
ptr++;
}
USB0ADR = 0; // Clear auto-read
}


//------------ Asm subroutine -------------
//-------------- FIFO_RW.h ----------------
/*
* FIFO_RW.h
*/

#ifndef _FIFO_RW_
#define _FIFO_RW_

extern void FIFO_Read_idata( BYTE fifo_adr, BYTE n, BYTE idata * ptr );
extern void FIFO_Read_pdata( BYTE fifo_adr, BYTE n, BYTE pdata * ptr );
extern void FIFO_Read_xdata( BYTE fifo_adr, BYTE n, BYTE xdata * ptr );
extern void FIFO_Write_idata( BYTE fifo_adr, BYTE n, BYTE idata * ptr );
extern void FIFO_Write_pdata( BYTE fifo_adr, BYTE n, BYTE pdata * ptr );
extern void FIFO_Write_xdata( BYTE fifo_adr, BYTE n, BYTE xdata * ptr );

#endif


;-------------- FIFO_RW.a51 ----------------
; FIFO_RW.a51 generated from FIFO_RW.c
;
; void FIFO_Read_idata( BYTE fifo_adr, BYTE n, BYTE idata * ptr );
; void FIFO_Read_pdata( BYTE fifo_adr, BYTE n, BYTE pdata * ptr );
; void FIFO_Read_xdata( BYTE fifo_adr, BYTE n, BYTE xdata * ptr );
; void FIFO_Write_idata( BYTE fifo_adr, BYTE n, BYTE idata * ptr );
; void FIFO_Write_pdata( BYTE fifo_adr, BYTE n, BYTE pdata * ptr );
; void FIFO_Write_xdata( BYTE fifo_adr, BYTE n, BYTE xdata * ptr );

$NOMOD51

$include (c8051f320.inc) ; Include register definition file.

NAME FIFO_RW

?PR?_FIFO_Read_idata?FIFO_RW SEGMENT CODE
?PR?_FIFO_Read_pdata?FIFO_RW SEGMENT CODE
?PR?_FIFO_Read_xdata?FIFO_RW SEGMENT CODE
?PR?_FIFO_Write_idata?FIFO_RW SEGMENT CODE
?PR?_FIFO_Write_pdata?FIFO_RW SEGMENT CODE
?PR?_FIFO_Write_xdata?FIFO_RW SEGMENT CODE
PUBLIC _FIFO_Read_idata
PUBLIC _FIFO_Read_pdata
PUBLIC _FIFO_Read_xdata
PUBLIC _FIFO_Write_idata
PUBLIC _FIFO_Write_pdata
PUBLIC _FIFO_Write_xdata

; void FIFO_Read_idata( BYTE fifo_adr, BYTE n, BYTE idata * ptr )

RSEG ?PR?_FIFO_Read_idata?FIFO_RW
_FIFO_Read_idata:
USING 0

;---- Variable n assigned to Register 'R5' ----
;---- Variable fifo_adr assigned to Register 'R7' ----

MOV A,R5 ; if (n == 0)
JZ rdFi_ret ; return;

MOV A,R7 ; USB0ADR = fifo_adr | 0xC0;
ORL A,#0C0H ; Set auto-read and initiate first read
MOV USB0ADR,A ; set FIFO address

MOV R0,AR3 ; R0 = ptr;

rdFi_loop:
MOV A,USB0ADR ; Wait for BUSY->'0' (data ready)
JB ACC.7,rdFi_loop
MOV A,USB0DAT ; *ptr++ = USB0DAT;
MOV @R0,A
INC R0
DJNZ R5,rdFi_loop ; loop n times

CLR A ; Clear auto-read
MOV USB0ADR,A

rdFi_ret:
RET
; END OF _FIFO_Read_idata


; void FIFO_Write_idata( BYTE fifo_adr, BYTE n, BYTE idata * ptr )

RSEG ?PR?_FIFO_Write_idata?FIFO_RW
_FIFO_Write_idata:
USING 0

;---- Variable n assigned to Register 'R5' ----
;---- Variable fifo_adr assigned to Register 'R7' ----

MOV A,R5 ; if (n == 0)
JZ wtFi_ret ; return;

MOV R0,AR3 ; R0 = ptr;
wtFi_loop1:
MOV A,USB0ADR ; Wait for BUSY->'0'
JB ACC.7,wtFi_loop1

MOV A,R7 ; Set address (mask out bits7-6)
ANL A,#03FH
MOV USB0ADR,A

wtFi_loop2:
MOV A,@R0 ; USB0DAT = *ptr++
MOV USB0DAT,A
INC R0
wtFi_loop3:
MOV A,USB0ADR ; Wait for BUSY->'0' (data ready)
JB ACC.7,wtFi_loop3
DJNZ R5,wtFi_loop2 ; loop n times

wtFi_ret:
RET
; END OF _FIFO_Write_idata

; void FIFO_Read_pdata( BYTE fifo_adr, BYTE n, BYTE pdata * ptr )

RSEG ?PR?_FIFO_Read_pdata?FIFO_RW
_FIFO_Read_pdata:
USING 0

;---- Variable n assigned to Register 'R5' ----
;---- Variable fifo_adr assigned to Register 'R7' ----

MOV A,R5 ; if (n == 0)
JZ rdFp_ret ; return;

MOV A,R7 ; USB0ADR = fifo_adr | 0xC0;
ORL A,#0C0H ; Set auto-read and initiate first read
MOV USB0ADR,A ; set FIFO address

MOV R0,AR3 ; R0 = ptr;

rdFp_loop:
MOV A,USB0ADR ; Wait for BUSY->'0' (data ready)
JB ACC.7,rdFp_loop
MOV A,USB0DAT ; *ptr++ = USB0DAT;
MOVX @R0,A
INC R0
DJNZ R5,rdFp_loop ; loop n times

CLR A ; Clear auto-read
MOV USB0ADR,A

rdFp_ret:
RET
; END OF _FIFO_Read_pdata


; void FIFO_Write_pdata( BYTE fifo_adr, BYTE n, BYTE pdata * ptr )

RSEG ?PR?_FIFO_Write_pdata?FIFO_RW
_FIFO_Write_pdata:
USING 0

;---- Variable n assigned to Register 'R5' ----
;---- Variable fifo_adr assigned to Register 'R7' ----

MOV A,R5 ; if (n == 0)
JZ wtFp_ret ; return;

MOV R0,AR3 ; R0 = ptr;
wtFp_loop1:
MOV A,USB0ADR ; Wait for BUSY->'0'
JB ACC.7,wtFp_loop1

MOV A,R7 ; Set address (mask out bits7-6)
ANL A,#03FH
MOV USB0ADR,A

wtFp_loop2:
MOVX A,@R0 ; USB0DAT = *ptr++
MOV USB0DAT,A
INC R0
wtFp_loop3:
MOV A,USB0ADR ; Wait for BUSY->'0' (data ready)
JB ACC.7,wtFp_loop3
DJNZ R5,wtFp_loop2 ; loop n times

wtFp_ret:
RET
; END OF _FIFO_Write_pdata


; void FIFO_Read_xdata( BYTE fifo_adr, BYTE n, BYTE xdata * ptr )

RSEG ?PR?_FIFO_Read_xdata?FIFO_RW
_FIFO_Read_xdata:
USING 0

;---- Variable n assigned to Register 'R5' ----
;---- Variable fifo_adr assigned to Register 'R7' ----

MOV A,R5 ; if (n == 0)
JZ rdFx_ret ; return;

MOV A,R7 ; USB0ADR = fifo_adr | 0xC0;
ORL A,#0C0H ; Set auto-read and initiate first read
MOV USB0ADR,A ; set FIFO address

MOV DPL,R3 ; DPTR = ptr;
MOV DPH,R2

rdFx_loop:
MOV A,USB0ADR ; Wait for BUSY->'0' (data ready)
JB ACC.7,rdFx_loop
MOV A,USB0DAT ; *ptr++ = USB0DAT;
MOVX @DPTR,A
INC DPTR
DJNZ R5,rdFx_loop ; loop n times

CLR A ; Clear auto-read
MOV USB0ADR,A

rdFx_ret:
RET
; END OF _FIFO_Read_xdata


; void FIFO_Write_xdata( BYTE fifo_adr, BYTE n, BYTE xdata * ptr )

RSEG ?PR?_FIFO_Write_xdata?FIFO_RW
_FIFO_Write_xdata:
USING 0

;---- Variable n assigned to Register 'R5' ----
;---- Variable fifo_adr assigned to Register 'R7' ----

MOV A,R5 ; if (n == 0)
JZ wtFx_ret ; return;

MOV DPL,R3 ; DPTR = ptr;
MOV DPH,R2
wtFx_loop1:
MOV A,USB0ADR ; Wait for BUSY->'0'
JB ACC.7,wtFx_loop1

MOV A,R7 ; Set address (mask out bits7-6)
ANL A,#03FH
MOV USB0ADR,A

wtFx_loop2:
MOVX A,@DPTR ; USB0DAT = *ptr++
MOV USB0DAT,A
INC DPTR
wtFx_loop3:
MOV A,USB0ADR ; Wait for BUSY->'0' (data ready)
JB ACC.7,wtFx_loop3
DJNZ R5,wtFx_loop2 ; loop n times

wtFx_ret:
RET
; END OF _FIFO_Write_xdata

END

[This message has been edited by Tsuneo (edited November 05, 2005).]

IP: Logged

All times are CT (US)

next newest topic | next oldest topic

Administrative Options: Close Topic | Archive/Move | Delete Topic
Post New Topic  Post A Reply
Hop to:

Contact Us | MCU User Forum

Have you seen our MCU Knowledge Base?


Ultimate Bulletin Board 5.47b