From 9ce06c02929726ad07cf3a408dad972f099dde86 Mon Sep 17 00:00:00 2001 From: Kai Lauterbach Date: Wed, 19 Oct 2011 00:04:59 +0200 Subject: [PATCH] Major changes on the core of the framework from klaute * Some interferrences with the two timers (usb/led) * Big cleanup from the codebase and separate logical parts * Documenting the code * Big space optimizations on the code to fit on the AVR --- firmware/Makefile | 22 +++--- firmware/globals.h | 37 ++++++++++ firmware/main.c | 169 +++++++++---------------------------------- firmware/main.h | 110 +++------------------------- firmware/usb.c | 45 +++++++++--- firmware/usb.h | 16 +++- firmware/usbconfig.h | 6 +- 7 files changed, 144 insertions(+), 261 deletions(-) create mode 100644 firmware/globals.h diff --git a/firmware/Makefile b/firmware/Makefile index 411143a..44c7e72 100644 --- a/firmware/Makefile +++ b/firmware/Makefile @@ -44,11 +44,9 @@ MCU = attiny2313 # This is only used to define F_CPU in all assembler and c-sources. F_CPU = 12000000UL -# 8MHz internal (basic firmware) -#LFUSE=0xE4 -# external clock -LFUSE=0xFF -HFUSE=0xDF +# external clock, boden, noclkdiv +LFUSE=0xEF +HFUSE=0xDB # Output format. (can be srec, ihex, binary) FORMAT = ihex @@ -81,7 +79,7 @@ OPT = s # Native formats for AVR-GCC's -g are stabs [default], or dwarf-2. # AVR (extended) COFF requires stabs, plus an avr-objcopy run. #DEBUG = stabs -DEBUG = # dwarf-2 +DEBUG = # List any extra directories to look for include files here. # Each directory must be seperated by a space. @@ -113,19 +111,17 @@ CINCS = -Iusbdrv CFLAGS = #-g$(DEBUG) CFLAGS += $(CDEFS) $(CINCS) CFLAGS += -O$(OPT) -CFLAGS += -funsigned-char +#CFLAGS += -funsigned-char #CFLAGS += -funsigned-bitfields #CFLAGS += -fpack-struct #CFLAGS += -fshort-enums -CFLAGS += -fno-split-wide-types +#CFLAGS += -fno-split-wide-types CFLAGS += -fno-move-loop-invariants CFLAGS += -fno-tree-scev-cprop #CFLAGS += -fno-inline-small-functions #CFLAGS += -fno-tree-loop-optimize -#CFLAGS += -ffunction-sections -#CFLAGS += -fdata-sections -CFLAGS += -mcall-prologues -CFLAGS += -mtiny-stack +#CFLAGS += -mcall-prologues +#CFLAGS += -mtiny-stack #CFLAGS += -mint8 CFLAGS += -Wall -Wstrict-prototypes CFLAGS += -Wa,-adhlns=$(<:.c=.lst) @@ -133,7 +129,7 @@ CFLAGS += $(patsubst %,-I%,$(EXTRAINCDIRS)) CFLAGS += $(CSTANDARD) CFLAGS += -DF_CPU=$(F_CPU) CFLAGS += -ffunction-sections -CFLAGS += -fdata-sections +#CFLAGS += -fdata-sections CFLAGS += -Wl,--gc-sections diff --git a/firmware/globals.h b/firmware/globals.h new file mode 100644 index 0000000..b3827b0 --- /dev/null +++ b/firmware/globals.h @@ -0,0 +1,37 @@ +#define F_CPU 12000000UL + +// Bitpopelei +#define set_bit(var, bit) ((var) |= (1 << (bit))) +#define clear_bit(var, bit) ((var) &= (unsigned)~(1 << (bit))) + +// Bool +#define FALSE 0 +#define TRUE 1 + +// Definitionen +#define PIXEL_TON 30 +#define PIXEL_TOFF 10 + +#define sleep_nop(cnt) for (uint8_t i = 0; i < cnt; i++) { asm volatile("nop"::); } + +// Pixelmakros +#define PSET(x,y,z) (0b01000000 | ((z * 3 + x) + y * 9)) +#define PCLEAR(x,y,z) (0b00000000 | ((z * 3 + x) + y * 9)) + +// Instructions +#define CLEAR 0b10000000 +#define SET 0b10010000 +#define FPS 0b10110000 +#define NEXT 0b11110000 + +// Variablen +#define VAR_FPS 0 + +// Für CLEAR und SET +#define CLEAR_ALL 0 +#define SET_ALL 0 + +// Für NEXT +#define JUMP_FORWARD 1 +#define JUMP_BACKWARD 2 + diff --git a/firmware/main.c b/firmware/main.c index 8c20017..bd7e764 100644 --- a/firmware/main.c +++ b/firmware/main.c @@ -1,190 +1,91 @@ /* - * Based on the code of the Mini-LED-Cube 1.0 + * Based on the code of the Mini-LED-Cube 1.0 * - * Copyright (C) 2009 Paul Wilhelm - * http: *mosfetkiller.de/?s=miniledcube + * Copyright (C) 2009 Paul Wilhelm + * http: *mosfetkiller.de/?s=miniledcube * * Changed by Kai Lauterbach (klaute at web dot de) */ #include "main.h" -// Main +// Main int main(void) { - // Initialisierung + // Initialisierung init(); init_usb(); - // Hauptschleife - while (1) + // Hauptschleife + //while (1) + for (;;) { //wdt_reset(); // we are alive, so don't reset the µC usbPoll(); // keep connected - /* - unsigned char instruction = pgm_read_byte(&(program_pointer[program_counter])); - - if ((instruction & 0b10000000) == 0) - // Pixel - { - unsigned char coord = instruction & 0b00111111; // Uns interessieren nur die 6 untersten Bits - - unsigned char y = coord / 9; - unsigned char x = (coord - y * 9) % 3; - unsigned char z = (coord - y * 9) / 3; - buffer[x][y][z] = (instruction & 0b01000000) / 0b01000000; - } - else - // Instruction - { - unsigned char operation = instruction & 0b11110000; // Uns interessieren nur die 4 obersten Bits - - if (operation == CLEAR || operation == SET) - { - unsigned char frame = instruction & 0b00001111; - - // Folgende Werte entsprechen SET_ALL - unsigned char x_min = 0, x_max = 3, y_min = 0, y_max = 3, z_min = 0, z_max = 3; - - // Folgendes kann noch optimiert werden. - - // Y-Z-Ebene (links, mitte, rechts) - if (frame == 1) { x_min = 0; x_max = 1; } - if (frame == 2) { x_min = 1; x_max = 2; } - if (frame == 3) { x_min = 2; x_max = 3; } - - // X-Z-Ebene (unten, mitte, oben) - if (frame == 4) { y_min = 0; y_max = 1; } - if (frame == 5) { y_min = 1; y_max = 2; } - if (frame == 6) { y_min = 2; y_max = 3; } - - // X-Y-Ebene (hinten, mitte, vorne) - if (frame == 7) { z_min = 0; z_max = 1; } - if (frame == 8) { z_min = 1; z_max = 2; } - if (frame == 9) { z_min = 2; z_max = 3; } - - if (frame < 10) - { - for (unsigned char z = z_min; z < z_max; z++) - for (unsigned char y = y_min; y < y_max; y++) - for (unsigned char x = x_min; x < x_max; x++) - if (operation == SET) buffer[x][y][z] = 1; else buffer[x][y][z] = 0; - } else - { - for (unsigned char a = 0; a < 3; a++) - for (unsigned char b = 0; b < 3; b++) - { - unsigned char x = 0, y = 0, z = 0; - - if (frame == 10) { x = a; y = b; z = b; } // Unten hinten nach oben vorne - if (frame == 11) { x = a; y = a; z = b; } // Unten links nach oben rechts - if (frame == 12) { x = a; y = b; z = 2 - b; } // Unten vorne nach oben hinten - if (frame == 13) { x = a; y = 2 - a; z = b; } // Oben links nach unten rechts - if (frame == 14) { x = b; y = a; z = b; } // Hinten links nach vorne rechts - if (frame == 15) { x = a; y = 2 - b; z = 2 - a; } // Vorne links nach hinten rechts - - if (operation == SET) buffer[x][y][z] = 1; else buffer[x][y][z] = 0; - } - } - } else - - if (operation == FPS) - { - if (program_counter + 1 < program_length) program_counter++; // else: Fehler - unsigned char byte = pgm_read_byte(&(program_pointer[program_counter])); - - fps = byte; - } else - - if (operation == NEXT) - { - // VAR_FPS = 0: Frame nicht zeichnen, keine Wartezeit - if (fps > 0) - { - // Temporäres Array ins "echte" Array kopieren - for (unsigned char z = 0; z < 3; z++) - for (unsigned char y = 0; y < 3; y++) - for (unsigned char x = 0; x < 3; x++) - cube[x][y][z] = buffer[x][y][z]; - - for (unsigned char i = 0; i < fps; i++) - { - _delay_ms(5); - } - } - } - - } - - // Programmzähler erhöhen, bzw. bei Erreichen des Programmendes wieder von vorn beginnen - if (program_counter + 1 < program_length) program_counter++; else program_counter = 0; - */ - } } - -// Initialisierung +// Initialisierung void init() { - // Ports vorbereiten - DDRB = 0b11111111; // PB0-PB7: LED 1-8 (Kathoden) - PORTB = 0b11111111; // HIGH + // Ports vorbereiten + DDRB = 0b11111111; // PB0-PB7: LED 1-8 (Kathoden) + PORTB = 0b11111111; // HIGH - DDRD = 0b1111000; // PD6: LED 9 (Kathode); PD5-PD3: A-C (Anoden) + DDRD = 0b1111000; // PD6: LED 9 (Kathode); PD5-PD3: A-C (Anoden) PORTD = 0b1000000; - // Timer-Interrupt "TIMER1" vorbereiten - cli(); + // Timer-Interrupt "TIMER1" vorbereiten + //cli(); // set_bit(TIMSK, OCIE1A); set_bit(TCCR1B, WGM12); - // Animations-Geschwindigkeit + // Animations-Geschwindigkeit OCR1AH = 0x01; OCR1AL = 0x00; - clear_bit(TCCR1B, CS12); // Prescaler 64 + clear_bit(TCCR1B, CS12); // Prescaler 64 set_bit(TCCR1B, CS11); set_bit(TCCR1B, CS10); sei(); } - -// Interruptvektor von TIMER1 +// Interruptvektor von TIMER1 SIGNAL(SIG_OUTPUT_COMPARE1A) { - // Pixel multiplexen -/**/ - for (unsigned char z = 0; z < 3; z++) - { - for (unsigned char y = 0; y < 3; y++) - { - for (unsigned char x = 0; x < 3; x++) - { - unsigned char n = z * 3 + x; - // LED an + // Pixel multiplexen + for (uint8_t z = 0; z < 3; z++) + { + for (uint8_t y = 0; y < 3; y++) + { + for (uint8_t x = 0; x < 3; x++) + { + uint8_t n = z * 3 + x; + + // LED an if (cube[x][y][z] == 1) { if (n < 8) clear_bit(PORTB, n); else clear_bit(PORTD, 6); set_bit(PORTD, y + 3); } - // ON-Time - for (unsigned long i = 0; i < PIXEL_TON; i++) { asm volatile("nop"::); } + // ON-Time + sleep_nop(PIXEL_TON); - // LED aus + // LED aus if (cube[x][y][z] == 1) { clear_bit(PORTD, y + 3); if (n < 8) set_bit(PORTB, n); else set_bit(PORTD, 6); } - // OFF-Time - for (unsigned long i = 0; i < PIXEL_TOFF; i++) { asm volatile("nop"::); } + // OFF-Time + sleep_nop(PIXEL_TOFF) } } } -/**/ + } + diff --git a/firmware/main.h b/firmware/main.h index 50b4408..72cd2ae 100644 --- a/firmware/main.h +++ b/firmware/main.h @@ -4,119 +4,33 @@ // http://mosfetkiller.de/?s=miniledcube // // Changed by Kai Lauterbach (klaute at web dot de) - -// Interner RC-Oszillator, CKDIV8 Disabled +// +// Externes Quarz, CKDIV8 Disabled #ifndef __main_h__ #define __main_h__ -#define F_CPU 12000000UL +// Includes +#include "globals.h" -// Includes -#include #include #include -#include +//#include +//#include //#include -// Bitpopelei -#define set_bit(var, bit) ((var) |= (1 << (bit))) -#define clear_bit(var, bit) ((var) &= (unsigned)~(1 << (bit))) +// Cube-Array +uint8_t cube[3][3][3]; +uint8_t buffer[3][3][3]; // Framebuffer -// Bool -#define FALSE 0 -#define TRUE 1 +volatile uint8_t frame_done = 0; -// Definitionen -#define PIXEL_TON 30 -#define PIXEL_TOFF 10 - -// Cube-Array -unsigned char cube[3][3][3]; -unsigned char buffer[3][3][3]; // Framebuffer - -// Prototypen +// Prototypen void init(void); +void loop(uint8_t); extern void init_usb(void); extern void usbPoll(void); -/* -// Programmzähler -unsigned int program_counter = 0; - -// Framezähler -volatile unsigned char frame_counter = 0, fps = 0; - - -// Pixelmakros -#define PSET(x,y,z) (0b01000000 | ((z * 3 + x) + y * 9)) -#define PCLEAR(x,y,z) (0b00000000 | ((z * 3 + x) + y * 9)) - -// Instructions -#define CLEAR 0b10000000 -#define SET 0b10010000 -#define FPS 0b10110000 -#define NEXT 0b11110000 - -// Variablen -#define VAR_FPS 0 - -// Für CLEAR und SET -#define CLEAR_ALL 0 -#define SET_ALL 0 - -// Für NEXT -#define JUMP_FORWARD 1 -#define JUMP_BACKWARD 2 - - -// Animation in pgmspace -const prog_char program_1[] = -{ - FPS, 10, - - CLEAR, SET + 12, NEXT, CLEAR, SET + 14, NEXT, // Vor- und zurück tanzen - CLEAR, SET + 12, NEXT, CLEAR, SET + 14, NEXT, - CLEAR, SET + 12, NEXT, CLEAR, SET + 15, NEXT, - CLEAR, SET + 12, NEXT, CLEAR, SET + 15, - - FPS, 5, CLEAR, SET + 8, NEXT, CLEAR, SET + 14, NEXT, // Umdrehung - FPS, 5, CLEAR, SET + 2, NEXT, CLEAR, SET + 15, NEXT, - FPS, 6, CLEAR, SET + 8, NEXT, CLEAR, SET + 14, NEXT, - FPS, 6, CLEAR, SET + 2, NEXT, CLEAR, SET + 15, NEXT, - FPS, 7, CLEAR, SET + 8, NEXT, CLEAR, SET + 14, NEXT, - FPS, 7, CLEAR, SET + 2, NEXT, CLEAR, SET + 15, NEXT, - FPS, 8, CLEAR, SET + 8, NEXT, CLEAR, SET + 14, NEXT, - FPS, 8, CLEAR, SET + 2, NEXT, CLEAR, SET + 15, NEXT, - FPS, 9, CLEAR, SET + 8, NEXT, CLEAR, SET + 14, NEXT, - FPS, 9, CLEAR, SET + 2, NEXT, CLEAR, SET + 15, NEXT, - FPS, 10, CLEAR, SET + 8, NEXT, CLEAR, SET + 14, NEXT, - FPS, 10, CLEAR, SET + 2, NEXT, CLEAR, SET + 15, NEXT, - CLEAR, SET + 8, NEXT, CLEAR, SET + 12, NEXT, // Umfallen - CLEAR, SET + 4, NEXT, CLEAR, SET + 5, NEXT, CLEAR, SET + 6, NEXT, // Ebenen - CLEAR, SET + 1, NEXT, CLEAR, SET + 2, NEXT, CLEAR, SET + 3, NEXT, - CLEAR, SET + 7, NEXT, CLEAR, SET + 8, NEXT, CLEAR, SET + 9, NEXT, - - FPS, 10, // Außen langlaufen - - CLEAR, - PSET(0,0,0), PSET(1,0,0), PSET(0,1,0), PSET(1,1,0), PSET(0,2,0), PSET(1,2,0), NEXT, - PCLEAR(0,0,0), PSET(2,0,0), PCLEAR(0,1,0), PSET(2,1,0), PCLEAR(0,2,0), PSET(2,2,0), NEXT, - PCLEAR(1,0,0), PSET(2,0,1), PCLEAR(1,1,0), PSET(2,1,1), PCLEAR(1,2,0), PSET(2,2,1), NEXT, - PCLEAR(2,0,0), PSET(2,0,2), PCLEAR(2,1,0), PSET(2,1,2), PCLEAR(2,2,0), PSET(2,2,2), NEXT, - PCLEAR(2,0,1), PSET(1,0,2), PCLEAR(2,1,1), PSET(1,1,2), PCLEAR(2,2,1), PSET(1,2,2), NEXT, - PCLEAR(2,0,2), PSET(0,0,2), PCLEAR(2,1,2), PSET(0,1,2), PCLEAR(2,2,2), PSET(0,2,2), NEXT, - PCLEAR(1,0,2), PSET(0,0,1), PCLEAR(1,1,2), PSET(0,1,1), PCLEAR(1,2,2), PSET(0,2,1), NEXT, - PCLEAR(0,0,2), PSET(0,0,0), PCLEAR(0,1,2), PSET(0,1,0), PCLEAR(0,2,2), PSET(0,2,0), NEXT, - PCLEAR(0,0,1), PCLEAR(0,1,1), PCLEAR(0,2,1), - - SET + 7, NEXT, CLEAR, SET + 8, NEXT, CLEAR, SET + 9, NEXT, - CLEAR, SET + 8, NEXT, CLEAR, SET + 7, NEXT, -}; - -const prog_char *program_pointer = program_1; -unsigned int program_length = sizeof(program_1); -*/ #endif // __main_h__ diff --git a/firmware/usb.c b/firmware/usb.c index fdcf4f5..3915e30 100644 --- a/firmware/usb.c +++ b/firmware/usb.c @@ -12,19 +12,43 @@ usbMsgLen_t usbFunctionSetup(uchar data[8]) { -usbRequest_t *rq = (void *)data; + usbRequest_t *rq = (void *)data; - if((rq->bmRequestType & USBRQ_TYPE_MASK) == USBRQ_TYPE_VENDOR){ - if(rq->bRequest == CUSTOM_RQ_SET_STATUS){ + if ( (rq->bmRequestType & USBRQ_TYPE_MASK) == USBRQ_TYPE_VENDOR ) + { + if ( rq->bRequest == CUSTOM_RQ_SET_STATUS ) + { - // receive animation data + /*if (rq->wIndex.bytes[0] == 0) + cube[0][0][0] = 1; + if (rq->wIndex.bytes[0] == 1) + cube[0][0][1] = 1; + if (rq->wIndex.bytes[0] == 2) + cube[0][0][2] = 1; + if (rq->wIndex.bytes[0] == 3) + cube[0][1][0] = 1;*/ + + if (rq->wIndex.bytes[0] == 0) + x = rq->wValue.bytes[0]; + + else if (rq->wIndex.bytes[0] == 1) + y = rq->wValue.bytes[0]; + + else if (rq->wIndex.bytes[0] == 2) + z = rq->wValue.bytes[0]; + + else if (rq->wIndex.bytes[0] == 3) + cube[x][y][z] = rq->wValue.bytes[0]; + + } else if ( rq->bRequest == CUSTOM_RQ_GET_STATUS ) { + // Send one byte to the USB host. - }else if(rq->bRequest == CUSTOM_RQ_GET_STATUS){ //static uchar dataBuffer[1]; // buffer must stay valid when usbFunctionSetup returns - //dataBuffer[0] = ((LED_PORT_OUTPUT & _BV(LED_BIT)) != 0); - //usbMsgPtr = dataBuffer; // tell the driver which data to return + //usbMsgPtr = 0; // tell the driver which data to return //return 1; // tell the driver to send 1 byte - return 0; // tell the driver to send 1 byte + + //return 0; // tell the driver to send 0 byte + } }else{ /* class requests USBRQ_HID_GET_REPORT and USBRQ_HID_SET_REPORT are @@ -43,11 +67,14 @@ void init_usb(void) usbInit(); usbDeviceDisconnect(); /* enforce re-enumeration, do this while interrupts are disabled! */ + i = 0; while(--i){ /* fake USB disconnect for > 250 ms */ //wdt_reset(); _delay_ms(1); + //sleep_nop(255); } + usbDeviceConnect(); sei(); // enable global interrupts @@ -68,7 +95,7 @@ void init_usb(void) ...mainloop start... - wdt_reset(); // we are alive, please dont reset the µC + wdt_reset(); // we are alive, please dont reset the µC (optional) usbPoll(); // keep the usb connection up ...end mainloop... diff --git a/firmware/usb.h b/firmware/usb.h index eeae5c1..f1e4c03 100644 --- a/firmware/usb.h +++ b/firmware/usb.h @@ -10,6 +10,8 @@ #ifndef __usb_h__ #define __usb_h__ +#include "globals.h" + /* This example should run on most AVRs with only little changes. No special hardware resources except INT0 are used. You may have to change usbconfig.h for @@ -19,12 +21,11 @@ We assume that an LED is connected to port B bit 0. If you connect it to a different port or bit, change the macros below: */ -#include -//#include #include /* for sei() */ +//#include +//#include #include /* for _delay_ms() */ - -#include /* required by usbdrv.h */ +//#include /* required by usbdrv.h */ #include "usbconfig.h" #include "usbdrv.h" @@ -54,6 +55,13 @@ PROGMEM char usbHidReportDescriptor[22] = { /* USB report descriptor */ void init_usb(void); +volatile uint8_t x; +volatile uint8_t y; +volatile uint8_t z; + +// usb buffer +//extern uint8_t buffer[3][3][3]; // Framebuffer +extern uint8_t cube[3][3][3]; // Framebuffer #endif // __usb_h__ diff --git a/firmware/usbconfig.h b/firmware/usbconfig.h index 2562001..c7e6685 100644 --- a/firmware/usbconfig.h +++ b/firmware/usbconfig.h @@ -27,11 +27,11 @@ section at the end of this file). /* This is the port where the USB bus is connected. When you configure it to * "B", the registers PORTB, PINB and DDRB will be used. */ -#define USB_CFG_DMINUS_BIT 3 +#define USB_CFG_DMINUS_BIT 1 /* This is the bit number in USB_CFG_IOPORT where the USB D- line is connected. * This may be any bit in the port. */ -#define USB_CFG_DPLUS_BIT 6 +#define USB_CFG_DPLUS_BIT 2 /* This is the bit number in USB_CFG_IOPORT where the USB D+ line is connected. * This may be any bit in the port. Please note that D+ must also be connected * to interrupt pin INT0! [You can also use other interrupts, see section @@ -116,7 +116,7 @@ section at the end of this file). /* Define this to 1 if the device has its own power supply. Set it to 0 if the * device is powered from the USB bus. */ -#define USB_CFG_MAX_BUS_POWER 200 +#define USB_CFG_MAX_BUS_POWER 250 /* Set this variable to the maximum USB bus power consumption of your device. * The value is in milliamperes. [It will be divided by two since USB * communicates power requirements in units of 2 mA.]