CMSIS Blinky KL26 - Configure Timer and Interrupt

cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

CMSIS Blinky KL26 - Configure Timer and Interrupt

1,447 Views
fwilliams42
Contributor I

I've just started getting into ARM based processors. I have a Teensy LC board running a MKL26Z64VFT4 processor. I would like to write a blinky program to get up and running, and I don't want to use any particular libraries that are not standard between manufacturers, so I'm writing it at the register level. I'm using a header from FreeScale with reference manual KL26P121M48SF4RM.

I am trying to configure Timer0 to trigger every half second to call an interrupt handler. However I'm sure how to set this up just from the datasheet. Attached is my code so far setting up the timer, and creating the function to call when the interrupt occurs, but without a way to tell the program to call that function.

I'm coming from an AVR background where this was done using something such as ISR(TIMER0_OVF_VEC).

If I could also be pointed to further resources with examples similar to this but for other sections described in the datasheet I would appreciate it greatly.

0 Kudos
5 Replies

1,393 Views
bobpaddock
Senior Contributor III


Coming from AVR-LibC you may have used the 'atomic' functions for controlling IRQs.
I've attached the ARM equivalent header, as it is particularly niggly to find.


1,394 Views
bobpaddock
Senior Contributor III

AVR GCC/AVR-LibC hides things behind the macros such as ISR().
In the ARM world things must be spelled out, or create your own set of ISR() macros.

The equivalent ARM GCC code would be:

#define ATTR_NO_INSTRUMENT_FUNCTION __attribute__( ( no_instrument_function ) )

/* 10 ms base tick for all timers: */
void ATTR_NO_INSTRUMENT_FUNCTION SysTick_Handler( void ) __attribute__((used, interrupt("IRQ")));
void ATTR_NO_INSTRUMENT_FUNCTION SysTick_Handler( void )
{
}

The SysTick timer would be a good place to start learning as it is by ARM rather than any specific vendor, so there is a lot of common code examples to be found.

ATTR_NO_INSTRUMENT_FUNCTION has to do with the, rather obscure, Cygwin tracing methodology.

The 'used' attribute prevents the function from being removed by optimizations such as Link Time Optimization.  interrupt("IRQ")) is what the AVR-LibC ISR macro does.

Also as Myke mentions the vector table needs to point to the functions.  CMSIS does have a standard naming convention for some of the common items such as SysTick_Handler.  Often simply defining your function with the standard name is enough to have things work.
It depends on how the startup code is structured.

What I believe you are ask for is addressed in the 'Driver' middle ware here:

https://developer.arm.com/tools-and-software/embedded/cmsis

Still at the end of the day someone has to write the register level code, for each vendor, for the layer below those.

I agree that often the code supplied by manufactures sucks.  I've run into cases where it was clear the code they offered had never actually been complied and tried.

Start with the 'Blinky' example in the current release (11.4.0) of MCUXPresso and SDK to see how things get set up.


It would be far better world if all manufactures just showed some simple examples in the data sheets or app-nodes of how to do things, rather than saying "Use the IDE".   At the end of the day the liability of my product is on me, so I'm not prone to rely on some hidden 'magically' generated code that is hard to find and even harder to validate.






1,433 Views
myke_predko
Senior Contributor III

@fwilliams42 

Can you explain the logic behind the statement "I don't want to use any particular libraries that are not standard between manufacturers, so I'm writing it at the register level" - I get you don't want to get locked into a specific manufacturer's product line but there are ways to write high level functions that will access manufacturer device specific IO driver libraries that are a LOT easier and more maintainable than writing to device registers.  

I'm sure that a number of people here would be happy to discuss different strategies and approaches with you.  Personally, based on what you've written, I would recommend creating "sliver" inline methods that provide consistent access to driver IO libraries like:

inline static uint32_t readIOpin(uint32_t regAddr) {
return deviceSpecificReadIOPin(regAddr);
}

With the latest version of GCC with C99 support, the code generated should be at least as efficient as calling "deviceSpecificReadIOPin" directly.  When you're working with another device and want to reuse the code, just copy and modify the sliver methods.  

If I can make one comment, working with a single device manufacturer and developing a relationship with them to the point where you are using their parts almost exclusively is not a bad thing.  If you can develop a relationship wth a local FAE (Field Applications Engineer) and sales team, you will get priority on questions and issues, new device notifications, get possible price breaks on parts and (really important during this Covid crisis) part allocations and supply status information.  

Over the years, developing these relationships have become more difficult for everyone, not just small players as local field teams have been reduced and more support shifted to online, but you can still do it.  

1,427 Views
fwilliams42
Contributor I

@myke_predko 

As I'm just getting into ARM-based MCUs I don't have any preferences yet between vendors. For 8-bit MCUs I focused only on Atmel / AVR parts, and I feel like that limited me from using PIC or similar parts for fear of wasting a large amount of time relearning things.

When trying out things in various manufacturer IDEs at the moment, I've noticed an exorbitantly large amount of pre-generated code (40+ headers, libraries, etc.). Then on forums people mention some serious problems with their experience with manufacturer libraries. What concerns me is that I find threads from many years ago complaining about that, and even still in 2021, which leads me to believe that they're not going to be improved. 

It's my understanding that ARM's CMSIS standardization forces manufacturers to keep the lowest level of interface consistent. My presumption is that if I learn to effectively use that, then I am both no longer bound by a manufacturer, and never stuck relearning a chip.

All of my above statements are "I think" statements. I really don't know what I want or need yet. I have a prototype I'd like to get running in a few weeks. It uses some basic I2C, SPI, and serial communication, and I know I need some decent processing power to FFT some sensor results, hence my switch to ARM.

0 Kudos

1,407 Views
myke_predko
Senior Contributor III

@fwilliams42 

You''re comparing apples to oranges when you're talking about 32bit devices like the AVR, PICMicro as well as the 8051, 680x architectures in the same breath as 32bit architectures like ARM Cortex and MPIs.  I worked with different 8bit architectures for years (and wrote books about them concurrently).  I don't think you can realistically work at the same level with ARM (or MIPs) or any other 32bit architecture - there's too much to learn to be productive in less than a year.  That's why the libraries exist.  

When I looked at your attached example code, I'm not sure you realize that you are relying on what is in effect manufacturer supplied device specific code resources and would probably not be available for different devices even if they are the same Cortex M architectures.  The interrupt vectors are predefined by NXP and it's unlikely that other ARM vendors doing it the same way (taking advantage of C99's "weak" method label addresses).  It also includes register structure and SRAM definitions that are definitely specific to NXP.

I also want to point out that your application is probably a quarter of the size I would expect for an actual "blinky" application.  You haven't set up clocking (the device is running at the default power up 32.768kHz) and you need to setup the crossbar switch for more efficient operation.  There's a lot more you need to do before you can consider this a "complete" application.  

That's great that you want to base your applications on CMSIS, that's a big step in the right direction from trying to create applications that access registers directly like in an AVR.  

People complain.  If I were going to buy a USB charger from Amazon, I'd use the approach that you're using and look at the complaints before I look at the five star reviews.  For Microcontrollers/Processors, that's an approach that will NEVER be useful in selecting a device.  If somebody is keeping with a device despite deficiencies that have been complained about for a long time then there are positives about that device you're not seeing.  

Hardware companies typically don't understand software development processes and while senior management has the desire to provide tools to make their products more attractive they don't have the will to pay to go all the way.  I find, as a rule, chip manufacturers only get about 80% of the required work done before release and funding isn't available for adequate support.  

It's tough to commit to a part family/manufacturer and you're right to want to test drive different products before deciding on which way to go.  Don't limit yoursef by working at the level of 1s and 0s - take advantage of the full extent of the tools available to you and look at ALL the other aspects of the device as part of your selection criteria.  Once you've done that, you can get deeper into the chip and be able to get more out of it.  

Finally, if you use the available libraries right from the start you'll get projects working faster and you'll definitely have more fun with the chip!