Im writing some C/asm program for the AVR MCU. Im still learning as I go so I hope I have made some sort of mistake in my code.
I have a buffer volatile unsigned char suart_0_rx_buffer[SUART_0_BUF_SIZE+1]; in my C code that I am accessing in my asm code as below. All I want to do is store a byte s0_Rxbyte in the buffer and increment the pointer s0_index every time. 's0_Rxbyte` is always a non zero value.
suart_0_wr_buf_2: ldi s0_z_low, lo8(suart_0_rx_buffer)
ldi s0_temp1, hi8(suart_0_rx_buffer)
add s0_z_low, s0_index
adc s0_z_high,s0_temp1
suart_0_wr_buf_3: st Z+, s0_Rxbyte
inc s0_index
clr s0_temp1
st Z, s0_temp1
If I try and print the contents in a loop in my C code I am getting absolutely nothing.
I didnt want to attach everything here because it will be cluttered.
So does anyone see any problems with the asm code above ?
Managed to figure it out in the end. It was a case of a simple error in the assembly code that caused it write an incorrect location in the SRAM.
suart_0_wr_buf_2: clr s0_temp1
ldi s0_z_low, lo8(suart_0_rx_buffer)
ldi s0_z_high, hi8(suart_0_rx_buffer)
add s0_z_low, s0_index
adc s0_z_high, s0_temp1
suart_0_wr_buf_3: st Z+, s0_Rxbyte
inc s0_index
st Z, s0_temp1
Related
I am working on translating assembly code to 'C', to which I came across a instruction which I am finding difficult to understand, here is the code
add a,#0-3
jc c_fail
I don't understand the line add a,#0-3
add a,#0-3 is same as add a,#-3 that will adds A with -3. -3 will be considered as 0xFD in 8051 MCU. So, if A value be equal or greater than 3 (a >= 3), program will goes to the c_fail address due to carry flag.
Also, you can replace it with subb a,#3, if use from the jnc instead of jc in its next line.
For testing the MPU and playing around with exploits, I want to execute code from a local buffer running on my STM32F4 dev board.
int main(void)
{
uint16_t func[] = { 0x0301f103, 0x0301f103, 0x0301f103 };
MPU->CTRL = 0;
unsigned int address = (void*)&func+1;
asm volatile(
"mov r4,%0\n"
"ldr pc, [r4]\n"
:
: "r"(address)
);
while(1);
}
In main, I first turn of the MPU. In func my instructions are stored. In the ASM part I load the address (0x2001ffe8 +1 for thumb) into the program counter register. When stepping through the code with GDB, in R4 the correct value is stored and then transfered to PC register. But then I will end up in the HardFault Handler.
Edit:
The stack looks like this:
0x2001ffe8: 0x0301f103 0x0301f103 0x0301f103 0x2001ffe9
The instructions are correct in the memory. Definitive Guide to Cortex says region 0x20000000–0x3FFFFFFF is the SRAM and "this region is executable,
so you can copy program code here and execute it".
You are assigning 32 bit values to a 16 bit array.
Your instructions dont terminate, they continue on to run into whatever is found in ram, so that will crash.
You are not loading the address to the array into the program counter you are loading the first item in the array into the program counter, this will crash, you created a level of indirection.
Look at the BX instruction for this rather than ldr pc
You did not declare the array as static, so the array can be optimized out as dead and unused, so this can cause it to crash.
The compiler should also complain that you are assigning a void* to an unsigned variable, so a typecast is wanted there.
As a habit I recommend address|=1 rather than +=1, in this case either will function.
I'll explain the problem briefly. I have a Leon3 board (gr-ut-g99). Using GRMON2 I can load executables at the desired address in the board.
I have two programs. Let's call them A and B. I tried to load both in memory and individually they work.
What I would like to do now is to make the A program call the B program.
Both programs are written in C using a variant of the gcc compiler (the Gaisler Sparc GCC).
To do the jump I wrote a tiny inline assembler function in program A that jumps to a memory address where I loaded the program B.
below a snippet of the program A
unsigned int return_address;
unsigned int * const RAM_pointer = (unsigned int *) RAM_ADDRESS;
printf("RAM pointer set to: 0x%08x \n",(unsigned int)RAM_pointer);
printf("jumping...\n");
__asm__(" nop;" //clean the pipeline
"jmp %1;" // jmp to programB
:"=r" (return_address)
:"r" (RAM_pointer)
);
RAM_ADDRESS is a #define
#define RAM_ADDRESS 0x60000000
The program B is a simple hello world. The program B is loaded at the 0x60000000 address. If I try to run it, it works!
int main()
{
printf ("HELLO! I'M BOOTED! \n");
fflush(stdout);
return 0;
}
What I expect when I run the ProgramA, is to see the "jumping..." message on the console and then see the "HELLO! I'M BOOTED!" from the programB
What happens instead an IU exception.
Below I posted the messages show by grmon2 monitor. I also reported the "inst" report which should show the last operations performed before the exception.
grmon2> run
IU exception (tt = 0x07, mem address not aligned)
0x60004824: 9fc04000 call %g1
grmon2> inst
TIME ADDRESS INSTRUCTION RESULT SYMBOL
407085 600047FC mov %i3, %o2 [600063B8] -
407086 60004800 cmp %i4 [00000013] -
407089 60004804 be 0x60004970 [00000000] -
407090 60004808 mov %i0, %o0 [6000646C] -
407091 6000480C mov %i4, %o3 [00000013] -
407092 60004810 cmp %i4, %l0 [80000413] -
407108 60004814 bleu 0x60004820 [00000000] -
407144 60004818 ld [%i1 + 0x20], %o1 [FFFFFFFF] -
407179 60004820 ld [%i1 + 0x28], %g1 [FFFFFFFF] -
407186 60004824 call %g1 [ TRAP ] -
I also tried to substitute the "jmp" with a "jmpl" or a "call" but it does not worked.
I'm quite confused.
I do not know how to cope well with the problem and therefore I do not know what other information it is necessary to provide.
I can say that, the programB is loaded at 0x60000000 and the entry_point is, of course, 0x60000000. Running directly program B from that entry point it works good!
Thanks in advance for your help!
Looks to me like you did execute the jump, and it got to program B, as evidenced by the addresses of the instructions in the trace buffer. But where you crashed was in stdio trying to print stuff. Stdio makes extensive use of function pointers, and the sequence clearly shows a call instruction with the target address in a register, which indicates use of a function pointer.
I suggest putting fflush(stdout) in program A just before the jump, and this will allow you to see the messages before doing the jump. Then, in program B, instead of using printf, just put some known value in memory that you can examine later via the monitor to verify that it got there.
My guess is that the stdio library has some data or parameter that needs to be set up at the start of the program, and that's not being done or not done properly. Not sure about the platform you are running on, but do you have some sort of debugging or single stepping ability, like in a debugger? If so, just single step through the jump and follow where the program goes.
I'm looking to make a very short pulse after a rising edge signal input.
The hard part here is that I would like to control (to high resolution) the timing of the delay before my pulse, and the duration of my pulse. I can easily control this by just stringing together nops by myself, hard coding delays, but I'm not sure how to do it for some arbitrary delay, with the same level of accuracy.
After a lot of headaches chasing down timers, and then eventually realizing I am ultimately limited by the interrupt routine entry/exit time, I am now settling at trying to control my delay via nops.
I had assumed this C switch statement would be what I wanted (after compiling, hoping it would become efficient and just change the program counter to the right spot), but it produces some very odd behavior...
switch(delayTime){
case 10:
__asm__ __volatile__("nop");
case 9:
__asm__ __volatile__("nop");
case 8:
__asm__ __volatile__("nop");
case 7:
__asm__ __volatile__("nop");
case 6:
__asm__ __volatile__("nop");
case 5:
__asm__ __volatile__("nop");
case 4:
__asm__ __volatile__("nop");
case 3:
__asm__ __volatile__("nop");
case 2:
__asm__ __volatile__("nop");
case 1:
__asm__ __volatile__("nop");
}
PORTD = 0x10;
...
Ideally, I would like to essentially run through some code that would compile into this: (it's some weird pseudocode of C and assembly, still not sure how to do some of it in assembly)
0x005 Reg1 = 0xFF-val1 %(where somehow 0xFF is known? / found out?)
0x006 Reg2 =0x1FF-val2
0x007 IJMP Reg1
0x008 NOP
0x009 NOP
0x00A NOP
...
0x0FF MOV 0x40, PORTD % assign the value 0x40 to the static variable "PORTD"
0x100 IJMP Reg2
0x101 NOP
0x102 NOP
0x103 NOP
0x104 NOP
...
0x1FF MOV 0x00, PORTD % assign the value 0x00 to the static variable "PORTD"
I'm just overall not sure how to find the memory location for the code after/during run time so that the "0xFF" and "0x1FF" aspects of this program are not really so bad (it seems like it's super dangerous to just, get the assembly of the code, and then hard code that in... I'd rather not do that). Also, while it's easy to just flood it with the 200+ nops, how to get the IJMP cmd to behave the way I want it to? (I honestly don't even know if that's the command I want)..
I guess in general I'm looking for some assembly command (that I can't seem to find) that allows me to "add N to Program Counter" and I can just make sure that that command is run in assembly with at least N+1 commands of assembly ahead of it, hardcoded in.
As a side note, all of this is executing inside of an interrupt routine, so I don't feel so bad about playing around with the PC... Also, I know is kinda bad blocking for up to 500 operations, but for the task at hand, timing is more important than how badly it blocks as a routine.
I'm not familiar with the AVR instruction set, but the general idea is to use the CALL instruction to put the program counter (PC) on the stack. Then use POP to move the PC to the Z register. Then you can ADD some number to the Z register, and use IJMP to jump to the resulting address.
So something along these lines
delay: call delay1 ; push the PC onto the stack
delay1: pop r30 ; pop the PC into the Z registers
pop r31
add r30,r0 ; add some amount to the PC value
addc r31,r1
ijmp ; use IJMP to jump to the resulting address
nop
nop
nop
...
Random thoughts:
On the 8MB machines, you need a third pop to remove the third byte of
the PC from the stack.
Z is only sixteen bits, therefore this code must be in the first
128KB of program memory.
I'm not sure which register (r30 or r31) is supposed to be popped
first.
The value added to Z must be relative to delay1 since call is
going to push the address of delay1 onto the stack. In other words,
the minimum amount that needs to be added is 6, since that's the
number of instructions from delay1 to the first nop.
The minimum delay is determined by the six instructions up to and
including the ijmp. You should increase r1/r0 (reduce the number of
nops) accordingly.
Like I said, I'm no expert on the AVR instruction set, so you should take this as a general suggestion, and be prepared to spend some time working out the particulars. Good luck!
I am trying to program Blinky program from Keil complier to P89LPC936 microcontroller through a universal programmer(SuperPro). But the microcontroller is not running. But when i write a simple program in assambly and program the same hardware it works fine. Please I need help regarding it where i am doing wrong.
Here is code >>>
Code:
/* Blinky.C - LED Flasher for the Keil LPC900 EPM Emulator/Programmer Module */
#include <REG936.H> // register definition
void delay (unsigned long cnt)
{
while (--cnt);
}
void main()
{
unsigned char i;
P1M1 |= 0x20;
P1M2 &= 0xDF;
P2M1 &= 0xE7;
P2M2 |= 0x18;
delay (20000);
for(;;)
{ for (i = 0x01; i; i <<= 1)
{ P2 = i; // simulate running lights
delay (20000);
}
for (i = 0x80; i; i >>= 1)
{ P2 = i;
delay (20000);
}
}
}
Here is Hex file >>>
:10006B008F0B8E0A8D098C08780874FF12004DECEB
:06007B004D4E4F70F32210
:100003004391205392DF53A4E743A5187F207E4EEC
:100013007D007C0012006B7B01EB6013F5A07F2059
:100023007E4E7D007C0012006BEB25E0FB80EA7BBB
:1000330080EB60E3F5A07F207E4E7D007C00120004
:070043006BEBC313FB80EA25
:01004A002293
:04FFF00023001E00CC
:08FFF800000000000000000001
:030000000200817A
:0C00810078FFE4F6D8FD75810B02000347
:10004B007401FF3395E0FEFDFC080808E62FFFF670
:10005B0018E63EFEF618E63DFDF618E63CFCF622E9
:00000001FF
And here is the assembly code and its hex file which is working absolutely right.
Code:
; LPC936A1.A51
; Oct 7, 2010 PCB: ?
; Features: ?
; ?
$mod51
RL1 bit P2.3
RL2 bit P2.4
DSEG AT 20H
FLAG1: ds 1
STACK: ds 1
FRL1 bit FLAG1.0 ; Relay 1
CSEG
org 0H
ajmp Reset
org 30H
Reset: mov 0A5H,#0FFH
Start: mov c,FRL1 ;
mov RL1,c
cpl c
mov FRL1,c
mov RL2,c
acall Delay0
ajmp Start
Delay0: mov R7,#250
Delay: mov R6,#61
Delay1: nop
nop
nop
nop
nop
nop
nop
nop
djnz R6,Delay1
djnz R7,Delay
ret
Text: DB '(C) DIGIPOWER 2010'
Text0: DB ' LPC936A1 '
END
And its hex is
:020000000130CD
:1000300075A5FFA20092A3B3920092A411400133D0
:100040007FFA7E3D0000000000000000DEF6DFF2D7
:10005000222843292044494749504F5745522032CE
:0D006000303130204C5043393336413120CF
:00000001FF
Please help i m stuck.
Regards
Dani
I don't work with keil tools for a long time and I never used that micro, so probably I won't be able to help you much.
Did you tried running it on the emulator?
Try to put a breakpoint in main and check if it stops there. There might me some issue with c_start and your main isn't being called.
Look at the assembly of the initialization code and check for something odd. I think you can check the assembly code generated by the compiler. You might have to turn on some option to generate intermediate files
You might also check "Electronics and Robotics" at stackexchange. There you may find people working with electronics that might provide better help.
You say that you write a program in assembly and it works fine, but not in C. Have you verified that your C environment is configured to place your code and data in the correct spots in memory?
Also, some chips have a "reset vector" that is called when the chip is first powered and also when the chip resets. Does your C environment set this vector correctly? Does it put code that will jump to your program when it starts to run?
Disassemble or compile the C to assembler to see what the compiler is doing. What is working or not in your C program? does the led just glow? Your assembler looks to be burning about 140,000 instructions but the C maybe 40,000? that could make the difference between an led you can see with your eyes and one that looks to be on but not blinking.
The C program appears to be setting up registers that the assembler does not. is there a bug there? are they disabling something that shouldnt be touched?
bottom line is you need to move the two programs toward each other, complicate the assembler until it approaches what the C is doing and adjust the C toward the assembler (have to look at the output of the compiler though).
Try:
void delay (unsigned long cnt)
{
while (--cnt) {
#pragma asm
NOP
#pragma endasm
}
}