Category: ARM

Self-shutdown and any-key power-up

1. October 2013 16:27 by Jens Willy Johannsen
Categories: ARM

I need the Thermometer's MCU to be able to switch itself off to save battery power. And I also need to be able to power up the device by pressing any of the buttons. At the same time, of course, I need to be able to distinguish which button has been pressed.

I am using a MAX1796 PMIC which has a SHDN pin that turns off the device when high. Note that many PMIC's have a shutdown feature that doesn't disconnect the output pin from the input pin when shut down, but which simply disables the voltage regulation. I need a PMIC with what in the datasheets is called "true disconnect" (the MAX1796 has that. An example of a PMIC that doesn't is the MAX1724 which I first planned on using but rejected for this reason.)

Self-shutdown

Inspired by this post on electronics.stackexchange.com, I designed this basic circuit to switch off the PMIC from the MCU and to switch it on from a push button. (I have not taken into account the delay from the user pressing the button to the MCU starting up and taking over control of the PMIC so if the user lets go of the button before the MCU is ready, power will turn off again):

Basic circuit

Basic circuit

  • Normally, the SHDN pin is pulled up and the PMIC is off.
  • When pressing the push button, SHDN gets grounded and the PMIC turns on.
  • The MCU will on start-up configure a GPIO pin as low and thus the SHDN pin is grounded to allow the PMIC to remain on.
  • When switching itself off, the MCU sets the GPIO pin high and the PMIC turns off.

NOTE: many PMIC's has a #SHDN pin which shuts down the PMIC when low and not high like the MAX1796.

Any-key power-up

I would like the device to turn on when the user presses any button (as opposed to a dedicated "power-on" button).

The buttons work as inputs that are pulled high so a HIGH value means the button is not pressed and a LOW value means the button is pressed.

But, of course, I can't just connect the switches like this:

Push buttons tied together

Push buttons tied together

Because the MCU would then be unable to distinguish which button has been pressed since they are all tied together.

Diodes to the rescue! Adding diodes like this will fix it:

With diodes

With diodes

This way, pressing switch doesn't affect the voltage at the other GPIO pins. But: a normal diode has a voltage drop of about 0.7 V. This means that the voltage at the SHDN pin will be 0.7 V when pressing a switch. To check if this is low enough to be considered "low" some perusing of the datasheet is necessary and reveals the following:

Parameter Symbol Min Max Units
SHDN Input Voltage VIL 0.2 ✕ VBATT V

And is we assume that VBATT is at max. 3.3 V, we get 0.66 V for the maximum allowed LOW voltage. In other words: a voltage of 0.7 V will not be interpreted as LOW.

But if we use a Schottky diode (like the trusty ZLLS1000) with a voltage drop of about 0.4 V, everything will be fine.

At least that's the theory. We'll see how it works out in real life…

No comments No comments »

LPC11U24/LPC1347 JTAG/SWD debugging with LPC-Link

23. September 2013 21:41 by Jens Willy Johannsen
Categories: ARM

I had some problems getting my ROV on-board controller (which uses a LPC1347) programmed from LPCXpresso.

After doing the research I should have done before I had the PCBs made (doh), I found out I had messed up the SWD programming/debugging connections.

And so, in order to spare anyone else the same trouble, here is a small recap of which wires to connect to what.

Connections from LPC11U24/LPC1347

These are the minimal connections from the MCU to the LPC-Link:

Pin name LQFP48 pin no. Connect to
#RESET/PIO0_0 3 SWD pin 10 (#RST)
SWDIO/PIO0_15/AD4/ 25 CT32B1_MAT2 39 SWD pin 2
SWCLK/PIO0_10/SCK0/CT16B0_MAT2 29 SWD pin 4

Note: It is not necessary to have pull-up resistor on #RESET (or any other pin) unless other parts of the circuit might affect the levels since it is internally pulled up to VDD.

Connections from JTAG/SWD

These are the minimal connections from the LPC-Link to the MCU board.

Pin number Connect to LQFP48 pin no. Comment
1 3.3V on MCU 8, 44
2 SWDIO 39
3 n/c Optional GND (see note 1)
4 SWCLK 29
5 n/c Optional GND (see note 1)
6 n/c Optional SWO (see note 2)
7 n/c
8 n/c
9 GND 5, 41
10 #RESET 3

Note 1: It is sufficient to connect one of the GND pins (e.g. SWD pin 9) as pins 3, 5 and 9 are all connected on the LPC-Link.

Note 2: SWD pin 6 can be connected to PIO0_9/MOSI0/CT16B0_MAT1/SWO (LQFP pin 28) but this is not required.

Pin numbering

This image shows the pin numbering on the LPC-Link. Pin 1 has been marked in red.

Do yourself a favor and perform a continuity check from the LPC-Link side to your MCU board to make sure which pins go where.

LPC-Link pinout

LPC-Link pinout

(Image composited from images from http://www.keil.com and http://www.embeddedartists.com.)

Be aware that the 0.1" pins on the right edge of the board do not follow the JTAG pin numbering but have these connections:

  1. VCC
  2. SWDIO
  3. SWCLK
  4. SWO
  5. TDI
  6. #RESET
  7. EXT. PWR
  8. GND

The required pins are 1, 2, 3, 6 and 8.

Connection procedure

Sometimes LPCXpresso can't initialize the LPC-Link even though it is connected. I have found that following the following procedure works every time:

  1. Launch LPCXpresso IDE
  2. Power up device
  3. Attach to LPC-Link
  4. Connect LPC-Link to computer by USB
  5. Debug firmware from LPCXpresso
No comments No comments »

Repetitive Interrupt Timer on LPC1347

9. March 2013 19:30 by Jens Willy Johannsen
Categories: ARM

For my ROV project I need to control an RC servo to tilt the camera up and down. I've gotten that working nicely using a 16-bit timer to generate an appropriate PWM waveform.

But when I change the the position by a lot – for example, going from one endpoint to the middle position – the servo moves too fast. (Which, incidentally, draws a huge current which makes my 5 V rail drop enough to reset the MAX7456 – but that is fixable.) So I need to slow the movement down by gradually changing the position instead of jumping straight from one position to another.

The full servo movement corresponds to a change in timer match value by 1000 (the PWM timer is set up so the match values correspond to PWM pulse on-time in microseconds so minimum is 1000 and maximum is 2000). I would like the full range of movement to take one second so I thought that changing the position in increments of 10 at a frequency of 100 sounds about right.

Unfortunately, I'm fresh out of timers: CT32B0 and -1 are used for motor control PWM, CT16B0 is used for periodic analog-to-digital conversions (for the pressure sensor used as depth gauge) and CT16B1 is used for servo PWM. Yeah, sure, I guess I could use a timer for more than one purpose but since the LPC1347 actually has one more timer, I might as well use that: the Repetitive Interrupt Timer.

The Repetitive Interrupt Timer (RIT for short) generates interrupts every X clock cycles and if I configure the timer to fire an interrupt every 720,000 clock cycles I get a 100 Hz interrupt (on a 72 HMz PCLK) in which I can move the servo if necessary. Nice.

This is the code I came up with:

Repetitive Interrupt Timer on LPC1347

// MIN and MAX macros
#ifndef MIN
#define MAX(a,b) (((a)>(b))?(a):(b))
#define MIN(a,b) (((a)<(b))?(a):(b))
#endif

// Servo position variables
volatile uint16_t servo_position;
volatile uint16_t servo_target;

// Stop RI timer – otherwise we can't reset the counter
LPC_RITIMER->CTRL = 0;

// Init RI timer (we don't need to enable timer – it is always running as per the updated User Manual UM10524)
LPC_RITIMER->COMPVAL = 720000;
LPC_RITIMER->COMPVAL_H = 0;

// Reset counter (otherwise it might already be above the compare value and then it would take a loong time to overflow to zero)
LPC_RITIMER->COUNTER = 0;
LPC_RITIMER->COUNTER_H = 0;

// Set RITENCLR (clear on match), RITENBR (halt timer on debug) and RITEN (start timer)
LPC_RITIMER->CTRL = (1<< 1) | (1<< 2) | (1<< 3);

// Enable RIT interrupt
NVIC_EnableIRQ( RIT_IRQn ); 

// Interrupt routine 
// (Yes, it's a little weird that the interrupt routine is called OSTIMER but the NVIC interrupt is called RIT_IRQn)
void OSTIMER_IRQHandler()
{
    // Clear interrupt
    LPC_RITIMER->CTRL |= (1<< 0);   // Write RITINT to clear

    // If we're at target, do nothing
    if( servo_position == servo_target )
        return;

    if( servo_target > servo_position )
        servo_position += MIN( servo_target - servo_position, 10 );
    else // Not equal and not greater than, so it's less than – we don't need to check
        servo_position -= MIN( servo_position - servo_target, 10 );
}
Comments 4 comments »

SPI on LPC1347 vs capacitance, part II

6. February 2013 22:35 by Jens Willy Johannsen
Categories: ARM

Aha! Gotcha!

(This is a follow-up to my last post about GPIO delay and capacitance.)

Looking again at the scope captures, I thought that the stray capacitance from boards and wires couldn't possibly account for the huge 18 microsecond delay. And my colleague, who has an actual education in these things, agreed. Thanks, Niels :)

Then we took a look at the base board schematic. And lo and behold:

The culprit: C42

The culprit: C42

A 100 nF capacitor right on the PIO1.13 line. Yes, it's called GPIO_21 in the schematic – it is slightly confusing but it is, in fact, PIO1.13. Removing the J33 jumper (thereby disconnecting PIO1.13 from the capacitor) and removing the 48 cycles delay it looked like this on the scope:

Nice steep transitions on the CS line

Nice steep transitions on the CS line

and like this on the logic analyzer.

And no unnecessary delays

And no unnecessary delays

Everyone is happy. Now off to cobble together some RS-485 code.

No comments No comments »

SPI on LPC1347 vs capacitance

5. February 2013 22:07 by Jens Willy Johannsen
Categories: ARM

Or "Capacitance matters – who'd've thunk it"

I am using SPI to talk to a MAX7456 video overlay IC from an LPC1347 MCU in my ROV project.

That should be easy enough since the LPC1347 contains twp SPI compatible synchronous serial ports ("SSP" for short). Perusing the manual and some code examples I came up with code to initialize the SSP for SPI comms and to send SPI data.

But, alas, it didn't work :(

Connecting my trusty Saleae Logic analyzer I saw that the CS line was toggled low and then high again for every byte. Which the MAX7456 apparently doesn't like – it wants the CS line to be low for the entire command (which consists of several bytes) – just as described in the datasheet.

So I switched to manually toggling a GPIO line low before transmitting SPI data and then high again when transmission is done. Like this:

#define MAX7456_CS_ON LPC_GPIO->CLR[ 1 ] = (1<< 13)
#define MAX7456_CS_OFF LPC_GPIO->SET[ 1 ] = (1<< 13)

MAX7456_CS_ON;

spi_transfer(VM0_reg);
spi_transfer(MAX7456_reset);

MAX7456_CS_OFF;

And, for reference, the spi_transfer() function looks like this:

void spi_transfer( uint8_t data )
{
    // Wait until SSP is not busy and TX FIFO is not full
    while ( (LPC_SSP0->SR & (SSPSR_TNF|SSPSR_BSY)) != SSPSR_TNF )
        ;

    // Send data
    LPC_SSP0->DR = data;
}

But that didn't work either. Looking at the logic analyzer it turned out that CS came low several microseconds after the SPI transmission started. Weird, since the the GPIO pin is set low before I start the SPI. I also tried using the byte pin and word pin registers but the result was the same.

So it just looks like the GPIO is just really, really slow. What I finally came up with that works was this:

#define MAX7456_CS_ON { uint8_t i; LPC_GPIO->CLR[ 1 ] = (1<< 13); for( i=0; i<48; i++ ) __NOP(); }
#define MAX7456_CS_OFF LPC_GPIO->SET[ 1 ] = (1<< 13)

In other words: let the CPU wait for 48 clock cycles after setting the pin low before trying to do something else.

On the logic analyzer, it looks like this:

Logic analyzer capture. With delay.

Logic analyzer capture. With delay.

Still weird though. Until I connected a scope instead of a logic analyzer. Then it looked like this without the delay:

Scope capture. Without delay.

Scope capture. Without delay.

And this with the delay:

Scope capture. With delay.

Scope capture. With delay.

So it looks like the delay is, in fact, not the MCU's GPIO that is slow but rather capacitance. So even though the pin was toggled low the capacitance caused the voltage to decay slowly (relatively speaking) instead of instantly. So without the delay, the voltage never dropped low enough for the MAX7456 to consider the CS low. Now bear in mind that the pin is connected to the MAX7456 though the LPCXpresso board, the LPCXpresso Base Board, a jumper wire and then the MAX7456 breakout board. All of which have non-zero capacitance.

In other words: when working with high-speed (in this case 4 MHz) signals, make sure you design the board with that in mind and minimize capacitance (and inductance).

Unfortunately, I have no experience with that kind of semi-advanced PCB layout. Fortunately I can fix it in software and the delay I introduce will not pose a problem in this case.

Comments 2 comments »

Soft UART on LPC13xx

23. January 2013 11:32 by Jens Willy Johannsen
Categories: ARM | Projects

For the ROV project I need two UART connections (one for RS485 to the onboard controller and one for receiving input from the VNC2 USB host controller).

And since the LPC1347 only has one UART I needed a soft UART for one of the connections. Fortunately for me, NXP provides an implementation in AN10955. There was only one problem with it: it doesn't work. Or rather, it works for a while and then stops receiving anything (scoping the UART line confirmed that the VNC2 chip continued to send data so the problem had to be in the soft UART code).

Yea, intermittent errors – what's not to like… (Read on for the problem and the solution.)

Read the entire post »

Comments 2 comments »

Measuring battery voltage with ADC on LPC1347

24. October 2012 21:39 by Jens Willy Johannsen
Categories: ARM

For the GPS Tracker project, I need to measure the battery voltage using the ADC but since the raw battery voltage is higher than the MCU's VCC of 3.3 V I need to use a voltage divider to get the maximum voltage below 3.3 V. (See this article on microBuilder.eu on how to do that properly.)

For the breadboard prototype I won't worry too much about power consumption but for the final version I probably should make the kind of controlled voltage divider mentioned in the microBuilder article.

Resistor values

When picking values for the voltage divider I want to use as much of the ADC's full range as possible to get the highest accuracy without exceeding the VDD level . If I just divided by 50% (e.g. two 10k resistors), the measured battery range would be about 0 to 2.1 V. Ideally the range should be 0 to VDD but even though the pins are 5 V tolerant in digital mode they may not exceed VDD in analog mode so I'll try with the 0 to 2.1 V range and see if that is accurate enough.

I also need to balance power consumption and accuracy. Higher value resistors pass less current through the voltage divider but lower current means lower accuracy in the ADC.
It helps to put a capacitor on the input pin so the ADC can pull current out of the capacitor if it needs more than voltage divider can provide. Like this:

ADC voltage divider

E.g. 2 x 1 MΩ resistors and a 0.1 µF capacitor.

With those values, the capacitor will be charged to about ⅔ capacity in 0.2 seconds and that should be ample capacitance for the ADC to perform one measurement and since I'll be doing one-shot ADC conversions the 0.2 secs recharge time (less, actually since the capacitor will not be completely drained by a single conversion) is not a problem.

ADC conversions on LPC1347

This is what I need to do in order to perform a one-shot ADC conversion:

Initialize the ADC

  1. Configure pin TDI/PIO0_11 as AD0 input pin
    LPC_IOCON->TDI_PIO0_11 = 0x02;
  2. Power up ADC analog block:
    LPC_SYSCON->PDRUNCFG &= ~(1 << 4);
  3. Power up ADC clock:
    LPC_SYSCON->SYSAHBCLKCTRL |= (1 << 13);
  4. Configure control register:
    LPC_ADC->CR = b00000000010000000000010000000001; /* _or */
    LPC_ADC->CR = (1<< 0) | (4<< 8) | (1<< 22);

The control registered is configured as follows:

(0:7) SEL = 1 to select AD0 pin (pin 32 on LQFP48)
(8:15) CLKDIV=4 for 72MHz / 4+1 = 14.4 MHz ADC clock speed
(16) BURST=0 for software-controlled conversions
(17:21) (reserved)
(22) LPWRMODE=1 to enable low-power mode that only powers up ADC circuitry when performing a conversion
(23) MODE10BIT = 0 for 12 bit resolution
(24:26) START = 000 – no conversion until I say so
(27) EDGE – not relevant for software-controlled conversions
(28:31) (reserved)

Analog power and voltage reference pins are already connected on the LQFP48 package: VFREP is internally tied to VDD and VFREN is tied to VSS. Likewise for VDDa and VSSa.

Perform the conversion and read the value

LPC_ADC->CR |= (1 << 24);              /* start A/D convert */
while( LPC_ADC->GDR & (1 << 31) == 0 ) /* wait until end of A/D convert */
    ;

LPC_ADC->CR &= 0xF8FFFFFF;      /* stop ADC now (START = 000)*/    
if( LPC_ADC->GDR & (1 << 30) )  /* if overrun, return zero */
    return 0 ;

ADC_Data = ( LPC_ADC->GDR >> 4 ) & 0xFFF;
return ADC_Data;    /* return A/D conversion value */
Comments 1 comment »

nxpUSBlib on LPC1347

5. October 2012 14:01 by Jens Willy Johannsen
Categories: ARM

Since I had some problems gettings USB CDC working I decided to try using NXP's nxpUSBlib instead of the more simple examples that I only got almost working. But I ran into a couple of problems...

LPC1347 support

The first problem was getting the thing compiling for the LPC1347. The most recent version (0.97) does support the LPC1347 but not quite.

Having downloaded the archive and imported everything into Code Red LPCXpresso IDE as per the readme, I tried to configure the BSP (development board), CDL (CMSIS and device) and nxpUSBlib projects for the LPC1347 MCU. No problems.
But when I tried to select the LPC1347 for the Example_VirtualSerialDevice project it turned out that there was no such build configuration. There is a LPC13Uxx configuration for the Example_MassStorageDevice, however.

Read the entire post »

Comments 1 comment »

GPS Tracker update

5. October 2012 9:16 by Jens Willy Johannsen
Categories: ARM | Projects | Telit GE865

Success! More or less, anyway.

Using the nxpUSBlib (having made a few modifications – I'll do a post on that soon) I've managed to get USB CDC working and I got the GSM initialization and SMS receiving working.

At the moment, on receiving an SMS, the system will reply to the sender with the current GPS status regardless of the contents of the SMS.


(The GPS has no fix because it is on my workbench with no satellites in view.)

Power supply considerations

But: I need to do some careful design of the power supply. The GSM module is extremely power hungry. Especially when registering on the network or doing any other network related tasks – like sending or receiving SMSes. And the battery I'm currently using can not supply enough power for both the GSM module and (through a linear 3.3 V voltage regulator) the MCU and GPS module.

So I'll have to get a beefier battery (this 2000 mAh one) or this 6000 mAh one) and also add a low ESR capacitor (as recommended in the GSM module datasheet).
And I'll also add P-channel MOSFETs as high-side switches for the GSM and GPS modules in order to be able to switch power on and off to these modules.
At the moment I run the prototype off two separate power supplies: the 3.7 V LiPo battery directly connected to the GSM module and a 9 V battery supplying the MCU and GPS module through a 3.3 V LDO voltage regulator.

Comments 3 comments »

Moving to LPCXpresso

23. September 2012 13:47 by Jens Willy Johannsen
Categories: ARM | Projects

I’ve made quite a bit of headway with the firmware for the GPS Tracker project but there are still some problems – mainly with the command parser and the USB CDC interface.

So I decided I needed some way of debugging the firmware. After looking at several options (they have to run on Mac OS X), I decided to get a LPC1347-based LPCXpresso.

The LPCXpresso consists of two parts:

  1. An LPC MCU with a minimal amount of support components: crystal, capacitors, an LED and a mini-USB socket with the required resistors and PNP transistor.
  2. The “LPC-Link” which is a programmer and JTAG debugger which connects to the computer by USB. The LPC Link can actually be severed from the MCU part of the board and will then work as a normal JTAG debugger which can be connected to MCUs (LPCXpresso or otherwise) using a 10-pin connector.

The LPCXpresso also comes with a free version of Code Red’s Eclipse-based IDE with built-in/preconfigured support for the GNU tool chain and standard C libraries and debugging views for inspecting memory and peripherals and whatnot.

Read more about the LPCXpresso here: http://ics.nxp.com/lpcxpresso and about the IDE here: http://www.code-red-tech.com/lpcxpresso.php.

I prefer the LPCXpresso to the mbed because the MCU board contains no extra components (compared to what I will use on my own boards) and all code is standard C and CMSIS libraries (so no proprietary firmware environment and libraries) – and still I have the ability to debug code and inspect memory at will.

LPC11U24 + LPC1343 –> LPC1347

The LPCXpresso is available with a number of different LPC MCUs. I chose the LPC1347-based one.

Basically, the LPC1347 is a newer version of the LPC1343 and it has the same GPIO structure as the LPC11Uxx devices and the same USB ROM drivers and it now has EEPROM as well. Read this blog entry on microBuilder.eu for a comparison between the LPC1343 and the LPC1347.

I have decided to focus on only one ARM MCU instead of both the LPC11U24 and the LPC1343 – and that will be the LPC1347 (for now at least). Yes, it has a slightly higher power consumption than the LPC11Uxx but on the other hand it is faster and has a Cortex M3 core instead of a Cortex M0 core.

So the plan is:

  1. Make the necessary changes to compile the current firmware code for an LPC1347 (which shouldn’t be too much of a hassle since peripherals for the LPC11U24 and the LPC1347 are pretty much the same) in the LPCXpresso IDE (removing the current linker script and CMSIS files).
  2. Rebuild the breadboard prototype using the LPCXpresso.
  3. Debug, find the problems and fix them…
Comments 2 comments »

GPS Tracker progress

2. September 2012 14:35 by Jens Willy Johannsen
Categories: ARM | Projects

For the GPS Tracker project I’ve been working on – struggling with, actually – getting all the communications subsystems working. I need to use UART for communication with the GSM module, soft UART (since the LPC11U24 has only one hardware UART port) for the GPS module and USB CDC for command and debugging.

And apart from the occasional programming blunders (like forgetting to increase a pointer when iterating elements in an array) I’ve had lots and lots of weird problems. But I finally got UART and soft UART working together and then I took a really long, hard look at the example USB CDC code I’ve been working with.
And it turned out that I needed to change a couple of things:

  1. The linker script (which should be for an LPC11U24 device) specified a RAM size of only 4 KB. This has been fixed to specify an SRAM size of 6 KB.
  2. The USB interface was initialized with a memory buffer at what was, in effect, an arbitrary place in the SRAM memory. The original code used usb_param.mem_base = 0x10001000 and usb_param.mem_size = 0x1000.
    For an LPC11U24, location 0x10001000 is at two thirds up in the SRAM area (which is from 0x1000000 to 0x10001800).
    This has now been changed to use usb_param.mem_base = 0x20004800 and usb_param.mem_size = 0x0800 pointing to the top of the USB RAM area with a size of 2 KB (which is the size of the USB RAM).
  3. My USB_CDC_send() function calls the WriteEP directly. This has been changed to copy data into a serial fifo buffer and calling WriteEP from the VCOM_bulk_in_hdlr() function when the USB host requests data. And the max packet size is also observed now.

And with these changes in place I was rewarded with the following session on the USB CDC terminal connection:

sys test
OK - Response from SYS TEST
sys version
OK - b155 on 2012-09-02 13:34:17 +0200, git 31db1bb904695fc5347a136dbf2c819520162099
gps status
OK - GPS status: 1, sats: 6/12, time: 121246.854, lat: 5538.7522N, lng: 01233.1385E

Nice :)
Next steps are getting the ADC working for monitoring the battery level and implementing the interface for the GSM module.

Comments 1 comment »

GPS Tracker components

14. August 2012 16:33 by Jens Willy Johannsen
Categories: ARM | Projects

To continue my GSM-GPS Tracker project, here is an overview of the system and the components it comprises:

(Click to see large version)

Firmware components

The firmware components can be divided into peripheral drivers and core functionality.

The project is hosted on Github and all the driver code along with linker script, startup code, CMSIS files and Makefile has been moved into a Git submodule (the root of all evil, I know, but in this case it actually made sense) so I can reuse that in my other LPC projects. The submodule is also on Github.

Peripheral drivers

  • ADC for battery voltage monitoring
  • EEPROM for storing/reading settings (already working)
  • UART for GSM module communications (already working)
  • Soft UART for GPS module comms since the LPC11U24 only has one hardware UART (already working)
  • USB CDC for local programming and debugging (already working)

Core functionality

  • Command parser for commands received by SMS or USB CDC
  • NMEA parser to extract coordinates and timestamps from GPS module output
  • SMS receive/reply GSM module interfacing
  • Position logging storing current and the X last known positions with timestamps
Comments 4 comments »

LPC ARM USB CDC

2. August 2012 12:55 by Jens Willy Johannsen
Categories: ARM

…the unabbreviated title would be very long :)

Anywho, this is just a quick post to link to my Github project which contains firmware for using an LPC11U24 as a USB "communications device" – i.e. a serial port.

At the moment, it simply writes input from the serial interface to the USB and vice versa. So you can connect the device to a computer with both USB and a serial cable (I use a serial-to-USB cable since I have no "real" serial ports on my MacBook Pro) and then open terminal connections to both interfaces (using "screen /dev/tty.xxx 9600" or something similar) and everything typed in one window gets written in the other window.
There's probably a couple of debugging messages as well.

The project is based on NXP's example code found here: http://www.lpcware.com/content/nxpfile/usb-rom-driver-examples-using-lpcxpresso-lpc11uxx and compiles with the Yagarto toolchain.

Why?

Why would I want to do USB connectivity by way of CDC instead of e.g. HID? Because implementing HID functionality in Mac OS X applications is a pain in the ass, that's why.
Serial port connectivity, however, is so very much simpler. Especially if you use the excellent ORSSerialPort library.

Where?

Right here: https://github.com/jenswilly/LPC11U24-USBCDC

Comments 3 comments »

From AVR to ARM

27. July 2012 23:23 by Jens Willy Johannsen
Categories: ARM

It seems more and more people are moving away from using AVR and PIC microprocessors and switching to ARM processors. So I thought I might take a look as well.

I'll skip the usual intro stuff about ARM (read about it on Wikipedia or somewhere). For my purposes, the ARM Cortex-M series which is the "Microcontroller profile" is what's interesting. The general sentiment is that the 32 bit ARM Cortex-M MCUs are better and faster the 8 bit AVR and PIC processors and have support for more peripherals. The only real disadvantage is that there are no ARM processors available in DIP packages for easy prototyping. Although I must add that another disadvantage is that there are a lot more code examples etc. available for AVR and PIC compared to pretty much any ARM processor.

Choice of processor

It looks like the Cortex-M0 and Cortex-M3 are what I'll be using. The M0's are best suited for low-power (as in battery powered) systems while the M3's are faster with higher performance and support for more peripherals.

There are several manufacturers of ARM Cortex-M0 and -M3 microprocessors. Among them are:

  • Atmel (SAM3)
  • STMicroelectronics (STM32)
  • NXP (LPC)
  • Energy Micro (Gecko)
  • TI (Stellaris)

It seems like the SMT32 and the LPC series are the most widely used. At least those were the devices I found the most information about. For now, I have chosen the NXP LPC series as my ARM of choice because:

  1. I can find enough information about them (mind you, there are nowhere near as much info and examples for ARM MCUs on the Internet as there is for the 8-bit AVR or PIC MCUs).
  2. They are cheap.
  3. They are readily available (meaning they are in stock at RS).
  4. It looks like it there is a Mac OS X compatible toolchain.
  5. Some of them have nice on-chip USB bootloaders.

… but in all honesty I could probably have picked any other from the list and never known the difference. Just like PIC vs. AVR or Canon vs. Nikon. So just pick whichever one you fancy that looks like it'll do the job and learn how to use it. I chose NXP's LPC series.

mbed

The mbed is a development board with either a LPC11U24 (Cortex-M0) or LPC1768 (Cortex-M3). It is built on a board with two rows of 0.1" pins suitable for mounting on a breadboard. The mbed is kind of like the ARM equivalent of AVR's Arduino: it is easy to program and has wrappers for most hardware and peripheral functions. The IDE and compiler are web-based so you write all code in a browser-based editor and download the compiled binary file. The mbed can be attached to the computer (Mac, Windows or Linux) by a USB cable and will appear as a USB mass storage device (aka "a disk"). Firmware is flashed by copying over the binary file to the USB disk and resetting the mbed.

Code for the mbed is written in C++ and uses libraries for hiding all the hardware register stuff. An example program for flashing a LED (really, really fast) looks like this:

#include "mbed.h"

DigitalOut myled(LED1);

int main() {
    while(1) {
        myled = 1;
        myled = 0;
    }
}

But it is also possible to forego the mbed.h libraries and use straight-up ARM C code in the mbed online IDE. Which appeals to me because I would like not to be tied to the mbed hardware and libraries so I can make my own ARM-powered devices. Here's how the same code might look in non-mbedified code (which still compiles fine in the mbed IDE):

#include "LPC11Uxx.h"

int main(void)
{
 LPC_SYSCON->SYSAHBCLKCTRL |= (1>> 6) | (1>> 16);
 LPC_IOCON->PIO1_8 = 0x00000080;
 LPC_GPIO->DIR[1] = 0x00000F00;

    while( 1 )
        LPC_GPIO->PIN[1] ^= (1>> 9);

    return 0;
}
Comments 1 comment »

Flashing LPC11U24 or LPC1343 from Mac OS X

27. July 2012 22:53 by Jens Willy Johannsen
Categories: ARM

Here is how to flash an LPC11U24 or LPC1343 from Mac OS X using the ROM-based USB bootloader.
This post is just code snippet-style and I'm assuming you have a compiled .bin file and have the MCU connected with a USB cable so a disk named "CRP DISABLD" appears on the desktop.

  1. Add the required checksum using the crc executable as described here: http://vn1k.blogspot.dk/2010/11/lpc1343-loading-binaries-using-on-chip.html
  2. In Terminal do
    $ df -h

    to identify the filesystem device that is mounted as the CRP DISABLD disk. It will be something like "/dev/disk1" (which I will use in this example).

  3. Unmount the disk using
    $ diskutil unmount /dev/disk1
  4. Copy binary file to device using
    $ dd if=firmware.bin of=/dev/disk1 seek=4

    This is where the tricky stuff happens. In order for everything to work we must write data beginning at sector 4. And if we just copy the file in the Finder the OS will start at sector 6.

The info here is extracted from http://vn1k.blogspot.dk/2010/11/lpc1343-loading-binaries-using-on-chip.html and http://jogglerwiki.info/index.php?title=Writing_image_files_to_USB_drives

No comments No comments »