Hi, I've been writing for ARM Cortex M in C for a while, using GCC toolchain. I'm a bit confused reading manuals, and provided examples with FASMARM Could somebody let me have a look at some code which shows how to build and place a proper vector table, handle IRQ's and so on without an OS?

Is it possible at all with FASMARM? GCC linker took care of placing right code in right sections of the elf file. I can't tell FASM that my ROM starts at 0x08000000 and my code is THUMB so vector table should be adjusted.

Or am I soo wrong?
Cheers!

03 Jan 2012, 09:43

malpolud

Joined: 18 Jul 2011
Posts: 344
Location: Broken hippocampus

malpolud

ok, so here is my attempt to write some code, processor: stm32f103rbt6

Got a nice .o file. It's quite late so I'm done for today. The goal is to get an .elf or a .hex file that could be loaded directly to the memory via OpenOCD.
I'm not sure if it just needs to be linked properly or some features must be added to the linker. If an utility must be developed I could try to cope with it. Maybe revolution could help showing the right path?

E: figured out a couple of issues and trying to solve them.

06 Jan 2012, 00:48

malpolud

Joined: 18 Jul 2011
Posts: 344
Location: Broken hippocampus

malpolud

Hi, sorry for posting 3 times at a row.

I managed to compile the code with FASMARM, link it with Code Sourcery GCC ld and burn it into flash.

As I mentioned: the elf file can be burned into flash. The architecture requires that the very first value loaded into flash is the stack pointer. After then an interrupt vector table is placed.

After writing flash and reset: Stack pointer sets the correct value. Program counter goes to 800001Ch which is the right address of the first instruction after label the _start. Unfortunately the instruction stored under 800001Ch is something like:
0011 0000 00011 1000
which doesn't seem to be a valid instruction. I'm pretty sure the problem here is the chosen instruction set.

What really bothers me is why I have to place an offset in my code (I mean the 800 0000h offset), plus tell the linker to offset my .text section? Otherwise it either doesn't respect the memory map placing (starts executing from the beginning of the memory map) or just doesn't burn in flash at all.

It is a 32-bit instruction combined with two 16-bit parts. It is a valid thumb instruction for a v7m capable processor. If you have a v5 processor then you would not be able to execute the v7m instructions.

Note that your processor selection value (7FC2080h) is very unorthodox. It enables the following:

Code:

V4T
X
Z
6M7M
T2
V7
SYNC
DIV
T2EE
MP

It would be very unlikely that a CPU will support v6M but not v5T. And also not having v1 through v6 but allowing v7 is just not right, since the v7 spec explicitly mandates the support for all older v1 through v6 instructions. While you can selectively disable certain parts of the instruction set, it is really only for testing purposes where you would want to allow only the new v7 instructions but disable all of the older v1-v6 instructions. There is no processor made that does that, so in production code you would probably not want to do that.

15 Jan 2012, 09:09

malpolud

Joined: 18 Jul 2011
Posts: 344
Location: Broken hippocampus

malpolud

Thank you revolution actually I was waiting for your help

It's a v7m processor. So what I should do is to enable everything from V1 to V7M? I will check it later, I have to abandon my attempts for a couple of weeks due to intensified university work.

Note that it can be disadvantageous to set the processor to a higher setting than the CPU is capable because of the extra encoding alternatives that the assembler has available.

15 Jan 2012, 20:55

malpolud

Joined: 18 Jul 2011
Posts: 344
Location: Broken hippocampus

malpolud

Ok, I've got my free time back, so I'm back having fun.

I tried to change processor encoding, but it's still not there. After enabling all from V1 to V4 plus V4T, X, Z, V5T, V6T, ALIGN, 6M, 7M (or the ones plus T2, T2EE) the first instruction is: 6054f8df. Or rather f8df? I'm checking ARM_v7m_arm out but it seems I make a mistake somewhere.

Could you explain how to figure out if a certain instruction is 16 or 32 bits? With F8DF6038 we've got five "ones" as bytes 31-27. Ok, 32 bit instruction. But if we run the second configuration, we read a word from 800001C we get 6054f8df. "Ones" only on 31 and 30 so it's a 16 bit instruction. It's a 16 bit instruction so we would rather read a half word. We do and what we get is: f8df which should be a 32bit instruction! Ehhh endianness...

It depends upon which mode the CPU is in. In THUMB mode the instruction encoding is different from ARM mode. You can't look at a group of 32 bits and say what instruction is encoded until you know the CPU mode. These instruction encode differently in each mode:

Also, instructions are always little endian encoded. But beware, in another thread there there is discussion about a system with firmware that reads instructions from an 8-bit eeprom in big-endian format and stores them in 16-bit memory in little-endian format for execution. So check your system to know what the firmware does with your binary code. If you are directly writing the firmware then this issue won't affect you.

I used the "Thumb" directive, so it is in thumb mode. But I mean this:

v7m_arm wrote:

The Thumb instruction stream is a sequence of halfword-aligned halfwords. Each Thumb instruction is either a single 16-bit halfword in that stream, or a 32- bit instruction consisting of two consecutive halfwords in that stream.

Last time I decoded a wrong instruction, cause I read a halfword from my "start" address. You said it's wrong, cause I decoded a 16 bit instruction instead of a 32 bit one, and you were right

I'm writing the firmware directly to the built in memory, but I'd like to understand how it works

20 Feb 2012, 00:29

malpolud

Joined: 18 Jul 2011
Posts: 344
Location: Broken hippocampus

malpolud

Ok, but with 6054f8df we've got:
00: F8DF
02: 6054
DF F8 54 60.

If I read a hw from 00 i get F8DF = 1111100011011111. According to man:

v7m_arm wrote:

If bits [15:11] of the halfword being decoded take any of the following values, the halfword is the first halfword of a 32-bit instruction:
• 0b11101
• 0b11110
• 0b11111

I burned the flash once more and check whats the instruction and what I got after reading a word is 6038F8DF - I was a bit confused why you say 6054F8DF is the same instruction with F8DF6038.

I show the hex codes in the same format as the ARM manual shows. With each of the 16-bit portions shown in the order as they appear in the binary output, and within each 16-bit portion written as normal hex number with the MSD first. You should really think of a thumb 32-bit instruction as two separate 16-bit portions and not as one monolithic 32-bit portion, that way it will make more sense to show it in the format I give above.

malpolud wrote:

There is one small thing left. 0x6038=
1100 0000111000
<Rt> <label>

111000 = 0x38 but 1100 =0xC so I would expect the value would be loaded to R12 not R6? Of course it is loaded to R6. Where should I search for the answer?

You missed one bit. The offset is 12 bits.

0x6 (register r6) shl 12 + 0x038 (offset)

20 Feb 2012, 02:10

malpolud

Joined: 18 Jul 2011
Posts: 344
Location: Broken hippocampus

malpolud

Well I shouldn't ask my last question

Thanks for help revolution

20 Feb 2012, 07:18

malpolud

Joined: 18 Jul 2011
Posts: 344
Location: Broken hippocampus

malpolud

Well after a couple whiles of debugging and finding out that FASMARM outputs perfect binary file that is executed correctly I figured out that the example provided does work. I've just mistaken the port I should toggle (8h instead of 4h)

What I'd love to achieve: possibility to build a vector table that doesn't have to be manually adjusted to work correctly with T2 instruction set. Perhaps a directive should be added? And I want to use FASM's linker.

Thank you revolution for FASMARM, it's so exciting! And for all your precious tips.

There is a problem with automatically adding one to the thumb addresses. Namely that the assembler does not know for what purpose you are generating the address. For executing and mode switching then you need to add one. For data access you wouldn't want to add one.

I would suggest that you use something like a proc macro to define an extra label (perhaps with some extension like .thumb added to the label) to indicate that the label is an entry point. Then you can build jump tables and check whether each label is for thumb code entry or for data access.

22 Feb 2012, 04:54

malpolud

Joined: 18 Jul 2011
Posts: 344
Location: Broken hippocampus

malpolud

I already did something like:

Code:

macro vector name {dw name +1}

but it's not sophisticated at all. I will try to do it the way you said.

22 Feb 2012, 07:46

malpolud

Joined: 18 Jul 2011
Posts: 344
Location: Broken hippocampus

malpolud

Ok, I have no idea how to do that, revolution you mean something like this:

Code:

vectors.thumb:
vector_1
....
vector_n
endvect ;optionally

?
I've been looking at the source, but unfortunately I can not figure out how to do that. Could you give me a hint - maybe piece of proper FASM's source code?
Cheers

I would suggest that you use something like a proc macro to define an extra label (perhaps with some extension like .thumb added to the label) to indicate that the label is an entry point. Then you can build jump tables and check whether each label is for thumb code entry or for data access.

Could you please say something more about it? I don't quite understand yet how proc works, trying to gather some information.

_________________There's nothing special about it,
It's either there when you're born or not.

You cannot post new topics in this forumYou cannot reply to topics in this forumYou cannot edit your posts in this forumYou cannot delete your posts in this forumYou cannot vote in polls in this forumYou cannot attach files in this forumYou can download files in this forum