Hi there,
We are using cortex M0 uC. We need to recognize at our code whether or not the debugger is attached. We have found after a lot of search and effort that we cannot use CoreDebug->DHCSR with cortex M0.
We have found a different approach using the HardFault exception and software breakpoint that indirect recognize if the debugger is attached.
In this approach using assembly if a hardware exception occurs due to a breakpoint then no debugger is attach and the HardFault exception return to the program skipping the breakpoint instruction.
Below is the assembly code we have found and slightly changed:
__asm("MOVS R0, #4"); __asm("MOV R1, __return_address()"); __asm("TST R0, R1"); __asm("BEQ _MSP"); __asm("MRS R0, PSP"); __asm("B _checkFaultInstruction"); __asm("_MSP: "); __asm("MRS R0, MSP"); __asm("_checkFaultInstruction: "); __asm("LDR R1, [R0,#24]"); __asm("LDRH R2, [R1]"); __asm("LDR R3,=0xBEAB"); __asm("CMP R2, R3"); __asm("BNE HardFault_HandlerC "); __asm("ADDS R1, #2"); __asm("STR R1, [R0,#24]"); __asm("BX __return_address()");
The compiler is throwing the follows errors:
1) __asm("LDR R3,=0xBEAB"); -> error #29: expected an expression We have replaced this instruction with: __asm("MOV R3, 0xBEAB"); Does this instruction has the same effect?
2) __asm("BX __return_address()"); -> error #1084: This instruction not permitted in inline assembler. How can we replace this unsupported instruction?
3) __asm("BNE HardFault_HandlerC "); -> error #114:label "HardFault_HandlerC" was reference but not defined HardFault_HandlerC is a function name 4) __asm("BX __return_address()"); -> error #114:label "..." was reference but not defined
What is wrong with 3 and 4?
Thanks in advance.
How about running your instructions from an assembler file instead? Wouldn't that be way better?
Inlining assembler like that is like writing C code with a maximum of trigraphs so we can produce easy-to-understand and maintainable code like:
!ErrorHasOccured() ??!??! HandleError();
I couldn't agree with you more, but assembly is out of my league.
It would be great if you could properly reformat my code but my real need is a solution to the actual problem.
Thanks
#1:
No, Because LDR R3, =0xBEAB
or what ever is typed, tells the processor to access the memory location defined and get the data stored at the memory location and put it into register R3.
the other thing you wrote places the immediate value typed in into R3 as typed in. # is for immediate value.
There is more code you need to add if you are ever going to get that code to work.
including some hard fault function that is missing in your project.
sorry, I noticed that you did not use # before.. Now I am not sure about my answer to part 1.
There is a document that I have used before as a example to add a assembler function:
DUI0203J_rvct_developer_guide.pdf
It is old but it did work for me to make a simple assembly function and call it from a C program.
infocenter.arm.com/.../DUI0203J_rvct_developer_guide.pdf
you can look at page 72 for an example.
I went and looked in a assembly book that I have. They give an example
LDR R5, =0x1FF400 ; say this is ok for assembler
The book refers to is as a pseudo operand.
What the assembler is to create is a instruction that will look like
LDR R5, [PC, #18] ; = OK for the assembler.
In the location, that is indirectly addressed by the processor at PC + #18 (the value 18 may be different).
Will be a 32 bit value stored 0x001FF400. and the register R5 will get the value from this memory location. when the instruction has been executed. The data stored at the address [PC, #18] is referred to as literal pool or a memory zone where the compiler can store data close to the code. The data must be somewhat near the code. The largest jump that can be made appears to be 4096. for this reason this is how the compiler can keep data close to to the data.
A move instruction can only store apparently up to 16 bits, and 8 bits. the LDR looks like it can store all 32 bits because of the way it places the data into memory before fetching the data.
-------------------------------------------------------------------------------
If all you want to do is load 16 bits then the following move instruction will work:
MOV.W Ri, #ImmNum
and for 8 bits
MOV Ri, #ImmNum
Ri is one of the registers.
It uses an immediate form where it fits the 8-bit+shift form, and where it doesn't it loads the constant from a literal pool it creates. This usually resides after the subroutine return code, or after a unconditional branch.
The bigger question is why?
If you're just trying it for the purposes of your own testing, dig into the DWT/ITM units, or DBGMCU type stuff, it should be easy enough to find something to key off, without using assembler or handlers.
If it's for software protection purposes, consider most hackers can actually code in assembler fluently, and read code without the source. It helps to have a skill level above that of your perceived threat.
According to the following link our replacement to the first error is ok. infocenter.arm.com/.../index.jsp
any ideas for the rest ones?