C/C++ Technical Support
Case Incidents:
Web Site Link:
FTP Site Links:
Data Manipulation on the Userproc.c
From: Jeff Subject: Re: Need Help To: Honshing Date: 04/25/99 Honshing- >I need some help on the UserProc again. When I use the CONVERSIONINFO to do >real time data manipulation on the userproc.c with the szStimName="rt" or >"rtd" and the StimMode='R' there is output wave form something.adc and >something.tim come out but the userprco (which I have been tested with RT code >with digital I/O) output does not output the digit I/O signal at all. Here is the >code, please hint me, Thank you!! Are you saying that you have a userproc.c program which works with digital I/O, and you can run from Hypersignal successfully? If not, then I suggest to get it working using Hypersignal in "user mode" first. If you can get it to work from Hypersignal, then you should be able to get it to work from a Windows C/C++ program. The C code below will cause Hypersignal to run with the second line in the Analog Conversion menu set to: a,rt,r which should be correct. What is the value of m_CSFilename? Jeff Brower
A/D and D/A Looping in Real Time
From: Yolanda Subject: Re: AD and DA Looping on M44 To: carsten Date: 07/07/99 Hi Carsten, >I was wondering if you had any examples on demo C programs that do AD and DA looping in real time. Yes, it will be rtcode.cpp which is located at \dspower\hwlib. I am also attaching a copy of rtcode.cpp just in case. >Also is it possible to download a program, like one that does continuous AD >to DA looping on all 8 channels in real time with some signal modification, >to the M44 board so that it would run through program either as soon as it >was powered up or when the user initialized it. Yes, you can use the HWLIB call DSLoadProcessorFile() to download any COFF file to the DSP. Then use the DSRunProcessor() to initiate the DSP to run. For proper sequence of initialization, please refer to rtcode.cpp for additional information. Attached is an excerpt from ISR6.ASM which shows you how the DSP code can be modified so that it will A/D and D/A more than 2 channels of data. Please search for the keyword "OUTLOOP". Please note that we have not compiled or tested the code so you might encounter some syntax error. Otherwise, the excerpt shows you the steps needed to set up 8 channels input and output. With regards, Yolanda
Casting Return Address Into a Short Int Pointer
From: Jeff Subject: Re: a few things tried... To: Scott Date: 07/31/99 Scott- >The return from DSGetSymbolAddress is DWORD which is a 32 bit unsigned int right. >Say my symbol is a short int. I have been unsuccessful in casting the returned >address into a short int pointer. These statements are performed after I have >downloaded the code to the DSP board with the init routines. Is there something I am missing? Yes! There is something... Let's say your variable in the DSP32C C (or .asm) code is a short int, called "Scott". In the host code (C/C++ or MATLAB or VB), you would do this (using C/C++ as example): dwScottAddr = DSGetSymbolAddress(hBoard, NULL, "_Scott"); Then, to write a value of 0x1234 to Scott, you would do: short int val = 0x1234; DSPutMem(hBoard, DS_GM_LINEAR_DATA, dwScottAddr / 2, DS_GM_SIZE_16, &val, 1); For a 32-bit variable in the DSP32C C code (i.e. a long int), you would do: long int val = 0x12345678; DSPutMem(hBoard, DS_GM_LINEAR_DATA, dwScottAddr / 4, DS_GM_SIZE32, &val, 1); The last value in the call is the count. To write an array, the count should reflect the length of the array. A memory type of DS_GM_LINEAR_PROGRAM could also be used, but for the DSP32C, data and program memory are the same (not true for some other DSP types). Note that the host data in the call must be a pointer, you cannot use a constant value in the DSPutMem (or DSGetMem) call. The divide-by-2 and divide-by-4 account for the unusual capability of the DSP32C (relative to other DSP devices) to perform mixed byte/short/long memory addressing. For byte accesses, you would not divide. Jeff Brower
Setting Parameters Through Userproc.c File
From: Yolanda Subject: Re: AD and DA Looping on M44 To: carsten Date: 07/14/99 Hi Carsten, >Thanks for all the info, The experimental code works. All 8 channels are >looping now. I have a question about the delay between the input and output >signals when using the a,rt,r command. It seems to vary depending on how >many channels are being used. I wondering if adding too much code to >userproc would cause this or something in isr6. Please check
" The 'a' entry causes an aquisition operation. The 'rt' entry causes real-time simultaneous input/output operation (mode 6). The 'rtd' entry works the same way, except recording to waveform file is enabled. " # of Channels vs delay time. 1) Using Hypersignal Macro In Hypersiganl Macro, the default buffer size is 12288. So if you have 2 channels, each channel will have 6144 samples. if you have 8 channels, each channel will have 1536 samples. Therefore, if you have more channels, you will have less delay time due to the fact that less samples will be collected for each channel. 2) Using HWLIB Usually, we will define bufSize which is the required number of samples for each channel. Then we will defined DSP_BUFLEN to be: (in MATLAB syntax) PutVarMem(hBoard, DSP_BUFLEN, bufSize * numChan); In this way, the delay time will be independent of number of channles. Hope this helps. Yolanda
Changes to rtcode.cpp to Result in Correct Data
From: Jeff Subject: Re: tried suggestions... To: Scott Date: 08/09/99 Scott- >I made the following changes to rtcode.cpp and did not see the correct >data displayed to the screen: > > BOOL InitHardware(LPCSTR szBoard) { > . > . > // get address of input time domain data > dwBufferBaseAddr = DSGetHVarMem(hBoard, DSP_TIMDATAADDR); > DSPutHVarMem(hBoard, DSP_TIMDATAADDR, dwBufferBaseAddr + >32768); > // put output time domain data buffer after input buffer > DSPutHVarMem(hBoard, DSP_STMDATAADDR, dwBufferBaseAddr + >2*wBuflen*NumChan + 32768); > return TRUE; > } > >Is there anything else I need to do? Yes. You need to change the actual values used later in your program. The code above should be: // get address of input time domain data dwBufferBaseAddr = DSGetHVarMem(hBoard, DSP_TIMDATAADDR); dwBufferBaseAddr += 32768; DSPutHVarMem(hBoard, DSP_TIMDATAADDR, dwBufferBaseAddr); // put output time domain data buffer after input buffer dwOutBufferBaseAddr = dwBufferBaseAddr + 2*wBuflen*NumChan; DSPutHVarMem(hBoard, DSP_STMDATAADDR, dwOutBufferBaseAddr); This way, the correct values for dw...BaseAddr will be used subsequently in your program anywhere they are referenced, and "consistency shall be maintained" !! For example, in subsequent DSGetMem calls, you would use dwBufferBaseAddr, and in DSPutMem calls, you would use dwOutBufferBaseAddr. Jeff Brower
Calling Hamm0 Function From Userproc.c
From: Jeff Subject: Re: strange... To: Scott Date: 08/13/99 Scott- >I have not gotten [hamm0] function to work being called from userproc.c Please let me see the current userproc.c source. One thought is that hamm0() is going to expect data in floating-point format, and data coming into userproc.c is 16-bit integer (A/D converter data). >It compiles fine and I can see the symbols for hamm0 show up in the W32LINK.MAP file. >When I run it, the green pen draws the inital data and it does not seem to be getting >the buffer ready message to update the screen. If I hit the hardware config button and >then hit the ok button, it looks like the output changes for one frame and then it freezes again. Don't do that; this is basically a reset, causing real-time acquisition to restart. If you can't see data on the rtcode trace, then processing is not correct on the DSP side (userproc.c) and this is where to focus. >Any ideas on this problem? I may start rolling my own programs for windowing >and FFT/IFFT if I can not figure out what's going on. There are window.s and fft.s asm. files included in the DSP32C source code interface. You can call these functions relatively easily from C programs. The best way would be to call a .asm "stub" which then calls the asm. functions; to get the code for the stub, look at modul3.s, where Window() and fft() functions are called. >Have you guys used any of these functions in libap32c.a ?? No, we have not. But if they are Lucent C compiler compatible, and use r14 as a stack pointer, they should work. Jeff Brower
Calling Libap32c Functions
From: Jeff Subject: Re: calling libap32c functions To: Scott Date: 08/19/99 Scott- >#include> >float A[2][2] = { > 1.0, 2.0, > 5.0, 6.0 >}; >float B[2][2] = { > 1.0, 2.0, > 2.0, 3.0 >}; >float C[2][2]; >void >UserProc(ptrIn, ptrOut, nLen, nNumTrace) >short int* ptrIn; >short int* ptrOut; >short int nLen; >short int nNumTrace; >{ > >#define x ((short*)ptrIn) >#define y ((short*)ptrOut) > >register float *a = A[0]; >register float *b = B[0]; >register float *c = C[0]; > > > mat2x2((float *)a, (float *)b, (float *)c); > >} It looks like there is a good reason to use registers to hold the pointers when calling libapi functions. If so, try: register float *a = &A[0]; register float *b = &B[0]; register float *c = &C[0]; mat2x2(a, b, c); If register pointers do not need to be used, try: mat2x2(A, B, C); Or alternatively: mat2x2(&A[0], &B[0], &C[0]); Jeff Brower
Calling Libap32c Functions in Regards to r19
From: Jeff Subject: Re: calling libap32c functions To: Robert Cc: Scott Date: 08/19/99 Robert- a-ha! r19, yes that could be a problem. I think you can also use this: call UserProc(r18) r19e = 4 /* set r19 before entering call */ r14e = r24 - N /* realign stack */ r19e = *page /* restore r19 to Sig. "page" value */ Signalogic code uses r19 as a "page pointer" which is used by some routines and code sections to maintain board independence for different memory modes and different starting memory banks. I think we had to do this at one point because of the large number and variety of DSP32C boards that were being supported. Note that r19 usage is documented in the Signalogic DSP Software Users Guide .hlp file, under "DSP32C Source Code Interface Modification Notes" section. Note also that the above method could still be a problem if a Signalogic routine is called in turn from UserProc or libap32c functions. Jeff Brower >Ack I remember numerous occasions where not only calling ap32c functions >would fail, but c runtime functions as well. I dont remember exactly how i >corrected it, but here is one solution: >Make the correction in the modul6.s file > >/* REI */ > r19e= 4 /* C code expects this */ > nop > call UserProc(r18) > nop > r14e = r14 - 16 /* re-align stack pointer */ > nop > r19e=0 /* Signalogic code expects this */ > nop > >by the time i figured out how to get userproc.c working, i basically was living and >breathing dsp32c assembly. I've finally gotten to the point where i dont need to >hack directly, so I have promptly forgotten most of it. > >Robert > >On Wed, 18 Aug 1999, Scott wrote: > >> Hi, >> >> Jeff tells me that you have been successful at programming the DSP32C board >> in C. Have you been able to use the AT&T C application library libap32c.a? >> >> I have been able to access functions in this library using test code and d3bug. But have had >> problems calling some functions from the userproc.c code used with the signalogic software. >> It seems the functions that give me problems are the ones that get passed array pointers. >> >> The code I have tried is simple. I have attached a sample userproc.c that has caused >> the system to hang. Can you execute something like this? >> >> Thanks,
Modification of rtcode Causing Flatline Flashes
From: Jeff Subject: Re: Some Success ??? To: Glenn Date: 08/31/99 Glenn- >1) Userproc builds OK with lnk.bat. I ran the 0.75*x[n] + 1000 example >and even though I had no input data I received noise through (with the expand punched up). > >2) I modified rtcode.c to download my b.out file (under Visual C 1.52c) >and got the noise pass thru, however, there were flashes of flatlines in >the display. Keep in mind that rtcode is not "synchronized" to what the DSP is doing in mode 6; that is, the DSP doesn't wait for the host if the host gets behind. This means that when the host gets done displaying data (or whatever processing), if it takes a long time, then the host doesn't know if the next buffer ready message is "old" or not. If it's old, the host could read from the same buffer the DSP is working in, causing inconsistent results; i.e. showing data not processed yet by the .75*x + 1000 on time, then showing processed data the next. Under Windows, things like displaying a buffer of data using Win GDI calls do tend to take a bit of time. At sampling rates of 120 kHz, with a typical buffer size of 1000 to 10000 points (10 msec to 100 msec), the host certainly is going to have a hard time staying in real-time; with buffer sizes less than 1000 there's no way. >This occurred at 20k, and 40k sampling rates. 110K sampling was even >odder, still with Flatline flashes. > >Question : Can we do a 120K sample and do a clean bit of real time >processing on the data, without baseline bounce ? There is also a mode 2 (digital scope), which allows the DSP and host to synchronize. In this case, the host can go off and do any type of display or processing, for any amount of time, and the host and DSP will always stay synchronized, one buffer apart, and never "partake of each other's buffer". But mode 2 is not continuous from the DSP's point of view; analog input data can be missed if the host cannot stay in real-time. We call this "frame based operation", rather than continuous operation. It is typically used in instrumentation applications, where the operator is not concerned as much with processing all points as with seeing an accurate snap-shot of what is happening, with no artifacts. It depends on what you need your DSP code to do. If you want continuous analog I/O operation on the DSP side, then you should use mode 6. If you cannot guarantee fast host operation in mode 6, then what you might do is create an isolated, "processed" data buffer in the DSP code, where you put results when they are finished, independently of what the DSP is doing in handling the double-buffered continuous input/output data. The host can then read from the isolated buffer as needed, on its own time schedule. Even if the DSP is putting new data there at the same time the host is reading, there (likely) won't be a dramatic change in what the user / operator sees. >3) I modified the dscope.c and built the dscope32 project under Visual C >5 (after finding out it would not build under 6.0). It also had the baseline >flashes, but the data itself (again noise) was much flatter. Dscope32 should build fine under Visual C 6.0. What error did you get? Did you open the dscope32.mdp file as the project file? If you are running the dscope dmeo, there should be no flashes whatsoever -- data display should be smooth, with no spikes or drop-out sections. What is your driver selection in the DSP/Analog Hardware Selector dialog box? Are you using "SigC32" or "SigC32 with no DMA"? You might try the "no DMA" driver selection. >Question : Shouldn't rtcode and dscope32 have worked the same ? Did >I miss something in the mod of dscope.cpp ? See comments about mode 6 and mode 2 above. >Attached are my files. Note that my first important bit of application to >demonstrate is a clean 49 KHz AM modulation of the input at an fs of 120 KHz. >Should be simple. Tell me what this means on the DSP side. What processing must be applied? Note that in mode 6, 120 kHz is pushing real-time limits. If you want very fast DSP processing, for example, more than 120 kHz in mode 6, you have to mess with the mode 6 ISR (interrupt service routine). Here are some general notes about this: -you can streamline the isr6.asm file, for mode 6 ISR (interrupt service routine). Features not required, such as triggering, recording maximum amplitude tracking, digital scale and offset, etc. should be removed. -you will need to use the Texas Inst. C3x assembler to assemble these changes, then re-link. The new COFF file (i.e. executable C3x program file) can then be used with standard Hypersignal and DSPower functions. See the section in Signalogic DSP Users Guide about modifying C3x Source Code for more information. -at some point, what you might want to do is add a user-defined property (variable in asm or C code on the DSP side) which you can set from the host, and instruct the DSP code whether to use the default ISR 6, or the "fast ISR 6". This would allow you to use the built-in mode 6 functionality when needed, and avoid it when higher performance is needed. Jeff Brower
W32DEF File and reset.s File
From: Jeff Subject: Re: wait states and other stuff To: Scott Date: 08/31/99 Scott- >Do I need to explicitly set the external memory waits >states to zero within area A? I thought I read somewhere >that this was done already so I did not have to worry about that in userproc. Already done. See reset.s file. >In your last email you mentioned anabfk. I noticed that it is defined >or set to zero in the W32DEF file. So it looks like this must define >an offset since the memory 0x0000 0x200 is reserved for signalogic stuff. Right? Be careful, the value in w32def.s is the *default* value. The DSInitBoard and DSInitProcessor calls see the default value, and change the value depending on the board type and amount of memory. There are 2 important notes about this: -if you change the default value in w32def.s, re-assemble and re-link, then the host will not touch the value -to get the actual value being used, you must do a DSGetHVarMem(hBoard, DSP_TIMDATAADDR) call and read the value after downloading your program (i.e. calling DSLoadProcessor) >What is the purpose of the stimulas buffer stmbfk? It is set to 0x10000. Output buffer (actually 2 buffers, each of size determined by DSP_STMBUFLEN property). Anabfk is input, Stmbfk is output. Of course, anabfk is also 2 buffers, size determined by DSP_BUFLEN property. Note that in most applications, DSP_BUFLEN and DSP_STMBUFLEN should be set the same. >So the actual address of the input data found below is 0x43008 for the input data right? Sounds reasonable. >My C buffer starts at 0x41f4 according to the MAP file and is 0x1000 long. >So it looks like there should not be a problem of overlap there. Not with anabfk, but what about with code? Where is your last executable code? What is the last address it consumes? You have to study the map file to see what code section (including .text, .data, and .bss) is highest. >Looking at what comes back when I do: > >// get address of input time domain data > dwBufferBaseAddr = DSGetHVarMem(hBoard, DSP_TIMDATAADDR); > >// dwBufferBaseAddr gets set to 10240 > dwBufferBaseAddr += 32768; > >// dwBufferBaseAddr now set to 43008 > DSPutHVarMem(hBoard, DSP_TIMDATAADDR, dwBufferBaseAddr); > >// put output time domain data buffer after input buffer >// dwOutBufferBaseAddr is set to 45056 > > dwOutBufferBaseAddr = dwBufferBaseAddr + 2 * wBuflen*NumChan; > DSPutHVarMem(hBoard, DSP_STMDATAADDR, dwOutBufferBaseAddr); One possible problem here: the output buffer is only 2048 bytes higher than the input buffer. This means the input buffer size can be 512 samples max before bumping into output (i.e. 512 x 2 buffers x 2 bytes per sample). What is your buffer size? >One last question, if it is taking you too long to do the processing >to keep up with real time acquisition, do you need to do nothing for >the next couple of frame cycles to catch up and then do your >processing again? Like in the CAIP work they calculate sets of data at most >twice a second. So do they take a snapshot of data, process it, skip a few >frames to catch back up, take snapshot, etc.? That is one way to handle it. Keep in mind that in a system using a reasonably fast sampling rate, say anything 8 kHz or more, the user can't possibly make sense of a display showing every frame--even if the host code was very, very fast and the system can do it. And Windows C/C++ or Visual Basic or other code isn't going to be this fast, anyway. Most user-interface displays are concerned with giving the operator an accurate snap-shot, which updates a most a few times per sec. Jeff Brower
Analog Device C Runtime Procedure
From: Yolanda Subject: Re: Question To: Lionel Date: 09/07/99 Hi Lionel, >I would like to know how can I use a Analog Device C runtime procedure in your >UserProc.c. For example, I have a procedure Foo in a Foo.h header file. >How can I can Foo in the Userproc Since Userproc.c is a C procedure, you can call Foo from Userproc as you will in any C program: eg. void Userproc(void){ foo(100) /* call foo and pass 100 as parameters */ } If you want to call C routine from ASM or vice versa, then you will have to Consult the ADSP-21000 Family C Tools Manual Chapter 4 "Assembly Language Interface" for detail information. We call userproc() in our ASM file too. UserProc() is called from MODUL6.ASM. You can use that as a reference. Almost forget, you need to compile your foo.c and link it with the other files. To link it, edit A60link.cmd such that it include the object file of foo.c. Also, you might need to modify the archetecture file, A60link.ach. With regards Yolanda
Corrected UserProc Files
From: Jeff Subject: Re: Corrected UserProc files To: Lionel Cc: Jean Date: 09/21/99 Lionel- Yolanda has put together some new files and information which I have summarized here. 1) As shown in the error message in your compile.jpg screen print, "the memory size for section seg_pmco in the architecture file is insufficient", it was necessary to modify the seg_pmco segment in the a60link.ach architecture file to increase code space. We made this change for you, and the modified a60link.ach is attached below.
Note that if in the future, as you add more code or data areas, you may have to edit the different segments in a60link.ach to accommodate these changes. 2) Since you would like to use Analog Devices library files, in the linker batch file (lnk.bat) you will need to add the C Runtime library linker option, -lc. Note also that I think you can put the -lc option directly in the .cmd file. 3) In VibProc.c (formerly userproc.c), you have called a SWAP Macro which is defined in MACROS.H. However, macros.h is not included as the header file, so we add that in for you, too. Please remember in the future to add all .h files that will be needed for your application--standard C programming practice.
4) Note that our changes should enable to you successfully compile and link. This does not guarantee that your code will run! There may be some debugging in your future. Jeff Brower
Compile Error: LNK1136(Invalid or Corrupt File)
From: Jeff Subject: Re: NIST problem with HwLib + M44 To: Marc Date: 10/13/99 Marc- >I try to use your DSPower-HWLib Software. Compiling your dscope.cpp >example program with Visual C++ 6.0 under Windows 98 produce the error >LNK1136 ("invalid or corrupt file") for the hwlib.lib file. The >explanation for this error is : "The input file either has a corrupt >header or is zero size or abnormally small". Please load the "dscope32" project (browse and click on \dspower\hwlib\dscope32.mdp filename). I think what you are trying to do is load the "dscope" project, which is a Win16 project. Dscope32.mdp is a Win32 project for Visual C++ 5.0 and higher. It references hwlib32ms.lib, hwmgr32ms.lib, enmgr32ms.lib, and tlib32ms.lib, which are .lib files suitable for Microsoft Visual C++. Try this and tell us what happens. Also, when was the last software update you received from Signalogic? We have made a lot of improvements for M44 and module support. The current version of DSPower-HwLib software has more Visual C++ demos (including simultaneous analog I/O), more MATLAB demos, and more Visual Basic demos. Jeff Brower
DSP to Host Communication
From: Jeff Subject: Re: DSP to HOST Communication To: Scott Cc: Hanh Date: 10/28/99 Scott- >My machine at home seems to be doing weird things but at least it was able to >send data to the host program via the above function calls. Since I have been >having problems with the DSP board on my home machine, I have been using the >machine at school that I also installed a signalogic board on. It seems to run >my DSP code ok but I can not get anything across to the host code. > >The following is defined in userproc and host code: > >userproc.c: > >short int tdoa1; > >userproc(){ > >tdoa1 = 5; > >} > >rtcode.cpp: > >DWORD tdoa_ptr; > >short int T12; > >Winmain(){ > > tdoa_ptr = DSGetSymbolAddress(hBoard, NULL, "tdoa1"); > >} > >winproc(){ > >switch() > > case WM_BUF_READY (or something like that) > > DSGetMem(hBoard, DS_GM_LINEAR_DATA, tdoa_ptr/2, DS_GM_SIZE16, &T12, 1); > >I am always getting the value zero for T12. The declarations and divide-by-two in the above code look Ok. What is the value of tdoa_ptr after DSGetSymbolAddress call? Are you making DSGetSymbolAddress call after DSLoadFileBoard() or DSLoadFileProcessor() call? What is the return value of the DSGetMem() call? I don't think it makes any difference, but you might also try the DS_GM_LINEAR_DATA_RT parameter in the DSGetMem() call. >With the different CDs that you sent with possible bugs, could it be that I >don't have the latest on this machine to support this? There is always stuff we are adding and bugs we are fixing. But the GetSymbolAddress call has not changed or been in for repair in a long time. It should work fine in your software / CD version. >Although I do see the prototype for DSGetSymbolAddress in the header file. >Is there a new realease of the supporting code with patches and updates? Yes, there is a new release. I have asked Hanh to send to you an update CD so that you have the latest, although I don't think it will make a difference for GetSymbolAddress related functionality. Jeff Brower