Cortex M3 hand holding tutorial - Page 1
Forum section: electronics / general

author: TheBrick
author_rank: Regular Contributor
timestamp: June 15, 2014, 07:56:06 pm
content: Hi, I've bought ,my self a M3 development board (LPC-P1343) and Jtag cable / unit. I've set up my tool chain but I'd like to read though some tutorials about that step my though some code. There are some example that come with the code by not real explanation of what is being done. Running though my head are questions like "where did that function come from?", "what are you setting to 0X00000000F and why?", " Can I use the same .s file for everything and it is just some set-up for this device or do I have to customise it for every project".I've done some AVR programming before and the tutorials I found for that have been excellent. Stepped me through what was being done from blinking LEDs to UART to interrupts e.t.c. I've read some intro to cortex M3 documents and introductions (e.g.http://www.egr.msu.edu/classes/ece331/mason/web_files/ARM_CortexM3.pdf,some othe pdf from ARM) that tell me that its Harvard architecture and there are 15 general purpose registers e.t.c but all of the tutorials seem to be aimed aimed at specific boards or I feel like I've walked in to a conversation half way through. I thought that with CMSIS things should have a standard interface? I just need a dummies intro to get me rolling on some basic task then I will understand what bits I need to google to go further.Hoping someone can help point me in the right direction.

author: dannyf
author_rank: Super Contributor
timestamp: June 15, 2014, 08:02:06 pm
content: They are all highly alike, aside from the peripherals. So once you know how to set up one, you know how to set up another.Your issue looks like you need to know how to set up yours. That can be difficult without knowing specifically what tools you are using.

author: Tris20
author_rank: Regular Contributor
timestamp: June 15, 2014, 09:19:41 pm
content: There's a good book called "Fast and effective embedded systems design - applying the ARM mbed" which I got a while ago. It goes with the LPC1768 which also runs off the M3 and has a decent amount of good beginner code and descriptions. Not sure how useful the book will be for JTAG but it can certainly help you get used to a new embed provided you're happy to make a few minor changes to the code (mostly just pin outs) to get things to work.

author: SirNick
author_rank: Frequent Contributor
timestamp: June 17, 2014, 08:17:52 pm
content: Welcome to ARM. This appears to be the rite of passage for anyone learning them. It seems you're supposed to blindly jump in and start modifying code until you start to see the patterns for yourself. Does that function exist in every example, even those from different vendors? Then it's probably CMSIS. That kind of thing.The crappy orientation doesn't seem to be an impenetrable barrier, as Cortex Ms are pretty much the rage these days. But, as you can tell, Arduino it isn't.Just start digging in. Read the data sheet sections for I/O pins and the peripheral you want to use. Tweak the code and compile it, see if it works. It's foreign right now, but if you immerse yourself in it, you'll get there. I assume. I'm still logging time in the co-pilot's seat myself.

author: janoc
author_rank: Super Contributor
timestamp: June 17, 2014, 08:44:51 pm
content: There are quite a few decent tutorials online. One thing that helps you a lot is to be familiar with the gcc toolchain - most ARM toolchains are derived from it.Most of the stuff I have is for STM32, but for LPCs there are some as well - just adapt to your micro:http://www.dreamislife.com/arm/http://tenuki.fr/nio101/?page_id=67https://code.google.com/p/cortex-m3-tutorials/http://www.meatandnetworking.com/tutorials/arm-cortex-mx-quickstart/http://www.meatandnetworking.com/tutorials/lpc1114fn28-with-open-source-tools/These are pretty good overview of gcc, linker scripts, debugging with OpenOCD and gdb. It is for STM32 but most things are pretty much the same for the LPC chips too - you may just need a different configuration here and there.http://hertaville.com/the-stm32f0discovery-board/http://hertaville.com/2012/06/29/alternative-tutorials-for-setting-up-a-gcc-based-development-environment/There are likely some more. For JTAG, gdb and similar - have a look at OpenOCD and/or the website of the vendor of your JTAG tool.There are also a lot of videos and tutorials on Youtube, explaining the architecture, how to set up the toolchain, etc.For example:

author: SirNick
author_rank: Frequent Contributor
timestamp: June 17, 2014, 11:46:43 pm
content: That (the video) is a really good tutorial series. It starts out with the typical pointless and inevitably incomplete guide to how to use installation programs and write C code, but goes pretty quickly into useful info, assuming this isn't your first time using a computer.I really like how it works up from reading / writing memory to explaining the concept of memory maps and GPIO registers. Great approach to demystifying the inner workings.Good stuff, thanks for posting the link.

author: azrobbo
author_rank: Newbie
timestamp: June 18, 2014, 12:18:48 am
content: It sounds like something is wonky with your IDE & CMSIS setup. Since you're using an LPC MCU, you might check out NXP's free IDE:http://www.lpcware.com/lpcxpressoThe video linked off of that page is about an hour demo of setting up and using the IDE - hopefully that will get you going.Cheers.

author: nuhamind2
author_rank: Regular Contributor
timestamp: June 18, 2014, 02:34:59 am
content: I'm in the same boat. Have been reading a few document but never actually write a code. Lately I'm wondering about every file automatically included when I start a project and what purpose they serve. This PDF explain CMSIS and the level they are used.http://www.doulos.com/knowhow/arm/CMSIS/CMSIS_Doulos_Tutorial.pdf

author: dannyf
author_rank: Super Contributor
timestamp: June 18, 2014, 10:11:25 am
content: There are generally 3 types of files involved in a CMSIS start-up:1) the start-up file: it lays down the interrupt vector table, calls SystemInit() and then _main()/main(). Tpically written in assembly;2) the device file: it defines the interrupt vector table specific to the device and provides a set of clock management functions (SystemInit(), SystemCoreUpdate() and some basic nvic functions). Typically done in C. The .h file here is very important.3) the core file: defines a set of routines across CMx chips and key register mapping.For the most part, they are transparent to the programmer.

author: janoc
author_rank: Super Contributor
timestamp: June 19, 2014, 09:15:00 am
content: Here is another good general ARM tutorial, explaining the toolchain, the linker scripts etc.http://www.bravegnu.org/gnu-eprog/index.htmlAnd a very decent but brief walkthrough from compiling down to JTAG, but for STM32:http://www.triplespark.net/elec/pdev/arm/stm32.htmlI don't have issues with IDEs like LPCxpresso, but those things often hide everything behind an impenetrable wall of "black magic". OK if you want to get going quickly, but not when you are trying to learn and understand what is actually going on.There is also another thread going with a lot of good pointers:https://www.eevblog.com/forum/microcontrollers/arm-begginer-questions/

author: SirNick
author_rank: Frequent Contributor
timestamp: June 19, 2014, 06:56:23 pm
content: I gotta say, I'm a gcc fan but IAR looks like a nice package. From the YouTube videos above, it seems focused on getting down to business. Every little thing in LPCXpresso (Eclipse) is obscured by wizards and step-by-step dialogs that do who-knows-what. Ugh. Like you said, impenetrable black magic. I find that much harder to understand than compiling things by hand on the CLI, for e.g.Thanks everyone for the great links and such. Keep it coming.

author: dannyf
author_rank: Super Contributor
timestamp: June 19, 2014, 07:11:43 pm
content: QuoteWay too complicated, in my view.Depending on where I start, I can do the blinky and/or the FPU examples there within 15 minutes for sure, and likely within a couple minutes, in most IDEs (Keil / IAR / CoIDE or even LPCxpresso).There actually are minimum differences between the various IDEs, as long as you understand how a typical project is set up, how to link in source / header / library files and how to set up the various switches. After that, you can easily replicate whatever you do on one IDE to another.

author: janoc
author_rank: Super Contributor
timestamp: June 23, 2014, 08:39:32 am
content: Quote from: dannyf on June 19, 2014, 07:11:43 pmYeah, I am not arguing with that. If you are an experienced engineer, have the means to get these tools and want to be productive quickly, buy the toolchain and IDE and off you go. It is certainly faster than compiling/setting up own toolchain, IDE, what not. That's what these things are for, finally.However, for a newbie learning the platform, these "magic" IDEs won't do you any favours. If you want to go beyond the "Arduino-like magic button pushing" stage, one has to have the understanding how the code is actually compiled and what is going on behind the GUI. I have been teaching basic C/C++ programming to university students for several years and giving these folks something like Eclipse, Visual Studio or XCode was a sure-fire way to get them lost with the distractions of the IDE right there. If the code compilation, linking and deployment is reduced to a single click of the "Build" button, then good luck trying to explain the difference between a syntax and linking error, for example - everything becomes "it doesn't compile!" error ...I am a fairly experienced software developer myself, but when I started with ARM, it helped me a lot to actually see what is going on with the startup code, how the linker scripts are set up, how to make gdb talk to my JTAG, etc. Tools like LPCExpresso or Keil that I have tried are hiding these things from you - it somehow does the right thing, but good luck figuring out what is going on there if you don't even know what to look for yet!To conclude - you need to distinguish whether the objective is to bang out code quickly (then go for an IDE) or learning and pedagogy.

author: dannyf
author_rank: Super Contributor
timestamp: June 23, 2014, 09:29:24 am
content: QuoteIf they are hiding it from you, they are hiding it in plain sight: they are right there, in your project directory or linked directory, depending on how you set up the tools. If anything, any IDE makes it far easier for you to trace through the various files and see how they work together.

author: janoc
author_rank: Super Contributor
timestamp: June 23, 2014, 03:40:44 pm
content: Quote from: dannyf on June 23, 2014, 09:29:24 amDannyf, you have managed to completely miss my point. The "plain sight" is much less plain when a) you aren't aware that you need some sort of "startup file" to begin with, b) that the application will not work unless you use the correct linker script (and there could be different ones even for the same chip!), c) any of the power or RCC/NVIC/pin mapping idiosyncrasies isn't handled right, etc.That is the main value of doing the "bare bones" tutorials - to learn how things actually fit together, then you will know what to look for in the IDE. Remember, we are talking a complete newb here, perhaps someone who did some Arduino or PC programming, where all these things are taken care of by the default compiler setup and much simpler hardware.Then the person switches to an ARM IDE, where this is set up for you "in plain sight" using vendor libraries and tools and wonders why the project suddenly doesn't work at all, even though they just wanted to put some LED on another port - e.g. because power or clock to that port that isn't used in the vendor's example wasn't enabled. Good luck tracking that down if you don't know what you are looking for!I am certainly not advocating doing bare bones programming for production nor bashing IDEs as such. I am only speaking from experience of having to teach this stuff to complete neophytes for four years at a university.

author: dannyf
author_rank: Super Contributor
timestamp: June 23, 2014, 09:35:42 pm
content: -when a) you aren't aware that you need some sort of "startup file" to begin with, -startup files are not unique to arm chips or ide. Every mcu has them.-b) that the application will not work unless you use the correct linker script (and there could be different ones even for the same chip!), -that is actually a non issue for ide - I have yet run into an IDE where the default linker doesn't work.-c) any of the power or RCC/NVIC/pin mapping idiosyncrasies isn't handled right, etc.-again that's not unique to ide.I don't think any of the examples above represents extra difficulties brought on by the use of an IDE.

author: janoc
author_rank: Super Contributor
timestamp: June 24, 2014, 01:47:36 pm
content: Quote from: dannyf on June 23, 2014, 09:35:42 pmShow me one for an ATMega or PIC then. You won't find anything comparable to the typical ARM startup file (power and clock tree setup) on these. Some PICs have PLL, but that's about it.Quote from: dannyf on June 23, 2014, 09:35:42 pmThe issue is not that it won't work but that you may have to modify it - e.g. to put some data in flash. Again not something that is common on the smaller micros like the ATMega (there you use compiler directives for doing the same). Not specifically an "IDE problem", but it is a lot easier to be aware of it when you do things "bare bones" first.Anyway, I think we will have to agree to disagree here. You are obviously seeing it from the view point of an engineer doing this professionally every day, I am speaking from the position of someone who had to teach the programming basics to newbies. You would likely change your mind quickly if you had to teach this to someone who thinks that setting up a webpage is "programming" (that was the level of the students we had coming into the courses ...). IDE becomes a real distraction really quick in that case. Teach the simple/basic stuff first, move on to more complex topics/tools later!Cheers,

author: dannyf
author_rank: Super Contributor
timestamp: June 24, 2014, 03:35:19 pm
content: QuoteFairly easy:1) the best place to look for them is in the .lss/.lst files: you will see a vector table (avr), a initialization section, and a call to main() - that's identical to what you see on those ARM chips (and pretty much anything else).2) MPLAB I think also create a stylized strat-up.c in the project folder. gcc-avr utilizes a set of crt*.* files for start-up - you can google them as well.QuoteGating of clocks is not available on most pic / avr so you obviously wouldn't find them there.QuoteI actually find it the exact opposite. Maybe your perception, which I am sure is 100% legit, is a result of your way of doing things.

author: nctnico
author_rank: Super Contributor
timestamp: June 24, 2014, 04:09:52 pm
content: Quote from: janoc on June 24, 2014, 01:47:36 pmPICs and other controllers generally need a startup file written in assembly to setup the stack, clear the memory and initialise variables. The beauty of Cortex Mx devices is that they don't need all that because they can start a C binary directly and call C functions directly from an interrupt. This means you can write all the software in 100% pure C.

author: Bassman59
author_rank: Super Contributor
timestamp: June 24, 2014, 04:30:16 pm
content: Quote from: janoc on June 24, 2014, 01:47:36 pmI agree ... someone coming from the world of host application programming doesn't have the first clue that a startup file is necessary.

author: janoc
author_rank: Super Contributor
timestamp: June 24, 2014, 08:43:22 pm
content: Quote from: nctnico on June 24, 2014, 04:09:52 pmI beg your pardon? How do you start a "C binary" directly? (btw, what is a "C binary"? Is it any different from an "assembler binary"?) The variable init, stack setup etc. you have on the Cortex-es too - and more. Mainly clock and power setup, which the PICs/AVRs and similar typically don't have, because of simpler hardware.

author: dannyf
author_rank: Super Contributor
timestamp: June 24, 2014, 08:53:05 pm
content: QuoteThat's probably one of those "perfect understanding" of yours that is less than proper.The start-up files I have seen are mostly assembly source files, and C source file in one case.QuoteMy reaction exactly,

author: dannyf
author_rank: Super Contributor
timestamp: June 24, 2014, 08:59:40 pm
content: On PIC start-up file:here is one generated by XC8 under MPLAB for a PIC12F675 project that I worked on.Code:; Microchip MPLAB XC8 C Compiler V1.12; Copyright (C) 1984-2012 HI-TECH Software; Auto-generated runtime startup code for final link stage.;; Compiler options:;; -o12f675 rmw.cof -m12f675 rmw.map --summary=default --output=default \; main.p1 gpio.p1 --chip=12F675 -P --runtime=default --opt=default -N-1 \; -D__DEBUG=1 -g --asmlist --errformat=Error [%n] %f; %l.%c %s \; --msgformat=Advisory[%n] %s --warnformat=Warning [%n] %f; %l.%c %s;processor12F675global_main,start,reset_vecfnroot_mainpsectconfig,class=CONFIG,delta=2psectidloc,class=IDLOC,delta=2psectcode,class=CODE,delta=2psectpowerup,class=CODE,delta=2psectreset_vec,class=CODE,delta=2psectmaintext,class=CODE,delta=2Cset0Zset2PCLset2INDFset0OSCCALequ0x90psectosccal,class=CODE,delta=2global ___osccal_val___osccal_val:;oscillator constant would be pre-programmed hereSTATUSequ3PCLATHequ0Ahpsecteeprom_data,class=EEDATA,delta=2,space=2psectintentry,class=CODE,delta=2psectfunctab,class=CODE,delta=2globalintlevel0,intlevel1,intlevel2, intlevel3, intlevel4, intlevel5intlevel0:intlevel1:intlevel2:intlevel3:intlevel4:intlevel5:psectinit,class=CODE,delta=2psectcinit,class=CODE,delta=2psecttext,class=CODE,delta=2psectend_init,class=CODE,delta=2psectclrtext,class=CODE,delta=2FSRset4psectstrings,class=CODE,delta=2,reloc=256psectreset_vecreset_vec:; No powerup routine; No interrupt routinepsectinitstartpsectend_initbsfSTATUS,5;select bank 1fcall___osccal_valmovwf0x90 ^ 0x80bcfSTATUS,5;select bank 0global start_initializationljmp start_initialization;jump to C runtime clear & initialization; Config register CONFIG @ 0x2007;Brown-out Detect Enable bit;BOREN = OFF, BOD disabled;Data Code Protection bit;CPD = OFF, Data memory code protection is disabled;Oscillator Selection bits;FOSC = INTRCIO, INTOSC oscillator: I/O function on GP4/OSC2/CLKOUT pin, I/O function on GP5/OSC1/CLKIN;GP3/MCLR pin function select;MCLRE = OFF, GP3/MCLR pin function is digital I/O, MCLR internally tied to VDD;Watchdog Timer Enable bit;WDTE = OFF, WDT disabled;Code Protection bit;CP = OFF, Program Memory code protection is disabled;Power-Up Timer Enable bit;PWRTE = OFF, PWRT disabledpsectconfigorg 0x0dw 0x3194psect bank0,class=BANK0,space=1psect bank1,class=BANK1,space=1psect ram,class=RAM,space=1psect abs1,class=ABS1,space=1psect common,class=COMMON,space=1psect sfr0,class=SFR0,space=1psect sfr1,class=SFR1,space=1endstart

author: nctnico
author_rank: Super Contributor
timestamp: June 24, 2014, 09:08:42 pm
content: Quote from: janoc on June 24, 2014, 08:43:22 pmSimple. First you need an interrupt vector table.Code:typedef struct TCortexIrq{uint32_t __initial_sp; // 0x00 Top of Stackuint32_t Reset_Handler; // 0x04 Reset Handleruint32_t NMI_Handler; // 0x08 NMI Handleruint32_t HardFault_Handler; // 0x0c Hard Fault Handleruint32_t dummy1; // 0x10 reserveduint32_t dummy2; // 0x14 Reserved-snip-uint32_t WDT_IRQHandler; // 16+25: Watchdog Timeruint32_t BOD_IRQHandler; // 16+26: Brown Out Detectuint32_t dummy13; // 16+27: Reserveduint32_t PIOINT3_IRQHandler3; // 16+28: PIO INT3uint32_t PIOINT2_IRQHandler2; // 16+29: PIO INT2uint32_t PIOINT1_IRQHandler1; // 16+30: PIO INT1uint32_t PIOINT0_IRQHandler0; // 16+31: PIO INT0} TCortexIrq;Then that needs to be initialized and put in a section which is at the start of the memory:Code:extern void _stack_end();//Interrupt table. The first entry is the stack pointer the second entry points to mainconst TCortexIrq CortexIrq __attribute__((section("vectors"))) ={.__initial_sp=(uint32_t) _stack_end,//SP at the end of the memory.Reset_Handler=(uint32_t) main,.HardFault_Handler=(uint32_t) hardfault_handler,.TIMER32_0_IRQHandler=(uint32_t) timer_handler,.UART_IRQHandler=(uint32_t) UART0_IRQHandler,};Now the controller will call main and initialise the stack pointer with the value from _stack_end after a reset. The 'symbol' _stack_end is defined in the linker description file. Next we need some initialisation:Code:extern void __bss_start__();extern void _bss_end();extern void _data();extern void _edata();extern void _stack_end();extern void _datastart();int main(){memset(_data, 0, _stack_end - __bss_start__-32);//clear memory including most of the stackmemcpy(_data, _datastart , _edata-_data);//copy initialiased variablesSystemInit();__enable_irq();- run the firmware -}SystemInit() is located in a file from the CMSIS part and initialises the PLL and clock. __enable_irq() is a macro from core_cm0.h.The linker descriptor file looks like this:Code:/* ****************************************************************************************************** *//* lpc1113.ldLINKER SCRIPT*//* *//* identify the Entry Point */MEMORY{flash: ORIGIN = 0, LENGTH = 24K/* FLASH ROM*/ram: ORIGIN = 0x10000000, LENGTH = 4K/* free RAM area*/}/* now define the output sections */SECTIONS{. = 0;/* set location counter to address zero */startup : { *(vectors)} >flash/* the startup code goes into FLASH */.text :/* collect all sections that should go into FLASH after startup */{*(.init)*(.text)/* all .text sections (code) */*(.glue_7)*(.glue_7t)_etext = .;/* define a global symbol _etext just after the last code byte */*(.rodata)/* all .rodata sections (constants, strings, etc.) */*(.rodata*)/* all .rodata* sections (constants, strings, etc.) */_datastart = .;*(.data)} >flash/* put all the above into FLASH */.data :/* collect all initialized .data sections that go into RAM */{_data = .;/* create a global symbol marking the start of the .data section */*(.data)/* all .data sections */_edata = .;/* define a global symbol marking the end of the .data section */} >ram AT >flash/* put all the above into RAM (but load the LMA copy into FLASH) */.bss :/* collect all uninitialized .bss sections that go into RAM */{__bss_start__ = .;/* define a global symbol marking the start of the .bss section */*(.bss)/* all .bss sections */*(COMMON)__bss_end__ = .;/* define a global symbol marking the start of the .bss section */. += ( LENGTH(ram) - . ) - 32 ;_stack_end = .;} >ram/* put all the above in RAM (it will be cleared in the startup code */. = ALIGN(4);/* advance location counter to the next 32-bit boundary */_bss_end = . ;/* define a global symbol marking the end of the .bss section */}_end = .;/* define a global symbol marking the end of application RAM */See? Not a single line of assembly language required and nothing hidden under the hood.

author: dannyf
author_rank: Super Contributor
timestamp: June 24, 2014, 09:44:04 pm
content: QuoteThat's a C start-up file. We are still waiting for your "C binary".

author: nctnico
author_rank: Super Contributor
timestamp: June 24, 2014, 09:46:31 pm
content: Never heard of a compiler?

author: dannyf
author_rank: Super Contributor
timestamp: June 24, 2014, 09:49:11 pm
content: I think regulator people would call that "binary".Maybe people with "perfect understanding" would call that "C binary",

author: SirNick
author_rank: Frequent Contributor
timestamp: June 24, 2014, 10:37:12 pm
content: It seems to come down to the fact that people are often comfortable with one of two styles:1) Know nothing, and poke at it until works. If it quits working, poke at it until it works again. Fill in gaps as necessary along the way. I think in psychology, this is called the procedural learning style. Step-by-step. If it breaks, learn a new procedure.2) Understand how all the essential cogs turn, so an educated guess can be made at how to start from scratch, and how to anticipate, or at least fix errors that come up. This is the intuitive learning style. If it breaks, find out why, and consider how to apply this in the future.I'm in the second camp. Using an IDE is terrifying for me, because so much stuff "just happens", which means I don't know exactly what actually ended up on the chip, or really how it got there. I know I wrotesomecode, and it seems to be doing more or less the right thing, but I can't be confident that I did everything correctly. In which case, there's a good chance a different IC or a particular interrupt or a change in clock frequency could bring the whole house of cards down. Not great for confidence.In my line of work, I've noticed most people seem to be Type 1s. They just go about their job and do what they've been told (or learned) to do. There isn't much thought about whether what they've been told is always, only sometimes, or not at all correct. If they do what they're told but a process fails, well... *shrug* I followed the procedure I was given, didn't I?Now, once youknowwhat happens under the hood, an IDE can automate all of that tedious stuff and make your life easier. Great! But I agree wholeheartedly that, while you're learning, it's a distraction and makes it 10x harder to understand where and why something failed.

author: nctnico
author_rank: Super Contributor
timestamp: June 24, 2014, 10:59:13 pm
content: Quote from: SirNick on June 24, 2014, 10:37:12 pmIMHO it depends on what kind of IDE you are referring to. Some have extensive code generator wizards which can come up with all kinds of initialisation routines. Others 'only' automate building by hiding the process of creating makefiles and help to organize your source code.

author: andyturk
author_rank: Frequent Contributor
timestamp: June 24, 2014, 11:32:04 pm
content: Quote from: dannyf on June 24, 2014, 08:53:05 pmAnd what should the rest of us derive from *your* experience with looking at startup files? You spend your time working with outdated processors and apparently rarely leave the safety of your IDE. You talk like an expert, but I'm not so sure...Have you ever written code to start up a Cortex M3 from the reset vector?

author: westfw
author_rank: Super Contributor
timestamp: June 24, 2014, 11:52:01 pm
content: QuoteThe Keil ARM compiler used for Tiva Launchpad seems to be in assembler. The version used in the recent UTX "embedded programming" class was modified to be "barer" than normal. Pretty understandable, even without a detailed knowledge of ARM ASM. I guess. (Full of linker/debugging magic commands like:Code:MemManage_Handler\PROCEXPORT MemManage_Handler B .ENDPIt seems to be a trend in modern microcontroller IDEs to copy all the startup files (and similar) into the user's "project" space in source for, instead of leaving it as binary off in some random hidden system location. I can't argue too much with that, but it is something that desktop programmers are probably not used to.QuoteThat's a lot of praise for what amounts to "the initial SP is loaded from a known memory location, and the context saved by the ISR hardware is the same a defined to caller-saved by the C ABI." You still need assembler to do things like "turn on interrupts."

author: nctnico
author_rank: Super Contributor
timestamp: June 25, 2014, 12:14:47 am
content: On an LPC1113 (Cortex M0) the interrupts are enabled by default so no need for assembler there.

author: dannyf
author_rank: Super Contributor
timestamp: June 25, 2014, 12:19:17 am
content: QuoteIn case you are still interested, this is the avr start-up file in 1.8.0 - it hasn't changed for a long time.Code:/* Copyright (c) 2002, Marek Michalkiewicz <marekm@amelek.gda.pl>Copyright (c) 2007, 2008 Eric B. WeddingtonAll rights reserved.Redistribution and use in source and binary forms, with or withoutmodification, are permitted provided that the following conditions are met:* Redistributions of source code must retain the above copyrightnotice, this list of conditions and the following disclaimer.* Redistributions in binary form must reproduce the above copyrightnotice, this list of conditions and the following disclaimer inthe documentation and/or other materials provided with thedistribution.* Neither the name of the copyright holders nor the names ofcontributors may be used to endorse or promote products derivedfrom this software without specific prior written permission.THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THEIMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSEARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BELIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, ORCONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OFSUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESSINTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER INCONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THEPOSSIBILITY OF SUCH DAMAGE. *//* $Id: gcrt1.S 2114 2010-03-31 05:12:22Z arcanum $ */#if (__GNUC__ < 3) || (__GNUC__ == 3 && __GNUC_MINOR__ < 3)#error "GCC version >= 3.3 required"#endif#include "macros.inc".macrovector name.if (. - __vectors < _VECTORS_SIZE).weak\name.set\name, __bad_interruptXJMP\name.endif.endm.section .vectors,"ax",@progbits.global__vectors.func__vectors__vectors:XJMP__initvector__vector_1vector__vector_2vector__vector_3vector__vector_4vector__vector_5vector__vector_6vector__vector_7vector__vector_8vector__vector_9vector__vector_10vector__vector_11vector__vector_12vector__vector_13vector__vector_14vector__vector_15vector__vector_16vector__vector_17vector__vector_18vector__vector_19vector__vector_20vector__vector_21vector__vector_22vector__vector_23vector__vector_24vector__vector_25vector__vector_26vector__vector_27vector__vector_28vector__vector_29vector__vector_30vector__vector_31vector__vector_32vector__vector_33vector__vector_34vector__vector_35vector__vector_36vector__vector_37vector__vector_38vector__vector_39vector__vector_40vector__vector_41vector__vector_42vector__vector_43vector__vector_44vector__vector_45vector__vector_46vector__vector_47vector__vector_48vector__vector_49vector__vector_50vector__vector_51vector__vector_52vector__vector_53vector__vector_54vector__vector_55vector__vector_56vector__vector_57vector__vector_58vector__vector_59vector__vector_60vector__vector_61vector__vector_62vector__vector_63vector__vector_64vector__vector_65vector__vector_66vector__vector_67vector__vector_68vector__vector_69vector__vector_70vector__vector_71vector__vector_72vector__vector_73vector__vector_74vector__vector_75vector__vector_76vector__vector_77vector__vector_78vector__vector_79vector__vector_80vector__vector_81vector__vector_82vector__vector_83vector__vector_84vector__vector_85vector__vector_86vector__vector_87vector__vector_88vector__vector_89vector__vector_90vector__vector_91vector__vector_92vector__vector_93vector__vector_94vector__vector_95vector__vector_96vector__vector_97vector__vector_98vector__vector_99vector__vector_100vector__vector_101vector__vector_102vector__vector_103vector__vector_104vector__vector_105vector__vector_106vector__vector_107vector__vector_108vector__vector_109vector__vector_110vector__vector_111vector__vector_112vector__vector_113vector__vector_114vector__vector_115vector__vector_116vector__vector_117vector__vector_118vector__vector_119vector__vector_120vector__vector_121vector__vector_122vector__vector_123vector__vector_124vector__vector_125vector__vector_126vector__vector_127.endfunc/* Handle unexpected interrupts (enabled and no handler), whichusually indicate a bug. Jump to the __vector_default functionif defined by the user, otherwise jump to the reset address.This must be in a different section, otherwise the assemblerwill resolve "rjmp" offsets and there will be no relocs. */.text.global__bad_interrupt.func__bad_interrupt__bad_interrupt:.weak__vector_default.set__vector_default, __vectorsXJMP__vector_default.endfunc.section .init0,"ax",@progbits.weak__init;.func__init__init:#ifndef __AVR_ASM_ONLY__.weak__stack/* By default, malloc() uses the current value of the stack pointerminus __malloc_margin as the highest available address.In some applications with external SRAM, the stack can be belowthe data section (in the internal SRAM - faster), and __heap_endshould be set to the highest address available for malloc(). */.weak__heap_end.set__heap_end, 0.section .init2,"ax",@progbitsclr__zero_reg__outAVR_STATUS_ADDR, __zero_reg__ldir28,lo8(__stack)#ifdef _HAVE_AVR_STACK_POINTER_HIldir29,hi8(__stack)outAVR_STACK_POINTER_HI_ADDR, r29#endif/* _HAVE_AVR_STACK_POINTER_HI */outAVR_STACK_POINTER_LO_ADDR, r28#ifdef __AVR_3_BYTE_PC__ldir16, hh8(pm(__vectors))out_SFR_IO_ADDR(EIND), r16#endif/* __AVR_3_BYTE_PC__ */#ifdef __AVR_HAVE_RAMPD__outAVR_RAMPD_ADDR, __zero_reg__outAVR_RAMPX_ADDR, __zero_reg__outAVR_RAMPY_ADDR, __zero_reg__outAVR_RAMPZ_ADDR, __zero_reg__#endif#if defined(__GNUC__) && ((__GNUC__ <= 3) || (__GNUC__ == 4 && __GNUC_MINOR__ <= 3))#if BIG_CODE/* Only for >64K devices with RAMPZ, replaces the default codeprovided by libgcc.S which is only linked in if necessary. */.section .init4,"ax",@progbits.global __do_copy_data__do_copy_data:ldir17, hi8(__data_end)ldir26, lo8(__data_start)ldir27, hi8(__data_start)ldir30, lo8(__data_load_start)ldir31, hi8(__data_load_start)/* On the enhanced core, "elpm" with post-increment updates RAMPZautomatically. Otherwise we have to handle it ourselves. */#ifdef __AVR_ENHANCED__ldir16, hh8(__data_load_start)#elseldir16, hh8(__data_load_start - 0x10000).L__do_copy_data_carry:incr16#endifoutAVR_RAMPZ_ADDR, r16rjmp.L__do_copy_data_start.L__do_copy_data_loop:#ifdef __AVR_ENHANCED__elpmr0, Z+#elseelpm#endifstX+, r0#ifndef __AVR_ENHANCED__adiwr30, 1brcs.L__do_copy_data_carry#endif.L__do_copy_data_start:cpir26, lo8(__data_end)cpcr27, r17brne.L__do_copy_data_loop#ifdef __AVR_HAVE_RAMPD__outAVR_RAMPZ_ADDR, __zero_reg__#endif /* __AVR_HAVE_RAMPD__*/#endif /* BIG_CODE */#endif /* defined(__GNUC__) && ((__GNUC__ <= 3) || (__GNUC__ == 4 && __GNUC_MINOR__ <= 3)) */.set__stack, RAMEND#endif /* !__AVR_ASM_ONLY__ */.section .init9,"ax",@progbits#ifdef __AVR_ASM_ONLY__XJMPmain#else/* !__AVR_ASM_ONLY__ */XCALLmainXJMPexit#endif/* __AVR_ASM_ONLY__ */;.endfuncAs you can see, the pattern is identical: load up the interrupt vector table, some house keeping items and then call main().

author: dannyf
author_rank: Super Contributor
timestamp: June 25, 2014, 12:19:57 am
content: QuoteIs that done in your "C binary" file too?

author: andyturk
author_rank: Frequent Contributor
timestamp: June 25, 2014, 12:37:58 am
content: Quote from: westfw on June 24, 2014, 11:52:01 pmMaybe not a huge issue in the grand scheme of things, but it's nice that the Cortex designers did what they could to make it possible to write system code directly in standard C. Memory mapped peripherals also help. Interrupt stuff and access to other registers is generally available through intrinsic functions. It's debatable whether intrinsics should count as C (especially when you get down to inline assembly), but IMO it's preferable to do as much as possible in a high level language and only dip down to the lower level when absolutely necessary.One of my pet peeves is the code you see from OEMs and IDE vendors that's needlessly dependent on startup code written in assembly. For example, it's not unusual to see the .bss section of RAM being initialized by a loop in assembly code. Sure, it's fast, but the same loop in C would take only a few cycles more and be much more understandable.

author: andyturk
author_rank: Frequent Contributor
timestamp: June 25, 2014, 12:42:31 am
content: Quote from: dannyf on June 25, 2014, 12:19:57 amMaybe one of those "assembly binary" files?

author: janoc
author_rank: Super Contributor
timestamp: June 25, 2014, 09:04:24 pm
content: Quote from: dannyf on June 25, 2014, 12:19:17 amDanny, you are nitpicking over details and missing the forest for the trees, IMO. I am not sure what is your goal here. Are you trying to debunk my entire argument by picking a random (not very relevant) detail and showing that I am wrong on it?Moreover, the file you are showing is a red herring. It is actually part of the avr-libc runtime. You pretty much never deal with that part yourself, neither on ARM, nor AVR or any other architecture. It is a part of the compiler toolchain for the platform and different toolchains will have different runtime code like that.That AVR chip will work just fine if you don't do anything in that file, it is needed only to run a binary compiled with GCC, so that the expected symbols (like the interrupt vectors) are defined for the linker, the heap/stack are in the expected locations in memory, etc. If you program in assembler, you can pretty much ignore everything in that file and things will work just fine. Nothing in that file is doing any hardware initialization whatsoever.What I was talking about as a "start file" is the part of user's code where stuff like clock is being set up, Flash is initialized or peripherals powered up. That could be called from these runtime files, but could be also invoked by the user's code from main(). AVRs don't have anything like that - mainly because the architecture is much simpler compared to ARM.Which leads exactly to the point of why a newbie coming from e.g. an Arduino/AVR environment to ARM via a "black box" IDE could be screwed - they aren't used to needing to do this stuff (or to include the right vendor-provided files in their project). Most often this code is hidden somewhere in some vendor library code (e.g. inside CMSIS) - for example, for the LPCExpresso IDE the basic blink-a-LED example includes a fairly sizeable cr_startup_lpc176x.c that invokes SystemInit() from CMSIS towards the end - which does all the "magic" around clock and PLL setup. You have to dig for it to find it (it is not inside your project, CMSIS is an external dependency!). That assumes that you know what you are looking for, of course - this is code executed before user's main() is run, so it is not obvious that it is there for a newbie! And unlikely the library/runtime setup code, things like the PLL multipliers or the various clock prescalers are something that needs to be changed quite often by the developer to adapt the code to their hw.

author: nctnico
author_rank: Super Contributor
timestamp: June 25, 2014, 09:56:43 pm
content: Why would you need to change the clock or prescalers? I set them up once and re-use the same settings for every project. The easiest thing to do is have everything run at full speed. Only when you are working on very low power it may be necessary to switch to lower clocks. But then again ultra low power is not the strong suit of most ARM controllers anyway.

author: Dago
author_rank: Frequent Contributor
timestamp: June 26, 2014, 06:30:16 am
content: Quote from: nctnico on June 25, 2014, 09:56:43 pmI guess your point is the word "most" but I still need to point out that in relation to computing power the most lowest power MCUs are ARMs. Even in absolute stand-by/idle power use low-power ARMs tend to have one of the lowest power usages. In absolute terms MSP430s or some PICs might have lower power use but the µA/MHz is about the same or higher as ARMs.

author: janoc
author_rank: Super Contributor
timestamp: June 26, 2014, 07:07:20 pm
content: Quote from: nctnico on June 25, 2014, 09:56:43 pmFor example when you are taking a project and want to move it to another, different board. Or change the clock frequency/crystal. That alone will force you change the various prescalers to keep the PLL input within the allowed limits and to adapt the output to what the various peripherals need - e.g. USB often rigidly requires 48MHz clock. Or you want to switch from external clock to the internal RC oscillator. Or you don't need full speed and want to run slower to reduce current consumption/heat. It is a fairly common thing to do. I am quite surprised that you don't know this.And re low power - I am not sure where are you getting such info, STM32F103 takes about 5-50mA in run mode, depending on what you have enabled. In low power modes it is much less - e.g. in standby, running on the low speed clock, it takes around 1uA (!). And that is not really a chip optimized for such use. The Energy Micro EMF32 series is known for its low power capabilities - those things work down to tenth of nA! E.g. look here:http://www.silabs.com/products/mcu/lowpower/pages/efm32wg-wonder-gecko.aspxDave did even a video on Gecko demo board.

author: nctnico
author_rank: Super Contributor
timestamp: June 26, 2014, 08:00:04 pm
content: Quote from: janoc on June 26, 2014, 07:07:20 pmNot really in my world. If I use an USB enabled controller I have always have a 12MHz crystal next to it. Once setup I never have to touch it again. Same goes for controllers with an internal RC oscillators. I already mentioned the exception when it comes to power reduction. Anyway a newbie shouldn't need to worry much about having to change the PLL setup for every design.

author: SirNick
author_rank: Frequent Contributor
timestamp: June 27, 2014, 09:21:12 pm
content: Aw man, that's not at all true. A newbie should indeed know how and where the clocks are configured. You may be able to "fudge it" with whatever your template / demo code used, but blindly accepting clock setup as a given, or worse, not knowing it's there at all..? Who would seriously consider that OK?If you're using USB, you need a multiple of 12MHz. If you're going for high-speed calculation, you'll want to run as close as possible to it's highest speed. For an NXP LPC4k, that's upwards of 200MHz. Most other Cortex Ms can't run that fast, so there's one time where you really have to pay attention. If speed is not at all a concern and battery life and/or external components are, you need to optimize that way. Once you get past the very first stage of "I got helloworld.c to compile!" then it isveryrelevant.

author: janoc
author_rank: Super Contributor
timestamp: June 29, 2014, 11:30:48 pm
content: Quote from: nctnico on June 26, 2014, 08:00:04 pmIt is not abouthaving tobut aboutknowing where and howto change it! Also, without knowing the various prescaler values, good luck trying to figure out what your system clock actually is and what frequency the various peripherals are running at, as these could be different even with the same crystal and PLL settings! How would you configure e.g. timers or PWM in such situation?nctnico, your statement is really baffling.

author: nctnico
author_rank: Super Contributor
timestamp: June 29, 2014, 11:58:47 pm
content: I never said you would never need to touch it or not know it. However as a fresh starter with a microcontroller you start with an example. A good example has a remark which says which clock frequency is being used. That is how you know the clock frequency without knowing about how the PLL and clocks work. In order to move forward quickly you must skip the parts which are not interesting at that moment.In some designs I use SoCs with manuals having over 4000 pages. I'm not going to read all of them to figure out how to configure the I/O pins. I just skip to the section which describes the I/O pins. I just assume the bootloader and Linux 'know' how the clocks need to be setup.