Demo code for LPC812 Xpresso

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

Demo code for LPC812 Xpresso

2,827 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by wrighflyer on Mon Jan 21 12:37:40 MST 2013
Looking at the Code Red installation there is NXP_LPC8xx_SampleCodeBundle.zip with sample projects for the LPC812 based Xpresso board. But I cannot see where the source of the app that comes pre-loaded is located. Does anyone know if it ships with the Code Red software or is it on a website somewhere?

I can control the R/G/B LEDs OK but I'd like to know how to use the comparator to read the potentiometer that's on the board and I guess a look at the source of the demo app may be the easiest way to find out.

I've read about a 32 step voltage generator along with some details of the comparator so I assume the idea is that one input connects to the pot. voltage and then you step the 32 step generator until the comparator matches to use it as a sort of simple ADC.

WF1903
0 Kudos
Reply
10 Replies

2,519 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by wrighflyer on Wed Jan 30 10:23:54 MST 2013

Quote:
Anyway, I will flag this issue across to NXP for consideration in future updates to their LPC800 examples.


Jolly good! :-)

(as you say it just needs them to split the IRQ handlers themselves from the other library code - even the main body of the interrupt handler in this case PININT_Handler() could live with the other code - it's the 7 named functions that each invoke it that need splitting).
0 Kudos
Reply

2,518 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by CodeRedSupport on Wed Jan 30 05:08:08 MST 2013
Hmm. Putting interrupt handler code into libraries is never really a good idea. Interrupt handlers really should be in the application itself.

The reason these handlers are getting pulled in "needlessly" here is that the [FONT=Courier New]lpc8xx_gpio.c[/FONT] file is getting pulled into the link in order to resolve the call to [FONT=Courier New]GPIOInit()[/FONT], which thus means all of the other functions in that file as also visible for the link. Thus these interrupt handlers get used instead of the weak ones in the startup code.

Easiest way to resolve in the short term would be to put a [FONT=Courier New]#if 0 ... #endif[/FONT] around the function definitions of [FONT=Courier New]void PININT0_IRQHandler(void)[/FONT] to [FONT=Courier New]void PININT7_IRQHandler(void)[/FONT] in [FONT=Courier New]lpc8xx_gpio.c[/FONT].

You would then need to make sure that you put definitions for the interrupt handlers into any application projects where you really do want GPIO interrupts to be used.

Anyway, I will flag this issue across to NXP for consideration in future updates to their LPC800 examples.

Regards,
CodeRedSupport
0 Kudos
Reply

2,519 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by wrighflyer on Tue Jan 29 10:01:42 MST 2013
OK having a conversation with myself.  If I either define my own copies of the interrupt functions or make them "non weak" references in the CRT I do, indeed, get "multiple definition" link errors. Do I need to use -Wl,-u<symbol> or similar to make it forget the library copies or something?
0 Kudos
Reply

2,518 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by wrighflyer on Tue Jan 29 09:50:36 MST 2013
Oh wait, it isn't ALL the functions. It's those involved in interrupt handling. Is there an attribute on those functions in the lib that says "this is an interrupt handler so may not be called but must link anyway just in case". Or is it the fact that the CRT has weak links to dummy handlers then this resolves a hard link?

I think this is what's happening so is there a way to say "yes I'll use some of this library code but no, I don't want to link to its interrupt handler". I suppose a solution is to keep a local copy of the CRT and actually remove the weak linking references to the IRQs involved from the vector table?

I'm guessing I can't be the first to have hit this and there's probably a standard solution documented somewhere?

EDIT: OK I see one way to do this. The CRT file has:
#define ALIAS(f) __attribute__ ((weak, alias (#f)))

One way would be to define something like:
#define STRONGALIAS(f) __attribute__ ((alias (#f)))

though I have a feeling this is going to lead to "multiple definition" link errors?
0 Kudos
Reply

2,519 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by wrighflyer on Tue Jan 29 09:45:40 MST 2013
OK so this remains a mystery. If I build the lpc8xx_driver_lib then a typical build command is:
Building file: ../src/lpc8xx_gpio.c
Invoking: MCU C Compiler
arm-none-eabi-gcc -D__REDLIB__ -DDEBUG -D__CODE_RED -D__USE_CMSIS=CMSIS_CORE_LPC8xx -D__LPC8XX__ -I"C:\Documents and Settings\asl\My Documents\LPCXpresso\workspace\lpc800_driver_lib\inc" -I"C:\Documents and Settings\asl\My Documents\LPCXpresso\workspace\CMSIS_CORE_LPC8xx\inc" -O0 -g3 -Wall -c -fmessage-length=0 -fno-builtin -ffunction-sections -fdata-sections -mcpu=cortex-m0 -mthumb -MMD -MP -MF"src/lpc8xx_gpio.d" -MT"src/lpc8xx_gpio.d" -o "src/lpc8xx_gpio.o" "../src/lpc8xx_gpio.c"
Finished building: ../src/lpc8xx_gpio.c
that clearly contains -ffunction-sections and this is borne out by studying the .o file:
C:\Documents and Settings\asl\My Documents\LPCXpresso\workspace\lpc800_driver_lib\Debug\src>\nxp\LPCXpresso_5.0.14_1109\
lpcxpresso\tools\bin\arm-none-eabi-readelf.exe -S lpc8xx_gpio.o
There are 70 section headers, starting at offset 0x8b24:

Section Headers:
  [Nr] Name              Type            Addr     Off    Size   ES Flg Lk Inf Al
  [ 0]                   NULL            00000000 000000 000000 00      0   0  0
  [ 1] .text             PROGBITS        00000000 000034 000000 00  AX  0   0  2
  [ 2] .data             PROGBITS        00000000 000034 000000 00  WA  0   0  1
  [ 3] .bss              NOBITS          00000000 000034 000000 00  WA  0   0  1
  [ 4] .text.NVIC_Enable PROGBITS        00000000 000034 00002c 00  AX  0   0  4
  [ 5] .bss.flex_int_cou NOBITS          00000000 000060 000020 00  WA  0   0  4
  [ 6] .bss.flex_int_lev NOBITS          00000000 000060 000020 00  WA  0   0  4
  [ 7] .bss.flex_int_ris NOBITS          00000000 000060 000020 00  WA  0   0  4
  [ 8] .bss.flex_int_fal NOBITS          00000000 000060 000020 00  WA  0   0  4
  [ 9] .bss.gint0_counte NOBITS          00000000 000060 000004 00  WA  0   0  4
  [10] .bss.gint1_counte NOBITS          00000000 000060 000004 00  WA  0   0  4
  [11] .bss.gint0_level_ NOBITS          00000000 000060 000004 00  WA  0   0  4
  [12] .bss.gint0_edge_c NOBITS          00000000 000060 000004 00  WA  0   0  4
  [13] .bss.gint1_level_ NOBITS          00000000 000060 000004 00  WA  0   0  4
  [14] .bss.gint1_edge_c NOBITS          00000000 000060 000004 00  WA  0   0  4
  [15] .text.PININT_Hand PROGBITS        00000000 000060 0001e4 00  AX  0   0  4
  [16] .rel.text.PININT_ REL             00000000 00a0b4 000028 08     68  15  4
  [17] .rodata.PININT_Ha PROGBITS        00000000 000244 000020 00   A  0   0  4
  [18] .rel.rodata.PININ REL             00000000 00a0dc 000040 08     68  17  4
  [19] .text.PININT0_IRQ PROGBITS        00000000 000264 000010 00  AX  0   0  4
  [20] .rel.text.PININT0 REL             00000000 00a11c 000008 08     68  19  4
  [21] .text.PININT1_IRQ PROGBITS        00000000 000274 000010 00  AX  0   0  4
  [22] .rel.text.PININT1 REL             00000000 00a124 000008 08     68  21  4
  [23] .text.PININT2_IRQ PROGBITS        00000000 000284 000010 00  AX  0   0  4
  [24] .rel.text.PININT2 REL             00000000 00a12c 000008 08     68  23  4
  [25] .text.PIN3_IRQHan PROGBITS        00000000 000294 000010 00  AX  0   0  4
  [26] .rel.text.PIN3_IR REL             00000000 00a134 000008 08     68  25  4
  [27] .text.PININT4_IRQ PROGBITS        00000000 0002a4 000010 00  AX  0   0  4
  [28] .rel.text.PININT4 REL             00000000 00a13c 000008 08     68  27  4
  [29] .text.PININT5_IRQ PROGBITS        00000000 0002b4 000010 00  AX  0   0  4
  [30] .rel.text.PININT5 REL             00000000 00a144 000008 08     68  29  4
  [31] .text.PININT6_IRQ PROGBITS        00000000 0002c4 000010 00  AX  0   0  4
  [32] .rel.text.PININT6 REL             00000000 00a14c 000008 08     68  31  4
  [33] .text.PININT7_IRQ PROGBITS        00000000 0002d4 000010 00  AX  0   0  4
  [34] .rel.text.PININT7 REL             00000000 00a154 000008 08     68  33  4
  [35] .text.GPIOInit    PROGBITS        00000000 0002e4 00003c 00  AX  0   0  4
  [36] .text.GPIOSetPinI PROGBITS        00000000 000320 0000ec 00  AX  0   0  4
  [37] .rel.text.GPIOSet REL             00000000 00a15c 000008 08     68  36  4
  [38] .text.GPIOPinIntE PROGBITS        00000000 00040c 000074 00  AX  0   0  4
  [39] .text.GPIOPinIntD PROGBITS        00000000 000480 000074 00  AX  0   0  4
  [40] .text.GPIOPinIntS PROGBITS        00000000 0004f4 00002c 00  AX  0   0  4
  [41] .text.GPIOPinIntC PROGBITS        00000000 000520 000034 00  AX  0   0  4
  [42] .text.GPIOGetPinV PROGBITS        00000000 000554 000050 00  AX  0   0  4
  [43] .text.GPIOSetBitV PROGBITS        00000000 0005a4 000048 00  AX  0   0  4
  [44] .text.GPIOSetDir  PROGBITS        00000000 0005ec 000060 00  AX  0   0  4
  [45] .text.GPIOPattern PROGBITS        00000000 00064c 000018 00  AX  0   0  4
  [46] .text.GPIOSetPatt PROGBITS        00000000 000664 000024 00  AX  0   0  4
  [47] .text.GPIOSetPatt PROGBITS        00000000 000688 0000c8 00  AX  0   0  4
<snip>
Clearly each function IS in it's own .text.GPIO<whatever> section.

If I now build my own project that links to this the link command is:
Building target: lpc8test1.axf
Invoking: MCU Linker
arm-none-eabi-gcc -nostdlib -L"C:\Documents and Settings\asl\My Documents\LPCXpresso\workspace\CMSIS_CORE_LPC8xx\Debug" -L"C:\Documents and Settings\asl\My Documents\LPCXpresso\workspace\lpc800_driver_lib\Debug" -Xlinker -Map="lpc8test1.map" -Xlinker --gc-sections -mcpu=cortex-m0 -mthumb -T "lpc8test1_Debug.ld" -o "lpc8test1.axf"  ./src/cr_startup_lpc8xx.o ./src/main.o   -lCMSIS_CORE_LPC8xx -llpc800_driver_lib
Finished building target: lpc8test1.axf
That's linking to the lib (-llpc800_driver_lib and -L"C:\Documents and Settings\asl\My Documents\LPCXpresso\workspace\lpc800_driver_lib\Debug") and it's specifying --gc-sections. yet the .map file reveals:
Discarded input sections

<snip>
 .text.PIN3_IRQHandler
                0x00000000       0x10 C:\Documents and Settings\asl\My Documents\LPCXpresso\workspace\lpc800_driver_lib\Debug\liblpc800_driver_lib.a(lpc8xx_gpio.o)
 .text.GPIOSetPinInterrupt
                0x00000000       0xec C:\Documents and Settings\asl\My Documents\LPCXpresso\workspace\lpc800_driver_lib\Debug\liblpc800_driver_lib.a(lpc8xx_gpio.o)
 .text.GPIOPinIntEnable
                0x00000000       0x74 C:\Documents and Settings\asl\My Documents\LPCXpresso\workspace\lpc800_driver_lib\Debug\liblpc800_driver_lib.a(lpc8xx_gpio.o)
 .text.GPIOPinIntDisable
                0x00000000       0x74 C:\Documents and Settings\asl\My Documents\LPCXpresso\workspace\lpc800_driver_lib\Debug\liblpc800_driver_lib.a(lpc8xx_gpio.o)
 .text.GPIOPinIntStatus
                0x00000000       0x2c C:\Documents and Settings\asl\My Documents\LPCXpresso\workspace\lpc800_driver_lib\Debug\liblpc800_driver_lib.a(lpc8xx_gpio.o)
 .text.GPIOPinIntClear
                0x00000000       0x34 C:\Documents and Settings\asl\My Documents\LPCXpresso\workspace\lpc800_driver_lib\Debug\liblpc800_driver_lib.a(lpc8xx_gpio.o)
 .text.GPIOGetPinValue
                0x00000000       0x50 C:\Documents and Settings\asl\My Documents\LPCXpresso\workspace\lpc800_driver_lib\Debug\liblpc800_driver_lib.a(lpc8xx_gpio.o)
etc...
All of which show 0x00000000 as the amount discarded even though none of those functions are called by my code and then the final binary shows:
C:\Documents and Settings\asl\My Documents\LPCXpresso\workspace\lpc8test1\Debug>\nxp\LPCXpresso_5.0.14_1109\lpcxpresso\t
ools\bin\arm-none-eabi-nm.exe --size-sort lpc8test1.axf
<snip>
0000000e T PININT0_IRQHandler
0000000e T PININT1_IRQHandler
0000000e T PININT2_IRQHandler
0000000e T PININT4_IRQHandler
0000000e T PININT5_IRQHandler
0000000e T PININT6_IRQHandler
0000000e T PININT7_IRQHandler
00000012 T bss_init
00000012 T data_init
00000020 B flex_int_counter
00000020 B flex_int_falling_edge_counter
00000020 B flex_int_level_counter
00000020 B flex_int_rising_edge_counter
00000034 T readComparator
0000003c T GPIOInit
00000044 T ResetISR
00000044 T SwitchMatrix_Init
00000046 T GPIOSetBitValue
0000005e T GPIOSetDir
000000a0 T SystemInit
000000c0 T g_pfnVectors
00000150 T main
000001e4 T PININT_Handler
So all the functions from lpc8xx_gpio.c have been included even though the -ffunction-sections when they were built clearly put each function in separate sections and there's a --gc-sections on the linker invocation of the final linked binary.

Most odd. Anyone know why the section garbage collection might not be working? Is the position of the -gc-sections on the linker command line important or something?

WF1903
0 Kudos
Reply

2,519 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by wrighflyer on Tue Jan 29 06:10:38 MST 2013
Looking at it you are quite right. The lpc800_driver_lib is configured to build with -ffunction-sections and -fdata-sections and then the project itself (even "Debug") is configured to lik with -gc-sections. Yet I found that a call to a 3 line GPIO_Init() did add 700 bytes and I remember using avr-nm to check the sumbols and finding all the GPIO interrupt pin handlers in the .axf so I'm not entirely sure why it failed.

Perhaps I'll wind back and try it again and see if I can spot what's wrong including studying the discarded section of the .map. I have a distant memory of it just saying 0x00000 for all the files involved in the link. In fact it was the very fact that the .map had a "discarded" section that lead me to believe that -gc-sections had been attempted and perhaps my incorrect assumption, therefore, that -ffunction-sections must not have been used.
0 Kudos
Reply

2,519 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by whitecoe on Tue Jan 29 05:33:19 MST 2013
The LPC800 examples I've been using (from the LPCXpresso v5.0.14 examples subdirectory) seem to build with -function-sections and --gc-sections here (both the driver library directory and the example applications).

Exactly which examples are you using?

Might be worth you posting the map file from one of your project builds - which should show what code is/ is not being removed?
0 Kudos
Reply

2,519 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by wrighflyer on Tue Jan 29 05:16:14 MST 2013
OK I cannot guarantee that I'm doing this 100% right but can simply say that this "works" on an LPCXpresso 812. It cycles the LED through R-G-B repeatedly. The speed at which it does this is set by reading the variable resistor which is read like a simple 32 step ADC. The core things are the initialisation of the comparator. Also the switch matrix (I also enable SPI and UART at the same time with a view to doing some more experiments based on this) and then the readComparator() routine which, having connected the ACMP_I1 input to the +ve side and the voltage step generator to the -ve side just takes the step ladder through 32 steps until the comparator output bit (COMPOUT - bit 21) is seen to change state.
#ifdef __USE_CMSIS
#include "LPC8xx.h"
#endif

#include <cr_section_macros.h>
#include <NXP/crp.h>

// Variable to store CRP value in. Will be placed automatically
// by the linker when "Enable Code Read Protect" selected.
// See crp.h header for more information
__CRP const unsigned int CRP_WORD = CRP_NO_CRP ;

void GPIOSetDir( uint32_t portNum, uint32_t bitPosi, uint32_t dir )
{
  if( dir )
  {
        LPC_GPIO_PORT->DIR0 |= (1<<bitPosi);
  }
  else
  {
        LPC_GPIO_PORT->DIR0 &= ~(1<<bitPosi);
  }
  return;
}

void GPIOSetBitValue( uint32_t portNum, uint32_t bitPosi, uint32_t bitVal )
{
  if ( bitVal )
  {
        LPC_GPIO_PORT->SET0 = 1<<bitPosi;
  }
  else
  {
        LPC_GPIO_PORT->CLR0 = 1<<bitPosi;
  }
  return;
}

void SwitchMatrix_Init()
{
    /* I decided to put:
     *   pin8 = PIO_11 = UART0_RXD
     *   pin9 = PIO_10 = UART0_TXD
     *   pin12 = PIO_1 = SPI0_SCK
     *   pin13 = PIO_9 = SPIO_SSEL
     *   pin18 = PIO_6 = SPIO_MISO
     *   pin19 = PIO_0 = ACOMP_I0 (variable resistor)
     *   pin20 = PIO_14 = SPI0_MOSI
     */
    /* Enable SWM (switch matrix) clock */
    LPC_SYSCON->SYSAHBCLKCTRL |= (1<<7);

    /* Pin Assign 8 bit Configuration */
    /* U0_TXD */
    /* U0_RXD */
    LPC_SWM->PINASSIGN0 = 0xffff0b0aUL;
    /* SPI0_SCK */
    LPC_SWM->PINASSIGN3 = 0x01ffffffUL;
    /* SPI0_MOSI */
    /* SPI0_MISO */
    /* SPI0_SSEL */
    LPC_SWM->PINASSIGN4 = 0xff09060eUL;

    /* Pin Assign 1 bit Configuration */
    /* ACMP_I1 */
    /* SWCLK */
    /* SWDIO */
    /* RESET */
    LPC_SWM->PINENABLE0 &= ~(1<<0); // clear the ACOMP_I1 bit to 0 to enable it

    /* SWM clock no longer needed now it's configured */
    LPC_SYSCON->SYSAHBCLKCTRL &= ~(1<<7);
}

int readComparator(void) {
    int i, prev_output;
    LPC_CMP->LAD = 0x1; // enable with ladder = 0
    prev_output = LPC_CMP->CTRL & (1<<21);
    for(i=0; i < (0x20<<1); i += 2){
        LPC_CMP->LAD = 0x1 | i; // enable and set ladder voltage
        if ((LPC_CMP->CTRL & (1<<21)) != prev_output) {
            return (i>>1);
        }
    }
    return (i>>1);
}

int main(void) {

    volatile static int i = 0, j, k;

      /* Enable AHB clock to the GPIO domain. */
    LPC_SYSCON->SYSAHBCLKCTRL |= (1<<6);

    /* Peripheral reset control to GPIO and GPIO INT, a "1" bring it out of reset. */
    LPC_SYSCON->PRESETCTRL &= ~(0x1<<10);
    LPC_SYSCON->PRESETCTRL |= (0x1<<10);

    GPIOSetDir(0, 7, 1); // RED
    GPIOSetDir(0, 16, 1); // BLUE
    GPIOSetDir(0, 17, 1); // GREEN

    /* Comparator should be powered up first. Use of comparator requires BOD */
    /* NB: apart from the library code I cannot find this BOD requirement anywhere */
    LPC_SYSCON->PDRUNCFG &= ~( (0x1 << 15) | (0x1 << 3) );
    /* Enable AHB clock to the Comparator. */
    LPC_SYSCON->SYSAHBCLKCTRL |= (0x1 << 19);
    /* Peripheral reset control to Comparator, a "1" bring it out of reset. */
    LPC_SYSCON->PRESETCTRL &= ~(0x1 << 12);
    LPC_SYSCON->PRESETCTRL |= (0x1 << 12);
    /* switch off the pull-up on the pin that will be used for comp input */
    LPC_IOCON->PIO0_0 &= ~(0x3 << 3);
    /* connect voltage ladder to one input and ACOMP_I1 to the other input */
    LPC_CMP->CTRL |= (1 << 8); // +ve = ACOMP_I1 and default is -ve = ladder

    SwitchMatrix_Init();

    // Enter an infinite loop, just incrementing a counter
    while(1) {
        if (i == 0) {
            GPIOSetBitValue( 0, 7, 0 );
            GPIOSetBitValue( 0, 16, 1 );
            GPIOSetBitValue( 0, 17, 1 );
        }
        else if (i == 1) {
            GPIOSetBitValue( 0, 7, 1 );
            GPIOSetBitValue( 0, 16, 0 );
            GPIOSetBitValue( 0, 17, 1 );
        }
        else if (i == 2) {
            GPIOSetBitValue( 0, 7, 1 );
            GPIOSetBitValue( 0, 16, 1 );
            GPIOSetBitValue( 0, 17, 0 );
        }
        i++ ;
        if (i >= 3) {
            i = 0;
        }
        k = readComparator();
        for (j=0; j < (10000 * k); j++);
    }
    return 0 ;
}
I wasn't sure if there's a library function for software delays so just increment a volatile (j) in a for() loop to make the variable length delay between LED changes.

For some of the code I just "lifted" various bits from the library examples provided because for some reason they haven't been built with -ffunction-sections so -gc-sections cannot be used to only take selected functions from them and I found that a call to the three line GPIO_Init() function added 700 bytes to the code! Maybe the library authors expect you to take the whole of lpc8xx_gpio.c or whatever and that probably doesn't matter on LPCs with 64/128/256KB of flash but the LPC812's are 4/8/16KB devices and certainly in the 4KB device 700 bytes is a heft price to pay.

Wonder why they didn't build with -ffunction-sections?

WF1903
0 Kudos
Reply

2,519 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by wrighflyer on Fri Jan 25 12:58:52 MST 2013
Yeah I looked at the example but it's really just using it as a comparator. While the demo app is using a pot as input and acting almost like it's an ADC. Having read about the comparator in the chip and the stepped voltage generator it contains I have a strong suspicion that the way they are reading the pot voltage is to have that as one input to the comparator. The stepped voltage generator as the other. Run through the steps until it switches state. I'd just like to see an example of how this is done. The comparator example code itself does not show this.

I would just Google but the LPC812 seems "too new" and I can only find a handful of sites so far where people have done "early reviews" but not any wealth of example code for it just yet. Maybe I just have to be patient.

I wonder who would know what the actual demo code is and whether there's a chance of it being made public?

WF1903
0 Kudos
Reply

2,519 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by CodeRedSupport on Tue Jan 22 03:27:28 MST 2013
I'm not 100% sure what application NXP have programmed into production LPCXpresso812 boards is (as I haven't seen a production one), but the "comparator" example from the bundle is probably the one that you want to take a look at.

Regards,
CodeRedSupport
0 Kudos
Reply