TechplexEngineer
4/23/2013 - 4:55 PM

lab10_DAC.s

	INCLUDE stm32l1xx_constants.s
	AREA lab10_DAC, CODE, READONLY
	EXPORT	__main
	

	IMPORT	SIN_LOOKUP
	ALIGN
	ENTRY

__main	FUNCTION
	;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
	; Enable HSI & set as system clock
	BL	HSI_SETUP
	;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
	; GPIO PA.4 and PA.5 as Analog
	BL	ANALOG_OUT_CONF
	;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
	; Configure TIM4 as Master Trigger
	BL	TIM4_CONFIG
	;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
	; Configure DAC (DAC_OUT1 = PA.4, DAC_OUT2 = PA.5)
	BL	DAC_CONFIG
	;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
	; NVIC Interrupt
	BL	TIM4_INT_CONF


stop	B stop
	ENDFUNC ; END MAIN
HSI_SETUP	FUNCTION
	;1. Turn on HSI (RCC_CR_HSION)
	LDR	r0, =(RCC_BASE+RCC_CR)
	LDR	r1, [r0]
	ORR	r1, r1, #RCC_CR_HSION
	STR	r1, [r0]			;v
	
	;2. Wait for HSI ready (RCC_CR_HSIRDY)
	LDR	r0, =(RCC_BASE+RCC_CR)
hsi_wait	LDR	r1, [r0]
	AND	r1, r1, #RCC_CR_HSIRDY
	CMP	r1, #0
	BLO	hsi_wait			;v
	
	;4. Select HSI as the system clock (RCC_CFGR_SW_HSI)
	; 00: MSI oscillator used as system clock
	; 01: HSI oscillator used as system clock RCC_CFGR_SW_HSI
	; 10: HSE oscillator used as system clock
	; 11: PLL used as system clock
	LDR	r0, =(RCC_BASE+RCC_CFGR)
	LDR	r1, [r0]
	BIC	r1, r1, #RCC_CFGR_SW
	ORR	r1, r1, #RCC_CFGR_SW_HSI
	STR	r1, [r0]			;v
	
	;2. Wait for HSI to be selected as system clock (RCC_CFGR_SWS_HSI)
	LDR	r0, =(RCC_BASE+RCC_CFGR)
hsi_wait1	LDR	r1, [r0]
	AND	r1, r1, #RCC_CFGR_SWS_HSI
	CMP	r1, #0
	BLO	hsi_wait1			;v?
	
	BX 	lr
	ENDFUNC

ANALOG_OUT_CONF	FUNCTION
	; Note: DAC_OUT1 = PA.4, DAC_OUT2 = PA.5
	; 1. Enable the clock of GPIO A (RCC_AHBENR_GPIOAEN)
	LDR	r0, =(RCC_BASE+RCC_AHBENR)
	LDR	r1, [r0]
	ORR	r1, r1, #RCC_AHBENR_GPIOAEN
	STR	r1, [r0]			;v
	; 2. Set PA.4 and PA.5 as Analog (GPIO_MODER):: Analog: 0b11
	LDR	r0, =(GPIOA_BASE+GPIO_MODER)
	LDR	r1, [r0]
	ORR	r1, r1, #(GPIO_MODER_MODER4 :OR: GPIO_MODER_MODER5)
	STR	r1, [r0]			;v?
	
	BX	lr
	ENDFUNC

TIM4_CONFIG	FUNCTION
	; 1. Enable the clock of TIM4 (RCC_APB1ENR_TIM4EN)
	LDR	r0, =(RCC_BASE+RCC_APB1ENR)
	LDR	r1, [r0]
	ORR	r1, r1, #RCC_APB1ENR_TIM4EN
	STR	r1, [r0]			;v
	; 2. Set the prescaler (TIM4->PSC)
	LDR	r0, =(TIM4_BASE+TIM_PSC)

	MOV	r1, #(18+1)
	STR	r1, [r0]			;v
	; 3. Set the auto reload value (TIM4->ARR)
	LDR	r0, =(TIM4_BASE+TIM_ARR)
	MOV	r1, #(65535)
	STR	r1, [r0]			;v
	; 4. Set the compare register (TIM4->CCR1)
	LDR	r0, =(TIM4_BASE+TIM_CCR1)
	LDR	r1, [r0]
	MOV	r1, #19
	STR	r1, [r0]			;v
	; 5. Set OC1M bits of TIM4->CCMR1 for Channel 1 to Toggle OC1REF when TIM4_CNT=TIM4_CCR1
	; 011: Toggle - OC1REF toggles when TIMx_CNT=TIMx_CCR1.			;@ WHY?
	LDR	r0, =(TIM4_BASE+TIM_CCMR1)
	LDR	r1, [r0]
	BIC	r1, r1, #TIM_CCMR1_OC1M
	ORR	r1, r1, #(TIM_CCMR1_OC1M_0 :OR: TIM_CCMR1_OC1M_1)
	STR	r1, [r0]			;v
	; 6. Enable compare output 1 (TIM_CCER_CC1E)
	LDR	r0, =(TIM4_BASE+TIM_CCER)
	LDR	r1, [r0]
	ORR	r1, r1, #TIM_CCER_CC1E
	STR	r1, [r0]			;v
	; 7. Enable the update (TIM_EGR_UG)
	LDR	r0, =(TIM4_BASE+TIM_EGR)
	LDR	r1, [r0]
	ORR	r1, r1, #TIM_EGR_UG
	STR	r1, [r0]			;This looks like it goes into the wrong reg...
	; 8. Clear the update flag (TIM_SR_UIF)
	LDR	r0, =(TIM4_BASE+TIM_SR)
	LDR	r1, [r0]
	BIC	r1, r1, #TIM_SR_UIF
	STR	r1, [r0]			;This cleared what we just did
	; 9. Enable the TIM4 interrupts (TIM_DIER_UIE, TIM_DIER_CC1IE)
	LDR	r0, =(TIM4_BASE+TIM_DIER)
	LDR	r1, [r0]
	ORR	r1, r1, #(TIM_DIER_UIE :OR: TIM_DIER_CC1IE)
	STR	r1, [r0]			;v
	; 10. Select the master mode as OC1REF signal is as trigger output TRGO (TIM_CR2_MMS)
	; 100: Compare - OC1REF signal is used as trigger output (TRGO)
	LDR	r0, =(TIM4_BASE+TIM_CR2)
	LDR	r1, [r0]
	BIC	r1, r1, #(TIM_CR2_MMS)
	ORR	r1, r1, #(TIM_CR2_MMS_2)
	STR	r1, [r0]			;v
	; 11. Enable the timer (TIM_CR1_CEN)
	LDR	r0, =(TIM4_BASE+TIM_CR1)
	LDR	r1, [r0]
	ORR	r1, r1, #(TIM_CR1_CEN)
	STR	r1, [r0]			;v
	
	BX 	lr
	ENDFUNC
	
DAC_CONFIG	FUNCTION
	; 1. Enable DAC clock (RCC_APB1ENR_DACEN)
	LDR	r0, =(RCC_BASE+RCC_APB1ENR)
	LDR	r1, [r0]
	ORR	r1, r1, #(RCC_APB1ENR_DACEN)
	STR	r1, [r0]			;v
	; 2. Enable DAC output buffer (DAC_CR_BOFF1, DAC_CR_BOFF2)
	LDR	r0, =(DAC_BASE+DAC_CR)
	LDR	r1, [r0]
	BIC	r1, r1, #(DAC_CR_BOFF1 :OR: DAC_CR_BOFF2)
	STR	r1, [r0]			;v
	; 3. Select TIM4 TRGO as trigger for both outputs (DAC_CR_TSEL1, DAC_CR_TSEL2)
	;DAC_CR_TSEL1 ||| 101: Timer 4 TRGO event
	LDR	r0, =(DAC_BASE+DAC_CR)
	LDR	r1, [r0]
	BIC	r1, r1, #(DAC_CR_TSEL1)
	ORR	r1, r1, #(DAC_CR_TSEL1_0 :OR: DAC_CR_TSEL1_2)
	STR	r1, [r0]			;v
	;DAC_CR_TSEL2 ||| 101: Timer 4 TRGO event
	LDR	r0, =(DAC_BASE+DAC_CR)
	LDR	r1, [r0]
	BIC	r1, r1, #(DAC_CR_TSEL2)
	ORR	r1, r1, #(DAC_CR_TSEL2_0 :OR: DAC_CR_TSEL2_2)
	STR	r1, [r0]			;v
	; 4. Enable DAC1 and DAC2 (DAC_CR_EN1, DAC_CR_EN2)
	LDR	r0, =(DAC_BASE+DAC_CR)
	LDR	r1, [r0]
	ORR	r1, r1, #(DAC_CR_EN1 :OR: DAC_CR_EN2)
	STR	r1, [r0]			;v
	
	BX	lr
	ENDFUNC
	
TIM4_INT_CONF FUNCTION
	; 1. Enable TIM4_IRQn
	LDR	r0, =NVIC_BASE
	LDR	r1, [r0, #NVIC_ISER0]
	ORR	r1, r1, #1<<TIM4_IRQn
	STR	r1, [r0, #NVIC_ISER0]
	; 2. Set priority for TIM4_IRQn
	; LDR	r3, =NVIC_BASE
	; ADD	r0, r3, #NVIC_IPR0
	; LDR	r1, [r0, #28]
	; BIC	r1, r1, #NVIC_IPR7_PRI_30
	; STR	r1, [r0, #28]

	BX	lr
	ENDFUNC
	
TIM4_IRQHandler FUNCTION
	EXPORT  TIM4_IRQHandler
	PUSH	{lr,r4-r6}

	
	LDR	r0, =(TIM4_BASE+TIM_SR)
	LDR	r0, [r0]
	AND	r1, r0, #TIM_SR_CC1IF
	CMP	r1, #0		; check if the CC1IF is set
	POPEQ	{pc,r4-r6}		; not the interrupt we want, exit out
	
	LDR	r0, =value
	LDR	r6, [r0]
	MOV	r0, #36		; should be 36
	MUL	r6, r6, r0		;r6 = counter * 36
	MOV	r0, #10
	UDIV	r6, r6, r0		; r6 = r6 / 10
	MOV	r0, r6
	BL	SIN_LOOKUP 		;r0 = x degrees lookup value
	MOV	r4, r0		;Save the A value
	; ADD	r6, r6, #1		;(counter *3) + 1
	; MOV	r0, r6
	; BL	SIN_LOOKUP 		;r0 = x degrees lookup value
	; MOV	r5, r0		;Save the B value
	
	; LDR	r0, =value
	; LDR	r6, [r0]
	; MOV	r1, #36		; should be 36
	; MUL	r6, r6, r1		; r6 = c*36
	
	; ;frac = mod(r6, 10) 
	; ;;x  = mod(x, 360);
	; MOV	r3, #10
	; UDIV	r1, r6, r3 		;r1 = Q
	; MLS	r6, r1, r3, r6 	;MLS{cond}  Rd, Rn, Rm, Ra ;;ra - rn*rm
	; ;r6 = frac 						;;should I be handling two decimal places?
	
	; SUB	r0, r5, r4		; r0 = B-A
	; MUL	r0, r0, r6		; r0 = (B-A)*frac
	; MOV	r1, #10
	; SDIV	r0, r0, r6		; r0 = [(B-A)*frac]/10
	; ADD	r0, r0, r4		; r0 = [(B-A)*frac]/10 + A
	; MOV	r4, r0
	
	; Increment the counter
	LDR	r1, =value
	LDR	r6, [r1]
	ADD	r6, r6, #1
	STR	r6, [r1]
	
	;Put r0 into the DAC's Conversion Register
	;DAC->DHR12RD = sin(v) << 16 | sin(v);
	;When using dual channels, the values stored in a shared register		
	ORR	r4, r4, r4, lsl #16	; r4 = r4|r4<<16 ;;for both channels
	LDR	r0, =(DAC_BASE + DAC_DHR12RD)
	STR	r4, [r0]
	
	
	; ADD	r6, r6, #3		;floor(3.6)
	; MOV	r0, r6
	; BL	SIN_LOOKUP 		;r0 = x degrees lookup value
	; MOV	r4, r0		;Save the A value
	; ADD	r6, r6, #1		;ceil(3.6)	
	; MOV	r0, r6
	; BL	SIN_LOOKUP
	; MOV	r5, r0		;Save the B value
	
	; SUB	r0, r5, r4		; r0 = B-A
	; MOV	r1, #6
	; MUL	r0, r0, r1		; r0 = (B-A)*6
	; MOV	r1, #10
	; SDIV	r0, r0, r1		; r0 = [(B-A)*6]/10
	; ADD	r0, r0, r4		; r0 = [(B-A)*6]/10 + A
	; ;Store the calculated value 	; this is going to accumulate error
	; LDR	r1, =value
	; STR	r0, [r1]
	; ;Put r0 into the DAC's Conversion Register
	; ;DAC->DHR12RD = sin(v) << 16 | sin(v);
	; ;When using dual channels, the values stored in a shared register
	; MOV	r4, r0		
	; ORR	r4, r4, r4, lsl #16	; r4 = r4|r4<<16 ;;for both channels
	; LDR	r0, =(DAC_BASE + DAC_DHR12RD)
	; STR	r4, [r0]	
	
	POP	{pc,r4-r6}
	ENDFUNC

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
	AREA	mydata, DATA
value	DCD 0
	END