I’ve written an app using the local build environment, in which I have set up and used Timer 2 (TIM2) with an attached interrupt. It all compiles and runs fine in the local build environment, but borks in the Web IDE.
The IRQ handler is declared thus …
extern "C" void TIM2_IRQHandler()
{
static uint8_t currentDigitNumber = 0;
if (TIM_GetITStatus(TIM2, TIM_IT_Update) != RESET){
TIM_ClearITPendingBit(TIM2, TIM_IT_Update); // clear the interrupt flag
// do stuff here
}
}
The error I get from clicking the Verify button in the Web IDE is …
error: previous declaration of 'void TIM2_IRQHandler()' with 'C++' linkage
If I remove the ‘extern “C”’ part, then the code compiles. But the interrupt routine doesn’t actually run. In fact, nothing in loop() appears to be working, either – even though the core’s main status LED is doing its usual cyan pulsatatificating thing.
It seems to me that IRQ handlers should not use C++ “linkage” (calling conventions.) Perhaps there is a bug in the IDE compiler? Or maybe there’s another #pragma or something I can use to get around this little problem? It sure would be nice to be able to update this app in the field, the Spark IDE way.
Let me know if I’m missing something. It has been know to happen, once or twice!
Hey @gruvin - replicated this bug on my machine, and it doesn’t seem to be the fault of the Arduino pre-processor, because the issue comes up when it’s added to a library file (which isn’t processed) or when the pre-processor is turned off.
My only thought is that it might have to do with some configuration settings that might differ between the local build and the cloud; I’m discussing with @zachary and @mohit behind the scenes to see what they think
Hey @gruvin - this works now! In order to get this to compile, you need to add it to a library file; it can’t be part of your main .ino file. Then you need to #include "application.h" in that file. If you do that, it should compile as expected!
Since there's no way to edit application.h in the Web IDE, I had to move all variables and functions relied on by the IRQ handler into the additional library. But that strikes me as a better overall layout anyway -- in this case, essentially having a hardware abstraction layer, encapsulated in a library. Yay \o/
@BDub -- The application is fully functional using the command line tools. IRQ executes 200x a second.
Only, now I’m trying to duplicate the set-up in my command-line tools version and coming unstuck with the makefile.
Far as I can tell from the makefile (in core-firmware/build) it should automagically find all .cpp file in …/src, build and link them. But neither is actually happening. My new ‘library’ is ignored entirely.
My “library” is just an additional .cpp/h file pair, in the same folder/s as application.cpp.
EDIT: AH!! build.mk in the src directory. All sorted. Working great. Yay \o/
Sure. Sorry, I thought you were offering help in the last post, not asking for it.
The following sets up the timer itself, to upload/overflow 200x a second ...
// We'll use Timer 2 for LED output digit scanning
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
TIM_TimeBaseInitTypeDef timerInitStructure;
timerInitStructure.TIM_Prescaler = 45000; // 1,600 counts per second (for finer grain calibration)
timerInitStructure.TIM_Period = 7; // reload 200 times a second. Measured accuracy well within 5ppm
timerInitStructure.TIM_CounterMode = TIM_CounterMode_Up;
timerInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;
timerInitStructure.TIM_RepetitionCounter = 0;
TIM_TimeBaseInit(TIM2, &timerInitStructure);
TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE); // enable the timer update event, for our interrupt
TIM_Cmd(TIM2, ENABLE);
Note the first line (after the comment.) Only Timer1 gets its clock enabled automatically at power-on-reset. The others need to be explicitly enabled. (Because those timers can have other clock sources, including other timers. Such a cool MCU is this baby!)
And this part, along with TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE); above, enables the interrupt ...
// Set up an interrupt handler for the timer 2 reload event, enabled above
NVIC_InitTypeDef nvicStructure;
nvicStructure.NVIC_IRQChannel = TIM2_IRQn;
nvicStructure.NVIC_IRQChannelPreemptionPriority = 0;
nvicStructure.NVIC_IRQChannelSubPriority = 1;
nvicStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&nvicStructure);
@gruvin I was offering help, but I don’t have time to try EVERYTHING myself, so if users like you can post your results… it will help everyone that comes looking for an ISR based TIMER in the future Thanks!
EDIT: I amended the title to make this easier to find, and moved to FIRMWARE category.