Hello there,
The Board
This problem is occurring with the Arduino Uno board and an ATMega328P microcontroller.
Background Information:
I am working on porting over a microcontroller library that a colleague and I developed for the PIC32MX2xx/1xx series of microcontrollers to Arduino to offer the library to a larger user-base. The fundamental idea of the library is to create a dynamic, efficient method of configuring the internal peripherals of microcontrollers, such as timers, UART, SPI, I2C, ADC, etc. with ease. The library was originally written entirely in C, so that will explain some of the programming practices that will be displayed later in the post.
If you are interested in the background purpose of the library, the source code is available here. Information describing the internal library functionality or use cases is also provided in the wiki.
I have been working over the last few days to port the library over to Arduino and I am currently working on validating functionality of each of the peripherals. Source code for the port is available here if you are interested, although the wiki has yet to be ported. Functionality is nearly identical, with a few exceptions.
The Issue:
The issue that I am currently experiencing occurs when I'm attempting to validate the timer functionality. When the library is implemented within Atmel Studio 7, the code functions exactly as anticipated (see below for source code and probed pin output).
Source code in Atmel Studio:
#include "sublibinal.h"
void callback();
int main(void)
{
//Configure PD7 as an output
DDRD |= 1<<7;
//Configure the timer
Timer_Config tcon = {0};
tcon.enabled = TRUE;
tcon.frequency = 250;
tcon.pbclk = 16000000;
tcon.callback = &callback;
tcon.which_timer = TIMER_0;
initialize_timer(tcon);
//Enable system-wide interrupts
enable_Interrupts();
/* Replace with your application code */
while (1)
{
}
}
void callback()
{
if (PORTD & (1<<7))
PORTD &= ~(1<<7);
else
PORTD |= 1<<7;
}
Code Explanation
The functionality of this code is quite simple. First, Pin PD7 is configured for output so the frequency can be probed. Next, a library C struct is instantiated for configuring the timer, and each individual parameter of the structure is completed. pbclk parameter refers to the peripheral bus clock - in this case the ATMega328P's 16MHz clock (result of different terminology in PIC microcontrollers). The callback parameter is a function pointer to the ISR function that the program will call every time the interrupt triggers. Within this callback function, the value of PD7 is toggled to produce a square wave (or PWM) with a frequency of 1/2 the timer frequency. This structure is then passed to a configuration function to set the internal registers of the microcontroller for proper timer functionality. Finally, interrupts are enabled and the program begins execution.
Please see below for our resulting PWM waveform when probing the PD7 pin.
Output (Atmel Studio 7):
If you cannot see the image, it is provided as an attachment. The output frequency recorded is 124.4Hz.
This output is expected, as the interrupt toggles the pin value at a rate of 250Hz, making the resulting waveform have a frequency of roughly 125Hz.
However, the issue arises when that code is copied over into the Arduino development environment. When the same code is placed within the setup() function, the frequency output changes quite drastically, and does not respond to changes in the set up code (see below for source code and probed output).
Source Code in Arduino IDE:
#include <sublibinal.h>
void setup() {
//Configure PD7 as an output
DDRD |= 1<<7;
//Configure the timer
Timer_Config tcon;
tcon.enabled = TRUE;
tcon.frequency = 250;
tcon.pbclk = 16000000;
tcon.callback = (void *)&callback;
tcon.which_timer = TIMER_0;
initialize_timer(tcon);
//Enable system-wide interrupts
enable_Interrupts();
}
void loop() {
// put your main code here, to run repeatedly:
}
void callback()
{
if (PORTD & (1<<7))
PORTD &= ~(1<<7);
else
PORTD |= 1<<7;
}
As you can see, the code is identical. The change to the callback function assignment is because Arduino IDE compiler does not allow for implicit casting.
However, the resulting PWM waveform when probing the output pin PD7 is quite different:
Output (Arduino IDE):
If you can not see the image, they are provided as attachments. The output frequency shown is 31.16KHz.
Attempt at a solution:
It is my sneaking suspicion that what is occurring is a memory overwrite by the Arduino IDE, as Arduino utilizes Timer 0 for functions such as delay() and the output PWMs on pins. There may be a conflict within some of the Arduino libraries with ISR definitions as well. However, I am not overly knowledgable with the Arduino library source code. Is there any reason that an ISR definition conflict or a memory overwrite could be causing a problem such as this? I'm skeptical, as I have already verified and tested a UART implementation that utilizes the same ISRs as the Arduino library, and it functions exactly as anticipated. This leads me to believe it has something to do with internal configuration by Arduino libraries of the timers for use by the peripheral functions. I attempted moving the configuration into a once-executing statement within the loop() function, however this did not change the issue.
Any insight that anyone could provide in how to solve this problem would be greatly appreciated.