First issue: gdb runs but you can't step through the code.
Solution: gdb allocated too many breakpoints, and HW breakpoint is necessary for single stepping. Delete all breakpoints.
Second issue: gdb runs, but code never gets to main. seems to be stuck in the flash loader
Solution: code was not stuck in the flashloader, but in infinite loop of "abort()" within a static C++ constructor.
Things that were helpful:
set verbose on
in gdb start-up script (Project Properties -> Run/Debug Settings -> Startup Scripts -> Debug)
Also, comment out continue at end of script
#continue
so that debugger starts right after it loads the code. Also, replace "abort()" with https://github.com/scottt/debugbreak
Monday, July 28, 2014
Monday, February 13, 2012
Wrangling Setup (msi) projects
To add a custom action to a Setup/Deployment project, you can write a stand alone script (in VBS), or write a standalone executable, or you can add an Installer class to your main application. I like the last one, since it keeps everything together in less files.
1. Add an "Installer Class" to your project using the Add New Item
2. Override the 4 class: Install, Commit, Uninstall, Rollback.
3. If you want to do any logging, use
4. If you want to use passed parameters, use
5. Build
6. Add the application as a Custom Action to your setup project. Add it to ALL 4 actions, otherwise you'll get an obscure error.
7. To pass parameters, use CustomActionData field, and format it like
8. You can make it conditional by
a. adding a Checkbox to the user interface, and naming the property of the checkbox, ie DO_WHAT_I_WANT
b. Using that checkbox name (ie DO_WHAT_I WANT) as the Conditional of the custom action.
9. To debug, Use
where you need it.
1. Add an "Installer Class" to your project using the Add New Item
2. Override the 4 class: Install, Commit, Uninstall, Rollback.
3. If you want to do any logging, use
this.Context.LogMessage(string)4. If you want to use passed parameters, use
Context.Parameters5. Build
6. Add the application as a Custom Action to your setup project. Add it to ALL 4 actions, otherwise you'll get an obscure error.
7. To pass parameters, use CustomActionData field, and format it like
/name=value /name=value. Use double quotes if you have spaces in the values.8. You can make it conditional by
a. adding a Checkbox to the user interface, and naming the property of the checkbox, ie DO_WHAT_I_WANT
b. Using that checkbox name (ie DO_WHAT_I WANT) as the Conditional of the custom action.
9. To debug, Use
System.Diagnostics.Debugger.Launch();System.Diagnostics.Debugger.Break();where you need it.
Tuesday, February 7, 2012
Stack size of bootloader versus application
I got myself in a bind when I changed the stack size of my application, but didn't change the size of the stack in the bootloader.
I learned something new today: the CPU sets the stack pointer to the first word of the vector table on reset. If you have a bootloader that does something like jump to the reset vector (__vector_table + 4 bytes), it will NOT reload the stack pointer. If your stack pointer is not changed, you are likely to start writing all over the stack with your static variables. yuck.
In my case, the bootloader had a stack of 0xC00. My main app was running out of memory, so I changed the stack to 0xB80 (which was more than enough). However, I noticed that my app was still using a stack of size 0xC00, when it had only allocated 0xB80 to it. uhoh.
To fix this, I added these 2 lines to the ResetHandler in startup_stm32f10x_md_vl.s (or the equivalent for other STM32s)
Btw, IAR 6.3 has a feature to analyze the stack size. It kinda works, but it is a pain in the butt if you have C++ virtual functions or any function pointers.
I learned something new today: the CPU sets the stack pointer to the first word of the vector table on reset. If you have a bootloader that does something like jump to the reset vector (__vector_table + 4 bytes), it will NOT reload the stack pointer. If your stack pointer is not changed, you are likely to start writing all over the stack with your static variables. yuck.
In my case, the bootloader had a stack of 0xC00. My main app was running out of memory, so I changed the stack to 0xB80 (which was more than enough). However, I noticed that my app was still using a stack of size 0xC00, when it had only allocated 0xB80 to it. uhoh.
To fix this, I added these 2 lines to the ResetHandler in startup_stm32f10x_md_vl.s (or the equivalent for other STM32s)
Reset_Handler
;; MTL
;;force reload of the stack pointer!
;; it is stored on the start of the vector table
LDR R0,=__vector_table
LDR SP,[R0]
;;
LDR R0, =SystemInit
BLX R0
LDR R0, =__iar_program_start
BX R0
Btw, IAR 6.3 has a feature to analyze the stack size. It kinda works, but it is a pain in the butt if you have C++ virtual functions or any function pointers.
Monday, February 6, 2012
How to add options to a Setup and Deployment project in Visual Studio
Visual Studio has a "Setup and Deployment" project, that is mostly easy to set up with a bunch of clicks.
If you want to customize the installer (with options for the user), you need to write little programs to do each custom operation.
The scripts can be written as *.exe or *.dll files, which need to be compiled. That seems a bit overkill.
The scripts can also be written as VBS (Visual Basic Scripting) language. For someone like me, I don't want to know about VBS, but that's the only other option you have. VBS is not the same as VB, but it is similar. In addition, some of the default assemblies you have access to in VBS from the command line are not available from the Setup Project.
To test out a VBS script, you run the 'cscript' command from the command line, or double click it.
Here's a VBS script that opens a firewall. You add the script to the Custom Action -> Commit, and change the CustomActionData property to
You can make it conditional by adding something to the UserInterface (say Checkboxes (A)), name the property name of that checkbox, and then use that in a conditional for the custom action. Sorry that's vague, but should give me some hints when I actually need to implement it.
If you want to customize the installer (with options for the user), you need to write little programs to do each custom operation.
The scripts can be written as *.exe or *.dll files, which need to be compiled. That seems a bit overkill.
The scripts can also be written as VBS (Visual Basic Scripting) language. For someone like me, I don't want to know about VBS, but that's the only other option you have. VBS is not the same as VB, but it is similar. In addition, some of the default assemblies you have access to in VBS from the command line are not available from the Setup Project.
To test out a VBS script, you run the 'cscript' command from the command line, or double click it.
Here's a VBS script that opens a firewall. You add the script to the Custom Action -> Commit, and change the CustomActionData property to
[TARGETDIR]. There a bunch of variables you can pass in CustomActionData, but I've yet to find a complete list of them online.You can make it conditional by adding something to the UserInterface (say Checkboxes (A)), name the property name of that checkbox, and then use that in a conditional for the custom action. Sorry that's vague, but should give me some hints when I actually need to implement it.
Dim target
'msgbox "start"
'msgbox Session.Property("CustomActionData")
target = Session.Property("CustomActionData")
'msgbox target
Set objFirewall = CreateObject("HNetCfg.FwMgr")
Set objPolicy = objFirewall.LocalPolicy.CurrentProfile
filename = target & "cog-trk-db-service.exe"
'msgbox filename
Set objApplication = CreateObject("HNetCfg.FwAuthorizedApplication")
objApplication.Name = "cog-trk-db-service"
objApplication.IPVersion = 2
objApplication.ProcessImageFileName = filename
objApplication.RemoteAddresses = "*"
objApplication.Scope = 0
objApplication.Enabled = True
Set colApplications = objPolicy.AuthorizedApplications
colApplications.Add(objApplication)
msgbox "Firewall exception created for " & filename
'msgbox "stop"
STM32 fault handling
http://blog.frankvh.com/2011/12/07/cortex-m3-m4-hard-fault-handler/
Here is the IAR version of the asm.
http://blog.frankvh.com/2011/12/07/cortex-m3-m4-hard-fault-handler/
Here is the IAR version of the asm.
NAME HardFault_Handler
AAPCS BASE,INTERWORK
PRESERVE8
REQUIRE8
EXTERN hard_fault_handler_c
SECTION .text:CODE:REORDER(2)
THUMB
PUBLIC HardFault_Handler
PUBLIC BusFault_Handler
HardFault_Handler
BusFault_Handler
TST LR, #4
ITE EQ
MRSEQ R0, MSP
MRSNE R0, PSP
B hard_fault_handler_c
END
Tuesday, June 28, 2011
Learning about SQL
There are more than one way to do queries in SQL in .NET. I'm summarizing them here for my own use:
- SqlReader - reads one line of a table at a time, after a SELECT statement is made
- SqlDataAdapter -still learning about this. appears to be a magic box where things just happen.
- Linq - DataContext - uses high level LINQ statements to do the query. Has the advantage of mostly keeping things tightly typed. Has the disadvantage that it doesn't do generic SQL commands (like add a new column to a table).
Friday, June 11, 2010
C# example of directly getting the local time from a Domain Controller
In case you need to get the current time (appears to be UTC) from a trusted source rather than rely on the local computer to report the time (which can be easily changed), this snippet gives guidance. You can get the name of a domain controller from the LOGONSERVER environment variable.
using System.DirectoryServices.ActiveDirectory;
DirectoryContext context = new
DirectoryContext(DirectoryContextType.DirectoryServer, "insert_domain_controller_name_here");
DomainController dc =
DomainController.GetDomainController(context);
DateTime dt = dc.CurrentTime;
MessageBox.Show("Domain Time is " +
dt.ToLongTimeString());
Monday, August 24, 2009
Puzzler #1
unsigned char x = 0x80;
main (void) {
char y;
y = 0x80;
if (x != y) {
printf("This should not happen\n");
}
}
Why does the string "This should not happen" appear on the console? It does on VS2005 for x86, but may not on a 8051 processor.
Answer: The problem is that 'char' and 'unsigned char' are different when it comes to comparisons, and that compilers like to optimize the comparison using machine register sizes. C casts the operands to machine sizes: unsigned char 0x80 gets cast to 0x00000080, and signed char 0x80 gets cast to 0xFFFFFF80. Then when you compare them, they don't equate! ARGH....
Thursday, August 20, 2009
Using Bits in 8051 assembly
warning: this is a placeholder written from memory. I need to update it
Useful commands: The JB (Jump if Bit set) will jump if a bit is set. The encoding of the field is the bit offset from data memory address 0x20. If you forget this, and try encoding the bit directly, then you will actually get bit 0x20.0 + 0x20 = 0x24.0 (ie 32 bits down the line).
To declare the bit in ASM:
BSEG 0 ; offset 0 in the 0x20.0 to 2F.7 range.
BIT mybit ; declare mybit at 0x20.0
...
; useful 8-byte entry in the vector table (ie at offset 0x0003 in code space for an ISR)
CSEG AT 0x0003
JB mybit, passhop ; 3 bytes encoding
AJMP fail ; 2 bytes encoding
passhop: LJMP pass ; 3 bytes encoding = 8 bytes total
In C, you would declare the bit as:
extern bit myBit at 0x20;
How to read high resolution system time in Win32
// example of how to read the system clock.
SYSTEMTIME st;
::GetSystemTime(&st);
FILETIME ft;
::SystemTimeToFileTime(&st,&ft);
DWORD diff = ft.dwLowDateTime - lasttime;
double rate;
rate = DEF_BUF_SIZE * 1000.0 / (diff * 1e-7) ;
std::cout << " rate:" << rate << std::endl;
lasttime = ft.dwLowDateTime;
Wednesday, April 29, 2009
Memory Barriers in multi-threaded applications
Sometimes, the compiler can get in the way and break your code because it makes single-thread assumptions about your code. In addition, the microprocessors can break your code because it makes single-core assumptions. The way to fix this is use a memory barrier.
Here is a very good description of the problem of multi-threading.
Here is how to do it on a PowerPC, using the lwsync instruction.
Here is a very good description of the problem of multi-threading.
Here is how to do it on a PowerPC, using the lwsync instruction.
volatile unsigned variable1 = 0;
#define barrier() __asm__ volatile (”lwsync”)
#define ITERATIONS 50000000
void *writer(volatile unsigned *variable2) {
utilBindThreadToCPU(0);
for (;;) {
variable1 = variable1 + 1;
barrier();
*variable2 = *variable2 + 1;
}
return NULL;
}
How to predeclare typedefs for self-referential typedefs
Sometimes you need to have a typedef that refers to itself through a struct member, or there is a circular reference. Here is how to predeclare the typedef so you can use it before it is fully defined. It's basically 3 parts. First declare the struct, then declare the typedef, then define the struct using the typedef.
struct fileinfo;
struct cached_block;
typedef struct fileinfo FILEINFO;
typedef struct cached_block CACHED_BLOCK;
struct fileinfo {
FILEINFO *fi_next; /* list of all files */
CACHED_BLOCK *fi_blks; /* cached blocks for this file */
/* ... */
};
struct cached_block {
int cb_lbn; /* logical block number */
CACHED_BLOCK *cb_next; /* next cached block for this file */
FILEINFO *cb_file; /* file containing this block */
/* ... */
};
Thursday, February 12, 2009
Disassembling a binary using GNU tools on a weird architecture
objdump -D Release/tinyloader.bin --target=binary --architecture=xscale
The -D option is key. You can't use -d, since you are starting with a binary file that has no sections. The -D option ignores sections and disassembled everything.
Monday, January 26, 2009
How to install a bootloader on a STR912 without CAPS or Raisonance
ST recommends CAPS (their GUI) to install the STR912. However, that requires a Raisonance JTAG adapter. You can do it with just IAR EWARM and Segger tools.
- Download the JLINK software from Segger.com
- Run "J-LINK STR9 Commander" tool (it's under Segger-> JLink ARM 3.95a -> Processor Specific Utilities).
- Type "?" to get a list of commands
- Type "erase all" to fully erase the chip.
- Type "setb 1" to set the boot bit to bank 1.
- Type "q" to quit.
- Now you can use the flash loader of EWARM to install the code.
Adding an external file to a perl module
Let's say you want a perl module to scream "argh" on failure. You find a argh.wav file and want to bundle it with the perl pm file. The problem is loading the wav file without knowing the full path. Perl's current working directory can be any where, and the location of the wav file or module file may not be in the same location as the starting pl file. To find the starting pl file, you can use the FindBin::Bin module, but this doesn't work for modules. If you want to know the location of the module (pm) file instead, you can use the %INC hash to get it. This hash value gets set when you "use" the pm file. Once you know where the pm file is, you can use the dirname() function to get the directory name, then add the name of the wav file.
Here is an example (in a perl module called "Scream.pm"):
Here is an example (in a perl module called "Scream.pm"):
use File::Basename;
use Win32::Sound;
my $wavfile = dirname($INC{"Scream.pm"})."/argh.wav";
Win32::Sound::Play($wavfile);
Thursday, January 15, 2009
Tools for mocking-up C++ classes
I haven't played with this yet, but it seems to have its heart in the right place.
http://code.google.com/p/googlemock/wiki/ForDummies
http://code.google.com/p/googlemock/wiki/ForDummies
Neat source of icons
I stumbled upon this cache of free icons if you follow the LGPL.
http://commons.wikimedia.org/wiki/Crystal_Clear
Don't use a virtual function in a constructor
Virtual functions should be used until an object is fully constructed. That is because the constructor builds the virtual function table in pieces. When it is constructing the base class, the derived class virtual function table is not yet constructed. So if you call a virtual function, you are calling the virtual function of the base class not the derived class. This is worse if the base class is a pure interface, ie the virtual functions are declared as pure (ie " =0;"), because you can't call a pure function -- the pointer points to NULL and your program crashes.
Sunday, December 21, 2008
STR91x bootloader trouble, PFQ/BC
Most start-up code (91x_init.s for example) writes 0x191 to the SCU->SCR0 register, which among other things enables the PFQ/BC (Pre-Fetch Queue/Branch Cache). This is normally a good thing. Of the 16 entries in the Branch Cache, 15 are used for generic branches while the 16th one is used only for the special IRQ branch at address 0x18. It appears that this branch cache value is initialized when the PFQ/BC is turned on AND read-only after that. That means if the jump at 0x18 changes, the BC entry will be wrong.
Why would the jump at 0x18 ever change? It changes if you remap the banks, i.e. use BANK1 as the bootloader boot bank, and then switch to BANK0 as the main application. Of course, you shouldn't even do this if you are not using at least rev H of the STR912FAW, but that is a different story (the chip reset circuit has a bug that makes this impossible).
What happens if you don't do something special a programmer's worst nightmare: jumps are random when you let the program run, but if you step through the ASM code, it works fine (because the cache is turned off if you are doing single steps). And the random jumps are not a software bug that you can fix.
But there is a fix. Change the boot code to disable the PFQ/BC, then reenable it later in your code.
Later you can reenable using the 91x_lib call (inside __low_level_init() if you are using IAR EWARM):
Why would the jump at 0x18 ever change? It changes if you remap the banks, i.e. use BANK1 as the bootloader boot bank, and then switch to BANK0 as the main application. Of course, you shouldn't even do this if you are not using at least rev H of the STR912FAW, but that is a different story (the chip reset circuit has a bug that makes this impossible).
What happens if you don't do something special a programmer's worst nightmare: jumps are random when you let the program run, but if you step through the ASM code, it works fine (because the cache is turned off if you are doing single steps). And the random jumps are not a software bug that you can fix.
But there is a fix. Change the boot code to disable the PFQ/BC, then reenable it later in your code.
; --- Enable 96K of RAM & Enable DTCM & AHB wait-states, disable PFQ/BC until it is flushed. The bootloader has cached the IRQ already and that is BAD!
LDR R0, = SCU_BASE_Address
LDR R1, = 0x0196 ; not 0x0191 as in other boot code!
STR R1, [R0, #SCU_SCR0_OFST]
Later you can reenable using the 91x_lib call (inside __low_level_init() if you are using IAR EWARM):
SCU_PFQBCCmd(ENABLE); // Enabled Branch Cache feature of STR91x.
Friday, December 19, 2008
Anatomy of STR912 boot sequence in EWARM
Power-on: waits til voltages rise above Low-Voltage Detect, then sets PC to 0x00000000
First instruction jumps to Reset Handler. The jump is usually a LD PC,[PC+xxx] command that loads the PC from a table just past the end of the vector handlers.
Reset Handler is always written in ASM because it needs to do things that are unsafe in C, like initializing flash memory interfaces, RAM interfaces and needs access to the CPSR register, which you don't have from C. This usually sets the flash memory interface, sets up stack space for each of the system modes, then jumps to ?main. In EWARM, the Reset Handler is installed at 0x180, and is given the symbol __iar_program_start. If you do not write your own, EWARM will pick one for you.
?main - This does basically 3 things:
I've seen several examples (the code from ST) that does the low level init in main() and not earlier. This is not a big deal, but it means that the clock will be running much slower on power-up, so if you are doing a lot of C++ initialization, it will boot slower (perhaps 4x slower if you are using a 25 MHz crystal and can run the PLL at 96 MHz).
First instruction jumps to Reset Handler. The jump is usually a LD PC,[PC+xxx] command that loads the PC from a table just past the end of the vector handlers.
Reset Handler is always written in ASM because it needs to do things that are unsafe in C, like initializing flash memory interfaces, RAM interfaces and needs access to the CPSR register, which you don't have from C. This usually sets the flash memory interface, sets up stack space for each of the system modes, then jumps to ?main. In EWARM, the Reset Handler is installed at 0x180, and is given the symbol __iar_program_start. If you do not write your own, EWARM will pick one for you.
?main - This does basically 3 things:
- Call __low_level_init(). You can write this in C, as long as you are careful not to use global variables. This is useful for setting the clock speed and other things that don't need to be done in ASM. EWARM has a default dummy __low_level_init().
- Call __iar_init_memory. Not something the user should deal with. This is where the C global variables are initialized, and global C++ objects are constructed.
- Call main. This is the traditional C entry point.
I've seen several examples (the code from ST) that does the low level init in main() and not earlier. This is not a big deal, but it means that the clock will be running much slower on power-up, so if you are doing a lot of C++ initialization, it will boot slower (perhaps 4x slower if you are using a 25 MHz crystal and can run the PLL at 96 MHz).
Subscribe to:
Posts (Atom)