element14 Community
element14 Community
    Register Log In
  • Site
  • Search
  • Log In Register
  • 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 3: InterruptIn Class and example
  • 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: 16 Nov 2019 6:53 PM Date Created
  • Views 845 views
  • Likes 4 likes
  • Comments 1 comment
  • sx1276
  • lora
  • halcogen
  • mbed
  • semtech
  • hercules
Related
Recommended

Port an MBED design to non-MBED - Phase 3: InterruptIn Class and example

Jan Cumps
Jan Cumps
16 Nov 2019

The port of the MBED InterruptIn is complete.

In this blog you can see the internals of this class and how to set up configuration and handling.

 

My port is for a Hercules TMS570LC43. I use the HAL utility and api for that controller where possible.

 

 

The MBED InterruptIn class allows you to handle interrupts with objects. You can set what object and what method of that object gets called when the interrupt fires.

The SemTech SX1276 LoRa library uses the InterruptIn class to handle the digital signals DIO0 -> DIO5.

 

 

image

The pins DIO0 to 5 are used by the radio to flag changes within the system. These are configurable.

In the example that comes with the SX1276 shield, the first line in the below table is used.

DIO0 switching from high to low flags thet receiving is finished, etc ...

Each of the six pins have unique flagging function and the SX1276 library handles them in an object oriented way.

(note: Pin DIO5 is ignored in this example. There's a handler that's never called. Interrupts are not generated for it.

 

image

 

How does MBED and the SemTech example do this?

 

The library has a class that abstracts the SemTech chip, called SM1276.

This class has a method for each of the 6 digital signals.

 

void SX1276::OnDio0Irq( void ) {
// ...
}

void SX1276::OnDio1Irq( void ) {
// ...
}


void SX1276::OnDio2Irq( void ) {
// ...
}


void SX1276::OnDio3Irq( void )
{
    switch( this->settings.Modem )
    {
    case MODEM_FSK:
        break;
    case MODEM_LORA:
        if( ( Read( REG_LR_IRQFLAGS ) & RFLR_IRQFLAGS_CADDETECTED ) == RFLR_IRQFLAGS_CADDETECTED )
        {
            // Clear Irq
            Write( REG_LR_IRQFLAGS, RFLR_IRQFLAGS_CADDETECTED | RFLR_IRQFLAGS_CADDONE );
            if( ( this->RadioEvents != nullptr ) && ( this->RadioEvents->CadDone != nullptr ) )
            {
                this->RadioEvents->CadDone( true );
            }
        }
        else
        {
            // Clear Irq
            Write( REG_LR_IRQFLAGS, RFLR_IRQFLAGS_CADDONE );
            if( ( this->RadioEvents != nullptr ) && ( this->RadioEvents->CadDone != nullptr ) )
            {
                this->RadioEvents->CadDone( false );
            }
        }
        break;
    default:
        break;
    }
}


void SX1276::OnDio4Irq( void )
{
    switch( this->settings.Modem )
    {
    case MODEM_FSK:
        {
            if( this->settings.FskPacketHandler.PreambleDetected == false )
            {
                this->settings.FskPacketHandler.PreambleDetected = true;
            }
        }
        break;
    case MODEM_LORA:
        break;
    default:
        break;
    }
}


void SX1276::OnDio5Irq( void )
{
// ...
}

 

The 6 SX1276 DIO pins are connected to 6 gpio pins of the Hercules. I have to choose pins that support interrupts for the first 5.

 

The SX1276 class defines the logic for the handlers.

 

SX1276::SX1276( RadioEvents_t *events,
                PinName mosi, PinName miso, PinName sclk, PinName nss, PinName reset,
                PinName dio0, PinName dio1, PinName dio2, PinName dio3, PinName dio4, PinName dio5 )
            :   Radio( events ),
                spi( mosi, miso, sclk ),
                nss( nss ),
                reset( reset ),
                dio0( dio0 ), dio1( dio1 ), dio2( dio2 ), dio3( dio3 ), dio4( dio4 ), dio5( dio5 ),
                isRadioActive( false )
{

// ...
    this->dioIrq = new DioIrqHandler[6];

    this->dioIrq[0] = &SX1276::OnDio0Irq;
    this->dioIrq[1] = &SX1276::OnDio1Irq;
    this->dioIrq[2] = &SX1276::OnDio2Irq;
    this->dioIrq[3] = &SX1276::OnDio3Irq;
    this->dioIrq[4] = &SX1276::OnDio4Irq;
    this->dioIrq[5] = nullptr;

    this->settings.State = RF_IDLE;
}

// ..

 

The SX1276 class has data members for these interrupts.

 

class SX1276 : public Radio
{
protected:
// ...
    InterruptIn dio0;
    InterruptIn dio1;
    InterruptIn dio2; 
    InterruptIn dio3;
    InterruptIn dio4;
    DigitalIn dio5;
// ...

 

In the class that represents the evaluation board (a subclass of the SX1276 class) the hardware specific things are done,

like assigning the hardware pins and set rise time triggers.

 

SX1276MB1xAS::SX1276MB1xAS( RadioEvents_t *events ) :   SX1276( events, D11, D12, D13, D10, A0, D2, D3, D4, D5, D8, D9 ),
                            AntSwitch( A4 ), 
                            Fake( A3 ) {
// ...
    IoIrqInit( dioIrq );
// ...
}

void SX1276MB1xAS::IoIrqInit( DioIrqHandler *irqHandlers ) {
// ...

    dio0.rise( mbed::callback( this, static_cast< TriggerMB1xAS > ( irqHandlers[0] ) ) );
    dio1.rise( mbed::callback( this, static_cast< TriggerMB1xAS > ( irqHandlers[1] ) ) );
    dio2.rise( mbed::callback( this, static_cast< TriggerMB1xAS > ( irqHandlers[2] ) ) );
    dio3.rise( mbed::callback( this, static_cast< TriggerMB1xAS > ( irqHandlers[3] ) ) );
    dio4.rise( mbed::callback( this, static_cast< TriggerMB1xAS > ( irqHandlers[4] ) ) );
}

 

The effect of all this is that we have the pins defined and have defined the object and method  that will be called in rising edge.

 

The Port for InterruptIn

 

I was able to keep the InterruptIn class device independent. I just had to provide gpio_api and gpio_irq_api functions specific to the Hercules.

I'm highlighting a few of those below.

 

uint32_t uInts = 0U;

typedef struct {
  uint64_t pin;
  gpio_irq_t *obj;
  gpio_irq_handler handler;
  uint32_t id;
} irqarray;

static irqarray __irq_ids [MAXINTERRUPTS] = {0};

int gpio_irq_init(gpio_irq_t *obj, PinName pin, gpio_irq_handler handler, uint32_t id)
{
  if (pin == NC) {
    return -1;
  }
  __irq_ids[uInts].pin = pin;
  __irq_ids[uInts].obj = obj;
  __irq_ids[uInts].handler = handler;
  __irq_ids[uInts].id = id;
  uInts++;
  return 0;
}

void gpio_irq_set(gpio_irq_t *obj, gpio_irq_event event, uint32_t enable) {
  // Hercules: not applicable, done in HALCoGen, if this is constant throughout the run
  // when you want to change this in runtime, implementation is needed
}

void interruptfired(uint32_t port, uint32_t bit, uint32_t edge) {
  uint64_t pin = port;
  pin = pin << 32;
  pin = pin |= bit;

  uint32_t i;
  bool  bFound = false;
  for (i = 0; i < uInts; i++) {
    if(pin == __irq_ids[i].pin) {
      bFound = true;
      break;  // found, no need to continue
    }
  }
  if (bFound) {
    gpio_irq_event derivedEdge = edge ? IRQ_RISE : IRQ_FALL;
    __irq_ids[i].handler(__irq_ids[i].id, derivedEdge);
  }
  return;
}

 

Here's how I defined them in the Hercules specific HAL configuration utility HALCoGen:

 

image

 

and

 

image

 

The effect of this configuration (Hercules specific) is that a low level handler (a single one, called for any of the pins)  will be called on the rising edge of these pins.

I implemented it as below. It will call the function I created in my port interruptfired(), documented above) that will act as bridge between HALCoGen's low level API and the higher level C++ objects.

 

void gioNotification(gioPORT_t *port, uint32 bit) {
  uint32 bitInNotificationRegister = bit;
  if(port == gioPORTB) {
    bitInNotificationRegister += 8;
  }
  uint32 edge = (gioREG->POL >> bitInNotificationRegister) & 1U;
  interruptfired((uint32_t)port, bit, edge);
}

 

The first part of the code inspects the Hercules registers to find out if the trigger cause was a rising edge or falling edge event.

Then it calls my bridge function with the port, pin and the edge info.

 

Result

 

The result of an interrupt firing can be seen in the stack trace below.

In this example, the pin DIO0 lipped from low to high.

 

image

 

From bottom to top, the first 3 functions in the stack are from the Hercules low level HALCoGen layer.

Level 0: An assembler function (that I did not write image - it's generated by the utility) that looks in the interrupt table and calls the low low level handler.

Level 1: That low low level handler does some bookkeeping that's not supposed to be altered, then calls the user changeable handler gioNotification().

Level 3: In this handler (documented above) I query the edge that triggered the interrupt and hand over to my ported MBED interrupt code.

Level 4: My bridge function looks up which handler reference is linked to this pin and edge.

Level 5 and above: This is the default MBED ported code that will then call the method of the correct object. In this case the OnDio0Irq() method of my radio object.

 

It's easier to understand this by looking at the full code (the MBED code is published on Github, I will upload my port together with the SX1276 example when it works).

Explaining it is harder.

If there's a part of the mechanism that you want to dig into, just ask.

 

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
  • DAB
    DAB over 5 years ago

    Nice update Jan.

     

    DAB

    • 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