I have some code to transfer a large amount of data over a SPI port running at the system clock/2 so I need my code to be as fast as possible. The code generated for my current method does not seem to be as optimal as it could be. I am using optimization (8, speed) with the 7.07 C51. Here is a simplified version of my code:
//this variable set in buffer data function static unsigned char xdata * data spiDataPtr; void transferData(void) small { //do not want to store changes in //spiDataPtr so use temp pointer unsigned char xdata * tempPtr; unsigned char data i; unsigned char data temp; tempPtr = spiDataPtr; //transfer set block size for(i = 0xff; i != 0; i--) { SPIDATA = *tempPtr; //initiate transfer tempPtr++; //prepare for next send while busy transfering while(!SPITXDONE); //wait for transfer to complete temp = SPIDATA; //read to avoid colission error } }
Here's what I get when I compile with C51 V7.07. Note that I just made up address values for the SPI SFRs.
; FUNCTION transferData (BEGIN) ; SOURCE LINE # 6 ; SOURCE LINE # 13 ;---- Variable 'tempPtr' assigned to Register 'DPTR' ---- 0000 850082 R MOV DPL,spiDataPtr+01H 0003 850083 R MOV DPH,spiDataPtr ; SOURCE LINE # 16 ;---- Variable 'i' assigned to Register 'R7' ---- 0006 7FFF MOV R7,#0FFH 0008 ?C0001: ; SOURCE LINE # 17 0008 E0 MOVX A,@DPTR 0009 F590 MOV SPIDATA,A ; SOURCE LINE # 18 000B A3 INC DPTR 000C ?C0004: ; SOURCE LINE # 19 000C 3091FD JNB SPITXDONE,?C0004 000F ?C0005: ; SOURCE LINE # 20 000F 859000 R MOV temp,SPIDATA ; SOURCE LINE # 21 0012 DFF4 DJNZ R7,?C0001 ; SOURCE LINE # 22 0014 ?C0006: 0014 22 RET ; FUNCTION transferData (END)
Hi, I think you should use #ASM/ENDASM for routines which must be as fast as possible really. Even example shown above is not fast enough. Really, it may be optimized much more:
MOV R7,#0FFH LOOP: MOVX A,@DPTR JNB SPITXDONE,$ XCH A,SPIDATA INC DPTR DJNZ R7,LOOP RET
Ah, thanks for the information Jon. I was indeed doing a little bit more in the function but I did not think it would matter as I was not manipulating any other xdata variables, just resetting and reusing the tempPtr. After moving the extra code out of the function it compiled the way I thought it should have initially. The ASM example is interesing Oleg and I will keep it in mind for future projects, but for mantainability reasons I am trying to avoid ASM in this project. I actually have the C code set up to do the DJNZ during the wait state and with the DPTR being incemented properly now the extra code of the C version still takes just below the SPI transfer time. There will only be 2 clocks lost by not having the XCH command and that is acceptable. I am using a Cygnal chip so the commands take very few clock cycles. The SPI tx done flag is indeed bit addressable.