Beginner: trying to learn and understand

cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

Beginner: trying to learn and understand

1,034 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by mihaval on Sun Nov 04 14:18:05 MST 2012
Hi!

I'm a beginner in LPC world, having programmed microcontrollers only using higher-level languages. I have experience with Netduino (similar to Arduino) and have started learning LPC family of microcontrollers recently.

I have LPC1114 and a base board from Embedded Artists and so far, I'm working my way through examples and it is very interesting to read them and see different approaches on how to solve some basic issues.

I've gone through LPC1114 PDF and I can roughly understand most of the blinky code. I do understand the mechanics of blinky code, but I have a few specific questions regarding it:

1) where do clkconfig.c/.h, adc.c/.h, gpio.c/.h etc come from? I know I can copy/paste them to my projects, but it is better to understand where they come from, imho. Some come from CMSIS library from NXP support site, others from???? For instance, function GPIOSetDir from gpio.c/.h. Where does it come from?

2) Is there a published API, which is available which lists all of the functions like init_timer32 etc? I see it is defined in a file which has NXP's header (comment) and it is reasonably documented within the source code itself. Where does this file (i.e. timer32.h /.c) come from?

I also see that this code is functionally equivalent to this project: http://code.google.com/p/lpc1343codebase/

3) __WFI(); -- I suppose this means Wait For Interrupt and it is implemented as an assembly operation "wfi". I see that this is part of CMSIS library but I don't know where to find documentation about it

4) LPC1114/302, 303, etc. How do I know which LPC variation I have? I have bough LPCXpresso and  I don't see the variation number on the packaging. The vendor part number is OM11049.
Update: I found the mapping between part number and uC variation: it is in lpcxpresso.getting.started.pdf. Apparently, mine is /302.

5) Register descriptions (such as LPC_TMR32B0) can be found in LPC user manual under TMR32B0 for instance. Is there a documented mapping between TMR32B0MR0 register (in user manual) and LPC_TMR32B0->MR0 API?

6) In trying to understand the mechanics of timers etc, I created a new (semihosted) project where I'm trying to use a simple delay with timers. I've taken delay implementation from timer32.c and have initialized (enabled) timer using LPC_SYSCON->SYSAHBCLKCTRL |= (1<<9); The problem I seem to be having is that the timer is either not really enabled or something else is wrong, since there is no visible delay in the running program, even though there should be 1 second delay there.
Apparently, there is something missing. And even if I change the original blinky application to modify the code to use delay instead of interrupt, the delay function does not work. Code:
  while(1)
  {
  GPIOSetValue( LED_PORT, LED_BIT, LED_ON );
  delay32Ms(0, 1000);
  GPIOSetValue( LED_PORT, LED_BIT, LED_OFF );
  }


Kind regards,
Miha.
0 Kudos
6 Replies

687 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by mihaval on Tue Nov 13 23:27:31 MST 2012

Quote: daniel.widyanto

The WFI is ARM instruction to enter power saving mode. Once the MCU execute WFI, the PC (program counter) will stop at that point, until wake up source asserted (Timer, UART, GPIO etc). There are few power saving mode that you can choose (sleep, deep sleep, deep power down), and each has their own wake-up source to choose.



Thank you!
0 Kudos

687 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by daniel.widyanto on Tue Nov 13 22:31:09 MST 2012
Hi Miha,

The WFI is ARM instruction to enter power saving mode. Once the MCU execute WFI, the PC (program counter) will stop at that point, until wake up source asserted (Timer, UART, GPIO etc). There are few power saving mode that you can choose (sleep, deep sleep, deep power down), and each has their own wake-up source to choose.

So, yes, in term of energy consumption, it's less when WFI() is executed in main loop.
0 Kudos

687 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by mihaval on Mon Nov 12 01:02:36 MST 2012

Quote: daniel.widyanto

For 9) I'm not sure if you're new to embedded system, but yes, everyone needs while(1) in main() to stop the MCU from executing other section of Flash memory.

In case you forgot, the LPCXpresso / Code Red startup file also implement while(1) in its startup file. So when the main() is returning, the startup file will catch and hold the MCU from executing other unprogrammed Flash memory section.



Hi Daniel!

With regards to that, my question was mostly about performance / energy.

while(1) {} loops forever and uses CPU cycles to do that I suppose. I don;t know how that gets optimized in the compiler though. So the question was whether the code
while(1) {
__WFI();
}


is more efficient, since it blocks on __WFI(). The question I guess is how asm("wfi") is implemented -- whether it is an infite polling loop as well, but I suppose it is not?

Regards,
Miha.
0 Kudos

687 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by daniel.widyanto on Mon Nov 12 00:21:20 MST 2012
For 6) Well, I don't know which code that you are using, but in the standard code, the SystemCoreClockUpdate() is not called from anywhere, and the initial value of SystemCoreClock is 12Mhz (Internal RC value). So, yes, I suppose you need to call SystemCoreClockUpdate() before using SystemCoreClock

void delay32Ms(uint8_t timer_num, uint32_t delayInMs)
{
  if (timer_num == 0)
  {
    /* setup timer #0 for delay */
    LPC_TMR32B0->TCR = 0x02;/* reset timer */
    LPC_TMR32B0->PR  = 0x00;/* set prescaler to zero */
    LPC_TMR32B0->MR0 = delayInMs * ((SystemCoreClock/(LPC_TMR32B0->PR+1)) / 1000);
    LPC_TMR32B0->IR  = 0xff;/* reset all interrrupts */
    LPC_TMR32B0->MCR = 0x04;/* stop timer on match */
    LPC_TMR32B0->TCR = 0x01;/* start timer */
  
    /* wait until delay time has elapsed */
    while (LPC_TMR32B0->TCR & 0x01);
  }
}


For 7) Read http://support.code-red-tech.com/CodeRedWiki/WhatIsSemiHosting

For Hmm..This part I cannot solve, since it's related to CodeRed's proprietary software. FYI, all of demo code that I used from LPCXpresso example folder will stop at main().

For 9) I'm not sure if you're new to embedded system, but yes, everyone needs while(1) in main() to stop the MCU from executing other section of Flash memory.

In case you forgot, the LPCXpresso / Code Red startup file also implement while(1) in its startup file. So when the main() is returning, the startup file will catch and hold the MCU from executing other unprogrammed Flash memory section.
0 Kudos

687 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by mihaval on Mon Nov 05 00:45:30 MST 2012

Quote: daniel.widyanto
Welcome to the club



Thanks! ANd thanks for the explanations.


Quote: daniel.widyanto
6) Open the delay32Ms() source code in timer32.c. You'll notice the the counting is based on 'SystemCoreClock' variable. Now inside the CMSIS package, find "system_LPC11Uxx.h", "SystemCoreClock" variable definition, and also another function to update the "SystemCoreClock" value before it can be used.



The CMSIS specification is a nice collection of information regarding the API. Thanks for the pointer. It's a shame it's all so scattered around, but I'll have it covered eventually :).

Ad 6) I was actually having a developer bug regarding this - one sleep to little in a while loop. Before I realized it though, I went through header file and made some changes (none of which worked, for sure). So I was wondering, which setting were you referring to, as I didn't find anything that would alter the program anyhow?
Did you mean this definitions:
#define CLOCK_SETUP 1                                 /* Clock Setup              */
#define SYSCLK_SETUP 1                                /* System Clock Setup       */
#define SYSOSC_SETUP 1


.. or are you referring to function SystemCoreClockUpdate? In any case, I added the definitions and explicitly called SystemCoreClockUpdate in the blinky_main:main(). Even before that, the debugger showed the value of this variable as 48000000, so I guess it has been set to correct value even before that? And I can confirm that the delay32Ms works even though I don't set this variables. Should I be calling SystemCoreClockUpdate(); explicitly inside my main()?

7) I also noticed, that the blinky_main program is much smaller compared to my "semihosted hellow world" sample (~2.5k vs ~12k). Is this normal? (note, that I'm not using "common" drivers, just CMSIS and the project is semihosted.

More of a nuissance than anything else: most of the time I start debugging, the debugger would start, but would not stop in main or on any of my custom breakpoints. I need to "pause" the process and restart it and then it works as expected. This is happening for all of the sample projects.

9) A question on best-practice or preformance/energy efficency. So far, I've implemented blinking using three techniques: timer + interrupt, delay and systick interrupt. It seems to me that the  one with the timer is most effictient since it uses __WFI to put the uC to a low-energy state. delay and systick seem pretty much the same to me. The delay uses while(1) to wait for the timer to clear and the systick uses while(1) in the main loop so that it never ends. I guess an infinite sleep would be better there? Is there such a thing as an infinite sleep in the main (so that only interrupt handlers do the work)?

Kind regards,
Miha.
0 Kudos

687 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by daniel.widyanto on Sun Nov 04 20:54:52 MST 2012
Welcome to the club :)

1) If you ask who made it, it's NXP. But it's delivered as bundle code for LPCXpresso example.

2) If you ask on how to get it, go to Quickstart panel->'Import projects()'->Select your LPCXpresso example directory->Select "NXP_LPCXpresso1114-302_2011_02-07.zip"->Select "common" project to import. Inside the "driver" of "common" project, there are *.c and *.h of simple library to access the peripherals

3) In your CMSIS package, find "core_cm0.h". The WFI implementation is there. These internal functions are standardized in CMSIS by ARM. See http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0552a/CIHCAEJD.html

4) Find a chip which has 48-pins (black square with 12-pins on each side), next to shiny metal components (the crystal). Read the marking on that chip and you'll know which MCU that's attached in your board. There's another black square chip, next to the crystal, which marked LPC3154. That's another MCU as well, but to run the JTAG function :)  

5) Read CMSIS : http://www.arm.com/products/processors/cortex-m/cortex-microcontroller-software-interface-standard.p...

6) Open the delay32Ms() source code in timer32.c. You'll notice the the counting is based on 'SystemCoreClock' variable. Now inside the CMSIS package, find "system_LPC11Uxx.h", "SystemCoreClock" variable definition, and also another function to update the "SystemCoreClock" value before it can be used.

Have fun !
0 Kudos