Library Conflict with Internal Timers [Arduino Uno]

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.

Any insight that anyone could provide in how to solve this problem would be greatly appreciated.

That is going to be hard, since you didn't post complete code.

Check the Arduino source main.cpp and wring.c,

Cheers!

I have provided the code below for your convenience on what is done within the initialize_timer() function.

#include "Timer.h"

void (*timer_0_callback) (void);

Error initialize_timer(Timer_Config config) {
	Error return_code = ERR_NO_ERR;
	uint16_t period;
	
	switch(config.which_timer)
	{
		case TIMER_0:
			TCCR0B &= ~((1 << CS02)|(1 << CS01)|(1 << CS00)); //clear the clk prescaler bits
			//figure out the prescaler, set the period register
			if(config.frequency > (float)config.pbclk/(UINT8_MAX))
			{
				TCCR0B |= (1 << CS00);
				period = config.pbclk/(config.frequency*1);
			}
			else if(config.frequency > (float)config.pbclk/(UINT8_MAX*8))
			{
				TCCR0B |= (1 << CS01);
				period = config.pbclk/(config.frequency*8);
			}
			else if(config.frequency > (float)config.pbclk/(UINT8_MAX*64))
			{
				TCCR0B |= (1 << CS01)|(1 << CS00);
				period = config.pbclk/(config.frequency*64);
			}
			else if(config.frequency > (float)config.pbclk/(UINT8_MAX*256))
			{
				TCCR0B |= (1 << CS02);
				period = config.pbclk/(config.frequency*256);
			}
			else if(config.frequency > (float)config.pbclk/(UINT8_MAX*1024))
			{
				TCCR0B |= (1 << CS02)|(1 << CS00);
				period = config.pbclk/(config.frequency*1);
			}
			else
			{
				return ERR_BAD_CONFIG;
			}
			OCR0A = period;
			
			//set mode to CTC (WGM bits are 010)
			TCCR0B &= ~(1 << WGM02);
			TCCR0A |= (1 << WGM01);
			TCCR0A &= ~(1 << WGM00);

			if (config.callback != NULL) {			
				//setup interrupts
				TIMSK0 = (1 << OCIE0A);
				timer_0_callback = config.callback;
			}
			
			break;
		case TIMER_1:
			return ERR_BAD_CONFIG;
			break;
		case TIMER_2:
			return ERR_BAD_CONFIG;
			break;
		default:
			//error?
			return_code = ERR_BAD_CONFIG;
			break;
		
	}
	
	return return_code;
}

ISR(TIMER0_COMPA_vect)
{
	if (timer_0_callback != NULL) 
	{
		timer_0_callback();
	}
}

Here is the source for Timer.h:

typedef enum
{
	TIMER_0,
	TIMER_1,
	TIMER_2
	
} Timer_Type;


typedef struct TIMER_CONFIG
{
	Timer_Type which_timer;
	uint32_t frequency;
	uint32_t pbclk;
	void (*callback);
	uint8_t enabled;
} Timer_Config;

Error initialize_timer(Timer_Config config);

The other definitions are located within another header, but are not important. If you are interested, it is also available on the github links provided in the main post (include/System.h).

Essentially, the program works to figure out which clock divider it must select to attain the specified frequency with the highest amount of granularity. It then uses the decided clock division to create a period for the timer and utilizes OCAx to create a frequency as close as possible to the user requested frequency.

In reply to Kowalski:
Thanks for the links to those source files! I was previously looking at wiring.c, but couldn't find main.cpp for some reason. After searching through the code, it doesn't look like Arduino is overwriting the configuration, as setup() and loop() are both called after init(). I additionally did some testing by transmitting the configuration registers over UART to check if anything was being overwritten, but it looks like the clock prescalers and the period register are both what they are expected to be. Could this problem be occurring due to conflicting ISRs?

Thanks for the help Kowalski! You got me pointed in the right direction. For some reason, some of the (very limited?) configuration within the init() function of Arduino was causing the timer to malfunction. I attempted zero-ing out the configuration registers before passing them to my own configuration function, and normal expected behavior returned. Thanks for the help!