diff --git a/ov1_report/Abstract forslak K.txt b/ov1_report/Abstract forslak K.txt deleted file mode 100644 index cbfe68f..0000000 --- a/ov1_report/Abstract forslak K.txt +++ /dev/null @@ -1 +0,0 @@ -In this report, we discuss and describe the first exercise in the Energy efficient computer system cours. In this excercise we developed a simple program for an EFM32 Giant Gecko microcontroller. The program lets the user manipulate a row of LEDs using buttons on a game pad. Low energy modes and interrupts are used to reduce power consumption. \ No newline at end of file diff --git a/ov1_report/EoA b/ov1_report/EoA deleted file mode 100644 index be0801d..0000000 --- a/ov1_report/EoA +++ /dev/null @@ -1,14 +0,0 @@ -\section{Evaluation of Assignment} % (fold) -\label{sec:evaluation_of_assignment} - The assignment was a good introduction to using the EFM32GG board. The -compendium was easy to follow and made the task rather trivial. However the use -of the reference manual was tedious, as it was not always easy to look up the -information you actually needed. As an example we tried to find out how you -returned from the interrupt handler, looked at the quick reference and tried to -find the instruction there, but was unable to do so. You may be able to find it -in the 900 page reference manual, but trying to search through that manual for a -task like this should not be neccecary. In all I would say that the task itself -is a good introduction to the course, but even though you want us to look at the -reference manual, it should be for those things that it would be logical to look -up in the manual. - diff --git a/ov1_report/Introduction.txt b/ov1_report/Introduction.txt deleted file mode 100644 index 6f3264b..0000000 --- a/ov1_report/Introduction.txt +++ /dev/null @@ -1,5 +0,0 @@ -A microcontroller is a CPU with the most necessary components included on the same silicon dye, i.e. the flexible GPIO I/O controller. The purpose of this integration is to allow for more minimal and energy efficient designs. The GPIO controller is included in the EFM32GG microcontroller and is essential for this exercise. - -An import aspect of this exercise is to use interrupts for controlling the buttons on the game pad. An interrupt, in contrast to continuously polling the I/O, allows the CPU to enter a low power state if there is no work to be done. The interrupt will then awake the CPU and start the necessary interrupt handler routine. - -For the exercise we were given access to an EFM32GG-DK3750 development board with an ARM Cortex M3 based EFM32GG microcontroller. We were also given access to a custom peripheral game pad, with buttons and LEDs, for the development board. For this microcontroller, we were expected to write a small program in the assembly programming language. The program should allow a user to use the buttons on the game pad to control the LEDs. The program should do this while using as little energy as possible. \ No newline at end of file diff --git a/ov1_report/report.tex b/ov1_report/report.tex index f528412..2c471f6 100644 --- a/ov1_report/report.tex +++ b/ov1_report/report.tex @@ -1,3 +1,4 @@ + \documentclass[a4paper, 12pt]{article} \usepackage{graphicx} \title{Exercise 1, Group 2 \\ TDT4258 \\ Energy Efficient Computer Systems} @@ -5,18 +6,21 @@ \begin{document} \maketitle \begin{abstract} -In this report, we describe and discuss the first exercise in the Energy efficient computer systems course. In this excercise we developed a simple program for an EFM32 Giant Gecko microcontroller. The program lets the user manipulate a row of LEDs (light emitting diodes) using buttons on a game pad. Low energy modes and interrupts are used to reduce power consumption. + In this report, we describe and discuss the first exercise in the Energy efficient computer systems course. In this excercise we developed a simple program for an EFM32 Giant Gecko microcontroller. The program lets the user manipulate a row of LEDs (light emitting diodes) using buttons on a game pad. Low energy modes and interrupts are used to reduce power consumption. \end{abstract} +\pagebreak \section{Introduction} % (fold) \label{sec:introduction} - A microcontroller is a CPU with the most necessary components included on the same silicon dye, i.e. the flexible GPIO I/O controller. The purpose of this integration is to allow for more minimal and energy efficient designs. The GPIO controller is included in the EFM32GG microcontroller and is essential for this exercise. - An import aspect of this exercise is to use interrupts for controlling the buttons on the game pad. An interrupt, in contrast to continuously polling the I/O, allows the CPU to enter a low power state if there is no work to be done. The interrupt will then awake the CPU and start the necessary interrupt handler routine. + A microcontroller is a CPU with the most necessary components included on the same silicon die, i.e. the flexible GPIO I/O controller. The purpose of this integration is to allow for more minimal and energy efficient designs. The GPIO controller is included in the EFM32GG microcontroller and is essential for this exercise. + + An important aspect of this exercise is to use interrupts for controlling the buttons on the game pad. An interrupt, in contrast to continuously polling the I/O, allows the CPU to enter a low power state if there is no work to be done. The interrupt will then awake the CPU and start the necessary interrupt handler routine. + For the exercise we were given access to an EFM32GG-DK3750 development board with an ARM Cortex M3 based EFM32GG microcontroller. We were also given access to a custom peripheral game pad, with buttons and LEDs, for the development board. For this microcontroller, we were expected to write a small program in the assembly programming language. The program should allow a user to use the buttons on the game pad to control the LEDs. The program should do this while using as little energy as possible. % section introduction (end) \section{Description and Methodology} % (fold) \label{sec:description_and_methodology} - \subsection{Description of Program} % (fold) + \subsection{Description of the Program} % (fold) \label{sub:description_of_program} The functionality of the program is very simple. A single LED will be lit on the gamepad, and the user can press button 1 and 3 (``left'' and ``right'') to move the light left or right. @@ -54,13 +58,19 @@ \section{Results and Tests} % (fold) \label{sec:results_and_tests} \subsection{Functional Tests} % (fold) \label{sub:functional_tests} + \begin{figure}[!ht] + \centerline{\includegraphics[width=0.7\textwidth]{IMG064}} + \centerline{\includegraphics[width=0.7\textwidth]{IMG065}} + \caption{Pressing the buttons makes the light move.} + \label{fig:buttons} + \end{figure} \begin{enumerate} \item Pressing the left (button 1) or right (button 3) buttons should make the light move left or right, respectively. \\ Result: It does. \item The buttons should not glitch, i.e. a press should not be registered twice.\\ Result: This did happen occasionally. \end{enumerate} - For the last one, our theory is that the built-in glitch filter in the EFM32GG has a period that is too short (typically 10-50ns according to the data sheet). Since it is implemented in hardware, this period isn't user configurable. + For the last one, our theory is that the built-in glitch filter in the EFM32GG has a period that is too short (10-50ns according to the data sheet). Since it is implemented in hardware, this period isn't user configurable. % subsection functional_tests (end) \subsection{Power Consumption} % (fold) @@ -70,7 +80,7 @@ \section{Results and Tests} % (fold) \caption{eaProfiler graph showing power consumption} \label{fig:profiler} \end{figure} - The graph in Figure \ref{fig:profiler} shows the difference in power consumption for one button pressed and no buttons pressed. When no buttons are pressed, the power consumption is very low, only 5.54 $\mu$ W. When a button is pressed, the power consumption increases considerably. Note that this is due to current flowing through the switch to ground, not because the MCU is running all the time. + The graph in Figure \ref{fig:profiler} shows the difference in power consumption for one button pressed and no buttons pressed. When no buttons are pressed, the power consumption is very low, only 5.54 $\mu$W. When a button is pressed, the power consumption increases considerably. Note that this is due to current flowing through the switch to ground, not because the MCU is running all the time. Also note that the LED is not included in the calculation, because it would dwarf everything else. % subsection power_consumption (end) @@ -78,7 +88,7 @@ \section{Results and Tests} % (fold) \section{Evaluation of Assignment} % (fold) \label{sec:evaluation_of_assignment} -The assignment was a good introduction to using the EFM32GG microcontroller. The compendium was easy to follow and made the task manageable. However the use of the reference manual was tedious, as it was not always easy to look up the information you actually needed. As an example we tried to find out how to return from the interrupt handler; looking at the quick reference and tried to find the instruction there, but were unable to do so. You may be able to find it in the 900 page reference manual, but trying to search through the manual for a task like this should not be necessary. Even though you want us to look at the reference manual, it should be for those things that we could realistically be expected to find there. Other than this, the exercise served as a good introduction to the course. + The assignment was a good introduction to using the EFM32GG microcontroller. The compendium was easy to follow and made the task manageable. However the use of the reference manual was tedious, as it was not always easy to look up the information you actually needed. As an example we tried to find out how to return from the interrupt handler; looking at the quick reference and tried to find the instruction there, but were unable to do so. You may be able to find it in the 900 page reference manual, but trying to search through the manual for a task like this should not be necessary. Even though you want us to look at the reference manual, it should be for those things that we could realistically be expected to find there. Other than this, the exercise served as a good introduction to the course. % section evaluation_of_assignment (end) \section{Conclusion} % (fold) @@ -88,6 +98,11 @@ \section{Conclusion} % (fold) \section{References} % (fold) \label{sec:references} - + \begin{itemize} + \item TDT4258 Exercise Compendium, from the course pages on It's Learning. + \item ARM Thumb-2 Quick Reference, from the course pages on It's Learning. + \item EFM32GG990 Datasheet, \\ + \textit{http://cdn.energymicro.com/dl/devices/pdf/d0046\_efm32gg990\_datasheet.pdf} + \end{itemize} % section references (end) \end{document} \ No newline at end of file diff --git a/ov2_code/Makefile b/ov2_code/Makefile new file mode 100644 index 0000000..211b474 --- /dev/null +++ b/ov2_code/Makefile @@ -0,0 +1,29 @@ +# Example Makefile +# +# Exercise 2, TDT4258 + +CC=arm-none-eabi-gcc +LD=arm-none-eabi-gcc +OBJCOPY=arm-none-eabi-objcopy + +CFLAGS=-mcpu=cortex-m3 -mthumb -g -std=c99 -Wall +LDFLAGS=-mcpu=cortex-m3 -mthumb -g -lgcc -lc -lcs3 -lcs3unhosted -lefm32gg -Llib +ASFLAGS=-mcpu=cortex-m3 -mthumb -g +LINKERSCRIPT=lib/efm32gg.ld + +ex2.bin : ex2.elf + ${OBJCOPY} -O binary $< $@ + +ex2.elf : ex2.o timer.o dac.o gpio.o interrupt_handlers.o + ${LD} -T ${LINKERSCRIPT} $^ -o $@ ${LDFLAGS} + +%.o : %.c + ${CC} ${CFLAGS} -c $< -o $@ + +.PHONY : upload +upload : + -eACommander.sh -r --address 0x00000000 -f "ex2.bin" -r + +.PHONY : clean +clean : + -rm -rf *.o *.elf *.bin *.hex diff --git a/ov2_code/dac.c b/ov2_code/dac.c new file mode 100644 index 0000000..9580dca --- /dev/null +++ b/ov2_code/dac.c @@ -0,0 +1,22 @@ +#include +#include + +#include "efm32gg.h" +#include "ex2.h" + +void setupDAC() +{ + /* + TODO enable and set up the Digital-Analog Converter + + 1. Enable the DAC clock by setting bit 17 in CMU_HFPERCLKEN0 + 2. Prescale DAC clock by writing 0x50010 to DAC0_CTRL + 3. Enable left and right audio channels by writing 1 to DAC0_CH0CTRL and DAC0_CH1CTRL + 4. Write a continuous stream of samples to the DAC data registers, DAC0_CH0DATA and DAC0_CH1DATA, for example from a timer interrupt + */ + + *CMU_HFPERCLKEN0 |= CMU2_HFPERCLKEN0_DAC0; + *DAC0_CTRL = 0x50010; + *DAC0_CH0CTRL = 1; + *DAC0_CH1CTRL = 1; +} diff --git a/ov2_code/efm32gg.h b/ov2_code/efm32gg.h new file mode 100644 index 0000000..8731123 --- /dev/null +++ b/ov2_code/efm32gg.h @@ -0,0 +1,143 @@ +#include + +// GPIO + +#define GPIO_PA_BASE 0x40006000 +#define GPIO_PB_BASE 0x40006024 +#define GPIO_PC_BASE 0x40006048 + +#define GPIO_PA_CTRL ((volatile uint32_t*)(GPIO_PA_BASE + 0x00)) +#define GPIO_PA_MODEL ((volatile uint32_t*)(GPIO_PA_BASE + 0x04)) +#define GPIO_PA_MODEH ((volatile uint32_t*)(GPIO_PA_BASE + 0x08)) +#define GPIO_PA_DOUT ((volatile uint32_t*)(GPIO_PA_BASE + 0x0c)) +#define GPIO_PA_DOUTSET ((volatile uint32_t*)(GPIO_PA_BASE + 0x10)) +#define GPIO_PA_DOUTCLR ((volatile uint32_t*)(GPIO_PA_BASE + 0x14)) +#define GPIO_PA_DOUTTGL ((volatile uint32_t*)(GPIO_PA_BASE + 0x18)) +#define GPIO_PA_DIN ((volatile uint32_t*)(GPIO_PA_BASE + 0x1c)) +#define GPIO_PA_PINLOCKN ((volatile uint32_t*)(GPIO_PA_BASE + 0x20)) + +#define GPIO_PB_CTRL ((volatile uint32_t*)(GPIO_PB_BASE + 0x00)) +#define GPIO_PB_MODEL ((volatile uint32_t*)(GPIO_PB_BASE + 0x04)) +#define GPIO_PB_MODEH ((volatile uint32_t*)(GPIO_PB_BASE + 0x08)) +#define GPIO_PB_DOUT ((volatile uint32_t*)(GPIO_PB_BASE + 0x0c)) +#define GPIO_PB_DOUTSET ((volatile uint32_t*)(GPIO_PB_BASE + 0x10)) +#define GPIO_PB_DOUTCLR ((volatile uint32_t*)(GPIO_PB_BASE + 0x14)) +#define GPIO_PB_DOUTTGL ((volatile uint32_t*)(GPIO_PB_BASE + 0x18)) +#define GPIO_PB_DIN ((volatile uint32_t*)(GPIO_PB_BASE + 0x1c)) +#define GPIO_PB_PINLOCKN ((volatile uint32_t*)(GPIO_PB_BASE + 0x20)) + +#define GPIO_PC_CTRL ((volatile uint32_t*)(GPIO_PC_BASE + 0x00)) +#define GPIO_PC_MODEL ((volatile uint32_t*)(GPIO_PC_BASE + 0x04)) +#define GPIO_PC_MODEH ((volatile uint32_t*)(GPIO_PC_BASE + 0x08)) +#define GPIO_PC_DOUT ((volatile uint32_t*)(GPIO_PC_BASE + 0x0c)) +#define GPIO_PC_DOUTSET ((volatile uint32_t*)(GPIO_PC_BASE + 0x10)) +#define GPIO_PC_DOUTCLR ((volatile uint32_t*)(GPIO_PC_BASE + 0x14)) +#define GPIO_PC_DOUTTGL ((volatile uint32_t*)(GPIO_PC_BASE + 0x18)) +#define GPIO_PC_DIN ((volatile uint32_t*)(GPIO_PC_BASE + 0x1c)) +#define GPIO_PC_PINLOCKN ((volatile uint32_t*)(GPIO_PC_BASE + 0x20)) + +#define GPIO_EXTIPSELL ((volatile uint32_t*)(GPIO_PA_BASE + 0x100)) +#define GPIO_EXTIPSELH ((volatile uint32_t*)(GPIO_PA_BASE + 0x104)) +#define GPIO_EXTIRISE ((volatile uint32_t*)(GPIO_PA_BASE + 0x108)) +#define GPIO_EXTIFALL ((volatile uint32_t*)(GPIO_PA_BASE + 0x10c)) +#define GPIO_IEN ((volatile uint32_t*)(GPIO_PA_BASE + 0x110)) +#define GPIO_IFC ((volatile uint32_t*)(GPIO_PA_BASE + 0x11c)) + +// CMU + +#define CMU_BASE2 0x400c8000 + +#define CMU_HFPERCLKDIV ((volatile uint32_t*)(CMU_BASE2 + 0x008)) +#define CMU_HFCORECLKEN0 ((volatile uint32_t*)(CMU_BASE2 + 0x040)) +#define CMU_HFPERCLKEN0 ((volatile uint32_t*)(CMU_BASE2 + 0x044)) +#define CMU_CMD ((volatile uint32_t*)(CMU_BASE2 + 0x024)) + +#define CMU2_HFPERCLKEN0_DAC0 (1 << 17) +#define CMU2_HFPERCLKEN0_PRS (1 << 15) +#define CMU2_HFPERCLKEN0_GPIO (1 << 13) +#define CMU2_HFPERCLKEN0_TIMER1 (1 << 6) + +#define CMU_HFCORECLKEN0_DMA (1 << 0) + +// TIMER1 + +#define TIMER1_BASE 0x40010400 + +#define TIMER1_CMD ((volatile uint32_t*)(TIMER1_BASE + 0x04)) +#define TIMER1_IEN ((volatile uint32_t*)(TIMER1_BASE + 0x0c)) +#define TIMER1_IFC ((volatile uint32_t*)(TIMER1_BASE + 0x18)) +#define TIMER1_TOP ((volatile uint32_t*)(TIMER1_BASE + 0x1c)) +#define TIMER1_CNT ((volatile uint32_t*)(TIMER1_BASE + 0x24)) + +// NVIC + +#define ISER0 ((volatile uint32_t*)0xe000e100) +#define ISER1 ((volatile uint32_t*)0xe000e104) +#define ICER0 ((volatile uint32_t*)0xe000e180) +#define ICER1 ((volatile uint32_t*)0xe000e184) +#define ISPR0 ((volatile uint32_t*)0xe000e200) +#define ISPR1 ((volatile uint32_t*)0xe000e204) +#define ICPR0 ((volatile uint32_t*)0xe000e280) +#define ICPR1 ((volatile uint32_t*)0xe000e284) +#define IABR0 ((volatile uint32_t*)0xe000e300) +#define IABR1 ((volatile uint32_t*)0xe000e304) + +// IPR + +#define IPR_BASE 0xe000e400 + +#define IPR0 ((volatile uint32_t*)(IPR_BASE + 0x00)) +#define IPR1 ((volatile uint32_t*)(IPR_BASE + 0x04)) +#define IPR2 ((volatile uint32_t*)(IPR_BASE + 0x08)) +#define IPR3 ((volatile uint32_t*)(IPR_BASE + 0x0c)) + +// EMU + +#define EMU_BASE2 0x400c6000 + +#define EMU_CTRL ((volatile uint32_t*)(EMU_BASE2 + 0x000)) + +// DAC0 + +#define DAC0_BASE2 0x40004000 + +#define DAC0_CTRL ((volatile uint32_t*)(DAC0_BASE2 + 0x000)) +#define DAC0_CH0CTRL ((volatile uint32_t*)(DAC0_BASE2 + 0x008)) +#define DAC0_CH1CTRL ((volatile uint32_t*)(DAC0_BASE2 + 0x00c)) +#define DAC0_IEN ((volatile uint32_t*)(DAC0_BASE2 + 0x010)) +#define DAC0_IF ((volatile uint32_t*)(DAC0_BASE2 + 0x014)) +#define DAC0_IFS ((volatile uint32_t*)(DAC0_BASE2 + 0x018)) +#define DAC0_IFC ((volatile uint32_t*)(DAC0_BASE2 + 0x01c)) +#define DAC0_CH0DATA ((volatile uint32_t*)(DAC0_BASE2 + 0x020)) +#define DAC0_CH1DATA ((volatile uint32_t*)(DAC0_BASE2 + 0x024)) +#define DAC0_COMBDATA ((volatile uint32_t*)(DAC0_BASE2 + 0x028)) + +// DMA + +#define DMA_BASE 0x400c2000 + +#define DMA_STATUS ((volatile uint32_t*)(DMA_BASE + 0x0000)) +#define DMA_CONFIG ((volatile uint32_t*)(DMA_BASE + 0x0004)) +#define DMA_CTRLBASE ((volatile uint32_t*)(DMA_BASE + 0x0008)) +#define DMA_ALTCTRLBASE ((volatile uint32_t*)(DMA_BASE + 0x000c)) +#define DMA_CHUSEBURSTS ((volatile uint32_t*)(DMA_BASE + 0x0018)) +#define DMA_CHUSEBURSTC ((volatile uint32_t*)(DMA_BASE + 0x001c)) +#define DMA_REQMASKC ((volatile uint32_t*)(DMA_BASE + 0x0024)) +#define DMA_CHENS ((volatile uint32_t*)(DMA_BASE + 0x0028)) +#define DMA_CHALTC ((volatile uint32_t*)(DMA_BASE + 0x0034)) +#define DMA_IFC ((volatile uint32_t*)(DMA_BASE + 0x1008)) +#define DMA_IEN ((volatile uint32_t*)(DMA_BASE + 0x100c)) +#define DMA_CH0_CTRL ((volatile uint32_t*)(DMA_BASE + 0x1100)) + +// PRS + +#define PRS_BASE 0x400cc000 + +#define PRS_CH0_CTRL ((volatile uint32_t*)(PRS_BASE + 0x010)) + +// System Control Block + +#define SCR ((volatile uint32_t*)0xe000ed10) +#define SYSTICK_CTRL ((volatile uint32_t*)0xe000e010) +#define SYSTICK_LOAD ((volatile uint32_t*)0xe000e014) + diff --git a/ov2_code/ex2.c b/ov2_code/ex2.c new file mode 100644 index 0000000..7688679 --- /dev/null +++ b/ov2_code/ex2.c @@ -0,0 +1,100 @@ +#include +#include + +#include "efm32gg.h" +#include "ex2.h" + +/* + TODO calculate the appropriate sample period for the sound wave(s) + you want to generate. The core clock (which the timer clock is derived + from) runs at 14 MHz by default. Also remember that the timer counter + registers are 16 bits. +*/ +/* The period between sound samples, in clock cycles */ +#define SAMPLE_PERIOD 0 + +/* Your code will start executing here */ +int main(void) +{ + /* Call the peripheral setup functions */ + setupGPIO(); + setupDAC(); + setupTimer(SAMPLE_PERIOD); + + /* Enable interrupt handling */ + setupNVIC(); + + /* TODO for higher energy efficiency, sleep while waiting for interrupts + instead of infinite loop for busy-waiting + */ + while(1); + + return 0; +} + +void setupNVIC() +{ + /* TODO use the NVIC ISERx registers to enable handling of interrupt(s) + remember two things are necessary for interrupt handling: + - the peripheral must generate an interrupt signal + - the NVIC must be configured to make the CPU handle the signal + You will need TIMER1, GPIO odd and GPIO even interrupt handling for this + assignment. + */ +} + +/* if other interrupt handlers are needed, use the following names: + NMI_Handler + HardFault_Handler + MemManage_Handler + BusFault_Handler + UsageFault_Handler + Reserved7_Handler + Reserved8_Handler + Reserved9_Handler + Reserved10_Handler + SVC_Handler + DebugMon_Handler + Reserved13_Handler + PendSV_Handler + SysTick_Handler + DMA_IRQHandler + GPIO_EVEN_IRQHandler + TIMER0_IRQHandler + USART0_RX_IRQHandler + USART0_TX_IRQHandler + USB_IRQHandler + ACMP0_IRQHandler + ADC0_IRQHandler + DAC0_IRQHandler + I2C0_IRQHandler + I2C1_IRQHandler + GPIO_ODD_IRQHandler + TIMER1_IRQHandler + TIMER2_IRQHandler + TIMER3_IRQHandler + USART1_RX_IRQHandler + USART1_TX_IRQHandler + LESENSE_IRQHandler + USART2_RX_IRQHandler + USART2_TX_IRQHandler + UART0_RX_IRQHandler + UART0_TX_IRQHandler + UART1_RX_IRQHandler + UART1_TX_IRQHandler + LEUART0_IRQHandler + LEUART1_IRQHandler + LETIMER0_IRQHandler + PCNT0_IRQHandler + PCNT1_IRQHandler + PCNT2_IRQHandler + RTC_IRQHandler + BURTC_IRQHandler + CMU_IRQHandler + VCMP_IRQHandler + LCD_IRQHandler + MSC_IRQHandler + AES_IRQHandler + EBI_IRQHandler + EMU_IRQHandler +*/ diff --git a/ov2_code/ex2.h b/ov2_code/ex2.h new file mode 100644 index 0000000..2f5bcfa --- /dev/null +++ b/ov2_code/ex2.h @@ -0,0 +1,10 @@ +#ifndef _EX2_H +#define _EX2_H + +/* Declaration of peripheral setup functions */ +void setupTimer(uint16_t period); +void setupDAC(); +void setupNVIC(); +void setupGPIO(); + +#endif \ No newline at end of file diff --git a/ov2_code/gpio.c b/ov2_code/gpio.c new file mode 100644 index 0000000..e23e00e --- /dev/null +++ b/ov2_code/gpio.c @@ -0,0 +1,22 @@ +#include +#include + +#include "efm32gg.h" +#include "ex2.h" + +/* function to set up GPIO mode and interrupts*/ +void setupGPIO() +{ + /* TODO set input and output pins for the joystick */ + + /* Example of HW access from C code: turn on joystick LEDs D4-D8 + check efm32gg.h for other useful register definitions + */ + *CMU_HFPERCLKEN0 |= CMU2_HFPERCLKEN0_GPIO; /* enable GPIO clock*/ + *GPIO_PA_CTRL = 2; /* set high drive strength */ + *GPIO_PA_MODEH = 0x55555555; /* set pins A8-15 as output */ + *GPIO_PA_DOUT = 0x0700; /* turn on LEDs D4-D8 (LEDs are active low) */ +} + + + diff --git a/ov2_code/interrupt_handlers.c b/ov2_code/interrupt_handlers.c new file mode 100644 index 0000000..95fe2e6 --- /dev/null +++ b/ov2_code/interrupt_handlers.c @@ -0,0 +1,26 @@ +#include +#include + +#include "efm32gg.h" +#include "ex2.h" + +/* TIMER1 interrupt handler */ +void __attribute__ ((interrupt)) TIMER1_IRQHandler() +{ + /* + TODO feed new samples to the DAC + remember to clear the pending interrupt by writing 1 to TIMER1_IFC + */ +} + +/* GPIO even pin interrupt handler */ +void __attribute__ ((interrupt)) GPIO_EVEN_IRQHandler() +{ + /* TODO handle button pressed event, remember to clear pending interrupt */ +} + +/* GPIO odd pin interrupt handler */ +void __attribute__ ((interrupt)) GPIO_ODD_IRQHandler() +{ + /* TODO handle button pressed event, remember to clear pending interrupt */ +} diff --git a/ov2_code/lib/efm32gg.ld b/ov2_code/lib/efm32gg.ld new file mode 100644 index 0000000..82b5c26 --- /dev/null +++ b/ov2_code/lib/efm32gg.ld @@ -0,0 +1,210 @@ +/* Linker script for Energy Micro EFM32GG devices + * + * Version: Sourcery CodeBench Lite 2011.09-69 + * Support: https://support.codesourcery.com/GNUToolchain/ + * + * Copyright (c) 2007, 2008, 2009, 2010 CodeSourcery, Inc. + * + * The authors hereby grant permission to use, copy, modify, distribute, + * and license this software and its documentation for any purpose, provided + * that existing copyright notices are retained in all copies and that this + * notice is included verbatim in any distributions. No written agreement, + * license, or royalty fee is required for any of the authorized uses. + * Modifications to this software may be copyrighted by their authors + * and need not follow the licensing terms described here, provided that + * the new terms are clearly indicated on the first page of each file where + * they apply. + */ + +OUTPUT_FORMAT ("elf32-littlearm", "elf32-bigarm", "elf32-littlearm") +ENTRY(__cs3_reset) + + +MEMORY +{ + rom (rx) : ORIGIN = 0x00000000, LENGTH = 1048576 + ram (rwx) : ORIGIN = 0x20000000, LENGTH = 131072 +} + +/* These force the linker to search for particular symbols from + * the start of the link process and thus ensure the user's + * overrides are picked up + */ + +EXTERN(__cs3_reset __cs3_reset_em) +EXTERN(__cs3_start_asm _start) +EXTERN(__cs3_stack) +EXTERN(__cs3_reset) + +EXTERN(__cs3_interrupt_vector_em) +EXTERN(__cs3_start_c main __cs3_stack __cs3_heap_end) + +/* Provide fall-back values */ +PROVIDE(__cs3_heap_start = _end); +PROVIDE(__cs3_heap_end = __cs3_region_start_ram + __cs3_region_size_ram); +PROVIDE(__cs3_region_num = (__cs3_regions_end - __cs3_regions) / 20); +PROVIDE(__cs3_stack = __cs3_region_start_ram + __cs3_region_size_ram); + +SECTIONS +{ + .text : + { + CREATE_OBJECT_SYMBOLS + __cs3_region_start_rom = .; + *(.cs3.region-head.rom) + ASSERT (. == __cs3_region_start_rom, ".cs3.region-head.rom not permitted"); + __cs3_interrupt_vector = __cs3_interrupt_vector_em; + *(.cs3.interrupt_vector) + /* Make sure we pulled in an interrupt vector. */ + ASSERT (. != __cs3_interrupt_vector_em, "No interrupt vector"); + + PROVIDE(__cs3_reset = __cs3_reset_em); + *(.cs3.reset) + PROVIDE(__cs3_start_asm = _start); + + *(.text.cs3.init) + *(.text .text.* .gnu.linkonce.t.*) + *(.plt) + *(.gnu.warning) + *(.glue_7t) *(.glue_7) *(.vfp11_veneer) + + *(.ARM.extab* .gnu.linkonce.armextab.*) + *(.gcc_except_table) + } >rom + .eh_frame_hdr : ALIGN (4) + { + KEEP (*(.eh_frame_hdr)) + } >rom + .eh_frame : ALIGN (4) + { + KEEP (*(.eh_frame)) + } >rom + /* .ARM.exidx is sorted, so has to go in its own output section. */ + PROVIDE_HIDDEN (__exidx_start = .); + .ARM.exidx : + { + *(.ARM.exidx* .gnu.linkonce.armexidx.*) + } >rom + PROVIDE_HIDDEN (__exidx_end = .); + .rodata : ALIGN (4) + { + *(.rodata .rodata.* .gnu.linkonce.r.*) + + . = ALIGN(4); + KEEP(*(.init)) + + . = ALIGN(4); + __preinit_array_start = .; + KEEP (*(.preinit_array)) + __preinit_array_end = .; + + . = ALIGN(4); + __init_array_start = .; + KEEP (*(SORT(.init_array.*))) + KEEP (*(.init_array)) + __init_array_end = .; + + . = ALIGN(4); + KEEP(*(.fini)) + + . = ALIGN(4); + __fini_array_start = .; + KEEP (*(.fini_array)) + KEEP (*(SORT(.fini_array.*))) + __fini_array_end = .; + + . = ALIGN(0x4); + KEEP (*crtbegin.o(.ctors)) + KEEP (*(EXCLUDE_FILE (*crtend.o) .ctors)) + KEEP (*(SORT(.ctors.*))) + KEEP (*crtend.o(.ctors)) + + . = ALIGN(0x4); + KEEP (*crtbegin.o(.dtors)) + KEEP (*(EXCLUDE_FILE (*crtend.o) .dtors)) + KEEP (*(SORT(.dtors.*))) + KEEP (*crtend.o(.dtors)) + + . = ALIGN(4); + __cs3_regions = .; + LONG (0) + LONG (__cs3_region_init_ram) + LONG (__cs3_region_start_ram) + LONG (__cs3_region_init_size_ram) + LONG (__cs3_region_zero_size_ram) + __cs3_regions_end = .; + . = ALIGN (8); + *(.rom) + *(.rom.b .bss.rom) + _etext = .; + } >rom + /* __cs3_region_end_rom is deprecated */ + __cs3_region_end_rom = __cs3_region_start_rom + LENGTH(rom); + __cs3_region_size_rom = LENGTH(rom); + + .data : ALIGN (8) + { + __cs3_region_start_ram = .; + *(.cs3.region-head.ram) + KEEP(*(.jcr)) + *(.got.plt) *(.got) + *(.shdata) + *(.data .data.* .gnu.linkonce.d.*) + . = ALIGN (8); + *(.ram) + . = ALIGN (8); + _edata = .; + } >ram AT>rom + .bss : ALIGN (8) + { + *(.shbss) + *(.bss .bss.* .gnu.linkonce.b.*) + *(COMMON) + . = ALIGN (8); + *(.ram.b .bss.ram) + . = ALIGN (8); + _end = .; + __end = .; + } >ram + /* __cs3_region_end_ram is deprecated */ + __cs3_region_end_ram = __cs3_region_start_ram + LENGTH(ram); + __cs3_region_size_ram = LENGTH(ram); + __cs3_region_init_ram = LOADADDR (.data); + __cs3_region_init_size_ram = _edata - ADDR (.data); + __cs3_region_zero_size_ram = _end - _edata; + + .stab 0 (NOLOAD) : { *(.stab) } + .stabstr 0 (NOLOAD) : { *(.stabstr) } + /* DWARF debug sections. + * Symbols in the DWARF debugging sections are relative to + * the beginning of the section so we begin them at 0. + */ + /* DWARF 1 */ + .debug 0 : { *(.debug) } + .line 0 : { *(.line) } + /* GNU DWARF 1 extensions */ + .debug_srcinfo 0 : { *(.debug_srcinfo) } + .debug_sfnames 0 : { *(.debug_sfnames) } + /* DWARF 1.1 and DWARF 2 */ + .debug_aranges 0 : { *(.debug_aranges) } + .debug_pubnames 0 : { *(.debug_pubnames) } + /* DWARF 2 */ + .debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) } + .debug_abbrev 0 : { *(.debug_abbrev) } + .debug_line 0 : { *(.debug_line) } + .debug_frame 0 : { *(.debug_frame) } + .debug_str 0 : { *(.debug_str) } + .debug_loc 0 : { *(.debug_loc) } + .debug_macinfo 0 : { *(.debug_macinfo) } + /* DWARF 2.1 */ + .debug_ranges 0 : { *(.debug_ranges) } + /* SGI/MIPS DWARF 2 extensions */ + .debug_weaknames 0 : { *(.debug_weaknames) } + .debug_funcnames 0 : { *(.debug_funcnames) } + .debug_typenames 0 : { *(.debug_typenames) } + .debug_varnames 0 : { *(.debug_varnames) } + + .note.gnu.arm.ident 0 : { KEEP (*(.note.gnu.arm.ident)) } + .ARM.attributes 0 : { KEEP (*(.ARM.attributes)) } + /DISCARD/ : { *(.note.GNU-stack) } +} diff --git a/ov2_code/lib/libefm32gg.a b/ov2_code/lib/libefm32gg.a new file mode 100644 index 0000000..c09d380 Binary files /dev/null and b/ov2_code/lib/libefm32gg.a differ diff --git a/ov2_code/timer.c b/ov2_code/timer.c new file mode 100644 index 0000000..82956fc --- /dev/null +++ b/ov2_code/timer.c @@ -0,0 +1,22 @@ +#include +#include + +#include "efm32gg.h" +#include "ex2.h" + +/* function to setup the timer */ +void setupTimer(uint16_t period) +{ + /* + TODO enable and set up the timer + + 1. Enable clock to timer by setting bit 6 in CMU_HFPERCLKEN0 + 2. Write the period to register TIMER1_TOP + 3. Enable timer interrupt generation by writing 1 to TIMER1_IEN + 4. Start the timer by writing 1 to TIMER1_CMD + + This will cause a timer interrupt to be generated every (period) cycles. Remember to configure the NVIC as well, otherwise the interrupt handler will not be invoked. + */ +} + +