Hello,
I am writing an I2C master transmitter object. The problem I am having is that the IRQ Handler for I2C1 is not firing. According to the manual, it should fire after the start condition is sent and the status register is 0x08. When I step through the code with the debugger, the status code is 0x08. I am using an MCB1700 development board. Why is it not firing? Did I not configure something properly? For tests, All I am doing is toggling an LED on when the interrupt fires. Once I solve this problem, I will write the rest of the code.
#include <stdio.h> #include <LPC17XX.h> #include "GPIO1Output.h" GPIO1Output out(P1_28); __irq void I2C1_IRQHandler(void) { if (LPC_I2C1->I2STAT == 0x08) { out.Set(); } } int main(void) { // Initialize I2C. LPC_PINCON->PINSEL0 = 0x0F; LPC_PINCON->PINMODE_OD0 = 0x03; NVIC_EnableIRQ(I2C1_IRQn); LPC_I2C1->I2CONSET = 0x40; LPC_I2C1->I2CONSET = 0x20; int status = LPC_I2C1->I2STAT; }
Any chance you'll be posting your diff report here, caring to do so using the proper format specifiers?
What do you mean by diff report?
Any diff tool out there ,including Winmerge, can save the result to a file.
"Diff" here is short for "Difference" - ie, the report of the differences between the files.
Here is the report for each file:
www.filedropper.com/differencereport
When I debug with the latest files, the debugger hangs and the t1: field keeps increasing. When I click the stop button, the yellow arrow appears pn the line with a B assembly statement (see screenshot). Does this say anything?
imageshack.us/.../
Infinite loop branching to itself.
Your interrupt handling must map in an access to your ISR from the relevant interrupt vector. Does your startup file do that?
How can I tell? I would think that the startup file would take care of that.
There is a reason why an embedded developer should have at least some knowledge about assembler for the target architecture. The way to tell is to locate the interrupt vectors in the startup file, and then follow the path until you either get to your ISR, or somewhere you do not want to reach - like your infinite branch.
The datasheet for your processor - actually "User Manual" is the name NXP users - does a good job of telling you where the interrupt vectors are.
Another thing you really have to know about is the difference between single-stepping C source code and single-stepping processor instructions. It is possible to single-step in the startup file too. It's your single-stepping source lines (which indirectly means that the compiler sets a breakpoint on the next source line) that have had you not notice the infinite loop until now. When suspecting interrupt problems, it's often needed to perform instruction-level single-stepping.
I use the startup file provided with Keil. Do they want me to set up the routines manually?
I just don't understand. In the example projects the interrupts work, and the startup and configuration files are no different (I looked at examples using the most recent files too). Im stuck and I seriously doubt I am doing anything wrong as I cannot figure out from the examples.
Thanks, Ben
Note that the NVIC function does not name the ISR. The mapping to ISR is just by having the correct name of the ISR in relation to the startup file. And any ISR not supplied by you have a default ISR supplied during linking.
So what did you find out when you single-stepped through the startup file? When your ISR was not called - what other function was called? Was it just a question of Keil having changed the default name for the ISR function?
Stepping through the startup file only just initializes the reset handler and the stack heap. Then it jumps into the infinate loop that is supposed to be the interrupt (the B instruction).
It appears as if the default ISR was called.
OK I figured it out. I am using C++ and this forum posting delivered the answer I was looking for. It talks about how the overloading of C++ functions could cause weak references to the intrrupt handlers.
electronics.stackexchange.com/.../bug-in-keil-arm-compiler-with-interrupt-handlers-and-c
All I have to do is put a wrapper around the interrupt functions and that fixes it.
extern "C" { ... Interrupt Functions. }
Is there a better way of doing this or do you always need the wrapper when using C++?
No, C++ does not cause weak references to interrupt handlers.
But C++ uses name mangling, which means the external name the linker sees contains extra characters encoding the returned data type, and the parameter list.
So a C++ file with a function void hello(void) will not let the linker see a function "hello". You don't need to use the braces to wrap. Standard C++ documentation tells you that you can specifiy directly for the function that it should use the C calling convention and have C bindings.