Tutorial and Hard Learned Lessons
|Original Name:||Renamed to:|
We wrote a simple C program, and got all sorts of compile and link errors. The biggest problem was that it couldn't find the _int00 entry point. It took a while but we realized we needed a linker.cmd file. We found one under the sample program in the CSL download, and used this: c672x_c67.cmd. Another issue we found was that the CSL framework has changed for the C672X, and so there is no CSL_INIT function, which older versions of the CSL documentation claim that you need. Once we remove this, we got the program to compile, link and download. Yea!
Library files can be dropped and dragged into the project, just like any source file. This is a nice feature.
The first step with any new controller design is to blink an LED. We were able to use the McAsp libraries from the CSL to configure the port pins as GPIO. We used the CSL_mcaspHwSetupRaw function to configure some of the pins as GPIO, set their direction to OUT, set them to an asserted state. Unfortunately, the pins wouldn't go high. Turns out the problem is that the PDCLEAR register was getting set after the PDOUT was set, with the call to the function, and so it was undoing the register contents of PDOUT. After we figured this out, we were able to get an LED lit.
I've noted that the CSL API is very limited. They don't have any functions to read the value of the McAsp registers, which is frustrating.
TI doesn't supply any GEL files for the C672X. One of the big questions I had was do you need a GEL file to connect to a C6722 chip. I asked TI for a sample GEL file and they told me to buy the PADK for $2000. It turns out you don't need a GEL file to connect.
I noticed that when I was trying to debug the McAsp port pins that they only had one register set for the McAsp, when in reality there are two ports. Same for other peripherals such as the SPIs. I also noticed that the registers where split between the two ports This made it difficult to debug, since what was displayed was the wrong memory location. I contacted TI and they acknowledged the error, in CCS. They gave the following link for as a solution:
This tells you to create custom XML files to configure register sets. Shouldn't TI solve this issue and create the correct XML file - not an end user. Maybe I should sell them the XML file once I get it working.
I've follows the directions in this link and after about 8 hours of messing with it was unable to get it working. I used a GEL file to load in the device registers, but the register window comes up blank and undefined.
I've sent a help request to TI and they told me that for the 6722 it doesn't retrieve it's values from an xml file, and were unwilling to provide a device file. They told me tough luck and to use the memory view instead.
I noticed that many of board configurations used by CsConfig are XML files, so I tried to see if I could create my own board file, and had some success, as described in this link:
You need to create your own board platform so that you can select it as a BIOS/DSP configuration. Under the [BIOS]/packages/mycompany/platforms/myboard there are a bunch of ".tci" template files, which you can use as a basis for setting up your custom platform file. Read the "readme.txt" file for instructions. We based our file off of the C6722 template.
need to modify two items within a comment !Name, and !Description.
Note these must remain in the comment, don't un-comment the lines. For
* !NAME! Daycounter.platforms.Day6722
* !DESCRIPTION 6XXX! Daycounter - 6722 Board Configuration
* !NAME! Daycounter.platforms.Day6722
Save this file as Platform.tci, and store in a directory [BIOS]\packages\Daycounter\platforms\Day6722
Now open and CCS and select "File/New BIOS/DSP Configuration" from the menu. Select the C6XXX tag and you should see the new custom board. Select this board, and a BIOS configuration window will pop up. This will be saved as a ".tcf" in your project directory file for future reference. You must add this ".tcf file to your project.
When the ".tcf" file is created, there are several other files which are created:
ProjNamecfg.h, ProjNamecfg_c.c, ProjName.cdb, ProjNamecfg.cmd
the linker command file cfg.cmd must be added to the project, or you will get a whole bunch of linker errors. Don't use the cdb file in place of the tcf. The .h and _c.c files will appear under the "Generated Files" directory. Include the cfg.h file in your source code.
When you build the project, the tconf.exe program executes the ".tcf" script. The compiler should be smart enough to know when ".tcf" file has been updated. To be sure you can do a "rebuild all", to get any changes to the script to be included in your program.
Ocasionally when you click on the ".tcf" file from the project window, nothing happens. I speculate that there is some sort of lock file mechanism that they use that get's out of sync. I haven't figured out which processes need to be killed to free the lock, but you can always restart windows to fix the issue.
If you've been using the evaluation copy of CCS and then decide to buy a license, when you try to install, it will tell you that you first need to un-install the previous version. I found that after installing, the bios_5_31_02 had the directory tree intact, but there were no files inside any of the directories. In addition, when I tried to open an existing DSP/BIOS configuration, it would give me a server error. After blowing two hours trying to resolve the problem, I realized that this directory had to be completely deleted, for the installation program to update it. I had remembered that there were several tci files that I has created, and so I fortuneately moved these before I deleted the directory. Once the directory was removed. I uninstalled, and then reinstalled, and the directory was installed correctly.
I'm amazed that the the install is smart enough to remove all of the files except the ones I created, but not smart enough to put them back for the reinstall. This bug wasted another 2 hours of my time. I absolutely hate code composer studio.
Open the Clock Manager property box. Set Microseconds/Int to the desired rate. This value is the tick period.
A PRD is a periodic function call. Create a simple function which will be called periodically. Toggling an LED makes a good test function. This function can be a void with no parameters. Under the Periodic Function Manager node create a new PRD. Under the function property put in the name of your function to be called with an underscore. Select the number of ticks. Select Continuous.
Edit the Periodic Function Manager node and set "Use CLK Manager to drive PRD" to true.
I've tried using the CSL to configure the GPIO pins on the McBSP and the PLLC, and both APIs are inadequate to do the job. As far as I can tell the API set's the registers but without any sort of intelligent ordering. There is no way to set a single register. They must be set as a group, and thus you can not setup registers in a sequence, which is critical for setting up peripherals like the PLL. After messing with the PLLC API and having it mess up the system clock such that the board had to be reset, I gave up, and used the PLL documentation to directly access the PLL registers. As far as I can tell all of the CSL APIs are very clunky, and are just a thin wrapper around the registers, and were created without any sort of necessary insight into how the sequence in which registers should be set up.
It makes much more sense to access the registers directly, and bypass CSL completely. TI would be better off supplying a independent register API, where you could access each register selectively. The end goal is to abstract the hardware, but if the API doesn't work, then people will bypass it anyway. The fact that they don't have any include files which contain register definitions is also very annoying.
Because the CSL doesn't really abstract the hardware at all, and provides such heinously bad documentation, you still need to read the documentation for each of the modules anyhow, to figure out each register that needs to be set. They would be much better off just dropping CSL all together, providing register definition files, and then give some real world examples, as they do with the MSP series.
I was having a problem with making program changes and having the compiler update the program. It took me a while to even recognize that my code changes where not being implemented. I was able to determine if the change was truly programmed by changing which LED was blinking each time I recompiled. It became clear that I had to do a CPU reset before compiling and loading the code, otherwise, the my code changes wouldn't take affect. Because code wasn't getting updated, or at least it seemed to be updated only randomly, I thought that the compiler/debugger was unreliable, or that I was losing my mind.
After some research, I found a TI document "Creating Device Initialization GEL Files" which described the reset process. While it didn't outright tell how to resolve this issue. I was able to figure out the following GEL script to get the program to load consistently:
It seems to me that they should supply a GEL file with ever processor that they make, so that you don't have to figure this out by trial and error. If a CPU reset is needed before loading code, TI should tell you this upfront.
Okay now I have the PRDs working but their resolution seems to only 1ms using the default frame work. So now I have to figure out how to change this.
The Boot Utilities are hidden nested in the C672X System Patch zip file: TMS320C672xxBootUtils.zip.. Extact the utilities into the CCS tools directory.
TI, in their infinite wisdom, decided to write genAIS the program which generates bootable images in perl, rather than as a windows executable. This forces the end user to download the 15 megabyte installation of Perl. CCS is targeted for Windows, so why would they force you to learn yet another tool, I guess they were worried the learning curve for their tools wasn't already steep enough. I suppose one of their engineers decided it would be more fun to program in Perl, than keep a single common platform for their end user customers.
I downloaded Active Perl 5.8 from www.activestate.com. Don't download the .zip version. Download the .msi version. You can click on it, and windows installer msiexec recognizes it and performs the install. Once you set up the following environment variables in windows you are ready to run genAis.
PATHEXT = %PATHEXT%; .PL
PATH = %PATH%; bootUtilDir\bin
Note: Active Perl 5.10 the current latest version doesn't support the TK.pm GUI module, so it won't run genBootCfg. Apparently the guy who wrote TK.pm died, and no one else is willing to support it, and so they dropped it from the latest install of Perl. So much for opens source software. Thanks to the idiot at TI who wrote this in perl, I've wasted another 2 hours figuring out that their tools are no-longer compatible with the standard install of Perl.
genBootCfg is a Perl script with a user interface. It is needed to create secondary boot loaders, or at a minimum to configure the PLL. The PLL needs to be configured at the begining of the script otherwise it will take forever for the code to load. Without the PLL it was taking about 20 seconds to load the DSP in SPI slave mode. This utility creates two files a ".cfg" and a ".c" file. The ".c" file must be compiled if you are using it. If you are merely configuring the PLL you only need the ".cfg" file. This is utilized by the genAis program. It will insert a bunch of SET commands to configure registers.
Create a batch file to execute genAis with the following line:
genAis.pl -i Debug/myprogram.out -o myprogram.ais -bootmode
spislave -otype ascii -pkg tqfp -cfg myprogram.cfg
This will create an ASCII readable AIS file.
Note that you will need to set the path for each file input and output. If you are not invoking in the folder that contains the genAis.pl file, then make sure you set the path with a CD command. For example:
genAis.pl -i C:\MyProject\Debug\MyProjectName.out -o C:\
.ais -bootmode spislave -otype ascii -pkg tqfp -cfg BootCfg250MHz.cfg
Make sure you use .pl extension in the batch file so that Vista recognizes.
Note that in Vista when you run the batch file it may not see the perl file because of windows security. The solution is to directly run genAis by double clicking on it. A windows security window pops up asking if you should run it. Click on the check box so that the message doesn't come up again. Now you can run the batch file.
When this was first ran it resulted in an error with a conflict in the memory map. This was fixed by opening the DSP/BIOS configuration, and selecting "System/MEM Memory Section Manager/IRAM" I changed the starting address from 0x10000000 to 0x10001000 and subtracted 0x1000 from the default length - 0x0001f000. This resolved the problem nicely, and the AIS file was generated.
I had some problems due to the PLL not being initialized properly. For example, the CPU Load graph wasn't getting updated. This was because the PLL wasn't turned on, and so the CPU was running at the oscillator rate. In addition, I couldn't seem to get the PRD to trigger more than about 40KHz. The various instruments are updated by the CPU, during the idle cycle, and so if an interrupt is firing, and leaving no time for the idle, then the CPU load graph doesn't get updated.
The PLL has very stringent requirements that must be observed. These are listed in the data sheet. I tried using the chip support library, but of course this was buggy, and there was no real world example. Instead I followed the PLL documentation, and modified the registers directly.
Another interesting symptom that I was seeing before I got the PLL working was that the processor would run for a second and then go off to no-where land. I believe this was because one or more of the PLL registers was incorrectly configured.
You may find this hard to believe, but TI doesn't provide a single example on how to use the CSL with DSP/BIOS. So there isn't a single example, on how to make your own hardware interrupt service routines. I set up HWI_INT5 to generate an interrupt that toggles an IO pin. Then I configured the RTI timer to generate periodic interrupts. I couldn't get it to invoke the interrupt. I eventually noticed that the interrupt associated with HWI_INT5 wasn't being enabled. I was surprised that the DSP/BIOS doesn't set enable the darn thing. Their technical support guy told me that the DSP/BIOS sets up the vector, and ISR framework, but the the CSL enables the interrupts.
Unfortunately, this core register isn't memory mapped and thus not directly accessible without the CSL. I was eventually able to figure out that the function CSL_intcEventEnable will enable the individual interrupts. Finding the define for the interrupt number was a total hassle. I needed to use CSL_INTC_EVENTID_RTI_INT_OVL_REQ which is defined as 5, but it was nowhere to be found in the documentation, and I had to scan the header files with another known interrupt to locate it.
I tried setting up the RTI using the second timer, but noticed that the registers I set, got clobbered after running the program. I figured out that the PRD manager was responsible for overwriting my changes. Fortunately they provide a hook for RTI initialization. So I moved my RTI initialization code to this hook, and the registers held their values.
I had trouble with the ISR only being called once. I figured that the interrupt needed to be explicitly cleared by the ISR. Turns out the RTIINTFLAG register is used to do this, despite this fact being completely undocumented. In addition, the register is not a simple read write register, when you write a 1 bit it will clear the pending interrupt. A one line comment in the documentation stating this fact would have saved 2 hours of wasted time. I kept writing zero to the register, and nothing would change.
Also the CSL is broken in regards to setting the RTIINTFLAG register. When the funciton:
CSL_rtiHwControl (hRti, CSL_RTI_CMD_CLEAR_INT0, &intEvent);
is invoked, it clears all of the pending interrupts in the RTINTFLAG register, not just the INT0 flag. The result is that my other pending RTI interrupts get's cleared, and thus never called.
So once again, you can't use CSL because it is a buggy piece of code. I'm starting to think that TI subcontracted the development of all of it's tools and APIs to Microsoft.
One of the most frustrating issues, I've encountered in this process was finding out that because of silicon errors on version 11 of the chip, SPI slave mode doesn't work if you have any other peripherals on the SPI bus. I had an serial flash eeprom on the bus, and it would cause the boot to fail with CRC errors because the DSP's SPI hardware had a bug. Of course the chip errata doesn't discuss the impact of the error on booting, and so it took a while to make the correlation. Version 12 of the chip solves the SPI issues.
It is impossible to getting distributors to check the version number of their DSPs. I ended up having to order one unit, and if they sent me version 12 then I'd order more.
There is sample code on implanting a host processor SPI master. This code is a necessity, because the booting documentation is very sparse. There are all sorts of timing constraints, that are not discussed. This can be found buried in the file:
Also it should be noted that the SPI must go at a slower rate 500kbits/sec until the PLL is configured, and then it can go up to 4Mbits/sec according to the documentation in this file.
I had a issue where I could not get the PLL to work above 100MHz. I assumed it was some sort of software issue. I tried all sorts of variations on the software thinking it was a delay issue or an initialization sequence issue. After wasting many hours on the problem, I gave up and started working on a different project, that required a different power supply. I then got a response back from TI about the issue - they gave me the PADK gel file which had code on how to initialize the PLL. I plugged in my C6722 board with the power supply that I had used with my other project, and everything started working. At that moment, I realized that it was a power supply issue. I had placed the recommended filter on the PLLH pin, but apparently that wasn't good enough. Once I resolved the power supply issues, the PLL started working as expected.
I have an ISR that is extremely time critical, and needed to be optimized for speed. When looking at the assembly code generated by the so called optimizing compiler, I was appalled at how much code was generated, even after using their intrinsic, register key words, etc. The code was absolutely terrible, and I realized that there was no other way than to rewrite the code in assembly.
I decided to rewrite the ISR which was called from the HWI dispatcher, in linear assembly. It appears that linear assembly is actually compiled with the C compiler, and not the assembler, and for this reason, it is documented in the C compiler manual, and not the assembler. Of course there isn't a single example on how to use linear assembly in an ISR, they give some lame simple examples with dot products.
The first critical thing to know is you absolutely have to use the .cproc and .endproc directives with linear assembly, otherwise many of the other directives don't work, and you can not single step through your code. You also have to use a .def on your function name or it won't be visible to the other modules.
Since my routine is an ISR, I'm not passing in values, but instead am using global variables. Global variables must be defined with the .global or .ref directive.
Here's a simple linear assembly C file:
MCASP0_BASE .equ 0x44000000
MCASP_PDOUT .equ 0x18
.def _HwiRti1 ; necessary so that it is visible
MVKH MCASP0_BASE,A0 ; A0= & MCASP0_PDOUT
MVKH _globalvar,A4 ; A4 points to _globalvar
The next question I had was: since this is an ISR how do I save context. The search for this answer wasted a couple of weeks. The documentation is vague on this. The interrupt keyword is mentioned, but it also mentions that if you are using HWI then it should not be used. The DSP/BIOS documentation mentions the HWI_enter/HWI_exit macros, but these do not work with linear assembly! They only work with regular assembly language. To make matters worse, the TI technical support guys were unsure themselves.
This is what I've figured out. When using the HWI dispatcher, you don't need to do anything special for the ISR. Any C routine will work. I don't fully understand all of this magic, but that's what the guys at TI say. I pointed out that this important fact is no where to be found in the documentation. Since the .cproc directive creates a C-compliant routine, it also should work as an ISR, without the need to save context etc. Another important fact is that the HWI_enter/HWI_exit macros don't even need to be used in regular assembly routines, if the HWI dispatcher is used, because apparently the dispatcher calls the macros once at the beginning and end. Apparently you only use the routines if you don't use the dispatcher. So make sure the "use dispatcher" box is checked.
Salt Lake City, UT, USA
Disclaimer: Daycounter, Inc. doesn't guarantee the accuracy of any of it's content. Use at your own risk.
© Copyright 2016 Daycounter, Inc. All rights Reserved.
Salt Lake City, UT, USA
Disclaimer: Daycounter, Inc. doesn't guarantee the accuracy of any of it's content. Use at your own risk.