Author Topic: Cortex M3 hand holding tutorial  (Read 17380 times)

0 Members and 1 Guest are viewing this topic.

Online nctnico

  • Super Contributor
  • ***
  • Posts: 28720
  • Country: nl
    • NCT Developments
Re: Cortex M3 hand holding tutorial
« Reply #25 on: June 24, 2014, 09:46:31 pm »
 :palm: Never heard of a compiler?
« Last Edit: June 24, 2014, 09:48:14 pm by nctnico »
There are small lies, big lies and then there is what is on the screen of your oscilloscope.
 

Offline dannyf

  • Super Contributor
  • ***
  • Posts: 8221
  • Country: 00
Re: Cortex M3 hand holding tutorial
« Reply #26 on: June 24, 2014, 09:49:11 pm »
I think regulator people would call that "binary".

Maybe people with "perfect understanding" would call that "C binary", :)
================================
https://dannyelectronics.wordpress.com/
 

Offline SirNick

  • Frequent Contributor
  • **
  • Posts: 589
Re: Cortex M3 hand holding tutorial
« Reply #27 on: June 24, 2014, 10:37:12 pm »
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 wrote some code, 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 you know what 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.
 

Online nctnico

  • Super Contributor
  • ***
  • Posts: 28720
  • Country: nl
    • NCT Developments
Re: Cortex M3 hand holding tutorial
« Reply #28 on: June 24, 2014, 10:59:13 pm »
Now, once you know what 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.
IMHO 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.
There are small lies, big lies and then there is what is on the screen of your oscilloscope.
 

Offline andyturk

  • Frequent Contributor
  • **
  • Posts: 895
  • Country: us
Re: Cortex M3 hand holding tutorial
« Reply #29 on: June 24, 2014, 11:32:04 pm »
The start-up files I have seen are mostly assembly source files, and C source file in one case.
And 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?
 

Offline westfw

  • Super Contributor
  • ***
  • Posts: 4393
  • Country: us
Re: Cortex M3 hand holding tutorial
« Reply #30 on: June 24, 2014, 11:52:01 pm »
Quote
The start-up files I have seen are mostly assembly source files, and C source file in one case.
The 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: [Select]
MemManage_Handler\
                PROC
                EXPORT  MemManage_Handler         [WEAK]
                B       .
                ENDP

It 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.

Quote
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.
That'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."
 

Online nctnico

  • Super Contributor
  • ***
  • Posts: 28720
  • Country: nl
    • NCT Developments
Re: Cortex M3 hand holding tutorial
« Reply #31 on: June 25, 2014, 12:14:47 am »
On an LPC1113 (Cortex M0) the interrupts are enabled by default so no need for assembler there.
There are small lies, big lies and then there is what is on the screen of your oscilloscope.
 

Offline dannyf

  • Super Contributor
  • ***
  • Posts: 8221
  • Country: 00
Re: Cortex M3 hand holding tutorial
« Reply #32 on: June 25, 2014, 12:19:17 am »
Quote
Show me one for an ATMega or PIC then.

In 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: [Select]
/* Copyright (c) 2002, Marek Michalkiewicz <marekm@amelek.gda.pl>
   Copyright (c) 2007, 2008 Eric B. Weddington
   All rights reserved.

   Redistribution and use in source and binary forms, with or without
   modification, are permitted provided that the following conditions are met:

   * Redistributions of source code must retain the above copyright
     notice, this list of conditions and the following disclaimer.

   * Redistributions in binary form must reproduce the above copyright
     notice, this list of conditions and the following disclaimer in
     the documentation and/or other materials provided with the
     distribution.

   * Neither the name of the copyright holders nor the names of
     contributors may be used to endorse or promote products derived
     from 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, THE
   IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
   LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
   CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
   SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
   INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
   CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   POSSIBILITY 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"

.macro vector name
.if (. - __vectors < _VECTORS_SIZE)
.weak \name
.set \name, __bad_interrupt
XJMP \name
.endif
.endm

.section .vectors,"ax",@progbits
.global __vectors
.func __vectors
__vectors:
XJMP __init
vector __vector_1
vector __vector_2
vector __vector_3
vector __vector_4
vector __vector_5
vector __vector_6
vector __vector_7
vector __vector_8
vector __vector_9
vector __vector_10
vector __vector_11
vector __vector_12
vector __vector_13
vector __vector_14
vector __vector_15
vector __vector_16
vector __vector_17
vector __vector_18
vector __vector_19
vector __vector_20
vector __vector_21
vector __vector_22
vector __vector_23
vector __vector_24
vector __vector_25
vector __vector_26
vector __vector_27
vector __vector_28
vector __vector_29
vector __vector_30
vector __vector_31
vector __vector_32
vector __vector_33
vector __vector_34
vector __vector_35
vector __vector_36
vector __vector_37
vector __vector_38
vector __vector_39
vector __vector_40
vector __vector_41
vector __vector_42
vector __vector_43
vector __vector_44
vector __vector_45
vector __vector_46
vector __vector_47
vector __vector_48
vector __vector_49
vector __vector_50
vector __vector_51
vector __vector_52
vector __vector_53
vector __vector_54
vector __vector_55
vector __vector_56
vector __vector_57
vector __vector_58
vector __vector_59
vector __vector_60
vector __vector_61
vector __vector_62
vector __vector_63
vector __vector_64
vector __vector_65
vector __vector_66
vector __vector_67
vector __vector_68
vector __vector_69
vector __vector_70
vector __vector_71
vector __vector_72
vector __vector_73
vector __vector_74
vector __vector_75
vector __vector_76
vector __vector_77
vector __vector_78
vector __vector_79
vector __vector_80
vector __vector_81
vector __vector_82
vector __vector_83
vector __vector_84
vector __vector_85
vector __vector_86
vector __vector_87
vector __vector_88
vector __vector_89
vector __vector_90
vector __vector_91
vector __vector_92
vector __vector_93
vector __vector_94
vector __vector_95
vector __vector_96
vector __vector_97
vector __vector_98
vector __vector_99
vector __vector_100
vector __vector_101
vector __vector_102
vector __vector_103
vector __vector_104
vector __vector_105
vector __vector_106
vector __vector_107
vector __vector_108
vector __vector_109
vector __vector_110
vector __vector_111
vector __vector_112
vector __vector_113
vector __vector_114
vector __vector_115
vector __vector_116
vector __vector_117
vector __vector_118
vector __vector_119
vector __vector_120
vector __vector_121
vector __vector_122
vector __vector_123
vector __vector_124
vector __vector_125
vector __vector_126
vector __vector_127
.endfunc

/* Handle unexpected interrupts (enabled and no handler), which
   usually indicate a bug.  Jump to the __vector_default function
   if defined by the user, otherwise jump to the reset address.

   This must be in a different section, otherwise the assembler
   will resolve "rjmp" offsets and there will be no relocs.  */

.text
.global __bad_interrupt
.func __bad_interrupt
__bad_interrupt:
.weak __vector_default
.set __vector_default, __vectors
XJMP __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 pointer
   minus __malloc_margin as the highest available address.

   In some applications with external SRAM, the stack can be below
   the data section (in the internal SRAM - faster), and __heap_end
   should be set to the highest address available for malloc().  */
.weak __heap_end
.set __heap_end, 0

.section .init2,"ax",@progbits
clr __zero_reg__
out AVR_STATUS_ADDR, __zero_reg__
ldi r28,lo8(__stack)
#ifdef _HAVE_AVR_STACK_POINTER_HI
ldi r29,hi8(__stack)
out AVR_STACK_POINTER_HI_ADDR, r29
#endif /* _HAVE_AVR_STACK_POINTER_HI */
out AVR_STACK_POINTER_LO_ADDR, r28

#ifdef __AVR_3_BYTE_PC__
ldi r16, hh8(pm(__vectors))
out _SFR_IO_ADDR(EIND), r16
#endif /* __AVR_3_BYTE_PC__ */

#ifdef __AVR_HAVE_RAMPD__
out AVR_RAMPD_ADDR, __zero_reg__
out AVR_RAMPX_ADDR, __zero_reg__
out AVR_RAMPY_ADDR, __zero_reg__
out AVR_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 code
   provided by libgcc.S which is only linked in if necessary.  */

.section .init4,"ax",@progbits
.global __do_copy_data
__do_copy_data:
ldi r17, hi8(__data_end)
ldi r26, lo8(__data_start)
ldi r27, hi8(__data_start)
ldi r30, lo8(__data_load_start)
ldi r31, hi8(__data_load_start)

/* On the enhanced core, "elpm" with post-increment updates RAMPZ
   automatically.  Otherwise we have to handle it ourselves.  */

#ifdef __AVR_ENHANCED__
ldi r16, hh8(__data_load_start)
#else
ldi r16, hh8(__data_load_start - 0x10000)
.L__do_copy_data_carry:
inc r16
#endif
out AVR_RAMPZ_ADDR, r16
rjmp .L__do_copy_data_start
.L__do_copy_data_loop:
#ifdef __AVR_ENHANCED__
elpm r0, Z+
#else
elpm
#endif
st X+, r0
#ifndef __AVR_ENHANCED__
adiw r30, 1
brcs .L__do_copy_data_carry
#endif
.L__do_copy_data_start:
cpi r26, lo8(__data_end)
cpc r27, r17
brne .L__do_copy_data_loop
#ifdef __AVR_HAVE_RAMPD__
out AVR_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__
XJMP main
#else /* !__AVR_ASM_ONLY__ */
XCALL main
XJMP exit
#endif /* __AVR_ASM_ONLY__ */
; .endfunc


As you can see, the pattern is identical: load up the interrupt vector table, some house keeping items and then call main().
================================
https://dannyelectronics.wordpress.com/
 

Offline dannyf

  • Super Contributor
  • ***
  • Posts: 8221
  • Country: 00
Re: Cortex M3 hand holding tutorial
« Reply #33 on: June 25, 2014, 12:19:57 am »
Quote
no need for assembler there.

Is that done in your "C binary" file too?
================================
https://dannyelectronics.wordpress.com/
 

Offline andyturk

  • Frequent Contributor
  • **
  • Posts: 895
  • Country: us
Re: Cortex M3 hand holding tutorial
« Reply #34 on: June 25, 2014, 12:37:58 am »
That'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."
Maybe 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.
 

Offline andyturk

  • Frequent Contributor
  • **
  • Posts: 895
  • Country: us
Re: Cortex M3 hand holding tutorial
« Reply #35 on: June 25, 2014, 12:42:31 am »
Quote
no need for assembler there.

Is that done in your "C binary" file too?
Maybe one of those "assembly binary" files?  :-//
 

Offline janoc

  • Super Contributor
  • ***
  • Posts: 3958
  • Country: de
Re: Cortex M3 hand holding tutorial
« Reply #36 on: June 25, 2014, 09:04:24 pm »
As you can see, the pattern is identical: load up the interrupt vector table, some house keeping items and then call main().

Danny, 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.

« Last Edit: June 25, 2014, 09:37:49 pm by janoc »
 

Online nctnico

  • Super Contributor
  • ***
  • Posts: 28720
  • Country: nl
    • NCT Developments
Re: Cortex M3 hand holding tutorial
« Reply #37 on: June 25, 2014, 09:56:43 pm »
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.
There are small lies, big lies and then there is what is on the screen of your oscilloscope.
 

Offline Dago

  • Frequent Contributor
  • **
  • Posts: 659
  • Country: fi
    • Electronics blog about whatever I happen to build!
Re: Cortex M3 hand holding tutorial
« Reply #38 on: June 26, 2014, 06:30:16 am »
But then again ultra low power is not the strong suit of most ARM controllers anyway.

I 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.
Come and check my projects at http://www.dgkelectronics.com ! I also tweet as https://twitter.com/DGKelectronics
 

Offline janoc

  • Super Contributor
  • ***
  • Posts: 3958
  • Country: de
Re: Cortex M3 hand holding tutorial
« Reply #39 on: June 26, 2014, 07:07:20 pm »
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.

For 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.aspx  Dave did even a video on Gecko demo board.

« Last Edit: June 26, 2014, 07:09:13 pm by janoc »
 

Online nctnico

  • Super Contributor
  • ***
  • Posts: 28720
  • Country: nl
    • NCT Developments
Re: Cortex M3 hand holding tutorial
« Reply #40 on: June 26, 2014, 08:00:04 pm »
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.

For 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.
Not 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.
There are small lies, big lies and then there is what is on the screen of your oscilloscope.
 

Offline SirNick

  • Frequent Contributor
  • **
  • Posts: 589
Re: Cortex M3 hand holding tutorial
« Reply #41 on: June 27, 2014, 09:21:12 pm »
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 is very relevant.
 

Offline janoc

  • Super Contributor
  • ***
  • Posts: 3958
  • Country: de
Re: Cortex M3 hand holding tutorial
« Reply #42 on: June 29, 2014, 11:30:48 pm »
Not 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.

It is not about having to but about knowing where and how to 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.

 

Online nctnico

  • Super Contributor
  • ***
  • Posts: 28720
  • Country: nl
    • NCT Developments
Re: Cortex M3 hand holding tutorial
« Reply #43 on: June 29, 2014, 11:58:47 pm »
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.
There are small lies, big lies and then there is what is on the screen of your oscilloscope.
 


Share me

Digg  Facebook  SlashDot  Delicious  Technorati  Twitter  Google  Yahoo
Smf