Code details - software PWM

Go To Last Post
7 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hello again ,

I'm making a software PWM program where I will be setting values in an array called "Led_intensity[8]"
and I have 8 led's which will glow according to the intensities .

Basically the way this works is that I have a timer .
And all 8 Pins start as high . And as the timer works its way to 255 , it turns of the leds according to their PWM intensity , but for that to work , the intensities have to first be sorted because the timer turns off the led with the smallest PWM value first and works its way up in an orderly fashion , setting the next OCR0 when a compare happens.
And when the timer overflows then it sets the whole PORT to high so the process can begin again.

The refresh frequency is set by the time that it takes the timer to overflow .
I'm running 8Mhz with a 256 prescaler on timer0.

The problem that i'm facing is that the program works for some values of the Led_intensity array , and bugs for other values .

Here is the sorting algorithm , I'm pretty sure it does its job correctly :

void Led_sorter()  // takes the  Led_intensity array and sorts it in rising magnitude into the Led_sorting_factor passing only the position , not the value
{
	for (int y=0; y<8;y++)
	{
		current_low = 256;
		
		for(int x = 0; x<8; x++)
		{
			if( (Led_intensity[x] < current_low) && (Led_sorting_mask[x] == 0))                                                   
			
			{ current_low = Led_intensity[x];   Led_sorting_factor[y] = x; }
			
			
		}
		
		Led_sorting_mask[Led_sorting_factor[y]] = 1; // value that has been sorted is marked so it is ignored in the next round
		
	}

	

All the arrays declared in this program are Global.
Is this a good way to do it ? Should I declare them volatile (I don't really know how to use volatile yet)

Here are the two ISR routines :

ISR(TIMER0_COMP_vect)
{
	
    clone_val = increment; 
	
	while(Led_intensity[Led_sorting_factor[clone_val]] == Led_intensity[Led_sorting_factor[clone_val + 1]])
	{
		clone_val ++;
	}
	
	increment = clone_val;
	increment ++;
	
	
	while(clone_val >= 0)
	{
		PORTB &= ~(1 << (Led_sorting_factor[clone_val])); 
		clone_val--;
	}
	
	
	
	OCR0 = Led_intensity[Led_sorting_factor[increment]];
	
	
	
	
}

ISR(TIMER0_OVF_vect)
{
	
	
	
	increment = 0; // reset the increment
	clone_val = 0;
	
	
	Led_sorter(); // sort the values 
	
	OCR0 = Led_intensity[Led_sorting_factor[0]]; // Setting PWM
	
	PORTB = 0xFF; // Turning on all outputs
	TCNT0 = 0;
	

}

Am I doing something in the ISR that should not be done?

Basically whenever a compare happens then the led with the smallest amount of PWM value gets turned off , in order of smallest to biggest . And then the next OCR0 value is set (inside the compare ISR )

Inside the ISR(TIMER0_COMP_vect) there is an algorithm which allows for duplicate values in the Led_instensity array .

The thing is that for a Led_intensity array of for example : int Led_intensity[8] = {27,25,100,14,254,2,79,16};
It works completely fine ,
but If I try to give it something like

Led_intensity[8] = {27,25,100,14,254,2,3,4};
where I have 3 consecutive values (2,3,4) , then the whole thing glitches .

Is there any way I can simulate this /debug my code?

I always read answers such as : Yes , use Atmel studio 6 simulator or 'debug your code' but I cannot find any tutorials on using Atmel studio 6 simulator and I've tried to do it bymyself and I have no idea what I'm doing :)

Also , are there dangers of using arrays and variables as global with ISR routines? That they might not get updated or something?

I have no idea if I have my optimizer activated in atmel studio 6 because I do not know how to access it.

Thanks in advance for the help

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Your codectakes time to execute, so for compare values that are close, by the time your code loads the next compare value, the timer has gone past already. You can avoid this by ensuring your compare values are not too close.

Your variables need to be declared volatile if they are shared between isrs and main line code. Volatile forces the compiler to always read and write the values from ram.
Clawson has written a tutorial on the importance of volatile and i wrote one on the traps when using interrupts.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Kartman wrote:
Your codectakes time to execute, so for compare values that are close, by the time your code loads the next compare value, the timer has gone past already. You can avoid this by ensuring your compare values are not too close.

Yes !! thats what I've been thinking :)
I've been using 8mhz and a prescaler of 256 , so I've been trying to connecting a 16mhz XTAL and prescaling the timer down to 1024 to give it a refresh rate of 60hz and enough clock cycles for the values that are close and it seems to be working fine so far..(thanks again to Clawson for the help on the XTAL)

What you said was my initial theory , but there was one thing that bugged me which caused me to discard it :

That thing was that , I was using a prescaler of 256 which meant that I had roughly 256 clock cycles to complete the code in the OCR0 ISR , but the thing is that it didn't look to me that the code in the ISR would need anywhere near 256 cycles . I tried simulating it , but I don't know how to do it and I couldn't find an explanation anywhere how to do simulate the code Until a breakpoint and calculate the clock cycles in AS 6.1

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

clawson wrote:
Kartman's tutorial:

https://www.avrfreaks.net/index.p...

My tutorial:

https://www.avrfreaks.net/index.p...

Very nice , thanks :) going to read it after dinner .

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Somewhat simpler sorting (replaces the mask array with a single value):

previous_low = -1;
for (int y = 0; y < 8; y++)
{
	current_low = 256;
	for (int x = 0; x < 8; x++)
	{
		if ( (Led_intensity[x] < current_low) && (Led_intensity[x] > previous_low) )
		{
			current_low = Led_intensity[x];
			Led_sorting_factor[y] = x;
		}
	}
	previous_low = current_low;
}

Regards,
Steve A.

The Board helps those that help themselves.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Koshchi wrote:
Somewhat simpler sorting (replaces the mask array with a single value):

previous_low = -1;
for (int y = 0; y < 8; y++)
{
	current_low = 256;
	for (int x = 0; x < 8; x++)
	{
		if ( (Led_intensity[x] < current_low) && (Led_intensity[x] > previous_low) )
		{
			current_low = Led_intensity[x];
			Led_sorting_factor[y] = x;
		}
	}
	previous_low = current_low;
}

Unfortunately this algorithm does not allow for duplicate values in the Led_intensity array.
It will skip them because the Previous_low will be the same as that value

This was actually very similar to my first version of the sorting algorithm but I had to remake it due to above mentioned reasons.
That's why I added a masking array which allows duplicate values.

Thanks for the input though!! much appreciated.