diff --git a/compile_commands.json b/compile_commands.json index a1775b4dd7edd23d0df2dc89570e3b5ee1905150..02f8d4eb769dd2a4bb7672c183bb5beb5c7d5cad 100644 --- a/compile_commands.json +++ b/compile_commands.json @@ -15,10 +15,10 @@ "-fstrict-overflow", "-Winline", "-o", - "_build/t01sk.o", - "t01sk.c" + "_build/main.o", + "main.c" ], - "directory": "/home/bradley/src/c/fortuna-tasks/task1", + "directory": "/home/bradley/src/c/fortuna-mines", "file": "t01sk.c" } ] diff --git a/lcd/font.h b/lcd/font.h new file mode 100644 index 0000000000000000000000000000000000000000..3f0a7c871bfe3bce56fc51235d2e9167dea8b87f --- /dev/null +++ b/lcd/font.h @@ -0,0 +1,104 @@ +/* Author: Steve Gunn + * Licence: This work is licensed under the Creative Commons Attribution License. + * View this license at http://creativecommons.org/about/licenses/ + */ + +#include <avr/pgmspace.h> + +const char font5x7[] PROGMEM = { + 0x00, 0x00, 0x00, 0x00, 0x00, // SPACE + 0x00, 0x00, 0x5F, 0x00, 0x00, // ! + 0x00, 0x03, 0x00, 0x03, 0x00, // " + 0x14, 0x3E, 0x14, 0x3E, 0x14, // # + 0x24, 0x2A, 0x7F, 0x2A, 0x12, // $ + 0x43, 0x33, 0x08, 0x66, 0x61, // % + 0x36, 0x49, 0x55, 0x22, 0x50, // & + 0x00, 0x05, 0x03, 0x00, 0x00, // ' + 0x00, 0x1C, 0x22, 0x41, 0x00, // ( + 0x00, 0x41, 0x22, 0x1C, 0x00, // ) + 0x14, 0x08, 0x3E, 0x08, 0x14, // * + 0x08, 0x08, 0x3E, 0x08, 0x08, // + + 0x00, 0x50, 0x30, 0x00, 0x00, // , + 0x08, 0x08, 0x08, 0x08, 0x08, // - + 0x00, 0x60, 0x60, 0x00, 0x00, // . + 0x20, 0x10, 0x08, 0x04, 0x02, // / + 0x3E, 0x51, 0x49, 0x45, 0x3E, // 0 + 0x00, 0x04, 0x02, 0x7F, 0x00, // 1 + 0x42, 0x61, 0x51, 0x49, 0x46, // 2 + 0x22, 0x41, 0x49, 0x49, 0x36, // 3 + 0x18, 0x14, 0x12, 0x7F, 0x10, // 4 + 0x27, 0x45, 0x45, 0x45, 0x39, // 5 + 0x3E, 0x49, 0x49, 0x49, 0x32, // 6 + 0x01, 0x01, 0x71, 0x09, 0x07, // 7 + 0x36, 0x49, 0x49, 0x49, 0x36, // 8 + 0x26, 0x49, 0x49, 0x49, 0x3E, // 9 + 0x00, 0x36, 0x36, 0x00, 0x00, // : + 0x00, 0x56, 0x36, 0x00, 0x00, // ; + 0x08, 0x14, 0x22, 0x41, 0x00, // < + 0x14, 0x14, 0x14, 0x14, 0x14, // = + 0x00, 0x41, 0x22, 0x14, 0x08, // > + 0x02, 0x01, 0x51, 0x09, 0x06, // ? + 0x3E, 0x41, 0x59, 0x55, 0x5E, // @ + 0x7E, 0x09, 0x09, 0x09, 0x7E, // A + 0x7F, 0x49, 0x49, 0x49, 0x36, // B + 0x3E, 0x41, 0x41, 0x41, 0x22, // C + 0x7F, 0x41, 0x41, 0x41, 0x3E, // D + 0x7F, 0x49, 0x49, 0x49, 0x41, // E + 0x7F, 0x09, 0x09, 0x09, 0x01, // F + 0x3E, 0x41, 0x41, 0x49, 0x3A, // G + 0x7F, 0x08, 0x08, 0x08, 0x7F, // H + 0x00, 0x41, 0x7F, 0x41, 0x00, // I + 0x30, 0x40, 0x40, 0x40, 0x3F, // J + 0x7F, 0x08, 0x14, 0x22, 0x41, // K + 0x7F, 0x40, 0x40, 0x40, 0x40, // L + 0x7F, 0x02, 0x0C, 0x02, 0x7F, // M + 0x7F, 0x02, 0x04, 0x08, 0x7F, // N + 0x3E, 0x41, 0x41, 0x41, 0x3E, // O + 0x7F, 0x09, 0x09, 0x09, 0x06, // P + 0x1E, 0x21, 0x21, 0x21, 0x5E, // Q + 0x7F, 0x09, 0x09, 0x09, 0x76, // R + 0x26, 0x49, 0x49, 0x49, 0x32, // S + 0x01, 0x01, 0x7F, 0x01, 0x01, // T + 0x3F, 0x40, 0x40, 0x40, 0x3F, // U + 0x1F, 0x20, 0x40, 0x20, 0x1F, // V + 0x7F, 0x20, 0x10, 0x20, 0x7F, // W + 0x41, 0x22, 0x1C, 0x22, 0x41, // X + 0x07, 0x08, 0x70, 0x08, 0x07, // Y + 0x61, 0x51, 0x49, 0x45, 0x43, // Z + 0x00, 0x7F, 0x41, 0x00, 0x00, // [ + 0x02, 0x04, 0x08, 0x10, 0x20, // slash + 0x00, 0x00, 0x41, 0x7F, 0x00, // ] + 0x04, 0x02, 0x01, 0x02, 0x04, // ^ + 0x40, 0x40, 0x40, 0x40, 0x40, // _ + 0x00, 0x01, 0x02, 0x04, 0x00, // ` + 0x20, 0x54, 0x54, 0x54, 0x78, // a + 0x7F, 0x44, 0x44, 0x44, 0x38, // b + 0x38, 0x44, 0x44, 0x44, 0x44, // c + 0x38, 0x44, 0x44, 0x44, 0x7F, // d + 0x38, 0x54, 0x54, 0x54, 0x18, // e + 0x04, 0x04, 0x7E, 0x05, 0x05, // f + 0x08, 0x54, 0x54, 0x54, 0x3C, // g + 0x7F, 0x08, 0x04, 0x04, 0x78, // h + 0x00, 0x44, 0x7D, 0x40, 0x00, // i + 0x20, 0x40, 0x44, 0x3D, 0x00, // j + 0x7F, 0x10, 0x28, 0x44, 0x00, // k + 0x00, 0x41, 0x7F, 0x40, 0x00, // l + 0x7C, 0x04, 0x78, 0x04, 0x78, // m + 0x7C, 0x08, 0x04, 0x04, 0x78, // n + 0x38, 0x44, 0x44, 0x44, 0x38, // o + 0x7C, 0x14, 0x14, 0x14, 0x08, // p + 0x08, 0x14, 0x14, 0x14, 0x7C, // q + 0x00, 0x7C, 0x08, 0x04, 0x04, // r + 0x48, 0x54, 0x54, 0x54, 0x20, // s + 0x04, 0x04, 0x3F, 0x44, 0x44, // t + 0x3C, 0x40, 0x40, 0x20, 0x7C, // u + 0x1C, 0x20, 0x40, 0x20, 0x1C, // v + 0x3C, 0x40, 0x30, 0x40, 0x3C, // w + 0x44, 0x28, 0x10, 0x28, 0x44, // x + 0x0C, 0x50, 0x50, 0x50, 0x3C, // y + 0x44, 0x64, 0x54, 0x4C, 0x44, // z + 0x00, 0x08, 0x36, 0x41, 0x41, // { + 0x00, 0x00, 0x7F, 0x00, 0x00, // | + 0x41, 0x41, 0x36, 0x08, 0x00, // } + 0x02, 0x01, 0x02, 0x04, 0x02};// ~ + diff --git a/lcd/ili934x.h b/lcd/ili934x.h new file mode 100644 index 0000000000000000000000000000000000000000..662949745508998ca2be6832dec77740a3fe6c9d --- /dev/null +++ b/lcd/ili934x.h @@ -0,0 +1,103 @@ +/* Author: Steve Gunn + * Licence: This work is licensed under the Creative Commons Attribution License. + * View this license at http://creativecommons.org/about/licenses/ + */ + +#define BLC 4 +#define RESET 7 + +#define CMD_ADDR 0x4000 +#define DATA_ADDR 0x4100 + +#define write_cmd(cmd) asm volatile("sts %0,%1" :: "i" (CMD_ADDR), "r" (cmd) : "memory"); +#define write_data(data) asm volatile("sts %0,%1" :: "i" (DATA_ADDR), "r" (data) : "memory"); +#define write_data16(data) asm volatile("sts %0,%B1 \n\t sts %0,%A1" :: "i" (DATA_ADDR), "r" (data) : "memory"); +#define write_cmd_data(cmd, data) asm volatile("sts %0,%1 \n\t sts %2,%3" :: "i" (CMD_ADDR), "r" (cmd), "i" (DATA_ADDR), "r" (data) : "memory"); + +/* Basic Commands */ +#define NO_OPERATION 0x00 +#define SOFTWARE_RESET 0x01 +#define READ_DISPLAY_IDENTIFICATION_INFORMATION 0x04 +#define READ_DISPLAY_STATUS 0x09 +#define READ_DISPLAY_POWER_MODE 0x0A +#define READ_DISPLAY_MADCTL 0x0B +#define READ_DISPLAY_PIXEL_FORMAT 0x0C +#define READ_DISPLAY_IMAGE_FORMAT 0x0D +#define READ_DISPLAY_SIGNAL_MODE 0x0E +#define READ_DISPLAY_SELF_DIAGNOSTIC_RESULT 0x0F +#define ENTER_SLEEP_MODE 0x10 +#define SLEEP_OUT 0x11 +#define PARTIAL_MODE_ON 0x12 +#define NORMAL_DISPLAY_MODE_ON 0x13 +#define DISPLAY_INVERSION_OFF 0x20 +#define DISPLAY_INVERSION_ON 0x21 +#define GAMMA_SET 0x26 +#define DISPLAY_OFF 0x28 +#define DISPLAY_ON 0x29 +#define COLUMN_ADDRESS_SET 0x2A +#define PAGE_ADDRESS_SET 0x2B +#define MEMORY_WRITE 0x2C +#define COLOR_SET 0x2D +#define MEMORY_READ 0x2E +#define PARTIAL_AREA 0x30 +#define VERTICAL_SCROLLING_DEFINITION 0x33 +#define TEARING_EFFECT_LINE_OFF 0x34 +#define TEARING_EFFECT_LINE_ON 0x35 +#define MEMORY_ACCESS_CONTROL 0x36 +#define VERTICAL_SCROLLING_START_ADDRESS 0x37 +#define IDLE_MODE_OFF 0x38 +#define IDLE_MODE_ON 0x39 +#define PIXEL_FORMAT_SET 0x3A +#define WRITE_MEMORY_CONTINUE 0x3C +#define READ_MEMORY_CONTINUE 0x3E +#define SET_TEAR_SCANLINE 0x44 +#define GET_SCANLINE 0x45 +#define WRITE_DISPLAY_BRIGHTNESS 0x51 +#define READ_DISPLAY_BRIGHTNESS 0x52 +#define WRITE_CTRL_DISPLAY 0x53 +#define READ_CTRL_DISPLAY 0x54 +#define WRITE_CONTENT_ADAPTIVE_BRIGHTNESS_CONTROL 0x55 +#define READ_CONTENT_ADAPTIVE_BRIGHTNESS_CONTROL 0x56 +#define WRITE_CABC_MINIMUM_BRIGHTNESS 0x5E +#define READ_CABC_MINIMUM_BRIGHTNESS 0x5F +#define READ_ID1 0xDA +#define READ_ID2 0xDB +#define READ_ID3 0xDC + +/* Extended Commands */ +#define RGB_INTERFACE_SIGNAL_CONTROL 0xB0 +#define FRAME_CONTROL_IN_NORMAL_MODE 0xB1 +#define FRAME_CONTROL_IN_IDLE_MODE 0xB2 +#define FRAME_CONTROL_IN_PARTIAL_MODE 0xB3 +#define DISPLAY_INVERSION_CONTROL 0xB4 +#define BLANKING_PORCH_CONTROL 0xB5 +#define DISPLAY_FUNCTION_CONTROL 0xB6 +#define ENTRY_MODE_SET 0xB7 +#define BACKLIGHT_CONTROL_1 0xB8 +#define BACKLIGHT_CONTROL_2 0xB9 +#define BACKLIGHT_CONTROL_3 0xBA +#define BACKLIGHT_CONTROL_4 0xBB +#define BACKLIGHT_CONTROL_5 0xBC +#define BACKLIGHT_CONTROL_7 0xBE +#define BACKLIGHT_CONTROL_8 0xBF +#define POWER_CONTROL_1 0xC0 +#define POWER_CONTROL_2 0xC1 +#define POWER_CONTROL3_(FOR_NORMAL_MODE) 0xC2 +#define POWER_CONTROL4_(FOR_IDLE_MODE) 0xC3 +#define POWER_CONTROL5_(FOR_PARTIAL_MODE) 0xC4 +#define VCOM_CONTROL_1 0xC5 +#define VCOM_CONTROL_2 0xC7 +#define NV_MEMORY_WRITE 0xD0 +#define NV_MEMORY_PROTECTION_KEY 0xD1 +#define NV_MEMORY_STATUS_READ 0xD2 +#define READ_ID4 0xD3 +#define POSITIVE_GAMM_CORRECTION 0xE0 +#define NEGATIVE_GAMMA_CORRECTION 0xE1 +#define DIGITAL_GAMMA_CONTROL 0xE2 +#define DIGITAL_GAMMA_CONTROL2 0xE3 +#define INTERFACE_CONTROL 0xF6 + +/* Undocumented commands */ +#define INTERNAL_IC_SETTING 0xCB +#define GAMMA_DISABLE 0xF2 + diff --git a/lcd/lcd.c b/lcd/lcd.c new file mode 100644 index 0000000000000000000000000000000000000000..3eaf9cf98bf448ba180365f47267796b76aaf992 --- /dev/null +++ b/lcd/lcd.c @@ -0,0 +1,262 @@ +/* Author: Steve Gunn + * Licence: This work is licensed under the Creative Commons Attribution License. + * View this license at http://creativecommons.org/about/licenses/ + * + * + * - Jan 2015 Modified for LaFortuna (Rev A, black edition) [KPZ] + */ + +#include <avr/io.h> +#include <avr/interrupt.h> +#include <util/delay.h> +#include "font.h" +#include "ili934x.h" +#include "lcd.h" + +lcd display; + +void init_lcd() +{ + /* Enable extended memory interface with 10 bit addressing */ + XMCRB = _BV(XMM2) | _BV(XMM1); + XMCRA = _BV(SRE); + DDRC |= _BV(RESET); + DDRB |= _BV(BLC); + _delay_ms(1); + PORTC &= ~_BV(RESET); + _delay_ms(20); + PORTC |= _BV(RESET); + _delay_ms(120); + write_cmd(DISPLAY_OFF); + write_cmd(SLEEP_OUT); + _delay_ms(60); + write_cmd_data(INTERNAL_IC_SETTING, 0x01); + write_cmd(POWER_CONTROL_1); + write_data16(0x2608); + write_cmd_data(POWER_CONTROL_2, 0x10); + write_cmd(VCOM_CONTROL_1); + write_data16(0x353E); + write_cmd_data(VCOM_CONTROL_2, 0xB5); + write_cmd_data(INTERFACE_CONTROL, 0x01); + write_data16(0x0000); + write_cmd_data(PIXEL_FORMAT_SET, 0x55); /* 16bit/pixel */ + set_orientation(West); + clear_screen(); + display.x = 0; + display.y = 0; + display.background = BLACK; + display.foreground = WHITE; + write_cmd(DISPLAY_ON); + _delay_ms(50); + write_cmd_data(TEARING_EFFECT_LINE_ON, 0x00); + EICRB |= _BV(ISC61); + PORTB |= _BV(BLC); +} + +void lcd_brightness(uint8_t i) +{ + /* Configure Timer 2 Fast PWM Mode 3 */ + TCCR2A = _BV(COM2A1) | _BV(WGM21) | _BV(WGM20); + TCCR2B = _BV(CS20); + OCR2A = i; +} + +void set_orientation(orientation o) +{ + display.orient = o; + write_cmd(MEMORY_ACCESS_CONTROL); + if (o==North) { + display.width = LCDWIDTH; + display.height = LCDHEIGHT; + write_data(0x48); + } + else if (o==West) { + display.width = LCDHEIGHT; + display.height = LCDWIDTH; + write_data(0xE8); + } + else if (o==South) { + display.width = LCDWIDTH; + display.height = LCDHEIGHT; + write_data(0x88); + } + else if (o==East) { + display.width = LCDHEIGHT; + display.height = LCDWIDTH; + write_data(0x28); + } + write_cmd(COLUMN_ADDRESS_SET); + write_data16(0); + write_data16(display.width-1); + write_cmd(PAGE_ADDRESS_SET); + write_data16(0); + write_data16(display.height-1); +} + + + +void set_frame_rate_hz(uint8_t f) +{ + uint8_t diva, rtna, period; + if (f>118) + f = 118; + if (f<8) + f = 8; + if (f>60) { + diva = 0x00; + } else if (f>30) { + diva = 0x01; + } else if (f>15) { + diva = 0x02; + } else { + diva = 0x03; + } + /* !!! FIXME !!! [KPZ-30.01.2015] */ + /* Check whether this works for diva > 0 */ + /* See ILI9341 datasheet, page 155 */ + period = 1920.0/f; + rtna = period >> diva; + write_cmd(FRAME_CONTROL_IN_NORMAL_MODE); + write_data(diva); + write_data(rtna); +} + +void fill_rectangle(rectangle r, uint16_t col) +{ + write_cmd(COLUMN_ADDRESS_SET); + write_data16(r.left); + write_data16(r.right); + write_cmd(PAGE_ADDRESS_SET); + write_data16(r.top); + write_data16(r.bottom); + write_cmd(MEMORY_WRITE); +/* uint16_t x, y; + for(x=r.left; x<=r.right; x++) + for(y=r.top; y<=r.bottom; y++) + write_data16(col); +*/ + uint16_t wpixels = r.right - r.left + 1; + uint16_t hpixels = r.bottom - r.top + 1; + uint8_t mod8, div8; + uint16_t odm8, odd8; + if (hpixels > wpixels) { + mod8 = hpixels & 0x07; + div8 = hpixels >> 3; + odm8 = wpixels*mod8; + odd8 = wpixels*div8; + } else { + mod8 = wpixels & 0x07; + div8 = wpixels >> 3; + odm8 = hpixels*mod8; + odd8 = hpixels*div8; + } + uint8_t pix1 = odm8 & 0x07; + while(pix1--) + write_data16(col); + + uint16_t pix8 = odd8 + (odm8 >> 3); + while(pix8--) { + write_data16(col); + write_data16(col); + write_data16(col); + write_data16(col); + write_data16(col); + write_data16(col); + write_data16(col); + write_data16(col); + } +} + +void fill_rectangle_indexed(rectangle r, uint16_t* col) +{ + uint16_t x, y; + write_cmd(COLUMN_ADDRESS_SET); + write_data16(r.left); + write_data16(r.right); + write_cmd(PAGE_ADDRESS_SET); + write_data16(r.top); + write_data16(r.bottom); + write_cmd(MEMORY_WRITE); + for(x=r.left; x<=r.right; x++) + for(y=r.top; y<=r.bottom; y++) + write_data16(*col++); +} + +void clear_screen() +{ + display.x = 0; + display.y = 0; + rectangle r = {0, display.width-1, 0, display.height-1}; + fill_rectangle(r, display.background); +} + +void display_char(char c) +{ + uint16_t x, y; + PGM_P fdata; + uint8_t bits, mask; + uint16_t sc=display.x, ec=display.x + 4, sp=display.y, ep=display.y + 7; + + /* New line starts a new line, or if the end of the + display has been reached, clears the display. + */ + if (c == '\n') { + display.x=0; display.y+=8; + if (display.y >= display.height) { clear_screen(); } + return; + } + + if (c < 32 || c > 126) return; + fdata = (c - ' ')*5 + font5x7; + write_cmd(PAGE_ADDRESS_SET); + write_data16(sp); + write_data16(ep); + for(x=sc; x<=ec; x++) { + write_cmd(COLUMN_ADDRESS_SET); + write_data16(x); + write_data16(x); + write_cmd(MEMORY_WRITE); + bits = pgm_read_byte(fdata++); + for(y=sp, mask=0x01; y<=ep; y++, mask<<=1) + write_data16((bits & mask) ? display.foreground : display.background); + } + write_cmd(COLUMN_ADDRESS_SET); + write_data16(x); + write_data16(x); + write_cmd(MEMORY_WRITE); + for(y=sp; y<=ep; y++) + write_data16(display.background); + + display.x += 6; + if (display.x >= display.width) { display.x=0; display.y+=8; } +} + +void display_string(char *str) +{ + uint8_t i; + for(i=0; str[i]; i++) + display_char(str[i]); +} + +void display_string_xy(char *str, uint16_t x, uint16_t y) +{ + uint8_t i; + display.x = x; + display.y = y; + for(i=0; str[i]; i++) + display_char(str[i]); +} + +void display_register(uint8_t reg) +{ + uint8_t i; + + for(i = 0; i < 8; i++) { + if((reg & (_BV(7) >> i)) != 0) { + display_char( '1' ); + } else { + display_char( '.' ); + } + } +} + diff --git a/lcd/lcd.h b/lcd/lcd.h new file mode 100644 index 0000000000000000000000000000000000000000..736634671b06c0df6d632d2860f6b13d48b9fd9e --- /dev/null +++ b/lcd/lcd.h @@ -0,0 +1,49 @@ +/* Author: Steve Gunn + * Licence: This work is licensed under the Creative Commons Attribution License. + * View this license at http://creativecommons.org/about/licenses/ + */ + +#include <avr/io.h> +#include <stdint.h> + + +#define LCDWIDTH 240 +#define LCDHEIGHT 320 + +/* Colour definitions RGB565 */ +#define WHITE 0xFFFF +#define BLACK 0x0000 +#define BLUE 0x001F +#define GREEN 0x07E0 +#define CYAN 0x07FF +#define RED 0xF800 +#define MAGENTA 0xF81F +#define YELLOW 0xFFE0 + +typedef enum {North, West, South, East} orientation; + +typedef struct { + uint16_t width, height; + orientation orient; + uint16_t x, y; + uint16_t foreground, background; +} lcd; + +extern lcd display; + +typedef struct { + uint16_t left, right; + uint16_t top, bottom; +} rectangle; + +void init_lcd(); +void lcd_brightness(uint8_t i); +void set_orientation(orientation o); +void set_frame_rate_hz(uint8_t f); +void clear_screen(); +void fill_rectangle(rectangle r, uint16_t col); +void fill_rectangle_indexed(rectangle r, uint16_t* col); +void display_char(char c); +void display_string(char *str); +void display_string_xy(char *str, uint16_t x, uint16_t y); +void display_register(uint8_t reg); diff --git a/mines.c b/mines.c new file mode 100644 index 0000000000000000000000000000000000000000..88c42eac49cea1c441a792a1bc6953f3e02a869b --- /dev/null +++ b/mines.c @@ -0,0 +1,205 @@ +/* COMP2215 Task 5---SKELETON */ + +#include "os.h" +#include <stdlib.h> + + +int blink(int); +int update_dial(int); +int collect_delta(int); +int check_switches(int); + + +int position = 0; + + +void main(void) { + os_init(); + + os_add_task( blink, 30, 1); + os_add_task( collect_delta, 500, 1); + os_add_task( check_switches, 100, 1); +// os_add_task( freeram_output, 20, 1); +// os_add_task( lose_mem, 250, 1); + + sei(); + for(;;){} + +} + + +int collect_delta(int state) { + position += os_enc_delta(); + return state; +} + + +int check_switches(int state) { + + if (get_switch_press(_BV(SWN))) { + display_string("North\n"); + } + + if (get_switch_press(_BV(SWE))) { + display_string("East\n"); + } + + if (get_switch_short(_BV(SWS))) { + display_string("South\n"); + } + + if (get_switch_long(_BV(SWS))){ + f_mount(&FatFs, "", 0); + if (f_open(&File, "myfile.txt", FA_READ) == FR_OK) { + uint16_t index = f_size(&File); + f_lseek(&File, index); + uint8_t arrayIndex = 0; + uint16_t* last25Newlines = calloc(25,25*sizeof(uint16_t)); + + char* character = malloc(sizeof(char)); + UINT* br = malloc(sizeof(UINT)); + display_string("\nLast 25 lines of saved data:\n"); + for(;index > 0 && arrayIndex < 25; ){ + index--; + f_read(&File, character,1,br); + if(*character == '\n'){ + last25Newlines[arrayIndex] = index; + arrayIndex++; + } + f_lseek(&File,index); + } + + for(arrayIndex = 24; arrayIndex > 0; arrayIndex--){ + uint8_t lineLength = last25Newlines[arrayIndex-1] - last25Newlines[arrayIndex]; + if(lineLength == 0){ + continue; + } + char* line = calloc(lineLength, lineLength*sizeof(char)); + + f_read(&File,line,lineLength,br); + sprintf(line,line); + display_string(line); + free(line); + } + + free(character); + free(br); + free(last25Newlines); + f_close(&File); + } else { + display_string("Can't read file! \n"); + } + } + + if (get_switch_press(_BV(SWW))) { + display_string("West\n"); + } + + if (get_switch_long(_BV(SWC))) { + f_mount(&FatFs, "", 0); + if (f_open(&File, "myfile.txt", FA_WRITE | FA_OPEN_ALWAYS) == FR_OK) { + f_lseek(&File, f_size(&File)); + f_printf(&File, "Encoder position is: %d \r\n", position); + f_close(&File); + display_string("Wrote position\n"); + } else { + display_string("Can't write file! \n"); + } + + } + + if (get_switch_short(_BV(SWC))) { + display_string("[S] Centre\n"); + } + + if (get_switch_rpt(_BV(SWN))) { + display_string("[R] North\n"); + } + + if (get_switch_rpt(_BV(SWE))) { + display_string("[R] East\n"); + } + +// if (get_switch_rpt(_BV(SWS))) { +// display_string("[R] South\n"); +// } + + if (get_switch_rpt(_BV(SWW))) { + display_string("[R] West\n"); + } + + if (get_switch_rpt(SWN)) { + display_string("[R] North\n"); + } + + + if (get_switch_long(_BV(OS_CD))) { + display_string("Detected SD card.\n"); + } + + return state; +} + + + + +int blink(int state) { + static int light = 0; + uint8_t level; + + if (light < -120) { + state = 1; + } else if (light > 254) { + state = -20; + } + + + /* Compensate somewhat for nonlinear LED + output and eye sensitivity: + */ + if (state > 0) { + if (light > 40) { + state = 2; + } + if (light > 100) { + state = 5; + } + } else { + if (light < 180) { + state = -10; + } + if (light < 30) { + state = -5; + } + } + light += state; + + if (light < 0) { + level = 0; + } else if (light > 255) { + level = 255; + } else { + level = light; + } + + os_led_brightness(level); + return state; +} + + +int freeram_output (int state){ + char out[10]; + sprintf(out, "%d\n", freeRam()); + display_string_xy(out, 290, 000); + if(state == 10){ + return 0; + } else { + return ++state; + } +} + +int freeRam () { + extern int __heap_start, *__brkval; + int v; + return (int) &v - (__brkval == 0 ? (int) &__heap_start : (int) __brkval); +} diff --git a/os.c b/os.c new file mode 100644 index 0000000000000000000000000000000000000000..d254951e199009d2a5a3b24254bafa9f5397f40c --- /dev/null +++ b/os.c @@ -0,0 +1,26 @@ +/* _____ _ ___ ____ + * | ___|__ _ __| |_ _ _ _ __ __ _ / _ \/ ___| + * | |_ / _ \| '__| __| | | | '_ \ / _` | | | \___ \ + * | _| (_) | | | |_| |_| | | | | (_| | |_| |___) | + * |_| \___/|_| \__|\__,_|_| |_|\__,_|\___/|____/ + * + */ + + +#include "os.h" +#include "debug.h" +#include "rios.h" +#include "ruota.h" + +void os_init(void) { + /* 8MHz clock, no prescaling (DS, p. 48) */ + CLKPR = (1 << CLKPCE); + CLKPR = 0; + + DDRB |= _BV(PB7); /* LED as output */ + + init_debug_uart1(); + init_lcd(); + os_init_scheduler(); + os_init_ruota(); +} diff --git a/os.h b/os.h new file mode 100644 index 0000000000000000000000000000000000000000..e3b1a3058e4cea0ebfdc718d0052aac747ac2759 --- /dev/null +++ b/os.h @@ -0,0 +1,39 @@ +/* FortunaOS + _____ _ ___ ____ + | ___|___ _ __ | |_ _ _ _ __ __ _ / _ \ / ___| + | |_ / _ \ | '__|| __|| | | || '_ \ / _` || | | |\___ \ + | _|| (_) || | | |_ | |_| || | | || (_| || |_| | ___) | + |_| \___/ |_| \__| \__,_||_| |_| \__,_| \___/ |____/ + + Minimalist Operating System for LaFortuna board, build on: + - The RIOS Scheduler + - Peter Dannegger’s Code for the Rotary Encoder + - Peter Dannegger’s Code for Switch debouncing + - Steve Gunn’s display driver + - ChanN’s FAT File System + + Occupies Timer T0 for scheduling and LED brightness. + +*/ + +#ifndef OS_H +#define OS_H + +#include <stdio.h> +#include <avr/io.h> +#include <avr/interrupt.h> +#include "lcd.h" +#include "rios.h" +#include "ruota.h" + + + +#define LED_ON PORTB |= _BV(PINB7) +#define LED_OFF PORTB &= ~_BV(PINB7) +#define LED_TOGGLE PINB |= _BV(PINB7) + + + +void os_init(void); + +#endif /* OS_H */ diff --git a/rios/rios.c b/rios/rios.c new file mode 100644 index 0000000000000000000000000000000000000000..488e0dd6111ee386ecafbfdb375a970a5de431e7 --- /dev/null +++ b/rios/rios.c @@ -0,0 +1,196 @@ +/* FortunaOS: Scheduler + + Template for preemptive version of RIOS implemented on an AVR + available from: http://www.cs.ucr.edu/~vahid/rios/rios_avr.htm + + Slightly modified by Klaus-Peter Zauner, Feb 2014, Mar 2015. + + For Copyright and License see end of file. + +*/ + +#include <stdint.h> +#include <avr/io.h> +#include <avr/interrupt.h> +#include <math.h> +#include <util/delay.h> +#include "rios.h" + + + + +typedef struct task { + uint8_t running; /* 1 indicates task is running */ + uint32_t period_ms; /* Rate at which the task should tick in ms*/ + uint32_t elapsedTime; /* Time since task's previous tick */ + int (*TaskFct)(int); /* Function to call for task's tick */ + int state; /* Current state of state machine */ +} task; + +task tasks[MAX_TASKS]; +int8_t tasksNum = -1; + + + +uint8_t runningTasks[MAX_TASKS+1] = {255}; /* Track running tasks, [0] always idleTask */ +const uint32_t idleTask = 255; /* 0 highest priority, 255 lowest */ +uint8_t currentTask = 0; /* Index of highest priority task in runningTasks */ + +unsigned schedule_time = 0; +ISR(TIMER0_OVF_vect) { + uint8_t i; + + for (i=0; i <= tasksNum; ++i) { /* Heart of scheduler code */ + if ( (tasks[i].elapsedTime >= tasks[i].period_ms) /* Task ready */ + && (runningTasks[currentTask] > i) /* Task priority > current task priority */ + && (!tasks[i].running) /* Task not already running (no self-preemption) */ + ) { + + cli(); + tasks[i].elapsedTime = 0; /* Reset time since last tick */ + tasks[i].running = 1; /* Mark as running */ + currentTask += 1; + runningTasks[currentTask] = i; /* Add to runningTasks */ + sei(); + + tasks[i].state = tasks[i].TaskFct(tasks[i].state); /* Execute tick */ + + cli(); + tasks[i].running = 0; /* Mark as not running */ + runningTasks[currentTask] = idleTask; /* Remove from runningTasks */ + currentTask -= 1; + sei(); + + } + tasks[i].elapsedTime += 1; + } + + +} + + + +#ifdef OS_LED_BRIGHTNESS + +/* Use PWM mode to also control LED brightness from Timer 0 */ +void os_init_scheduler() { + + /* Configure 8 bit Timer 0 for ISR */ + TCCR0A = _BV(COM0A1) /* Clear OCA0A on Compare match, set on TOP */ + | _BV(WGM01) /* fast PWM mode */ + | _BV(WGM00); + + TCCR0B |= _BV(CS00) + | _BV(CS01); /* F_CPU/64, DS p.112 */ + + + /* Interrupts at 488.3 Hz: FCPU/(510*N) with N=64, DS p.105 */ + + TIMSK0 = _BV(TOIE0); /* enable overflow interrupt for T0, DS p.113 */ + TCNT0 = 0; + OCR0A = 255; /* LED full brightness */ +} + +void os_led_brightness(uint8_t level) { + if (level) { + OCR0A = level; + DDRB |= _BV(PINB7); + } else { + DDRB &= ~_BV(PINB7); + } +} + + +#else + + +/* Use CTC mode to have periods of exactly 1 ms */ +void os_init_scheduler() { + + /* Configure 8 bit Timer 0 for 1 ms ISR */ + TCCR0A |= _BV(WGM01); /* Clear Timer on Compare match (CTC, Mode 2), DS p.111 */ + TCCR0B |= _BV(CS00) + | _BV(CS01); /* F_CPU/64, DS p.112 */ + + OCR0A = (uint8_t)(F_CPU / (64UL * 1000) - 1); /* 1 kHz interrupts */ + + TIMSK0 = _BV(OCIE0A); /* enable compare match interrupt for T0, DS p.113 */ + TCNT0 = 0; + +} + + +void os_led_brightness(uint8_t brightness) {} + +#endif /* OS_LED_BRIGHTNESS */ + + + +int os_add_task(int (*fnc)(int), uint32_t period_ms, int initState) { + int t; + + t = tasksNum + 1; + + if (t >= MAX_TASKS) { + t = -1; + } else { + + #ifdef OS_LED_BRIGHTNESS + tasks[t].period_ms = 488.3/1000.0 * period_ms + 0.5; + #else + tasks[t].period_ms = period_ms; + #endif /* OS_LED_BRIGHTNESS */ + + tasks[t].elapsedTime = tasks[t].period_ms; + tasks[t].running = 0; + tasks[t].TaskFct = fnc; + tasks[t].state = initState; + tasksNum = t; /* New task fully initialized */ + } + + return t; +} + + +/* + Copyright (c) 2013 Frank Vahid, Tony Givargis, and + Bailey Miller. Univ. of California, Riverside and Irvine. + RIOS version 1.2 + + Copyright (c) 2012 UC Regents. All rights reserved. + + Developed by: Frank Vahid, Bailey Miller, and Tony Givargis + University of California, Riverside; University of California, Irvine + <http://www.riosscheduler.org>http://www.riosscheduler.org + + Permission is hereby granted, free of charge, to any person + obtaining a copy of this software and associated documentation + files (the "Software"), to deal with the Software without + restriction, including without limitation the rights to use, + copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + * Redistributions of source code must retain the above + copyright notice, this list of conditions and the following + disclaimers. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimers in the documentation and/or other materials + provided with the distribution. + * Neither the names of any of the developers or universities nor + the names of its contributors may be used to endorse or + promote products derived from this Software without + specific prior written permission. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE CONTRIBUTORS OR COPYRIGHT + HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + OTHER DEALINGS WITH THE SOFTWARE. + (http://opensource.org/licenses/NCSA) + +*/ \ No newline at end of file diff --git a/rios/rios.h b/rios/rios.h new file mode 100644 index 0000000000000000000000000000000000000000..28e3aaf8357009549211b1eb1cc98b3d8507dc27 --- /dev/null +++ b/rios/rios.h @@ -0,0 +1,37 @@ +/* FortunaOS: Scheduler + + Based on template for preemptive version of RIOS implemented on an + AVR available from: http://www.cs.ucr.edu/~vahid/rios/rios_avr.htm + + For Copyright and License see end of rios.c file. + + + Usage: + - Tasks can be added before or after scheduler has been initialized. + - Global Iterrupts need to be enabled manually. + - Tasks can be added while the scheduler is running. + +*/ + +#ifndef RIOS_H +#define RIOS_H + +/* Limit for number of tasks: int8_t */ +#define MAX_TASKS 10 + + +/* Comment out the following line to get more precise 1 ms periods, + but loose brightness adjustement of LED +*/ +#define OS_LED_BRIGHTNESS + +void os_init_scheduler(); + +void os_led_brightness(uint8_t brightness); + + +/* Returns task priority (lower is higher) or -1 if not successful: */ +int os_add_task(int (*fnc)(int), uint32_t period_ms, int startState); + + +#endif /* RIOS_H */ diff --git a/ruota/ruota.c b/ruota/ruota.c new file mode 100644 index 0000000000000000000000000000000000000000..f8ff9496ab4e624b84d9f7ba8d72eb8e4bdf678c --- /dev/null +++ b/ruota/ruota.c @@ -0,0 +1,188 @@ +/* ruota.c + + Copyright Peter Dannegger (danni@specs.de) + http://www.mikrocontroller.net/articles/Entprellung + http://www.mikrocontroller.net/articles/Drehgeber + + Slightly adapted by Klaus-Peter Zauner for FortunaOS, March 2015 + +*/ + +#include <avr/io.h> +#include <avr/interrupt.h> +#include "rios.h" +#include "ruota.h" + + +#define ROTA PE4 +#define ROTB PE5 + +#define COMPASS_SWITCHES (_BV(SWW)|_BV(SWS)|_BV(SWE)|_BV(SWN)) +#define ALL_SWITCHES (_BV(SWC) | COMPASS_SWITCHES | _BV(OS_CD)) + + +int8_t os_enc_delta(void); +volatile int8_t delta; + + +volatile uint8_t switch_state; /* debounced and inverted key state: + bit = 1: key pressed */ +volatile uint8_t switch_press; /* key press detect */ +volatile uint8_t switch_rpt; /* key long press and repeat */ + + + +int scan_encoder(int state); +int scan_switches(int state); + + +void os_init_ruota(void) { + + /* Configure I/O Ports */ + DDRE &= ~_BV(ROTA) & ~_BV(ROTB); /* Rot. Encoder inputs */ + PORTE |= _BV(ROTA) | _BV(ROTB); /* Rot. Encoder pull-ups */ + + DDRE &= ~_BV(SWC); /* Central button */ + PORTE |= _BV(SWC); + + DDRC &= ~COMPASS_SWITCHES; /* configure compass buttons for input */ + PORTC |= COMPASS_SWITCHES; /* and turn on pull up resistors */ + + DDRB &= ~_BV(OS_CD); /* SD Card detection */ + PORTB |= _BV(OS_CD); + + /* Schedule encoder scan evry 2 ms */ + os_add_task( scan_encoder, 2, 0); + /* Schedule button scan at 10 ms */ + os_add_task( scan_switches, 10, 0); + +} + + +int scan_encoder(int state) { + static int8_t last; + int8_t new, diff; + uint8_t wheel; + + cli(); + wheel = PINE; + new = 0; + if( wheel & _BV(ROTB) ) new = 3; + if( wheel & _BV(ROTA) ) + new ^= 1; /* convert gray to binary */ + diff = last - new; /* difference last - new */ + if( diff & 1 ){ /* bit 0 = value (1) */ + last = new; /* store new as next last */ + delta += (diff & 2) - 1; /* bit 1 = direction (+/-) */ + } + sei(); + + return state; +} + + +/* Read the two step encoder + -> call frequently enough to avoid overflow of delta +*/ +int8_t os_enc_delta() { + int8_t val; + + cli(); + val = delta; + delta &= 1; + sei(); + + return val >> 1; +} + + + +int scan_switches(int state) { + static uint8_t ct0, ct1, rpt; + uint8_t i; + + cli(); + /* + Overlay port E for central button of switch wheel and Port B + for SD card detection switch: + */ + i = switch_state ^ ~( (PINC|_BV(SWC)|_BV(OS_CD)) \ + & (PINE|~_BV(SWC)) \ + & (PINB|~_BV(OS_CD))); /* switch has changed */ + ct0 = ~( ct0 & i ); /* reset or count ct0 */ + ct1 = ct0 ^ (ct1 & i); /* reset or count ct1 */ + i &= ct0 & ct1; /* count until roll over ? */ + switch_state ^= i; /* then toggle debounced state */ + switch_press |= switch_state & i; /* 0->1: key press detect */ + + if( (switch_state & ALL_SWITCHES) == 0 ) /* check repeat function */ + rpt = REPEAT_START; /* start delay */ + if( --rpt == 0 ){ + rpt = REPEAT_NEXT; /* repeat delay */ + switch_rpt |= switch_state & ALL_SWITCHES; + } + sei(); + + return state; +} + + + + +/* + Check if a key has been pressed + Each pressed key is reported only once. +*/ +uint8_t get_switch_press( uint8_t switch_mask ) { + cli(); /* read and clear atomic! */ + switch_mask &= switch_press; /* read key(s) */ + switch_press ^= switch_mask; /* clear key(s) */ + sei(); + return switch_mask; +} + + + + +/* + Check if a key has been pressed long enough such that the + key repeat functionality kicks in. After a small setup delay + the key is reported being pressed in subsequent calls + to this function. This simulates the user repeatedly + pressing and releasing the key. +*/ +uint8_t get_switch_rpt( uint8_t switch_mask ) { + cli(); /* read and clear atomic! */ + switch_mask &= switch_rpt; /* read key(s) */ + switch_rpt ^= switch_mask; /* clear key(s) */ + sei(); + return switch_mask; +} + + +/* + Check if a key is pressed right now +*/ +uint8_t get_switch_state( uint8_t switch_mask ) { + switch_mask &= switch_state; + return switch_mask; +} + + +/* + Read key state and key press atomic! +*/ +uint8_t get_switch_short( uint8_t switch_mask ) { + cli(); + return get_switch_press( ~switch_state & switch_mask ); +} + + +/* + Key pressed and held long enough that a repeat would + trigger if enabled. +*/ +uint8_t get_switch_long( uint8_t switch_mask ) { + return get_switch_press( get_switch_rpt( switch_mask )); +} + diff --git a/ruota/ruota.h b/ruota/ruota.h new file mode 100644 index 0000000000000000000000000000000000000000..1580275b648a08322f211a0f59d4513b60b2919e --- /dev/null +++ b/ruota/ruota.h @@ -0,0 +1,45 @@ +/* ruota.h + + | | | Signal on | | + | Port | Pin | Schematic | Function | + |------+-----+-----------+-----------------------| + | E | 4 | ROTA | Rotary Encoder A | + | E | 5 | ROTB | Rotary Encoder B | + | E | 7 | SWC | Switch wheel "Centre" | + |------+-----+-----------+-----------------------| + | C | 2 | SWN | Switch wheel "North" | + | C | 3 | SWE | Switch wheel "East" | + | C | 4 | SWS | Switch wheel "South" | + | C | 5 | SWW | Switch wheel "West" | + |------+-----+-----------+-----------------------| + | B | 6 | CD | SD Card Detetcion | + +*/ + + + +#define SWN PC2 +#define SWE PC3 +#define SWS PC4 +#define SWW PC5 +#define OS_CD PB6 +#define SWC PE7 + + + +#define REPEAT_START 60 /* after 600ms */ +#define REPEAT_NEXT 10 /* every 100ms */ + +void os_init_ruota(void); + +int8_t os_enc_delta(void); + +uint8_t get_switch_press( uint8_t switch_mask ); +uint8_t get_switch_rpt( uint8_t switch_mask ); +uint8_t get_switch_state( uint8_t switch_mask ); +uint8_t get_switch_short( uint8_t switch_mask ); +uint8_t get_switch_long( uint8_t switch_mask ); + + + +