Commit 0913809d authored by spookysys's avatar spookysys

lf dag 2

parent 0cbb0c29
......@@ -28,7 +28,7 @@ int main(void)
//Set LED pins as output
PORTB.DIRSET = (1 << LED1) | (1 << LED2) | (1 << LED3);
//Because the LEDs are active low, we invert the output
//Because the LEDs are active low, we invert the output. This means high PWM value -> bright led
PORTB.PIN0CTRL |= (1 << PORT_INVEN_bp);
PORTB.PIN1CTRL |= (1 << PORT_INVEN_bp);
PORTB.PIN4CTRL |= (1 << PORT_INVEN_bp);
......@@ -38,19 +38,48 @@ int main(void)
PORTA.PIN6CTRL |= (1 << PORT_PULLUPEN_bp);
PORTA.PIN7CTRL |= (1 << PORT_PULLUPEN_bp);
//Set clock prescaler div256
TCA0.SINGLE.CTRLA |= (TCA_SINGLE_ENABLE_bm); //Enable timer
TCA0.SINGLE.CTRLB |= (0x05 << TCA_SINGLE_WGMODE0_bp); //Set mode to single slope
/*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.
*/
TCA0.SINGLE.CTRLB |= (TCA_SINGLE_CMP0EN_bm) | (TCA_SINGLE_CMP1EN_bm); //Enable the compare channels
//First, enable the timer
TCA0.SINGLE.CTRLA |= (TCA_SINGLE_ENABLE_bm);
//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.)
TCA0.SINGLE.PER = 0x0fff; //We set our top to have a sufficiently high frequency (Top at 16 bit (0xffff) ~25Hz, 12 bit (0x0fff) ~400Hz)
TCA0.SINGLE.CMP0 = 0x0000;
TCA0.SINGLE.CMP1 = 0x0fff;
//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
while(1){
/*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.
if (!(PORTA.IN & (1 << SW1))){
if(!SW1_pressed){
TCA0.SINGLE.CMP0 = (((TCA0.SINGLE.CMP0 << 1) + 1) & (0x0fff)); //Shift in a 1, and cut off excess to 12 bit
......@@ -63,6 +92,7 @@ int main(void)
SW1_pressed = false;
}
if (!(PORTA_IN & (1 << SW2))){
if(!SW2_pressed){
TCA0.SINGLE.CMP1 = (((TCA0.SINGLE.CMP1 << 1) + 1) & (0x0fff)); //Shift in a 1, and cut off excess to 12 bit
......
......@@ -12,8 +12,8 @@
#include <util/delay.h>
#include <avr/interrupt.h>
#define LED1 0 // port B, connected to WO0
#define LED2 1 // port B, connected to WO1
#define LED1 0 // port B
#define LED2 1 // port B
#define LED3 4 // Port B
......@@ -24,14 +24,24 @@ int main(void)
*/
PORTB.DIR = (1 << LED1) | (1 << LED2);
PORTB.OUTTGL = (1 << LED1); //Only to start with LEDs off
PORTB.OUTTGL = (1 << LED1); //Starting with only 1 LED on
//We will be using a timer overflow interupt with timer A
//We set the prescaler to clk=clk/256
/*We will be using timer A that will trigger an overflow interupt.
This is a 16 bit timer that can run in 2 modes
-single mode as 1 16-bit timer
-dual/split mode as 2 8-bit timers
We will be using single mode in this exercise.
Hint because the register names can be hard to understand:
TCA0.SINGLE.CTRLA addresses the control A register for timer A
First we set the prescaler to clk=clk/256 and enable the timer.
This is done by setting the right bits in the control A register.
*/
TCA0.SINGLE.CTRLA |= (TCA_SINGLE_CLKSEL_DIV256_gc) | (TCA_SINGLE_ENABLE_bm);
//Next we Enable timer interupts on overflow
//Next we Enable timer interupts on overflow on timer A
TCA0.SINGLE.INTCTRL |= (TCA_SINGLE_OVF_bm);
//Finally we have to set the max value of the timer, the top.
......@@ -50,9 +60,11 @@ int main(void)
}
ISR(TCA0_OVF_vect){
//Do something with the led(s), like toggle.
PORTB.OUTTGL = (1 << LED1) | (1 << LED2);
TCA0.SINGLE.INTFLAGS = ( TCA_SINGLE_OVF_bm); //Clear the interupt flag
//Clear the interrupt flag.
//If we do not clear the flag, we will instantly jump back into the ISR again
TCA0.SINGLE.INTFLAGS = ( TCA_SINGLE_OVF_bm);
}
\ No newline at end of file
......@@ -12,42 +12,61 @@
#include <avr/interrupt.h>
#include <util/delay.h>
/*
In this exercise we will set up and use UART communication.
The embedded debugger has a virtual com port that we will use to communicate with the computer.
*/
void uart_init(unsigned long baud){
//From chapter 24.3 in datasheet
PORTB.OUTSET = (1 << PIN2_bp);
PORTB.DIRSET = (1 << PIN2_bp); //Setting up TX pin as output
USART0.BAUDH = (baud >> 8); //Shift register right by 8 bits
USART0.BAUDL = baud; //Set baud rate
PORTB.OUTSET = (1 << PIN2_bp); //Setting the TX pin high
USART0.BAUDH = (baud >> 8); //Shift register right by 8 bits to get the 8 high bits
USART0.BAUDL = baud; //Set baud rate without shifting to get the 8 low bits
//It turns out the compiler can handle this automatically, meaning this works just as well:
//USART0.BAUD = baud;
//USART.CTRLC CMODE bits default to async, 1 stop bit, 8 bit character size
USART0.CTRLB |= (1 << USART_RXEN_bp) | (1 << USART_TXEN_bp); //Enable RX and TX
USART0.CTRLA |= (1 << USART_RXCIE_bp); //Enable interrupts on incomming data
USART0.CTRLA |= (1 << USART_RXCIE_bp); //Enable interrupts on incoming data
}
// function to transmit data
void uart_transmit(unsigned char data){
//In this function we will be send data.
//First we should check that there isn't already data being sent
// if there is, we should probably wait for it to finish first
while (!(USART0.STATUS & (1 << USART_DREIF_bp))){
//wait for previous transmit to finish
};
//Put our new data into se sending register
USART0.TXDATAL = data;
}
int main(void)
{
uart_init(BAUD_9600); //start uart with baudrate of 9600
//Initialize the UART with our function.
//We will be using a baudrate of 9600 (defined as BAUD_9600 at the top of the file)
uart_init(BAUD_9600);
sei(); //Important for anything here to work
sei(); //Enable inerrupt, important for anything here to work
while (1)
{
//Do nothing, interrupts handle everything
//We don't really need to do anything here.
//the ISR will handle receiving.
}
}
......@@ -55,6 +74,7 @@ int main(void)
//Interrupt service routine for the receiver.
ISR(USART0_RXC_vect){
//Read out the received data to a variable
uint8_t data = USART0_RXDATAL;
//Do things with data:
uart_transmit(data + 1); //Example: Shift all characters by one step A -> B, B -> C etc.
......
......@@ -22,12 +22,12 @@ int main(void)
/*We will be using timer A that will trigger an overflow interupt.
This is a 16 bit timer that can run in 2 modes
-sigle mode as 1 16-bit timer
-single mode as 1 16-bit timer
-dual/split mode as 2 8-bit timers
We will be using single mode in this exercise.
Hint because the register names can be hard to understand:
TCA0.SINGLE.CTRLA adresses the control A register for timer A
TCA0.SINGLE.CTRLA addresses the control A register for timer A
First we set the prescaler to clk=clk/256 and enable the timer.
This is done by setting the right bits in the control A register.
......@@ -58,7 +58,7 @@ ISR(TCA0_OVF_vect){
//Do something with the led(s), like toggle.
//Clear the interupt flag.
//Clear the interrupt flag.
//If we do not clear the flag, we will instantly jump back into the ISR again
}
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment