Streamlining code for Digital I/O in LPC2000

Colleagues,

I’m new to ARMs (the usual disclaimer). Could anyone recommend a convenient library or methodology for streamlining the simple digital I/O. I’m concerned more about code convenience** and maintainability than the speed of execution. Here’s how it’s done in the IAR examples. I think it’s a lot of code for just being able to toggle a pin high or low.

// file: board.h
// USB link LED
#define USB_LINK_LED_MASK   (1UL<<18)
#define USB_LINK_LED_DIR    IO1DIR
#define USB_LINK_LED_FDIR   FIO1DIR
#define USB_LINK_LED_SET    IO1SET
#define USB_LINK_LED_FSET   FIO1SET
#define USB_LINK_LED_CLR    IO1CLR
#define USB_LINK_LED_FCLR   FIO1CLR
#define USB_LINK_LED_IO     IO1PIN
#define USB_LINK_LED_FIO    FIO1PIN

Of course, it’s not hard to write such library, or make an automatic code generator. But I’d like not to reinvent this wheel if possible. :slight_smile:

  • Nick

** E.g. being able to declare an array of pins that are physically scattered in different I/O banks.

Personal preference…

I put all the #defines for I/O bit numbers in one place.

And all the I/O port direction configs in one place.

Same, for the VIC setup.

And I don’t use macros - too obscure to understand a year from now.

I more than dislike arcane macros and

#define meaningOfLife = gobbledygook

example

IO0SET = (1<<BITNAME); // is what I prefer. Obvious

stevech:
example

IO0SET = (1<<BITNAME); // is what I prefer. 

Obvious

Easy to read. To write this, one would have to remember which port the I/O pin is on. How about this little C++ hack.
class IOPin
{
public:
  IOPin(short iPort, short iPin) : m_iPort(iPort), m_iPin(iPin) {}
  
  void MakeOutput() { *((unsigned long*)(0x3FFFC000 + 0x20*m_iPort)) |= (1UL << m_iPin); }  // FIOxDIR register
  void Set()        { *((unsigned long*)(0x3FFFC018 + 0x20*m_iPort))  = (1UL << m_iPin); }  // FIOxSET register
  void Clr()        { *((unsigned long*)(0x3FFFC01C + 0x20*m_iPort))  = (1UL << m_iPin); }  // FIOxCLR register
  
  // member variables are constant, so they might as well be public
  const short m_iPort;
  const short m_iPin;
};

Calling code

IOPin pinBlinkyLED(1, 18);

pinBlinkyLED.Set();
pinBlinkyLED.Clr();

It works on LPC2368 under IAR EW ARM, although it’s incomplete. Just a thought.

the C++ class is elegant.

It’s just that I’m old school. Having done asm and C projects for (way lotta) years - I prefer less code, simple code, minimize having to grep your butt off looking for #defines and class code to abstract something that was simple to begin with.

This is really frustrating to do if you inherit someone else’s poorly commented code, or even revisit code you wrote long ago.

But, again, I’m old school.

kender:

class IOPin

{
public:
IOPin(short iPort, short iPin) : m_iPort(iPort), m_iPin(iPin) {}

void MakeOutput() { ((unsigned long)(0x3FFFC000 + 0x20m_iPort)) |= (1UL << m_iPin); } // FIOxDIR register
void Set() { ((unsigned long)(0x3FFFC018 + 0x20
m_iPort)) = (1UL << m_iPin); } // FIOxSET register
void Clr() { ((unsigned long)(0x3FFFC01C + 0x20*m_iPort)) = (1UL << m_iPin); } // FIOxCLR register

// member variables are constant, so they might as well be public
const short m_iPort;
const short m_iPin;
};



Calling code




IOPin pinBlinkyLED(1, 18);

pinBlinkyLED.Set();
pinBlinkyLED.Clr();

It’s nice, but isn’t it also a lot of code? I wouldn’t like to type in definitions for a more than a few bits with that method. I would probably write a code generator, but equally that could be applied to generating #defines.

I guess you were right about not minding about execution speed ;). To my mind, setting a bit in a register like that should not take more than a few instructions and not require any memory overhead; I don’t know what that C++ compiles down to. In this case, the C++ methodology does not appear to add any value, only overhead.

I pretty much hate macros too, but bit twiddling is one place where I do use them. For setting up port direction, pullups etc I usually use a simple function as these are usually only called once at startup.

bobcousins:
It’s nice, but isn’t it also a lot of code? I wouldn’t like to type in definitions for a more than a few bits with that method.

The class definition has to be written once. It can be written in a separate file and reused between projects (given that the chip remains LPC23XX). It's included into the project once. Then each bit is declared with a single line: ``` IOPin pinMnemonicName(iPort, iBit) ``` Of course it's a matter of personal preference, but I wouldn't mind having a 100 of these one-line definitions.

kender:
Of course it’s a matter of personal preference, but I wouldn’t mind having a 100 of these one-line definitions.

Coding style and personal preferences aside there are some more pragmatic issues to consider when developing software for resource-limited microcontrollers such as the LPC2xxx family. I don't know the answers in this case but these are some of the questions that need to be asked for each technique (and any others that might be investigated):

How much machine code is actually generated (Both the initial setup and per instance)?

How much additional overhead is required for the C++ runtime etc.?

What is the execution time?

Would it be feasible to use in (fast) interrupt handlers?

etc. etc.

Yeah but he specifically stated that convenience is more important than speed of execution. Given that requirement, the solution he proposes is a neat and convenient one.