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. */
}