Monday, 1 September 2014

How create an assembler listing of your LPC810 project with LPCXpresso

I discovered this little gem today, often it is required to see what the actual code the C compiler is creating  looks like in assembler, you may  for instance want to find out how many clock cycles a particular routine takes or try to optimize the resulting assembly. You can do this automatically if you place a line like the one below in the Post Build Steps section.

arm-none-eabi-objdump  -d   src/<file1.o> src/<file2.o> "${BuildArtifactFileBaseName}.asm" 

The Post Build Steps can be found at

My Project -> Properties -> C/C++ Build -> Settings -> Build Steps

The objdump command will generate an assembly with C source listing file, just include the object files you require to be dissembled in the file list.

For example you could use this line to generate a disassembly listing of both main.c and cr_startup_lpc8xx.c 

arm-none-eabi-objdump  -d   src/main.o src/cr_startup_lpc8xx.o  > "${BuildArtifactFileBaseName}.asm"


Monday, 11 August 2014

Creating a 5 bit successive approximation (sar) ADC using the LPC810's Comparator

The only analog peripheral the LPC810 has it the analog comparator which can compare various external and internal voltages. The analogs pin are fixed pins in the LPC800 series of micro-controllers and exist on the same pins as PIO0_0 and PIO0_1


 In this example we are going to use the PIO0_1 pin which is ACMP_I2


and we have the potentiometer connected to PIO0_1.A word of warning, be careful not to have the POT turned to ground when you try to restart the LPC810 after programming or the LPC810 will boot into ISP mode again.

The steps in setting up the comparator is similar to the other peripherals, first we must turn on the clock to the comparator then select it in the switch matrix. We also need to power up the comparator like so:

LPC_SYSCON->PDRUNCFG &= ~(( 1  <<  15 )); // power up ACMP

Again replace the main.c in from the previous project with the one below :-


#include "LPC8xx.h"

#define BAUDRATE 57600
#define UART_CFG_DATALEN_8      (0x01 << 2)  /* UART 8 bit length mode */
#define UART_CFG_PARITY_NONE    (0x00 << 4)  /* No parity */
#define UART_CFG_STOPLEN_1      (0x00 << 6)  /* UART One Stop Bit Select */
#define UART_STAT_RXRDY         (0x01 << 0)  /* Receiver ready */
#define UART_STAT_TXRDY         (0x01 << 2)  /* Transmitter ready for data */
#define UART_CFG_ENABLE         (0x01 << 0)

uint32_t SystemCoreClock = 12000000; /* Value @ Reset */
uint32_t SystemMainClock = 12000000; /* Value @ Reset */

#define halt_clk(c) LPC_MRT->Channel[3].INTVAL = (c-3)

int uart0PollChar() {
 if (!(LPC_USART0->STAT & UART_STAT_RXRDY))
  return -1;
 return LPC_USART0->RXDATA;
}
void uart0putc(unsigned char c) {
 /* Wait until we're ready to send */
 while (!(LPC_USART0->STAT & UART_STAT_TXRDY))
  ;
 LPC_USART0->TXDATA = c;
}

void uart0puti(unsigned int n) {
 unsigned int rem = n % 10;
 unsigned int quot = n / 10;
 if (quot > 0)
  uart0puti(quot);
 uart0putc(rem + '0');
}

/* Use ACMP_2 as a simple 5 bit SAR adc */
int read_adc2() {
 int min = 0, max = 63, value = 31, count, compstat, laststat;
 LPC_CMP->CTRL = (0x2 << 8) | (0x3 << 25); /* positive input ACMP0_I2 , negative input voltage ladder , 20mV hysteresis */
 while (!((value == min) || (value == max))) {
  count = 0;
  LPC_CMP->LAD = 1 | (value); /* ladder Enable | Vref=Vdd | value */
  halt_clk(12 * 15); /* 15us worst case for ladder to settle */
  laststat = (LPC_CMP->CTRL >> 21) & 1;
  /* wait till reading is the same 3 times in row */
  do {
   halt_clk(6); /* wait 0.5us */
   compstat = (LPC_CMP->CTRL >> 21) & 1;
   if (compstat == laststat)
    count++;
   else
    count = 0;
   laststat = compstat;
  } while (count < 3);
  /* Binary divide */
  if (compstat) {
   min = value;
   value = value + ((max - value) >> 1);
  } else {
   max = value;
   value = value - ((value - min) >> 1);
  }
 }
 return value >> 1;
}

int main(void) {
 /* Enable AHB clock to the Switch Matrix , UART0 , GPIO , IOCON, MRT , ACMP */
 LPC_SYSCON->SYSAHBCLKCTRL |= (1 << 7) | (1 << 14) /*| (1 << 6)*//* | (1 << 18)*/
   | (1 << 10) | (1 << 19);

 /* Configure Switch Matrix so that Pin2 = U0_TXD and Pin8 = U0_RXD */
 LPC_SWM->PINASSIGN0 = 0xffff0004UL;

 /* On reset pio_2(swdio), pio_3(swclk) , pio_5(reset) are selected as fixed function.
  * We disable all fixed functions here so they will become GPIO unless a movable function
  * has been assigned in the switch matrix by the line above */
 LPC_SWM->PINENABLE0 = 0xffffffffUL & (~0x2); /* Enable fixed function ACMP_I2. This function is enabled on pin PIO0_1 */

 /* Set the UART clock divisor to 1  */
 LPC_SYSCON->UARTCLKDIV = 1; // note on reset the value is 0. i.e clock is disabled
 /* Configure UART0 baud rate */
 LPC_USART0->BRG = ((SystemMainClock / LPC_SYSCON->UARTCLKDIV) >> 4)
   / BAUDRATE - 1;
 LPC_SYSCON->UARTFRGMULT =
   ((((SystemMainClock / LPC_SYSCON->UARTCLKDIV) >> 4) * (0x100))
     / (BAUDRATE * (LPC_USART0->BRG + 1))) - (0x100);
 LPC_SYSCON->UARTFRGDIV = 0xFF; //note on reset the value is 0

 /* Set UART0 to 8N1 and finally enable */
 LPC_USART0->CFG = UART_CFG_DATALEN_8 | UART_CFG_PARITY_NONE
   | UART_CFG_STOPLEN_1 | UART_CFG_ENABLE;

 LPC_MRT->Channel[3].CTRL = (0x02 << 1); /* MRT3 (halt_clk) bus stall mode , no interrupts */

 /* Initialise the comparator ICMP_2 */
 LPC_SYSCON->PDRUNCFG &= ~((1 << 15)); // power up ACMP

 /* wait for the keypress 'a' */
 while (1) {
  switch (uart0PollChar()) {
  case 'a': {
   int v = read_adc2();
   uart0puti(v);
   uart0putc('\n');
   uart0putc('\r');
  }
   break;
  }
 }
 return 0;
}


The function read_adc2() does most of the work here and implements a simple 5 bit SAR ADC using the programmable voltage divider of the LPC800 series mcu's. It should be noted that theoretically this routine could get into an infinite loop if there was to much noise but it seems to work well for me.


Sunday, 10 August 2014

Control a relay module from a PC via a TTL UART with a LPC810

Previously a simple program was created to read the input from a simple comparator based light sensor, now we focus attention on LPC810 GPIO's again to drive a relay module with some simple UART commands sent from a PC.

The module has a green LED for power and a red LED that lights when the relay is active

Using the LPC810's Physical Pin 4 which is pio_2 to drive the relay.

The relay module was wired up as below:-


These modules appear to be slightly different , the one I purchased from ebay operated on 5v and did not have an opto-isolator and so is only suitable for low voltages (In fact i would be vary careful with any of these cheap non-ce devices  from china with  mains level voltages,  just because the relay may-be rated at 240v does not imply the entire module has been designed for 240v,  if your intent is on controlling mains voltages then get a CE certified one) . The relay's active led was lit when IN1 was logic 0 and was off when IN1 was logic 1.For it to work it required that the GPIO output was driven in open drain mode and the required 5v Vcc was obtained from the 5v pin on the USB TTL UART adapter,

To use the GPIO port to drive the relay module he following needs to be done:

  1. Enable the Clock to the GPIO and IOCON with LPC_SYSCON->SYSAHBCLKCTRL |= (1 << 6) | (1 << 18 )
  2. Reset all Fixed pins with LPC_SWM->PINENABLE0 = 0xffffffffUL;
  3. Put the GPIO in open drain mode and disable the internal pull up resistor with LPC_IOCON->PIO0_2 = (1 << 10) ;
  4. Set the PIO_2 direction to output with LPC_GPIO_PORT->DIR0 |= (1 << 2);

The GPIO port can be set or reset by putting a 1 or 0 in

 LPC_GPIO_PORT->B0[2]

when the index , two in this case is the index of the GPIO.


#include "LPC8xx.h"

#define BAUDRATE 57600
#define UART_CFG_DATALEN_8      (0x01 << 2)  /* UART 8 bit length mode */
#define UART_CFG_PARITY_NONE    (0x00 << 4)  /* No parity */
#define UART_CFG_STOPLEN_1      (0x00 << 6)  /* UART One Stop Bit Select */
#define UART_STAT_RXRDY         (0x01 << 0)  /* Receiver ready */
#define UART_STAT_TXRDY         (0x01 << 2)  /* Transmitter ready for data */
#define UART_CFG_ENABLE         (0x01 << 0)

uint32_t SystemCoreClock = 12000000; /* Value @ Reset */
uint32_t SystemMainClock = 12000000; /* Value @ Reset */

int uart0PollChar() {
 if (!(LPC_USART0->STAT & UART_STAT_RXRDY))
  return -1;
 return LPC_USART0->RXDATA;
}
void uart0putc(unsigned char c) {
 /* Wait until we're ready to send */
 while (!(LPC_USART0->STAT & UART_STAT_TXRDY));
 LPC_USART0->TXDATA = c;
}
int main(void) {
 /* Enable AHB clock to the Switch Matrix , UART0 , GPIO , IOCON*/
 LPC_SYSCON->SYSAHBCLKCTRL |= (1 << 7) | (1 << 14) | (1 << 6) | (1 << 18 );

 /* Configure Switch Matrix so that Pin2 = U0_TXD and Pin8 = U0_RXD */
 LPC_SWM->PINASSIGN0 = 0xffff0004UL;

 /* On reset pio_2(swdio), pio_3(swclk) , pio_5(reset) are selected as fixed function.
  * We disable all fixed functions here so they will become GPIO unless a movable function
  * has been assigned in the switch matrix by the line above */
 LPC_SWM->PINENABLE0 = 0xffffffffUL;

 /* Physical Pin 4 (pio_2) is configured as output */
 LPC_GPIO_PORT->DIR0 |= (1 << 2);

 /* pio_2 is set to open drain mode and it's pull up resistor disabled */
 LPC_IOCON->PIO0_2 = (1 << 10)  ;

 /* Set the UART clock divisor to 1  */
 LPC_SYSCON->UARTCLKDIV = 1; // note on reset the value is 0. i.e clock is disabled
 /* Configure UART0 baud rate */
 LPC_USART0->BRG = ((SystemMainClock / LPC_SYSCON->UARTCLKDIV) >> 4)
   / BAUDRATE - 1;
 LPC_SYSCON->UARTFRGMULT =
   ((((SystemMainClock / LPC_SYSCON->UARTCLKDIV) >> 4) * (0x100))
     / (BAUDRATE * (LPC_USART0->BRG + 1))) - (0x100);
 LPC_SYSCON->UARTFRGDIV = 0xFF; //note on reset the value is 0

 /* Set UART0 to 8N1 and finally enable */
 LPC_USART0->CFG = UART_CFG_DATALEN_8 | UART_CFG_PARITY_NONE
   | UART_CFG_STOPLEN_1 | UART_CFG_ENABLE;

 /* Set pio_2 according to which keypress '0' and '1' */
 while (1) {
  switch (uart0PollChar()) {
  case '0':
   LPC_GPIO_PORT->B0[2] = 0;
   uart0putc('0');
   break;
  case '1':
   LPC_GPIO_PORT->B0[2] = 1;
   uart0putc('1');
   break;
  }
 }
 return 0;
}


Interfacing a light sensor module to the LPC810

In the previous posts we looked at what could be done with NXP's LPC810 having only the UART connected. In this post let us connect a simple light sensor module like this one:



Any similar sensor module could be used they are available as magnetic reed switch, IR proximity detector ect. They all work the same way and use the trusty LM393 comparator to provide a on/off value on the data line D0 in this case when the light is above or below a certain threshold that can be adjusted by the potentiometer seen in blue.

It is wired up as so with Pin 3 (pio_3) connected to the DO line of the light sensor module.


We replace the main.c built up in the previous posts with a simplified one which simply outputs are 0 or 1 when the light level goes above or below the required threshold:-



#include "LPC8xx.h"

#define BAUDRATE 57600
#define UART_CFG_DATALEN_8      (0x01 << 2)  /* UART 8 bit length mode */
#define UART_CFG_PARITY_NONE    (0x00 << 4)  /* No parity */
#define UART_CFG_STOPLEN_1      (0x00 << 6)  /* UART One Stop Bit Select */
#define UART_STAT_RXRDY         (0x01 << 0)  /* Receiver ready */
#define UART_STAT_TXRDY         (0x01 << 2)  /* Transmitter ready for data */
#define UART_CFG_ENABLE         (0x01 << 0)

uint32_t SystemCoreClock = 12000000; /* Value @ Reset */
uint32_t SystemMainClock = 12000000; /* Value @ Reset */

void uart0putc(unsigned char c) {
 /* Wait until we're ready to send */
 while (!(LPC_USART0->STAT & UART_STAT_TXRDY));
 LPC_USART0->TXDATA = c;
}

int main(void) {
 /* Enable AHB clock to the Switch Matrix , UART0 , GPIO */
 LPC_SYSCON->SYSAHBCLKCTRL |= (1 << 7) | (1 << 14) | (1 << 6);

 /* Configure Switch Matrix so that Pin2 = U0_TXD and Pin8 = U0_RXD */
 LPC_SWM->PINASSIGN0 = 0xffff0004UL;

 /* Set the UART clock divisor to 1  */
 LPC_SYSCON->UARTCLKDIV = 1; // note on reset the value is 0. i.e clock is disabled
 /* Configure UART0 baud rate */
 LPC_USART0->BRG = ((SystemMainClock / LPC_SYSCON->UARTCLKDIV) >> 4)
   / BAUDRATE - 1;
 LPC_SYSCON->UARTFRGMULT =
   ((((SystemMainClock / LPC_SYSCON->UARTCLKDIV) >> 4) * (0x100))
     / (BAUDRATE * (LPC_USART0->BRG + 1))) - (0x100);
 LPC_SYSCON->UARTFRGDIV = 0xFF; //note on reset the value is 0

 /* Set UART0 to 8N1 and finally enable */
 LPC_USART0->CFG = UART_CFG_DATALEN_8 | UART_CFG_PARITY_NONE
   | UART_CFG_STOPLEN_1 | UART_CFG_ENABLE;

 /* Output changes to pio_03 over the uart as zeros and ones */
 char old_v = -1;
 while (1) {
  char v = LPC_GPIO_PORT->B0[3];
  if (v!=old_v){
   uart0putc(v+'0');
   uart0putc('\n');
   uart0putc('\r');
   old_v = v;
  }
 }
 return 0;
}


We enable the Clock to the GPIO peripheral in SYSAHBCLKCTRL , the GPIO's clock is actually enabled just after reset so this is not strictly necessary but makes the code a clearer at no extra cost.

Also after reset all Pins are set to GPIO and the pin direction is as input so we need to do nothing with the switch matrix or the GPIO direction register to attach a simple sensor.

The GPIO's input pin value is read by the line

char v = LPC_GPIO_PORT->B0[3];

which reads the pin value as a byte value which can be either 0 or 1

Monday, 4 August 2014

Some other uses for the LPC810 Multi Rate Timer (MRT)

In the last post a clock cycle accurate delay which stalled the CPU bus rather than eat up CPU cycles was created using the Multi Rate Timer while in this post we  look at some other simple uses for the remaining 3 channels of the MRT.

A Millisecond delay routine on channel 2, this delay routine will poll the Status register to see if the timer is still running and consume CPU cycles whist running, it will not however block interrupts which is necessary for long delays although a callback timer shown below may be more appropriate in some cases.

/* Delay by a number of milliseconds
 * Note the divide of SystemCoreClock will affect the accuracy
 * The overhead is approximately 286 +/- 10 (varies with the actual divide) clock cycles which is about 24us @ 12MHZ
 * Uses channel 2 of the MRT
 */

void delay_ms(int delay) {
 LPC_MRT->Channel[2].INTVAL = (((SystemCoreClock / 250L) * delay) >> 2)
   - 286 ;
 while (LPC_MRT->Channel[2].STAT & 0x02)
  ; //wait while running
}

It is initilized like so

 LPC_MRT->Channel[2].CTRL = (0x01 << 1); //MRT2 (delay_ms) single shot mode , no interrupts

A Profile timer on channel 1

/* Profiler on MRT Channel 1 */
volatile static uint32_t __profile_clocks;
#define PROFILE_START()  LPC_MRT->Channel[1].INTVAL = 0xffffffff //Force count down from max value
#define PROFILE_STOP()  __profile_clocks = LPC_MRT->Channel[1].TIMER //snatch timer value
#define PROFILE_COUNT()  (0x7fffffffUL - 8 - __profile_clocks )   //Return the number of clock cycles counted
#define PROFILE_PREPARE() (__profile_clocks)// fudge to even init clock cycles



The Profile timer is initilized like so

 LPC_MRT->Channel[1].CTRL = (0x01 << 1); //MRT1 (Profiler) single shot mode , no interrupts

and used like below

PROFILE_PREPARE();
PROFILE_START();
halt_clk(30);
PROFILE_STOP();
xprintf("30 profile clocks are %d\n\r",PROFILE_COUNT());

Finally on channel 0 we have a timer function that will execute a callback function after a specified amount of clock cycles, it can be made to repeat or used as a single shot timer.

/* timer()
 * the timer() function executes callback after clk clock cycles
 * repeat signals if the callback is to be repeated.
 * Uses MRT Channel 0
 */
void (*__callback)(void);

void timer(int clk,void (*callback)(void),bool repeat){
 if (repeat)
  LPC_MRT->Channel[0].CTRL = 0x1 ; /* MRT0 repeat mode , interrupts enabled */
 else
  LPC_MRT->Channel[0].CTRL = (0x01 << 1) | 0x1 ; /* MRT0 single shot mode , interrupts enabled */
 __callback = callback;
 LPC_MRT->Channel[0].INTVAL = clk | (1 << 31);
ISER[0] = (1 << 10); /* enable interrupts */
}
/* MRT_IRQHandler used for timer() function */
void MRT_IRQHandler(void){
 LPC_MRT->Channel[0].STAT = 0x1 ; /* clr interupt request */
 if (__callback)
  __callback();

}



Sunday, 3 August 2014

Microsecond delays using the LPC810's Multi Rate Timer (MRT).

A Situation that occurs frequently is the need to delay the CPU for a specific number of microseconds or clock cycles. An ideal way to do this with the with the Multi Rate Timer of the LPC810 is with a special mode called One-shot bus stall mode.

The Multi Rate Timer comprises of Four individual 31 bit timers capable of generating a repetitive interrupt similar to the SysTick Timer or counting down to zero and generating a single shot interrupt. All the four timers will trigger the same interrupt routine which will need to determine which of the interrupt enabled timers triggered it.

There is however another mode of operation which does not use interrupts and is known as the One-shot bus stall mode. This mode  will instead stall the bus interface of the System Clock for a specified number of clock cycles. This mode effectively stops all CPU activity until the MRT has finished counting down to zero and is ideal for creating a microsecond or fixed cycle delay functions as in the time the MRT is counting down to zero the CPU consumes very little power as opposed to a tradition delay loop or a polled timer delay loop.

We need to write the number of clock cycles to stall the bus to the INTVAL register of the timer, The bus is actually stalled for INTVAL+3 cycles as some time is needed by the MRT to actually stall the bus.

First lets use channel 3 of the MRT and initialize it to bus stall mode somewhere in our main routine.

LPC_MRT->Channel[3].CTRL = (0x02 << 1) ; //MRT3 (halt_clk) bus stall mode , no interrupts

Next lets define a macro that we can use to halt the CPU for a number of clock cycles, This macro works providing that the number of clock cycles is greater that 3.

#define halt_clk(clk) LPC_MRT->Channel[3].INTVAL = (clk-3)

For Instance

halt_clk(120); /* Gives a 10us delay with 12MHZ clock */



Saturday, 2 August 2014

Using the SysTick timer of the LPC810

Every Cortex M0 Mcu such as the LPC810 has a system timer know as the SysTick timer which is a simple 24 bit timer. The SysTick timer is intended to provide a regular interrupt that can be used to update a system tick count, the code below provides a SysTick_Handler which overrides the WEAK reference to SysTick_Handler in cr_startup.c

/* SysTick Handler to be interupted every 1ms */
uint32_t __tick;
void SysTick_Handler(void) {
 __tick++;
}

The following lines of code enable a SysTick interrupt to occur every 1 Millisecond

SysTick->LOAD = (SystemCoreClock / 1000 * 1/*# ms*/) - 1; /* Every 1 ms */
SysTick->VAL = 0;
__tick = 0;
SysTick->CTRL = 0x7; /* d2:ClkSrc=SystemCoreClock, d1:Interrupt=enabled, d0:SysTick=enabled */

We Load the System Timer with the repeat count in the LOAD field then set the initial value to zero in the VAL field rather  than leave it at some random value and also reset the __tick count to zero.
The CTRL field is set to enable Interrupts in bit d1 (Our SysTick_Handler above) and to use the SystemCoreClock rather than SystemCoreClock / 2 by setting bit d2, Then finally setting bit d0 enables the System Timer.

The Internal RC Clock of the LPC810 is specified to be accurate to within 1% which is about 14 Minutes a day or 6 seconds very 10 Minutes. The device I tried appears to be doing slightly better and losing 3 seconds every 10 Minutes.

The updated code for the example is below:


#include "LPC8xx.h"
#include "xprintf.h"

#define BAUDRATE 57600
#define UART_CFG_DATALEN_8      (0x01 << 2)  /* UART 8 bit length mode */
#define UART_CFG_PARITY_NONE    (0x00 << 4)  /* No parity */
#define UART_CFG_STOPLEN_1      (0x00 << 6)  /* UART One Stop Bit Select */
#define UART_STAT_RXRDY         (0x01 << 0)  /* Receiver ready */
#define UART_STAT_TXRDY         (0x01 << 2)  /* Transmitter ready for data */
#define UART_CFG_ENABLE         (0x01 << 0)

/*Which Clock source ?, if both are 0 then Internal RC Oscillator is used */
#define USE_PLL    0
#define USE_WATCHDOG   0

#define USE_SYSTICK  1

#define WATCHDOG_300KHZ ((1 << 5) | (0))
#define WATCHDOG_9375HZ ((1 << 5) | (0x1f))
#define WATCHDOG_2300KHZ ((0xf << 5) | (0))
#define PLL_60MHZ (0x24)
#define PLL_24MHZ (0x41)
#define PLL_96MHZ (0x07)

uint32_t SystemCoreClock = 12000000; /* Value @ Reset */
uint32_t SystemMainClock = 12000000; /* Value @ Reset */

#if (USE_SYSTICK)
uint32_t __tick;
void SysTick_Handler(void) {
 __tick++;
}
#endif

void uart0putc(unsigned char c) {
 /* Wait until we're ready to send */
 while (!(LPC_USART0->STAT & UART_STAT_TXRDY));
 LPC_USART0->TXDATA = c;
}

unsigned char uart0getc() {
 /* Wait until we're ready to receive */
 while (!(LPC_USART0->STAT & UART_STAT_RXRDY));
 return LPC_USART0->RXDATA;
}

short uart0PollChar() {
 if (!(LPC_USART0->STAT & UART_STAT_RXRDY))
  return -1;
 return LPC_USART0->RXDATA;
}

int main(void) {
 /* Enable AHB clock to the Switch Matrix , UART0 , IOCON */
 LPC_SYSCON->SYSAHBCLKCTRL |= (1 << 7) | (1 << 14) | (1 << 18);

#if (USE_PLL)
 /* Enable the PLL Clock for a maximum 30MHZ SystemCoreClock */
 LPC_SYSCON->SYSPLLCTRL = PLL_60MHZ; /* 60 MHZ pll output clock*/
 LPC_SYSCON->PDRUNCFG &= ~(0x1 << 7); /* Power-up SYSPLL          */
 while (!(LPC_SYSCON->SYSPLLSTAT & 0x01)); /* Wait Until PLL Locked    */

 LPC_SYSCON->MAINCLKSEL = 3; /* Select PLL Clock Output  */
 LPC_SYSCON->MAINCLKUEN = 0x01; /* Update MCLK Clock Source */
 while (!(LPC_SYSCON->MAINCLKUEN & 0x01)); /* Wait Until Updated       */

 LPC_SYSCON->SYSAHBCLKDIV = 2; /* Divide by 2 to get the maximum 30MHZ SystemCoreClock */

 SystemMainClock = 12000000 * ((LPC_SYSCON->SYSPLLCTRL & 0x01F) + 1); /* Calculate SystemMainClock for IRC directed to the PLL*/
 SystemCoreClock = SystemMainClock / LPC_SYSCON->SYSAHBCLKDIV; /*Calculate SystemCoreClock */

#elif (USE_WATCHDOG)
 /* Enable the Watchdog Oscillator for minimum power consumption*/
 LPC_SYSCON->WDTOSCCTRL = WATCHDOG_2300KHZ;
 LPC_SYSCON->PDRUNCFG &= ~(0x1 << 6); /* Power-up Watchdog          */
 LPC_SYSCON->MAINCLKSEL = 2; /* Select Watchdog Clock Output  */
 LPC_SYSCON->MAINCLKUEN = 0x01; /* Update MCLK Clock Source */
 while (!(LPC_SYSCON->MAINCLKUEN & 0x01)); /* Wait Until Updated       */

 if ((LPC_SYSCON->WDTOSCCTRL & (0x0f << 5)) == (0x01 << 5))
 SystemMainClock = 600000 / (2 * (1 + (LPC_SYSCON->WDTOSCCTRL & 0x1f)));
 else
 SystemMainClock = 4600000 / (2 * (1 + (LPC_SYSCON->WDTOSCCTRL & 0x1f)));

 SystemCoreClock = SystemMainClock / LPC_SYSCON->SYSAHBCLKDIV; /* Calculate SystemCoreClock */
 LPC_SYSCON->PDRUNCFG |= (1 << 7) | (1 << 1) | (1 << 0); /* Power down IRC & PLL as not needed now */
#endif

#if (USE_SYSTICK)
 SysTick->LOAD = (SystemCoreClock / 1000 * 1/*# ms*/) - 1; /* Every 1 ms */
 SysTick->VAL = 0;
 __tick = 0;
 SysTick->CTRL = 0x7; /* d2:ClkSrc=SystemCoreClock, d1:Interrupt=enabled, d0:SysTick=enabled */
#endif

 /* Set the UART clock divisor to 1  */
 LPC_SYSCON->UARTCLKDIV = 1; // note on reset the value is 0. i.e clock is disabled
 /* Configure UART0 baud rate */
 LPC_USART0->BRG = ((SystemMainClock / LPC_SYSCON->UARTCLKDIV) >> 4)
   / BAUDRATE - 1;
 LPC_SYSCON->UARTFRGMULT =
   ((((SystemMainClock / LPC_SYSCON->UARTCLKDIV) >> 4) * (0x100))
     / (BAUDRATE * (LPC_USART0->BRG + 1))) - (0x100);
 LPC_SYSCON->UARTFRGDIV = 0xFF; //note on reset the value is 0

 /* Set UART0 to 8N1 and finally enable */
 LPC_USART0->CFG = UART_CFG_DATALEN_8 | UART_CFG_PARITY_NONE
   | UART_CFG_STOPLEN_1 | UART_CFG_ENABLE;

 /* Initialise Chan's Embedded String Functions (xprintf ect) */
 xdev_out(uart0putc);
 xdev_in(uart0getc);

 /* Some variables for Clock logic */
 char buf[9];
 char err = 0;
 long refh, refm, refs; /* ref time */
 int reftick;
 int reftime; // ref time in seconds
 // Enter an infinite loop testing for a keypress
 while (1) {
  switch (uart0PollChar()) {
  case '0':
   xprintf("System Core Clock is %d hz\n\rSystem Main Clock is %d\n\r",
     SystemCoreClock, SystemMainClock);
   break;
  case '1':
   xprintf("current _tick is %d\n\r", __tick);
   break;
  case 's':
   //set clock time hh:mm:ss
   xprintf("Please enter current time hh:mm:ss > ");
   xgets(buf, 9);
   reftick = __tick;
   if (buf[2] == ':' && buf[5] == ':') {
    buf[2] = ' ';
    buf[5] = ' ';
    char *p = &buf[0];
    if (!(xatoi(&p, &refh) && xatoi(&p, &refm) && xatoi(&p, &refs)))
     err = 1;
    else
     reftime = ((refh * 60) + refm) * 60 + refs;
   } else {
    err = 1;
   }
   if (err == 1)
    xprintf("\n\rError the time format is incorrect,  You entered %s\n\r",buf);
   break;
  case 'c':
   //get clock time
  {
   int secs = (__tick - reftick) / 1000; //number of seconds since time set
   int current = (reftime + secs) % (60 * 60 * 60);
   int h = (current / (60 * 60)) % 24;
   int m = (current / 60) % 60;
   int s = current % 60;
   xprintf("Current time is %d:%d:%d  The number of seconds passed is %d\n\r", h, m, s, secs);
  }
   break;
 }
 }
 return 0;
}


Wednesday, 30 July 2014

The PLL and various Clock sources of a LPC810


Previously we found out that using the default CMSIS startup routines that  the LPC810's System core clock is 12 MHZ upon entry to main() and that the MAINCLKSEL is 0x00 meaning that the PLL is not engaged so the LPC810 is being driven directly by the IRC Oscillator which is actually the default starting condition of the LPC810 anyway.

Since saving bytes is clearly important on a device like this the call to the CMSIS SystemInit() can be removed from cr_startup_lpc8xx.c entirely. Find the following lines of code and remove them


#if defined (__USE_CMSIS) || defined (__USE_LPCOPEN)
    SystemInit();
#endif

Since we know the SystemCoreClock is 12 MHZ we can also remove the call to the CMSIS SystemCoreClockUpdate() function in main.c and replace it simply with:


uint32_t SystemCoreClock = 12000000;


By my calculations this will save a whopping 268 bytes which might just save the day.


Diagram from lpc8xx pll calculator.xlsx

From the diagram above the SystemCoreClock (Just System Clock in the diagram) is the Main Clock divided by SYSAHBCLKDIV. The SystemCoreClock is also drives the peripheral clocks, the exception here is the UART's that have there own divider UARTCLKDIV and are clocked from the Main Clock divided by UART(CLKDIV and also IOCON is clocked from the Main Clock divided by IOCONCLKDIV. The mistake in the first version of the Uart init routine was to assume it was driven from the SystemCoreClock like most of the other peripherals.

The LM810's phase locked loop

What if we would like the SystemCoreClock to be more that 12MHZ? The LPC810 is specified to run up to 30MHZ in this case we can use the PLL to increase the IRC frequency.With a PLL the input frequency is multiplied to a higher frequency and then divided down to provide the actual clock frequency used by the CPU .

On reset the Internal RC oscillator is selected as input to the PLL.The value of SYSPLLCTRL will control the multiplication factor. The lower 4 bits of this register (MSEL) plus 1 contain the PLL multiplier.

MSELPLL out clock MHZ
012
124
236
348
460
572
684
796
8108
9120

The PLL output clock must be less than or equal to 100MHZ hence the last two MSEL values are out of specification.

Were not quite there yet, the bits D5 and D6 together make the  PSEL value that we can use to calculate the VCO frequency.
The value of PSEL signifies how many bits we shift 0x1 left by to use as a multiplier for the PLL output clock.

VCO FREQ = 2 *  (1 << PSEL ) * (PLL out clock)

The VCO frequency must be between 156MHZ and 320MHZ so we have to select a PSEL that constrains the VCO frequency within this range.The table below shows the values of SYSPLLCTRL needed for the corresponding PLL output clock.

MSELPSELPLL out clock MHZSYSPLLCTRL
0312 0x60
12240x41
22360x42
31480x23
41600x24
51720x25
60840x06
70960x07
801080x08
901200x09

You will then need to use  SYSAHBCLKDIV to divide the output of the PLL down in order to get the required SystemCoreClock

Finally we set  MAINCLKSEL to 0x03 to select the PLL output as the Main Clock rather than the IRC Clock.

We should also note that we must wait for the PLL to lock and also wait for the PLL output to be selected as the Main Clock see the code for further details. The code will also allow you to select the Watchdog Clock if speed is not necessary with substantial power savings.


#include "LPC8xx.h"
#include "xprintf.h"

#define BAUDRATE 57600
#define UART_CFG_DATALEN_8      (0x01 << 2)  /* UART 8 bit length mode */
#define UART_CFG_PARITY_NONE    (0x00 << 4)  /* No parity */
#define UART_CFG_STOPLEN_1      (0x00 << 6)  /* UART One Stop Bit Select */
#define UART_STAT_RXRDY         (0x01 << 0)  /* Receiver ready */
#define UART_STAT_TXRDY         (0x01 << 2)  /* Transmitter ready for data */
#define UART_CFG_ENABLE         (0x01 << 0)

/*Which Clock source ?, if both are 0 then Internal RC Oscillator is used */
#define USE_PLL  (1)
#define USE_WATCHDOG  (0)

#define WATCHDOG_300KHZ ((1 << 5) | (0))
#define WATCHDOG_9375HZ ((1 << 5) | (0x1f))
#define WATCHDOG_2300KHZ ((0xf << 5) | (0))
#define PLL_60MHZ (0x24)
#define PLL_24MHZ (0x41)
#define PLL_96MHZ (0x07)

uint32_t SystemCoreClock=12000000; /* Value @ Reset */
uint32_t SystemMainClock=12000000; /* Value @ Reset */

void uart0putc(unsigned char c){
 /* Wait until we're ready to send */
  while (!(LPC_USART0->STAT & UART_STAT_TXRDY));
   LPC_USART0->TXDATA = c;
}

unsigned char uart0getc(){
 /* Wait until we're ready to receive */
 while (!(LPC_USART0->STAT & UART_STAT_RXRDY));
  return LPC_USART0->RXDATA;
}

short uart0PollChar() {
 if (!(LPC_USART0->STAT & UART_STAT_RXRDY))
  return -1;
 return LPC_USART0->RXDATA;
}


int main(void) {

 /* Enable AHB clock to the Switch Matrix , UART0 , IOCON */
 LPC_SYSCON->SYSAHBCLKCTRL |= (1 << 7) | (1 << 14) | (1 << 18);

#if (USE_PLL)
 /* Enable the PLL Clock for a maximum 30MHZ SystemCoreClock */
 LPC_SYSCON->SYSPLLCTRL    = PLL_60MHZ; /* 60 MHZ pll output clock*/
 LPC_SYSCON->PDRUNCFG     &= ~(0x1 << 7);        /* Power-up SYSPLL          */
 while (!(LPC_SYSCON->SYSPLLSTAT & 0x01));       /* Wait Until PLL Locked    */

 LPC_SYSCON->MAINCLKSEL    = 3;     /* Select PLL Clock Output  */
 LPC_SYSCON->MAINCLKUEN    = 0x01;      /* Update MCLK Clock Source */
 while (!(LPC_SYSCON->MAINCLKUEN & 0x01));       /* Wait Until Updated       */

 LPC_SYSCON->SYSAHBCLKDIV  =  2; /* Divide by 2 to get the maximum 30MHZ SystemCoreClock */

 SystemMainClock = 12000000 * ((LPC_SYSCON->SYSPLLCTRL & 0x01F) + 1); /* Calculate SystemMainClock for IRC directed to the PLL*/
 SystemCoreClock = SystemMainClock / LPC_SYSCON->SYSAHBCLKDIV; /*Calculate SystemCoreClock */

#elif (USE_WATCHDOG)
 /* Enable the Watchdog Oscillator for minimum power consumption*/
 LPC_SYSCON->WDTOSCCTRL = WATCHDOG_2300KHZ;
 LPC_SYSCON->PDRUNCFG &= ~(0x1 << 6); /* Power-up Watchdog          */
 LPC_SYSCON->MAINCLKSEL = 2; /* Select Watchdog Clock Output  */
 LPC_SYSCON->MAINCLKUEN = 0x01; /* Update MCLK Clock Source */
 while (!(LPC_SYSCON->MAINCLKUEN & 0x01)); /* Wait Until Updated       */

 if ((LPC_SYSCON->WDTOSCCTRL & (0x0f << 5)) == (0x01 << 5))
 SystemMainClock = 600000 / (2 * (1 + (LPC_SYSCON->WDTOSCCTRL & 0x1f)));
 else
 SystemMainClock = 4600000 / (2 * (1 + (LPC_SYSCON->WDTOSCCTRL & 0x1f)));

 SystemCoreClock = SystemMainClock / LPC_SYSCON->SYSAHBCLKDIV; /* Calculate SystemCoreClock */
 LPC_SYSCON->PDRUNCFG |= (1 << 7) | (1 << 1) | (1 << 0); /* Power down IRC & PLL as not needed now */
#endif

 /* Switch matrix , select uart */
 LPC_SWM->PINASSIGN0 = 0xffff0004UL;
 
 /* Set the UART clock divisor to 1  */
 LPC_SYSCON->UARTCLKDIV = 1; // note on reset the value is 0. i.e clock is disabled
 /* Configure UART0 baud rate */
 LPC_USART0->BRG = ((SystemMainClock / LPC_SYSCON->UARTCLKDIV) >> 4) / BAUDRATE - 1;
 LPC_SYSCON->UARTFRGMULT = ((((SystemMainClock / LPC_SYSCON->UARTCLKDIV) >> 4) * (0x100)) / (BAUDRATE * (LPC_USART0->BRG + 1))) - (0x100);
 LPC_SYSCON->UARTFRGDIV = 0xFF; //note on reset the value is 0

 /* Set UART0 to 8N1 and finally enable */
 LPC_USART0->CFG = UART_CFG_DATALEN_8 | UART_CFG_PARITY_NONE | UART_CFG_STOPLEN_1 | UART_CFG_ENABLE;

 /* Init Chan's Embedded String Functions (xprintf ect) */
 xdev_out(uart0putc);
 xdev_in(uart0getc);

    // Enter an infinite loop testing for the '0' and '1' keys
    while(1) {
     switch( uart0PollChar() ){
      case '0':
          xprintf("System Core Clock is %d hz\n\rSystem Main Clock is %d\n\r",SystemCoreClock,SystemMainClock);
      break;
      case '1':
          xprintf("Main clock select is %0x\n\rSYSAHBCLKDIV is %d\n\r",LPC_SYSCON->MAINCLKSEL,LPC_SYSCON->SYSAHBCLKDIV);
         break;
     }
    }
    return 0 ;
}

Chan's xprintf on the LPC810

Continuing on from the last post, now that the Uart is working and outputting some text we can add much more functionality to the debugging output with the excellent pint sized micro printf library from Chan.

You can get this library from http://elm-chan.org/fsw/strf/xprintf.html. When you have downloaded it then extract the xprintf.c and place in your src folder and also extract xprintf.h and place it in the inc folder.

In order to integrate this file we will need two functions that get and put characters to the Uart (or indeed any other device such as a LCD). The putc function must return void and take an unsigned char as an argument while the getc function must return an unsigned char and takes no arguments. These functions are shown below for the LPC810:


void uart0putc(unsigned char c){
 /* Wait until we're ready to send */
  while (!(LPC_USART0->STAT & UART_STAT_TXRDY));
   LPC_USART0->TXDATA = c;
}

unsigned char uart0getc(){
 /* Wait until we're ready to receive */
 while (!(LPC_USART0->STAT & UART_STAT_RXRDY));
  return LPC_USART0->RXDATA;
}

Now in our main loop we tell xprintf about them by using the xdev_out and xdev_in macros:


/* Init Chan's Embedded String Functions (xprintf ect) */
 xdev_out(uart0putc);
 xdev_in(uart0getc);

These can also be used again to switch the output to another device assuming the corresponding getc and putc functions exist for it.

Putting this all together we get a new main.c which now allows us to investigate the default clock settings configured by CMSIS (note that the Uart setup code has changed slightly in order to fix it taking the wrong clock signal which will become apparent if the main clock divisor in not one).


#include "LPC8xx.h"
#include "xprintf.h"

#define BAUDRATE 57600
#define UART_CFG_DATALEN_8      (0x01 << 2)  /* UART 8 bit length mode */
#define UART_CFG_PARITY_NONE    (0x00 << 4)  /* No parity */
#define UART_CFG_STOPLEN_1      (0x00 << 6)  /* UART One Stop Bit Select */
#define UART_STAT_RXRDY         (0x01 << 0)  /* Receiver ready */
#define UART_STAT_TXRDY         (0x01 << 2)  /* Transmitter ready for data */
#define UART_CFG_ENABLE         (0x01 << 0)

void uart0putc(unsigned char c){
 /* Wait until we're ready to send */
  while (!(LPC_USART0->STAT & UART_STAT_TXRDY));
   LPC_USART0->TXDATA = c;
}

unsigned char uart0getc(){
 /* Wait until we're ready to receive */
 while (!(LPC_USART0->STAT & UART_STAT_RXRDY));
  return LPC_USART0->RXDATA;
}

short uart0PollChar() {
 if (!(LPC_USART0->STAT & UART_STAT_RXRDY))
  return -1;
 return LPC_USART0->RXDATA;
}

int main(void) {
 /* Calculate and set SystemCoreClock */
 SystemCoreClockUpdate();

 /* Init Chan's Embedded String Functions (xprintf ect) */
 xdev_out(uart0putc);
 xdev_in(uart0getc);

 /* Enable AHB clock to the Switch Matrix and UART0 */
 LPC_SYSCON->SYSAHBCLKCTRL |= (1 << 7) | (1 << 14);

 /* Configure Switch Matrix so that Pin2 = U0_TXD and Pin3 = U0_RXD */
 LPC_SWM->PINASSIGN0 = 0xffff0004UL;

 /* Set the UART clock divisor to 1  */
 LPC_SYSCON->UARTCLKDIV = 1; // note on reset the value is 0. i.e clock is disabled
 int MainClock = SystemCoreClock * LPC_SYSCON->SYSAHBCLKDIV;

 /* Configure UART0 baud rate */
 LPC_USART0->BRG = ((MainClock / LPC_SYSCON->UARTCLKDIV) >> 4) / BAUDRATE - 1;
 LPC_SYSCON->UARTFRGMULT = ((((MainClock / LPC_SYSCON->UARTCLKDIV) >> 4) * (0x100)) / (BAUDRATE * (LPC_USART0->BRG + 1))) - (0x100);
 LPC_SYSCON->UARTFRGDIV = 0xFF; //note on reset the value is 0

 /* Set UART0 to 8N1 and finally enable */
 LPC_USART0->CFG = UART_CFG_DATALEN_8 | UART_CFG_PARITY_NONE | UART_CFG_STOPLEN_1 | UART_CFG_ENABLE;

    // Enter an infinite loop testing for the '0' and '1' keys
    while(1) {
     switch( uart0PollChar() ){
      case '0':
          xprintf("System Core Clock is %d hz\n\r",SystemCoreClock);
      break;
      case '1':
          xprintf("Main clock select is %0x\n\r",LPC_SYSCON->MAINCLKSEL);
      break;
     }
    }
    return 0 ;
}










Monday, 28 July 2014

A First program for the LPC810

Previously Flash Magic was used to talk to the ISP of a LPC810. Now we can look at how to program one. NXP provides the free eclipse based IDE LPCXpresso. With this you can compile up to 8k of executable without registering or up to 256k by registering and activating the free version.

You can get LPCXpresso from http://www.lpcware.com/lpcxpresso/download once you have installed it we can proceed and set up a project. Select File->New->Project and set the project up as below.
  • In the First wizard page select "LCPXpresso C Project"
  • In the second LPC8xx -> C Project
  • In the next give it a project Name
  • In the forth LPC8xx -> LPC810
  • In the next wizard page follow the instructions and install CMSIS. This only needs to be done once. Note that you only need the CMSIS_CORE_LPC8xx one. Now at this point there seems to be a bug and you have to exit the wizard after installing CMSIS and start over again until you get to this point in the wizard again in order to continue.
  • In the Sixth wizard page leave DSP Library as none
  • In the next uncheck enable Micro Trace Buffer
  • In the next uncheck enable CRP and check use INC folder

Finally we can click on finish.

Now we switch to the CMSIS project that's been included and build CMSIS for both debug and release.

Switch back to our project and set the active configuration to release.

There is one more this to do and that is to add the highlighted line below in Properties->C/C++ build->Settings->Build Steps->Post Build Steps

arm-none-eabi-size "${BuildArtifactFileName}"
arm-none-eabi-objcopy -O ihex ${BuildArtifactFileName} ${BuildArtifactFileBaseName}.hex
# arm-none-eabi-objcopy -v -O binary "${BuildArtifactFileName}""${BuildArtifactFileBaseName}.bin"
# checksum -p ${TargetChip} -d "${BuildArtifactFileBaseName}.bin"

which will generate a Hex file for Flash Magic when the program is built.

Now you should be able to run build and a Hex file should appear in your release directory. The current main.c does not do much at the moment it's just a infinite loop.

Since we have the UART already connected lets get some output , below is a minimal program to get you going and to connect to a terminal emulator:


#include "LPC8xx.h"

#define BAUDRATE 57600
#define UART_CFG_DATALEN_8      (0x01 << 2)  /* UART 8 bit length mode */
#define UART_CFG_PARITY_NONE    (0x00 << 4)  /* No parity */
#define UART_CFG_STOPLEN_1      (0x00 << 6)  /* UART One Stop Bit Select */
#define UART_STAT_RXRDY         (0x01 << 0)  /* Receiver ready */
#define UART_STAT_TXRDY         (0x01 << 2)  /* Transmitter ready for data */
#define UART_CFG_ENABLE         (0x01 << 0)

int uart0PollChar() {
 if (!(LPC_USART0->STAT & UART_STAT_RXRDY))
  return -1;
 return LPC_USART0->RXDATA;
}

void uart0SendString(char *buffer) {
 while (*buffer != 0) {
  while (!(LPC_USART0->STAT & UART_STAT_TXRDY));
  LPC_USART0->TXDATA = *buffer;
  buffer++;
 }
}

int main(void) {
 /* Calculate and set SystemCoreClock */
 SystemCoreClockUpdate();

 /* Enable AHB clock to the Switch Matrix and UART0 */
 LPC_SYSCON->SYSAHBCLKCTRL |= (1 << 7) | (1 << 14);

 /* Configure Switch Matrix so that Pin2 = U0_TXD and Pin3 = U0_RXD */
 LPC_SWM->PINASSIGN0 = 0xffff0004UL;

 /* Set the UART clock divisor to 1  */
 LPC_SYSCON->UARTCLKDIV = 1; // note on reset the value is 0. i.e clock is disabled

 /* Configure UART0 baud rate */
 LPC_USART0->BRG = (SystemCoreClock >> 4) / BAUDRATE - 1;
 LPC_SYSCON->UARTFRGMULT = (((SystemCoreClock >> 4) * (0x100)) / (BAUDRATE * (LPC_USART0->BRG + 1))) - (0x100);
 LPC_SYSCON->UARTFRGDIV = 0xFF; //note on reset the value is 0

 /* Set UART0 to 8N1 and finally enable */
 LPC_USART0->CFG = UART_CFG_DATALEN_8 | UART_CFG_PARITY_NONE | UART_CFG_STOPLEN_1 | UART_CFG_ENABLE;

    // Enter an infinite loop testing for the '0' and '1' keys
    while(1) {
     switch( uart0PollChar() ){
      case '0':
          uart0SendString("Hello\n\r");
      break;
      case '1':
          uart0SendString("World\n\r");
      break;
     }
    }
    return 0 ;
}


If you cut & paste the above in place of the existing main.c you should be able to get "hello" printed when you press the '0' key and "world" printed when you press the '1' key on a terminal emulator.

For a terminal emulator I use Realterm available from http://realterm.sourceforge.net/ remember to toggle the "open button" to recapture the Uart from flash magic after you have flashed an image else nothing will happen.




LPC810 a little 8 pin DIP ARM MCU

Recently I've got hold of some of NXP's dinky LPC810's. A 32 Bit ARM MCU in a 8 pin dual inline package that cost under £1 individually and less that 33p in quantity. These are incredibly easy to use and can simply be connected directly to a USB serial adapter and programmed via the inbuilt ISP. That is all you need, just 4 wires connecting the serial adapter and another grounding pin 5 on power up in order to switch to the ISP mode. No other components are necessary which makes this device a extremely simple way to get into ARM Cortex M0 programming.


The LPC810 can run up to 30Mhz on its internal RC oscillator and has 4k of flash and 1k of ram. That's not a lot for a 32bit mcu but my initial experiments suggest much can still be done with that. 

As for IO the 6 available pins can be configured for SPI, I2C and UART as well as their default GPIO. There is also a Comparator and a very flexible timer among other goodies.

It's maximum supply voltage is 4.6v but fortunately most of the LPC810's io pins are 5v tolerant. Running @ 30mhz 3.3v it will consume about 3ma for a continuous while loop and much less in its sleep modes.

The free program Flash Magic available from http://www.flashmagictool.com/ can be used to access the ISP functionality erase and program the chip. A simple way to test if you have wired it to the USB uart adapter correctly is to use Flash Magic to find the device ID.


.
Now you are ready to program the LPC810 but you will need  a Hex file first. In the Next post I will look at how to create programs for the LPC810.


.