main.c 6.05 KB
Newer Older
1
2
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
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
/**
 * \file
 *
 * \brief Empty user application template
 *
 */

/**
 * \mainpage User Application template doxygen documentation
 *
 * \par Empty user application template
 *
 * Bare minimum empty user application template
 *
 * \par Content
 *
 * -# Include the ASF header files (through asf.h)
 * -# "Insert system clock initialization code here" comment
 * -# Minimal main function that starts with a call to board_init()
 * -# "Insert application code here" comment
 *
 */

/*
 * Include header files for all drivers that have been imported from
 * Atmel Software Framework (ASF).
 */
/*
 * Support and FAQ: visit <a href="http://www.atmel.com/design-support/">Atmel Support</a>
 */
#include <asf.h>
#include "pin.h"
#include "tinyport.h"
#include "sinelut.h"

// status lights
pin_t stlb; // PA27
pin_t stlr; // PD13

// on and cal
pin_t enablepin;
pin_t dccalpin;

// uart port
tinyport_t tp3;

// All MK-PWMs are Peripheral B
// PWM0 is PID 31 position 31 in PCER0, PWM1 is PID 60, position 28 in PCER1
// PWM1L0: PD0
// PWM1H0: PD1
// PWM1L1: PD2
// PWM1H1: PD3
// PWM1L2: PD4
// PWM1H2: PD5

void startupflash(void){
	delay_ms(125);
	pin_clear(&stlb);
	pin_clear(&stlr);
	delay_ms(125);
	pin_set(&stlb);
	pin_set(&stlr);
	delay_ms(50);
	pin_clear(&stlb);
	pin_clear(&stlr);
	delay_ms(50);
	pin_set(&stlb);
	pin_set(&stlr);
	delay_ms(50);
	pin_clear(&stlb);
	pin_clear(&stlr);
	delay_ms(50);
	pin_set(&stlb);
	pin_set(&stlr);
	delay_ms(50);
	pin_clear(&stlb);
}

void setuppio(void){
	PMC->PMC_PCER0 = 1 << ID_PIOA;
	PMC->PMC_PCER0 = 1 << ID_PIOD;
}

void setuppwm(void){
	PMC->PMC_PCER1 = 1 << 28; // turn on peripheral clock for PWM 1
	// these are pins for channels 1, 2, 3 in lo / hi pairs
	PIOD->PIO_PDR = PIO_PER_P2 | PIO_PER_P3 | PIO_PER_P4 | PIO_PER_P5 | PIO_PER_P6 | PIO_PER_P7; // disable PIO
	PIOD->PIO_ABCDSR[0] = PIO_PER_P2 | PIO_PER_P3 | PIO_PER_P4 | PIO_PER_P5 | PIO_PER_P6 | PIO_PER_P7; // enable peripheral B
	//PIOD->PIO_ABCDSR[1] // already these are 0s, we want that [01] is peripheral B
	
	// PREA Clock is Peripheral Clock / 64
	// PREA Clock supplies Clock A, Clock A is PREA / 24
	// Clock B is off
	PWM1->PWM_CLK = PWM_CLK_PREA(2) | PWM_CLK_DIVA(7) | PWM_CLK_DIVB_CLKB_POFF;
	// Channel 0 uses CLCKA, uses Center Aligned, has dead time, is waveform aligned (with others?)
	PWM1->PWM_CH_NUM[1].PWM_CMR  = PWM_CMR_CPRE_CLKA | PWM_CMR_CES | PWM_CMR_DTE | PWM_CMR_CALG | PWM_CMR_CPOL;
	PWM1->PWM_CH_NUM[2].PWM_CMR  = PWM_CMR_CPRE_CLKA | PWM_CMR_CES | PWM_CMR_DTE | PWM_CMR_CALG | PWM_CMR_CPOL;
	PWM1->PWM_CH_NUM[3].PWM_CMR  = PWM_CMR_CPRE_CLKA | PWM_CMR_CES | PWM_CMR_DTE | PWM_CMR_CALG | PWM_CMR_CPOL;
	// Channel 0 uses this period
	// (2 * 2^PREA * DIVA * CPRD) / f_peripheralClock
	// so for 10kHz target frequency, we want 1 / 10000, 
	// have (2 * 64 * 12 * x )/ 150000000
	// ~ spreadsheets are your friends ~
	PWM1->PWM_CH_NUM[1].PWM_CPRD = PWM_CPRD_CPRD(255);
	PWM1->PWM_CH_NUM[2].PWM_CPRD = PWM_CPRD_CPRD(255);
	PWM1->PWM_CH_NUM[3].PWM_CPRD = PWM_CPRD_CPRD(255);
	// set duty cycle, initially, to low
	// this is between 0 and CPRD, so it looks like shooting for a big CPRD is (y)
	PWM1->PWM_CH_NUM[1].PWM_CDTY = PWM_CDTY_CDTY(1);
	PWM1->PWM_CH_NUM[2].PWM_CDTY = PWM_CDTY_CDTY(1);
	PWM1->PWM_CH_NUM[3].PWM_CDTY = PWM_CDTY_CDTY(1);
	// configure deadtime generator, between 0 and CPRD - CDTY
	PWM1->PWM_CH_NUM[1].PWM_DT = PWM_DT_DTH(2) | PWM_DT_DTL(2);
	PWM1->PWM_CH_NUM[2].PWM_DT = PWM_DT_DTH(2) | PWM_DT_DTL(2);
	PWM1->PWM_CH_NUM[3].PWM_DT = PWM_DT_DTH(2) | PWM_DT_DTL(2);
	// configure update mode
	// mode 1 is 'manual write of double buffer registers and automatic update of synchronous channels'
	// other modes are for manual write / manual  update and DMA mode
	// also add sync. channels - spec that 0, 1, 2 are ~ on the same wavelength, man ~
	PWM1->PWM_SCM = PWM_SCM_UPDM_MODE1;// | PWM_SCM_SYNC1 | PWM_SCM_SYNC2 | PWM_SCM_SYNC3;
	
	// now, boot it up
	PWM1->PWM_ENA = PWM_ENA_CHID1 | PWM_ENA_CHID2 | PWM_ENA_CHID3; // just channel 0 for now
}

void setupuart(void){
	// port 3
	// peripheral c
	// uart1
	// rx: pa5
	// tx: pa4
	
	PMC->PMC_PCER0 = 1 << ID_PIOA;
	PMC->PMC_PCER0 = 1 << ID_UART1; // UART1
	
	//tp3, uart1
	//PIOA->PIO_ABCDSR[0] = PIO_PER_P5;
	//PIOA->PIO_ABCDSR[0] = PIO_PER_P4;
	PIOA->PIO_ABCDSR[1] |= PIO_PER_P5;
	PIOA->PIO_ABCDSR[1] |= PIO_PER_P4;
}

void UART1_Handler(){
	if(UART1->UART_SR & UART_SR_RXRDY){
		uint8_t data = UART1->UART_RHR;
		while(!(UART1->UART_SR & UART_SR_TXRDY));
		UART1->UART_THR = data;
	} else {
		//
	}
}

int main (void)
{
	/* Insert system clock initialization code here (sysclk_init()). */

	board_init();
	sysclk_init();
	wdt_disable(WDT);
	
	setuppwm();
	
	setuppio();
	stlb = pin_new(PIOA, PIO_PER_P13);
	pin_output(&stlb);
	stlr = pin_new(PIOA, PIO_PER_P22);
	pin_output(&stlr);
	enablepin = pin_new(PIOA, PIO_PER_P23);
	pin_output(&enablepin);
	dccalpin = pin_new(PIOA, PIO_PER_P16);
	
	NVIC_DisableIRQ(UART1_IRQn);
	NVIC_ClearPendingIRQ(UART1_IRQn);
	NVIC_SetPriority(UART1_IRQn, 9);
	NVIC_EnableIRQ(UART1_IRQn);
	
	setupuart();
	tp3 = tinyport_new(UART1, PIOA, PERIPHERAL_C, PIO_PER_P5, PIO_PER_P4);
	tp_init(&tp3);
	
	startupflash();

	uint8_t scalar = 64; // 0 -> 255 (these will be chars from serial)
Jake Read's avatar
Jake Read committed
184
	uint8_t period = 20; // us between ++ in phase
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
	
	uint32_t phaseu = 0; // 0 -> 1023
	uint32_t phasev = 341; // advanced 120 degrees
	uint32_t phasew = 682; // advanced 240 degrees
	
	pin_set(&enablepin); // boot the gates
	
	while(1){
		// to update, must use duty update register, not just 'duty' 
		phaseu ++;
		phasev ++;
		phasew ++;
		if (phaseu > 1023){
			phaseu = 0;
		}
		if(phasev > 1023){
			phasev = 0;
		}
		if(phasew > 1023){
			phasew = 0;
		}

		PWM1->PWM_CH_NUM[1].PWM_CDTYUPD = PWM_CDTY_CDTY(sinelut[phaseu] * scalar / 255 + 4);
		PWM1->PWM_CH_NUM[2].PWM_CDTYUPD = PWM_CDTY_CDTY(sinelut[phasev] * scalar / 255 + 4);
		PWM1->PWM_CH_NUM[3].PWM_CDTYUPD = PWM_CDTY_CDTY(sinelut[phasew] * scalar / 255 + 4);
		
		delay_us(period * 10);
			
		if(pin_get_state(&stlr)){ // ? 
			pin_clear(&stlr);
		} else {
			pin_set(&stlr);
		}
		
		//tp_putchar(&tp3, 35); // http://www.asciitable.com/
	}
	/* Insert application code here, after the board has been initialized. */
}