element14 Community
element14 Community
    Register Log In
  • Site
  • Search
  • Log In Register
  • About Us
  • Community Hub
    Community Hub
    • What's New on element14
    • Feedback and Support
    • Benefits of Membership
    • Personal Blogs
    • Members Area
    • Achievement Levels
  • Learn
    Learn
    • Ask an Expert
    • eBooks
    • element14 presents
    • Learning Center
    • Tech Spotlight
    • STEM Academy
    • Webinars, Training and Events
    • Learning Groups
  • Technologies
    Technologies
    • 3D Printing
    • FPGA
    • Industrial Automation
    • Internet of Things
    • Power & Energy
    • Sensors
    • Technology Groups
  • Challenges & Projects
    Challenges & Projects
    • Design Challenges
    • element14 presents Projects
    • Project14
    • Arduino Projects
    • Raspberry Pi Projects
    • Project Groups
  • Products
    Products
    • Arduino
    • Avnet Boards Community
    • Dev Tools
    • Manufacturers
    • Multicomp Pro
    • Product Groups
    • Raspberry Pi
    • RoadTests & Reviews
  • Store
    Store
    • Visit Your Store
    • Choose another store...
      • Europe
      •  Austria (German)
      •  Belgium (Dutch, French)
      •  Bulgaria (Bulgarian)
      •  Czech Republic (Czech)
      •  Denmark (Danish)
      •  Estonia (Estonian)
      •  Finland (Finnish)
      •  France (French)
      •  Germany (German)
      •  Hungary (Hungarian)
      •  Ireland
      •  Israel
      •  Italy (Italian)
      •  Latvia (Latvian)
      •  
      •  Lithuania (Lithuanian)
      •  Netherlands (Dutch)
      •  Norway (Norwegian)
      •  Poland (Polish)
      •  Portugal (Portuguese)
      •  Romania (Romanian)
      •  Russia (Russian)
      •  Slovakia (Slovak)
      •  Slovenia (Slovenian)
      •  Spain (Spanish)
      •  Sweden (Swedish)
      •  Switzerland(German, French)
      •  Turkey (Turkish)
      •  United Kingdom
      • Asia Pacific
      •  Australia
      •  China
      •  Hong Kong
      •  India
      •  Korea (Korean)
      •  Malaysia
      •  New Zealand
      •  Philippines
      •  Singapore
      •  Taiwan
      •  Thailand (Thai)
      • Americas
      •  Brazil (Portuguese)
      •  Canada
      •  Mexico (Spanish)
      •  United States
      Can't find the country/region you're looking for? Visit our export site or find a local distributor.
  • Translate
  • Profile
  • Settings
Embedded and Microcontrollers
  • Technologies
  • More
Embedded and Microcontrollers
Blog Port an MBED design to non-MBED - Phase 2a: DigitalOut Class Constructor
  • Blog
  • Forum
  • Documents
  • Quiz
  • Polls
  • Files
  • Members
  • Mentions
  • Sub-Groups
  • Tags
  • More
  • Cancel
  • New
Join Embedded and Microcontrollers to participate - click to join for free!
  • Share
  • More
  • Cancel
Group Actions
  • Group RSS
  • More
  • Cancel
Engagement
  • Author Author: Jan Cumps
  • Date Created: 11 Nov 2019 9:48 PM Date Created
  • Views 1177 views
  • Likes 5 likes
  • Comments 5 comments
  • lora
  • mbed
  • semtech
  • hercules
Related
Recommended

Port an MBED design to non-MBED - Phase 2a: DigitalOut Class Constructor

Jan Cumps
Jan Cumps
11 Nov 2019

I've ported the MBED DigitalOut class to the Hercules controller that I'll be using.

It could be any controller or SBC, but having one example makes it tangible.

 

I've try to do this with as limited as possible impact to the SemTech library. That is my main goal.

If you are looking for performant code or the best possible choice from language purity perspective, you may want to click away.

I'm using 64 bit integers on a 32 platform and more of that stuff image.

 

Not all the things that I have to port may be applicable to your situation.

 

 

The pin versus pin/port dilemma

 

MBED uses these constructs to use an output pin:

 

Constructor:

DigitalIn::DigitalIn(PinName pin)

 

Declaration:

 

typedef enum {
    PA_0  = 0x00,
// ...
    PC_9  = 0x29,
// ...
    // Generic signals namings
    LED1        = PC_9,
 // ...
 // Not connected
    NC = (int)0xFFFFFFFF
} PinName;

DigitalOut led( LED1 );

 

Assign a value:

led = 0;

 

Toggle:

led = !led;

 

These are the great wonders of C++. I like them a lot. They use operator overrides to make a led behave like a boolean.

The part that does not, by defaut, fit my microcontroller is that it has a Port + Pin. So the PinName paradigm does not fit automatically on my controller.

An example of a port is GPIO port A, on address 0xFFF7BC34U

 

#define gioPORTA ((gioPORT_t *)0xFFF7BC34U)

 

Whenever I want to use a pin on that port, I have to tell the controller what port I'm using.

 

I could solve this in a neat way:

  • create a class or structure that holds both Port and Pin.
  • create an enumerator type for the pins I'm using.
  • create an collection of these structures, each structure indexed or keyed by the enumerator value, so that, in the implemntation, I can retrieve the corresponding Port and Pin.

 

What I did id somewhat sneakier, and controversial on a 32-bit microcontroller.

I defined the PinName type as a 32 bit unsigned integer.

Then I assigned the most significant 32 bits as location for the port. The lower 32 for the pin.

The example below shows the type definition, and assigning LED 1 to gioPortA, pin 1:

 

typedef uint64_t PinName;
const PinName LED1 = 0xFFF7BC3400000001;

 

In the constructor of the DigitalOut class, I split them up in two data members.

Declaration:

 

Class DigitalOut {
public:
  DigitalOut(PinName pin);
// ...
protected:
  uint32_t pin;
  uint32_t port;
};

 

Implementation:

 

DigitalOut::DigitalOut(PinName pin) {
  // hercules specific= The first 32 bits are the port address, lower 32 bits the pin
  this->pin =  pin & 0xffffffff; // the lower 32 bits are the pinnummer
  this->port = ((pin & 0Xffffffff00000000) >> 32);

  // if your controller uses APIs to set the pin direction, you'd do that here.
  // I'm using the Hercules HALCoGen utility to set pin directions, so they are in the right state
  // when the pin will be used first.
}

 

I can now use the GPIO API of my microcontroller and send the pins and ports without further analysis.

Here is how my DigitalOut class members looks like at the end of the constructor execution (for LED1, where the port is 0xFFF7BC34 and the pin 1 is 1).

at the time this variable declaration is executed, just after parsing the port and pin from PinName...

 

DigitalOut led( LED1 );

 

image

 

 

How would you do this, if you also had the constraint to make your design fully backward compatible with MBED?

 

Related blog
Use C++ with HALCoGen C Projects

Port an MBED design to non-MBED - Phase 1: compile without errors

Port an MBED design to non-MBED - Phase 2a: DigitalOut Class Constructor
Port an MBED design to non-MBED - Phase 2b: DigitalOut Class and Blinky example
Port an MBED design to non-MBED - Phase 3: InterruptIn Class and example
Port an MBED design to non-MBED - Phase 4: Timeout Class and Blinky example
Port an MBED design to non-MBED - Phase 5: OO Callbacks Simplified
  • Sign in to reply

Top Comments

  • fmilburn
    fmilburn over 5 years ago +2
    Hi Jan, I believe there is a typo What I did id somewhat sneakier, and controversial on a 32-bit microcontroller. I defined the PinName type as a 32 bit unsigned integer. PinName is uint64_ so 64 bit.…
  • Jan Cumps
    Jan Cumps over 5 years ago +1
    STM did it simpler , but not unlike me. // High nibble = port number (FirstPort <= PortName <= LastPort) // Low nibble = pin number #define STM_PORT(X) (((uint32_t)(X) >> 4) & 0xF) #define STM_PIN(X) …
  • Jan Cumps
    Jan Cumps over 5 years ago in reply to fmilburn +1
    No. Because this is part of the code specific for my microcontroller, and that's a 32-bit one. For 64-bit controllers this would be the default integer size and no-one would care. The controller and compiler…
Parents
  • fmilburn
    fmilburn over 5 years ago

    Hi Jan,

     

    I believe there is a typo

    What I did id somewhat sneakier, and controversial on a 32-bit microcontroller.

    I defined the PinName type as a 32 bit unsigned integer.

    PinName is uint64_ so 64 bit.

     

    Is this approach controversial because not all microcontrollers implement 64 bit integers?  I am learning a lot from reading this series btw. 

    • Cancel
    • Vote Up +2 Vote Down
    • Sign in to reply
    • More
    • Cancel
Comment
  • fmilburn
    fmilburn over 5 years ago

    Hi Jan,

     

    I believe there is a typo

    What I did id somewhat sneakier, and controversial on a 32-bit microcontroller.

    I defined the PinName type as a 32 bit unsigned integer.

    PinName is uint64_ so 64 bit.

     

    Is this approach controversial because not all microcontrollers implement 64 bit integers?  I am learning a lot from reading this series btw. 

    • Cancel
    • Vote Up +2 Vote Down
    • Sign in to reply
    • More
    • Cancel
Children
  • Jan Cumps
    Jan Cumps over 5 years ago in reply to fmilburn

    No. Because this is part of the code specific for my microcontroller, and that's a 32-bit one. For 64-bit controllers this would be the default integer size and no-one would care.

    The controller and compiler can deal with this though, and I don't have a strong opinion on this construct. But other people do.

     

    The good thing is that, if you are in this situation and you think it is not a proper design decision, there are several other implementation options available that would not need a 64 bit variable.

     

    In some companies they carry you out tarred and feathered if you use a 64 bit integer on a 32 bit microcontroller image

    • Cancel
    • Vote Up +1 Vote Down
    • Sign in to reply
    • More
    • Cancel
  • Jan Cumps
    Jan Cumps over 5 years ago in reply to fmilburn

    The photo below is not very spectacular, but it's the first gpio pin that's toggled by the ported DigitalOut object.

     

    image

     

    Code:

      DigitalOut led( LED1 );
      led = 0; // led off
      led = !led; // led toggle

     

    The last line in particular is interesting.

    This will call both the read and write operators of the object.

    First the read operator (right side of the equation) to read current value (0)

    Then it will invert that value ( !0 -> 1 )

    Then it assigns that to the left sie of the equation, resulting in writing a 1 to the pin.

     

    Code of the read and write operations in the DigitalOut class source:

    the gioxxx() functions are the implementation APIs of the Hercules controller I'm using. This code is isolated from the rest of the port to keep device dependent sources in a unique separate directory.

     

    DigitalOut &DigitalOut::operator= (int value) {
      gioSetBit((gioPORT_t *)(this->port), this->pin, value);
      return *this;
    }
    
    DigitalOut::operator int() {
      return gioGetBit((gioPORT_t *)(this->port), this->pin);
    }

     

    When you assign an int to an object of this class (in this case the object led), the first method operator= gets called.

    When you put the object as a right side argument or as an int parameter in a function call, it will call the second method operator int().

    • Cancel
    • Vote Up 0 Vote Down
    • Sign in to reply
    • More
    • Cancel
element14 Community

element14 is the first online community specifically for engineers. Connect with your peers and get expert answers to your questions.

  • Members
  • Learn
  • Technologies
  • Challenges & Projects
  • Products
  • Store
  • About Us
  • Feedback & Support
  • FAQs
  • Terms of Use
  • Privacy Policy
  • Legal and Copyright Notices
  • Sitemap
  • Cookies

An Avnet Company © 2025 Premier Farnell Limited. All Rights Reserved.

Premier Farnell Ltd, registered in England and Wales (no 00876412), registered office: Farnell House, Forge Lane, Leeds LS12 2NE.

ICP 备案号 10220084.

Follow element14

  • X
  • Facebook
  • linkedin
  • YouTube