PWM-LF.c 3.14 KB
Newer Older
Petter Breedveld's avatar
Petter Breedveld committed
1
/*
2
 * PWM-LF.c
Petter Breedveld's avatar
Petter Breedveld committed
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
 *
 * Created: 29.01.2017 23:43:39
 * Author : Petter
 */ 

#define F_CPU 3333333UL


#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>
#include <stdbool.h>

#define LED1 0 // port B, connected to WO0
#define LED2 1 // port B, connected to WO1
#define LED3 4 // Port B
#define SW1 5 // Port A
#define SW2 6 // Port A
#define SW3 7 // Port A


bool SW1_pressed,SW2_pressed; //Keeping track of button status

int main(void)
{
	//Set LED pins as output
29
	PORTB.DIRSET = (1 << LED1) | (1 << LED2) | (1 << LED3);
Petter Breedveld's avatar
Petter Breedveld committed
30
	
spookysys's avatar
spookysys committed
31
	//Because the LEDs are active low, we invert the output. This means high PWM value -> bright led
32
33
34
	PORTB.PIN0CTRL |= (1 << PORT_INVEN_bp);
	PORTB.PIN1CTRL |= (1 << PORT_INVEN_bp);
	PORTB.PIN4CTRL |= (1 << PORT_INVEN_bp);
Petter Breedveld's avatar
Petter Breedveld committed
35
36
	
	//Pullups
37
38
39
	PORTA.PIN5CTRL |= (1 << PORT_PULLUPEN_bp);
	PORTA.PIN6CTRL |= (1 << PORT_PULLUPEN_bp);
	PORTA.PIN7CTRL |= (1 << PORT_PULLUPEN_bp);	
Petter Breedveld's avatar
Petter Breedveld committed
40
	
spookysys's avatar
spookysys committed
41
42
43
44
45
	/*We will be using timer 1 in single (not split) mode.
	  It is highly recommended that you read chapter 20.3.3.4 in the datasheet 
	  on timer compare channels.
	  There you will find a sub-capter on the single-slope PWM we will be using.
	*/
Petter Breedveld's avatar
Petter Breedveld committed
46
	
spookysys's avatar
spookysys committed
47
48
	//First, enable the timer
	TCA0.SINGLE.CTRLA |= (TCA_SINGLE_ENABLE_bm); 
Petter Breedveld's avatar
Petter Breedveld committed
49
	
spookysys's avatar
spookysys committed
50
51
52
53
54
55
56
57
58
59
60
61
	//Set the mode of the timer to single slope PWM
	TCA0.SINGLE.CTRLB |= (0x03 << TCA_SINGLE_WGMODE0_bp);
	
	//We have to override the normal pin opperation so the PWM is pushed directly to the pin
	//Hint: WO0 and WO1 are connected to leds. We need to override them to get the PWM out.
	TCA0.SINGLE.CTRLB |= (TCA_SINGLE_CMP0EN_bm) | (TCA_SINGLE_CMP1EN_bm);
	
	/*Timer A is a 16 bit timer. This will give us a frequency of 25Hz, we can see it flicker.
	  By lowering the period, (PER) we get higher frequency at the cost of lower resolution.
	*/
	
	//Set the period to 12 bit. (This results in a frequency of ~400Hz.)
62
	TCA0.SINGLE.PER = 0x0fff; //We set our top to have a sufficiently high frequency (Top at 16 bit (0xffff) ~25Hz, 12 bit (0x0fff) ~400Hz)
spookysys's avatar
spookysys committed
63
64
65
66
	
	//We can now control the PWM duty cycle by simply writing values to the CMP0 and CMP1 registers.
	TCA0.SINGLE.CMP0 = 0x0000; //We have inverted the pin outputs so this is MIN
	TCA0.SINGLE.CMP1 = 0x0fff;	//We have inverted the pin outputs so this is MAX
Petter Breedveld's avatar
Petter Breedveld committed
67
68
69
70
	
	
    while(1){
		
spookysys's avatar
spookysys committed
71
72
73
74
75
76
77
78
79
80
81
82
		/*Have some fun with the leds. Examples:
		  Have them fade between max and min
		  Have them fade in a pattern (Heartbeat?) 
		  Change the brightness based on buttons

		*/
		
		//Here we use button pushes to shift the CMP register so we get brightness steps
		//adding and subtracting works just as well
		
		//It is largely up to the student to choose how the led brightness is changed.
		
83
		if (!(PORTA.IN & (1 << SW1))){
Petter Breedveld's avatar
Petter Breedveld committed
84
			if(!SW1_pressed){
85
86
				TCA0.SINGLE.CMP0 = (((TCA0.SINGLE.CMP0 << 1) + 1) & (0x0fff)); //Shift in a 1, and cut off excess to 12 bit
				TCA0.SINGLE.CMP1 >>= 1;
Petter Breedveld's avatar
Petter Breedveld committed
87
88
89
90
91
92
93
94
				SW1_pressed = true;
			}
		}
		
		else{
			SW1_pressed = false;
		}
		
spookysys's avatar
spookysys committed
95
		
Petter Breedveld's avatar
Petter Breedveld committed
96
97
		if (!(PORTA_IN & (1 << SW2))){
			if(!SW2_pressed){
98
99
				TCA0.SINGLE.CMP1 = (((TCA0.SINGLE.CMP1 << 1) + 1) & (0x0fff)); //Shift in a 1, and cut off excess to 12 bit
				TCA0.SINGLE.CMP0 >>= 1;
Petter Breedveld's avatar
Petter Breedveld committed
100
101
102
103
104
105
106
107
108
109
110
				SW2_pressed = true;
			}
		}
		
		else{
			SW2_pressed = false;
		}
		
    }
}