Hi I want to send an array of data to a USB pen drive using LPC1768. and USBhostlite code is available here: >ics.nxp.com/.../ and I removed Uart from codes so that it just copies data to usb. the codes that i modified are:
void Main_Write(void){ USB_INT32S fdw; USB_INT32U bytes_read; char temp[8]; USB_INT08U temp_buf[504]={0}; int i,j={0}; bytes_read=9; fdw = FILE_Open(FILENAME_W, RDWR); if (fdw>0) { do{ sprintf(temp,"%d",bytes_read); for (j=0;j<9;j++){ temp_buf [i]=(temp[j]); i++; } temp_buf [i]=0xA; i++; bytes_read ++; }while(i<=504); FILE_Write(fdw,temp_buf,504); FILE_Close(fdw); }else{ return; } }
sprintf converts bytes_read to ascii codes then it is sent to temp_buf using a do{...}while() then an "MSWRITE.TXT" file is created in usb disk and finally the buffer will be written to the usb disk.
these codes work properly, when size of the buffer(temp_buf) is less than "90". but when i change the buffer size to a bigger number(eg: 504), the program doesn't work! it even doesn't creates any empty text file(due to file_open) i traced file_open routine and i found that the problem is in MS_BulkRecv routine. because the program runs before calling MS_BulkRecv and halts during calling this line. this routine is as follows:
*********************************************************************************************** * RECEIVE THE BULK DATA * * Description: This function is used to receive the bulk data * * Arguments : None * * Returns : OK if Success * ERR_INVALID_BOOTSIG if Failed * **********************************************************************************************/ USB_INT32S MS_BulkRecv ( USB_INT32U block_number, USB_INT16U num_blocks, volatile USB_INT08U *user_buffer) { USB_INT32S rc; int i; volatile USB_INT08U *c = user_buffer; for (i=0;i<MS_BlkSize*num_blocks;i++) *c++ = 0; Fill_MSCommand(block_number, MS_BlkSize, num_blocks, MS_DATA_DIR_IN, SCSI_CMD_READ_10, 10); rc = Host_ProcessTD(EDBulkOut, TD_OUT, TDBuffer, CBW_SIZE); if (rc == OK) { rc = Host_ProcessTD(EDBulkIn, TD_IN, user_buffer, MS_BlkSize * num_blocks); if (rc == OK) { rc = Host_ProcessTD(EDBulkIn, TD_IN, TDBuffer, CSW_SIZE); if (rc == OK) { if (TDBuffer[12] != 0) { rc = ERR_MS_CMD_FAILED; } } } } return (rc); }
can any body tell me why this increase in buffer size causes the program not to work? and help me to solve it?
thanks Amir
> > What do you think the initial value of 'i' is?..
You haven't answered the question. (I think that in answering the question you will discover something important.)
> the compiler didn't tell me any warning.Because 'i' is a local variable.
Have you perhaps suppressed or overlooked the warning? The compiler (armcc) *does* give me that warning when I build the code you posted. In fact, part of the reason it is able to give the warning is *because* 'i' is a local variable.
(Even if the compiler didn't give you a warning (for example, if it wasn't smart enough to do so) that would not change the fact that there is a problem with the initial value of 'i' in the code. The compiler is not required to warn about all 'undefined behavior' and it doesn't.)
> > - Why do you read uninitialized elements of 'temp' beyond what 'sprintf' has written? > i can't understand you. Can you explain this to me, more?
sprintf only writes the bytes up to the terminating '\0', so the first time it's called it effectively does:
temp[0] = '9'; temp[1] = '\0';
but then your code also reads temp[1]... which have never been written. This is technically 'undefined behavior' but is unlikely to do anything more harmful that read some arbitrary values. Still, you probably don't really want them in your output buffer.
> What do you think the initial value of 'i' is?.. int i,j={0}; Keil debugger recognizes the initial value as '0'.
>sprintf only writes the bytes up to the terminating '\0', so... Thanks I got it! it will be solved with an if{...}.
even if i remove if{...} (after FILE_OPEN), the problem exists.
but I was Wrong. the max buffer size is 360. when i define a new buffer it doesn't works! Total size of the buffers must not exceed 360. and i don't know how to solve it!
Best Regards Amir
"Keil debugger recognizes the initial value as '0'."
So when you have an uninitialized variable and look at it with the debugger, you think that the value you see represents a valid initialization? Don't you think it matters what contents there was in RAM before you entered the function?
I think your method of using the debugger and look is a very bad method. Don't you think it is sooo much better to let the language standard decide if the good is ok or not? Or do you think any program without known or seen error is a correct program?
i saw in the debugger that previous value of 'i' resets to 0. doesn't int i,j={0};, works as initialization too? OK, I initialize the i in a separated line.; is this helps the buffer to have the larger Size?
You saw in the debugger a machine-code instruction that assigned a value of 0 to i?
OK! I thought the compiler creates what shows in the debugger. I suppose to initialize the i separately. and concentrate on the buffer size.
Thanks Dr Westermark Amir
Auto variables takes whatever values that are in the memory at that specific memory location.
The debugger then allows you to see the value.
But it is up to you to make sure that there is an assign that guarantees that the variable has the _correct_ value. And not just happens, by pure chance, to get a random value that looks "good".
doesn't int i,j={0};, works as initialization too?
It doesn't. Not for 'i', anyway.
Thanks Every body! My problem was solved I defined the array before main (after #includes). and it worked. I don't know why save the data in stack can cause this problem.
So you decided to do random "fixes" instead of trying to understand the code. Is that really a good methodology? Will it give you any advantages when you write your next program?
No! It is Crystal clear that i must improve my c language and remember what I have Learnt many years ago and have forgotten it already, But I didn't solved it by TRY and ERROR! Just one of my Friends Helped me with this! and told me that probably the problem comes from stack.
So not you, but your friend, solved it by trial and error then. Or why else the "probably comes from stack"? How many minutes would it have taken to verify if that was true or not?
Bugs shouldn't be fixed until you know _why_ they are bugs. And if the problem you see can be explained by that bug. Else, you will not know if the code changes fixes the bug or just (temporarily) hides the bug - or moves the problem somewhere else.
There is nothing "probable" about the amount of stack space needed for:
USB_INT08U temp_buf[504]={0};
So - did your program have room for that variable on the stack or not? Making it into a global variable means it consumes RAM all the time. Having it on the stack means the stack must be large enough. But that the same RAM can be used for other auto variables in other call trees too.
Of course there are other differences between auto and global variables: If you take the address of an auto variable and uses that address after the function returns, you can get very nice problems.