BenF V3 source code

Hi all,
Thanks for BenF’s firmware and source code. BenF is willing to share his source code. I just put it at google code.You can get it from
Thanks again!

Thank you very much for all the good work!

Many thanks to BenF! He has done a good thing here.

I have noticed that the source code is for V3.11 APP whereas the latest firmware release is V3.12 APP. Maybe BenF could point out the differences.

I especially appreciate the comments in the DSO201_LIB,cspy.bat file. Quite often a release of knowledge will be used in ways not anticipated by the author, and such is the case here.

I will study this source code to help me learn to program this processor and associated peripherals. The DSO will be my poor man’s development board for learning the STM32F10xxx. Plus I can always reload BenF Vxxx FW when ever I need to use the DSO as a DSO. I also have a TDS210 DSO for hardware signal analysis.

This will be a steep learning curve for me from PIC assembly-language to C-language for the STM32 (I have some C experience and this will help me to tie up many loose ends concerning assembly and linking). This should prove to be a good environment with tested code for many hardware functions. Now I have an interesting way to boot-strap myself into a very powerful embedded processor family. I have already downloaded much of the STM32 support documentation.

I guess it is now time to learn to assemble and link V3.11 so I can see it run on the DSO.

Once again, thanks to BenF

Thanks a lot BenF! This is Christmas one month early :slight_smile: I just had a quick look at it, and not only is the code clean and tidy, it also has a GPL license. Great stuff!

I would recommend to add author, copyright and licensing information to each file, to avoid any confusion and legal questions.

EDIT: Maybe interesting read:

I have just migrated the DSO201 v1.1 source code and Ben’s source from IAR4.0 to IAR5.0. You can get them from . I have tested both of them,DSO201 v1.1 passed,yet Ben’s not.I think the problem is __APP_Start,this function jumps to 0x0800C121, the static address maybe different in different IAR versions.

You can check the first bytes in the APP binary to see if its reset vector points to 0x0800C121.

It would be better if the code in the LIB, instead of jumping to a hard-coded address, would read the reset vector at 0x800C004 and jump to its value.

In fact, you can replicate pretty much what is done in the DS0201_DFU main() function.

Firstly: Can we PLEASE put the code into a repository instead of just a downloadable zip file? That would really help collaboration. Why not just use the Google code if people can consider using svn or mercurial? I can spend the time to do so if we can agree how and where.

Secondly: Can we now please get rid of the APP/LIB split? Or would this hit the 32kb limit in IAR?

Personally I would prefer a distributed system like git or mercurial, and I am familiar with git. Hosting can be done at for instance However, this question should be resolved by those who take the maintainer role.

Yes, it would hit the 32k free-as-in-beer IAR limit. I believe the size limit was the original reason for the split, although later they also added non-free stuff to the LIB so the source had to be kept split anyway.

I would recommend keeping the code compatible with both IAR and gcc, and see how it goes. Maybe tweak the gcc build system so that it optionally links one common binary. Then if the software grows, and keeping a multiple of LIBs becomes a headache, eventually ditch IAR. But I think at the current state, many people will prefer to use IAR.

For a normal user, the split should not be an issue. The complete set of binaries can be distributed in one .dfu file. But for some reason all binary releases so far has been using two separate .dfu files which can make things look a bit complicated and confusing.

also on a related note, can we get a consistent naming convention for the files posted on google code?
As somebody who does not read this forum every day sometimes it’s hard to figure out what each file represents only from the title. Maybe some folders / consistent tagging …

I find that 0x0800c121 is the entry point of the app using IAR4.0. You can find the following sentences in the map file of the app project:
Program entry at : 0800C121 Relocatable, from module : ?CMAIN .
__program_start 0800C121 Absolute parts (?ABS_ENTRY_MOD) __vector_table (stm32f10x_vector)
Yet the mapping file is different in IAR5.0 . You can not find that sentence. I just set the __APP_Start to __iar_program_start. It did’t work. And we can not set __APP_Start to 0x0800c004, because the reset function is not the main function.

0x800c004 is not the main function, but contains a pointer to the reset handler, which after initializing variables, jumps to main(). So just read the address out of 0x800c004 and jump to it. The same is done in the DFU boot loader, for chainloading the LIB.

Both APP and LIB should do their initializing of variables, and since they do not share data segments (RAM sections defined in linker script does not overlap) it should not cause any issues either.

0x800c004 is not the main function, but contains a pointer to the reset handler, which after initializing variables, jumps to main(). So just read the address out of 0x800c004 and jump to it. The same is done in the DFU boot loader, for chainloading the LIB.

Thanks for your reply. Yes, the 0x800c004 is the pointer of the reset vector,I tried that way and it did’t work. In Ben’s firmware using IAR4.0, __APP_Start is not the reset handler but the program entry __program_start. I think the among reset handler and __program_start,there are some IAR internal function.

Thanks, I see. So whatever the APP reset handler does before calling APP __program_start would make it fail. It would be interesting to know what is going on there. Maybe something important (but something that can only be done once) that we miss in the gcc build. Can you please attach an elf file produced by IAR, so that I can try disassemble it?

I studied the IAR stuff, and the __program_start is indeed the reset handler. You can see this in EWARM/stm32f10x_vector.c
And 0x0800C121 which is APP_START in Ben’s LIB matches the reset vector you can see in Ben’s APP binary (byte 5-8).

So there must be another reason it did not work. Does this patch work? It is against current gcc branch. The gcc branch should build fine on IAR as well, otherwise I would like to fix it!

I tested on IAR 4.0 with calling the reset vector rather than a hardcoded assembly branch instruction and it woks as expected.

One issue with the proposed patch however is the following:

-__APP_Start ;void __APP_Start(void)

  • B 0x0800C121

If you remove those lines, addresses for callback from APP back into LIB will be incorrect. You should be able to start APP, but as soon as you call back into LIB (such as GetFonts) it is likely to fail miserably unless you adjust the vectors in APP accordingly.

A related aspect to consider is the _APP_Start label in LIB. This is hardcoded in APP and serves as an offset from where branch addresses to LIB functions can be found. This label may very well be placed at a different offset on Gcc and perhaps also IAR 5.0. Once you start APP, interrupt vectors are reasssiged into the APP program segment (away from LIB). USB service interrupts however are channeled back into LIB and so this is likley to crash hard and fast unless addresses are properly mapped.

If you look at this logic and verify harcoded/absolute addresses against the map file, you may be able to pick up and see some progress again.


Thanks for looking at it! I originally thought these two lines only defined an __APP_Start() function (jumping to 0x0800C121, and I could just remove it since we do not use it (with the patch applied). But I understand the removal of this code will shift the following code a few bytes backwards… I should replace it with a dummy branch or enough NOPs. It is ugly in any case.

I don’t see anywhere that the branch table (in ASM_Function.s) is anchored to any address. Is it related to __APP_Start in any way? Anyway, I guess a better solution would be to put the table into a separate section and specify a fixed location in the linker script, for instance immediately after the interrupt vector table.

Very interesting. How are these channeled back? I thought the APP brings its own, complete set of interrupt routines.
EDIT: Oh, I got it: the __CTR_HP and _USB_Istr service the USB interrupts.

This definitely needs a solid rework in the gcc port. Tempting to get rid of the split and just link everything the normal way… But compatibility with IAR is the better way for now, I think.

However, the most important problem in the gcc port right now must be something different than these issues, because it does not seem to even come that far in the LIB that it will jump to APP. The screen remains white with no logos or texts displayed.

It is exacly like this in IAR4 - the vector table in LIB is located in segment CODE, which is
of type CODE and aligned on 2-byte boundaries; the table begins with __APP_start, so
other symbols could be located by computing the offset.

Here’s the excerpt from LIB’s ASM_Functions.s:

__APP_Start                ;void __APP_Start(void)
    B       0x0800C121
__USB_Istr                 ;
    B       USB_Istr
__CTR_HP                   ;
    B       CTR_HP
__MSD_WriteBlock           ;
    B       MSD_WriteBlock
__MSD_ReadBlock            ;
    B       MSD_ReadBlock
__Get_Font_8x14            ;
    B       Get_Font_8x14
__Get_Ref_Wave             ;
    B       Get_Ref_Wave
__SD_Set_Changed           ;void SD_Set_Changed(void);
    B       SD_Set_Changed

The only EXPORTED symbol is __APP_Start, which contains the IAR4 entry point for APP.

Now, the parallel definitions in APP’s ASM_Functions.s are these:

__CTR_HP                  ;void __CTR_HP(void)
    B       0x08004159
__USB_Istr                ;void __USB_Istr(void);
    B       0x08004155
__MSD_WriteBlock          ;u8 __MSD_WriteBlock(u8* pBuffer, u32 WriteAddr, u16 NumByteToWrite)
    B       0x0800415D
__MSD_ReadBlock           ;u8 __MSD_ReadBlock(u8* pBuffer, u32 ReadAddr, u16 NumByteToRead)
    B       0x08004161
__Get_Font_8x14           ;u16 __Get_TAB_8x14(unsigned char Code, unsigned short Row)
    B       0x08004165
__Get_Ref_Wave            ;u8 __Get_Ref_Wave(unsigned short i)
    B       0x08004169
__SD_Set_Changed          ;void __SD_Set_Changed(void)
    B       0x0800416D

from which you can infer that __APP_Start resides in memory at location 0x08004151 when LIB is compiled under IAR4. Of course, it won’t get the same address with IAR5 - there’s a brand new linker, there.

And, for the very same reason (as you already pointed out), __APP_Start should be updated to contain a different address - the APP entry point under both gcc and IAR5 will be different from 0x0800C121.

Well, this needs a solid rework in IAR5 too :wink:

A good starting point for me could be the one you proposed - a separate section whose address is specified via linker config. These notes explain how to do that in IAR5:

Don’t know about gcc, but another problem in the migration to IAR5 could be given by different stack alignment: from the migration guide at, I read


I’ve had a go with IAR5 - if you uncomment WaitForKey, the LIB works ok up to that point - so definitely we just need to update the jump into APP. I’ve then updated the symbol table inside APP, and bingo, it works :sunglasses: The magic numbers follow.

In LIB, use:

__APP_Start                ;void __APP_Start(void)
    B       0x08010cd1

In APP, when LIB’s main has WaitForKey uncommented, use:

__CTR_HP                  ;void __CTR_HP(void)
    B       0x08007219
__USB_Istr                ;void __USB_Istr(void);
    B       0x08007215
__MSD_WriteBlock          ;u8 __MSD_WriteBlock(u8* pBuffer, u32 WriteAddr, u16 NumByteToWrite)
    B       0x0800721D
__MSD_ReadBlock           ;u8 __MSD_ReadBlock(u8* pBuffer, u32 ReadAddr, u16 NumByteToRead)
    B       0x08007221
__Get_Font_8x14           ;u16 __Get_TAB_8x14(unsigned char Code, unsigned short Row)
    B       0x08007225
__Get_Ref_Wave            ;u8 __Get_Ref_Wave(unsigned short i)
    B       0x08007229
__SD_Set_Changed          ;void __SD_Set_Changed(void)
    B       0x0800722D

In APP, when LIB’s main has WaitForKey commented, use:

__CTR_HP                  ;void __CTR_HP(void)
    B       0x08007205
__USB_Istr                ;void __USB_Istr(void);
    B       0x08007201
__MSD_WriteBlock          ;u8 __MSD_WriteBlock(u8* pBuffer, u32 WriteAddr, u16 NumByteToWrite)
    B       0x08007209
__MSD_ReadBlock           ;u8 __MSD_ReadBlock(u8* pBuffer, u32 ReadAddr, u16 NumByteToRead)
    B       0x0800721D
__Get_Font_8x14           ;u16 __Get_TAB_8x14(unsigned char Code, unsigned short Row)
    B       0x08007211
__Get_Ref_Wave            ;u8 __Get_Ref_Wave(unsigned short i)
    B       0x08007215
__SD_Set_Changed          ;void __SD_Set_Changed(void)
    B       0x08007219

Have fun!