We are running a survey to help us improve the experience for all of our members. If you see the survey appear, please take the time to tell us about your experience if you can.
Hi All,
TARGET I am using C51 tools to compile a simple app for an ST uPSD33xx.
OUTLINE The problem I am experiencing maifests itself as an incorrect value in a pointer passed as an argument to a reentrant function.
DETAILS OK, I am writing a serial driver. Each channel of the serial driver has a struct to hold pointer to a data buffer, number of bytes, etc, etc. Each struct is static in XDATA as is the data buffer for each channel:
typedef struct serial_data_buffer_t { int8 xdata *pBuffer; uint16 read; uint16 write; uint16 length; uint16 bytesInBuffer; #ifdef SERIAL_HW_FLOW_CONTROL uint16 lowWater; uint16 highWater; #endif } SERIAL_DATA_BUFFER_T; typedef struct serial_channel_t { uint8 channelNumber; int32 baudRate; bool flowControlActive; bool txRunning; SERIAL_DATA_BUFFER_T txBuffer; SERIAL_DATA_BUFFER_T rxBuffer; } SERIAL_CHANNEL_T; #ifdef USE_SERIAL_PORT1 static int8 xdata serial1TxDataBuffer[SERIAL_PORT1_TX_BUFFER_SIZE]; static int8 xdata serial1RxDataBuffer[SERIAL_PORT1_RX_BUFFER_SIZE]; static SERIAL_CHANNEL_T xdata serialChannel1; #endif /* #ifdef USE_SERIAL_PORT1 */ #if (defined USE_SERIAL_PORT0) || (defined USE_SERIAL_PORT1) static void recieveByte (SERIAL_CHANNEL_T *pChannel) reentrant; static void sendByte (SERIAL_CHANNEL_T *pChannel) reentrant; static uint16 _writeSerial (char* buffer, uint16 numBytes, SERIAL_CHANNEL_T *pChannel); #endif /* #if (defined USE_SERIAL_PORT0) || defined (USE_SERIAL_PORT1) */
The pBuffer pointer is initialised at run time using straight forward assignment:
serialChannel1.txBuffer.pBuffer = (int8 xdata*) &serial1TxDataBuffer[0];
When a client wishes to transmit some data the following call chain takes place:
writeSerial1 ("Hello World!\n", strlen ("Hello World!\n"));
calls
bytesSent = _writeSerial (buffer, numBytes, &serialChannel1);
sendByte (pChannel);
The routine sendByte is declared reentrant as it is called from background (as just described) but also from the ISR (to contiune the transmission of the contents of the buffer).
The problem (first) occurs when sendByte is called from _writeSerial. The pChannel argument passed into sendByte is OK prior to the call (as viewed with the debugger), but once inside sendByte the pChannel argument contains a crazy value.
What could be causing this problem? Is there some fundamental problem or rule I am breaking here to cause this problem?
Any help appreciated
Cheers
Andy
Andy,
Regarding the functional calling from background and ISR - what, specifically, is the problem(s) with this? I have seen nothing in the Keil documentation to suggest that doing so in a 'bad idea'. In fact the tool chain supports directives to do just this (NOAREGS/ARGES, reentrant, etc - section 8.4.2.5 of the C51 Primer). Are you referring to the run-time overhead of making such a call?
As Drew has already pointed out, my basic concern is with the cost in terms of execution speed. My own tendencies lead toward duplicating the code in the ISRs in order to avoid reentrant function calls (and often to just avoid function calls at all). If the bit of code is large enough that duplicating it in the ISRs is difficult in terms of code size, then that's probably an indication that it doesn't belong in the ISR itself, but in main code. Those things notwithstanding, it's not a hard-and-fast rule, but just a bit of hard-earned advice I thought I'd pass along.
Regarding the 'crazy value' is it either 0x0000 or 0xFFFF and the data being pointed to is also not correct - all zeros - so something is definitley not 100%. What common problems are there regarding passing generic/memory-specific pointers to functions?
This situation is indeed strange. Unless you're missing something very obvious in the code (which is unlikely in what you've posted), you may be running up against the wall I call the "real-world." The fact that the call to a reentrant function isn't going well leads me to wonder about the state of the stack. When a function is tagged as reentrant, the compiler does not generate code to pass parameters in registers, but instead passes them on the stack. What is the value of the stack pointer when you're in the bad function call? One way to quickly get a feel for your stack usage is to initialize it all to some known value (like ascii 'X') at startup, then look at it when your program is running. If there are no 'X's left, you know you're at least perilously close to a stack overflow. Give that a try and let us know the results.
-Jay Daniel